membership.create() checks for joinable and player limit; factory creates joinable lexicons by default #10
74
amanuensis/backend/index.py
Normal file
74
amanuensis/backend/index.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
"""
|
||||||
|
Index query interface
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from amanuensis.db import DbContext, ArticleIndex, IndexType
|
||||||
|
from amanuensis.errors import ArgumentError
|
||||||
|
|
||||||
|
|
||||||
|
def create(
|
||||||
|
db: DbContext,
|
||||||
|
lexicon_id: int,
|
||||||
|
index_type: IndexType,
|
||||||
|
pattern: str,
|
||||||
|
logical_order: int,
|
||||||
|
display_order: int,
|
||||||
|
capacity: Optional[int],
|
||||||
|
) -> ArticleIndex:
|
||||||
|
"""
|
||||||
|
Create a new index in a lexicon.
|
||||||
|
"""
|
||||||
|
# Verify argument types are correct
|
||||||
|
if not isinstance(lexicon_id, int):
|
||||||
|
raise ArgumentError("lexicon_id")
|
||||||
|
if not isinstance(index_type, IndexType):
|
||||||
|
raise ArgumentError("index_type")
|
||||||
|
if not isinstance(pattern, str):
|
||||||
|
raise ArgumentError("pattern")
|
||||||
|
if not isinstance(logical_order, int):
|
||||||
|
raise ArgumentError("logical_order")
|
||||||
|
if not isinstance(display_order, int):
|
||||||
|
raise ArgumentError("display_order")
|
||||||
|
if capacity is not None and not isinstance(capacity, int):
|
||||||
|
raise ArgumentError("capacity")
|
||||||
|
|
||||||
|
# Verify the pattern is valid for the index type:
|
||||||
|
if index_type == IndexType.CHAR:
|
||||||
|
if len(pattern) < 1:
|
||||||
|
raise ArgumentError(
|
||||||
|
f"Pattern '{pattern}' too short for index type {index_type}"
|
||||||
|
)
|
||||||
|
elif index_type == IndexType.RANGE:
|
||||||
|
range_def = re.match(r"^(.)-(.)$", pattern)
|
||||||
|
if not range_def:
|
||||||
|
raise ArgumentError(f"Pattern '{pattern}' is not a valid range format")
|
||||||
|
start_char, end_char = range_def.group(1), range_def.group(2)
|
||||||
|
if start_char >= end_char:
|
||||||
|
raise ArgumentError(
|
||||||
|
f"Range start '{start_char}' is not before range end '{end_char}'"
|
||||||
|
)
|
||||||
|
elif index_type == IndexType.PREFIX:
|
||||||
|
if len(pattern) < 1:
|
||||||
|
raise ArgumentError(
|
||||||
|
f"Pattern '{pattern}' too short for index type {index_type}"
|
||||||
|
)
|
||||||
|
elif index_type == IndexType.ETC:
|
||||||
|
if len(pattern) < 1:
|
||||||
|
raise ArgumentError(
|
||||||
|
f"Pattern '{pattern}' too short for index type {index_type}"
|
||||||
|
)
|
||||||
|
|
||||||
|
new_index = ArticleIndex(
|
||||||
|
lexicon_id=lexicon_id,
|
||||||
|
index_type=index_type,
|
||||||
|
pattern=pattern,
|
||||||
|
logical_order=logical_order,
|
||||||
|
display_order=display_order,
|
||||||
|
capacity=capacity,
|
||||||
|
)
|
||||||
|
db.session.add(new_index)
|
||||||
|
db.session.commit()
|
||||||
|
return new_index
|
50
tests/test_index.py
Normal file
50
tests/test_index.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
from amanuensis.db.models import IndexType
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import amanuensis.backend.index as indq
|
||||||
|
from amanuensis.db import DbContext, Lexicon, User
|
||||||
|
|
||||||
|
from amanuensis.errors import ArgumentError
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_index(db: DbContext, make):
|
||||||
|
"""Test new index creation"""
|
||||||
|
lexicon: Lexicon = make.lexicon()
|
||||||
|
defaults: dict = {
|
||||||
|
"db": db,
|
||||||
|
"lexicon_id": lexicon.id,
|
||||||
|
"index_type": IndexType.ETC,
|
||||||
|
"pattern": "&c.",
|
||||||
|
"logical_order": 0,
|
||||||
|
"display_order": 0,
|
||||||
|
"capacity": 0,
|
||||||
|
}
|
||||||
|
kwargs: dict
|
||||||
|
|
||||||
|
# Character indexes require nonempty patterns
|
||||||
|
with pytest.raises(ArgumentError):
|
||||||
|
kwargs = {**defaults, "index_type": IndexType.CHAR, "pattern": ""}
|
||||||
|
indq.create(**kwargs)
|
||||||
|
kwargs = {**defaults, "index_type": IndexType.CHAR, "pattern": "ABC"}
|
||||||
|
assert indq.create(**kwargs)
|
||||||
|
|
||||||
|
# Range indexes must follow the 1-2 format
|
||||||
|
with pytest.raises(ArgumentError):
|
||||||
|
kwargs = {**defaults, "index_type": IndexType.RANGE, "pattern": "ABC"}
|
||||||
|
indq.create(**kwargs)
|
||||||
|
kwargs = {**defaults, "index_type": IndexType.RANGE, "pattern": "A-F"}
|
||||||
|
assert indq.create(**kwargs)
|
||||||
|
|
||||||
|
# Prefix indexes require nonempty patterns
|
||||||
|
with pytest.raises(ArgumentError):
|
||||||
|
kwargs = {**defaults, "index_type": IndexType.CHAR, "pattern": ""}
|
||||||
|
indq.create(**kwargs)
|
||||||
|
kwargs = {**defaults, "index_type": IndexType.CHAR, "pattern": "Prefix:"}
|
||||||
|
assert indq.create(**kwargs)
|
||||||
|
|
||||||
|
# Etc indexes require nonempty patterns
|
||||||
|
with pytest.raises(ArgumentError):
|
||||||
|
kwargs = {**defaults, "index_type": IndexType.CHAR, "pattern": ""}
|
||||||
|
indq.create(**kwargs)
|
||||||
|
kwargs = {**defaults, "index_type": IndexType.CHAR, "pattern": "&c."}
|
||||||
|
assert indq.create(**kwargs)
|
Loading…
Reference in New Issue
Block a user