Skip to content

Commit 4534b4c

Browse files
committed
adding xfix style queries
1 parent f1ed5b2 commit 4534b4c

File tree

3 files changed

+99
-5
lines changed

3 files changed

+99
-5
lines changed

aredis_om/model/model.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
TypeVar,
2323
Union,
2424
)
25-
from typing import get_args as typing_get_args, no_type_check
25+
from typing import get_args as typing_get_args
26+
from typing import no_type_check
2627

2728
from more_itertools import ichunked
2829
from redis.commands.json.path import Path
@@ -112,6 +113,9 @@ class Operators(Enum):
112113
NOT_IN = 11
113114
LIKE = 12
114115
ALL = 13
116+
STARTSWITH = 14
117+
ENDSWITH = 15
118+
CONTAINS = 16
115119

116120
def __str__(self):
117121
return str(self.name)
@@ -346,6 +350,21 @@ def __rshift__(self, other: Any) -> Expression:
346350
left=self.field, op=Operators.NOT_IN, right=other, parents=self.parents
347351
)
348352

353+
def startswith(self, other: Any) -> Expression:
354+
return Expression(
355+
left=self.field, op=Operators.STARTSWITH, right=other, parents=self.parents
356+
)
357+
358+
def endswith(self, other: Any) -> Expression:
359+
return Expression(
360+
left=self.field, op=Operators.ENDSWITH, right=other, parents=self.parents
361+
)
362+
363+
def contains(self, other: Any) -> Expression:
364+
return Expression(
365+
left=self.field, op=Operators.CONTAINS, right=other, parents=self.parents
366+
)
367+
349368
def __getattr__(self, item):
350369
if item.startswith("__"):
351370
raise AttributeError("cannot invoke __getattr__ with reserved field")
@@ -691,6 +710,21 @@ def resolve_value(
691710
result += "-(@{field_name}:{{{expanded_value}}})".format(
692711
field_name=field_name, expanded_value=expanded_value
693712
)
713+
elif op is Operators.STARTSWITH:
714+
expanded_value = cls.expand_tag_value(value)
715+
result += "(@{field_name}:{{{expanded_value}*}})".format(
716+
field_name=field_name, expanded_value=expanded_value
717+
)
718+
elif op is Operators.ENDSWITH:
719+
expanded_value = cls.expand_tag_value(value)
720+
result += "(@{field_name}:{{*{expanded_value}}})".format(
721+
field_name=field_name, expanded_value=expanded_value
722+
)
723+
elif op is Operators.CONTAINS:
724+
expanded_value = cls.expand_tag_value(value)
725+
result += "(@{field_name}:{{*{expanded_value}*}})".format(
726+
field_name=field_name, expanded_value=expanded_value
727+
)
694728

695729
return result
696730

tests/test_hash_model.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,3 +841,26 @@ class TypeWithUuid(HashModel):
841841
item = TypeWithUuid(uuid=uuid.uuid4())
842842

843843
await item.save()
844+
845+
846+
@py_test_mark_asyncio
847+
async def test_xfix_queries(members, m):
848+
member1, member2, member3 = members
849+
850+
result = await m.Member.find(m.Member.first_name.startswith("And")).first()
851+
assert result.first_name == "Andrew"
852+
853+
result = await m.Member.find(m.Member.last_name.endswith("ins")).first()
854+
assert result.first_name == "Andrew"
855+
856+
result = await m.Member.find(m.Member.last_name.contains("ook")).first()
857+
assert result.first_name == "Andrew"
858+
859+
result = await m.Member.find(m.Member.bio % "great*").first()
860+
assert result.first_name == "Andrew"
861+
862+
result = await m.Member.find(m.Member.bio % "*rty").first()
863+
assert result.first_name == "Andrew"
864+
865+
result = await m.Member.find(m.Member.bio % "*eat*").first()
866+
assert result.first_name == "Andrew"

tests/test_json_model.py

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -454,15 +454,15 @@ async def test_in_query(members, m):
454454
)
455455
assert actual == [member2, member1, member3]
456456

457+
457458
@py_test_mark_asyncio
458459
async def test_not_in_query(members, m):
459460
member1, member2, member3 = members
460461
actual = await (
461-
m.Member.find(m.Member.pk >> [member2.pk, member3.pk])
462-
.sort_by("age")
463-
.all()
462+
m.Member.find(m.Member.pk >> [member2.pk, member3.pk]).sort_by("age").all()
464463
)
465-
assert actual == [ member1]
464+
assert actual == [member1]
465+
466466

467467
@py_test_mark_asyncio
468468
async def test_update_query(members, m):
@@ -923,3 +923,40 @@ class TypeWithUuid(JsonModel):
923923
item = TypeWithUuid(uuid=uuid.uuid4())
924924

925925
await item.save()
926+
927+
928+
@py_test_mark_asyncio
929+
async def test_xfix_queries(m):
930+
await m.Member(
931+
first_name="Steve",
932+
last_name="Lorello",
933+
934+
join_date=today,
935+
bio="Steve is a two-bit hacker who loves Redis.",
936+
address=m.Address(
937+
address_line_1="42 foo bar lane",
938+
city="Satellite Beach",
939+
state="FL",
940+
country="USA",
941+
postal_code="32999",
942+
),
943+
age=34,
944+
).save()
945+
946+
result = await m.Member.find(m.Member.first_name.startswith("Ste")).first()
947+
assert result.first_name == "Steve"
948+
949+
result = await m.Member.find(m.Member.last_name.endswith("llo")).first()
950+
assert result.first_name == "Steve"
951+
952+
result = await m.Member.find(m.Member.address.city.contains("llite")).first()
953+
assert result.first_name == "Steve"
954+
955+
result = await m.Member.find(m.Member.bio % "tw*").first()
956+
assert result.first_name == "Steve"
957+
958+
result = await m.Member.find(m.Member.bio % "*cker").first()
959+
assert result.first_name == "Steve"
960+
961+
result = await m.Member.find(m.Member.bio % "*ack*").first()
962+
assert result.first_name == "Steve"

0 commit comments

Comments
 (0)