From 2df1beb6cbfbfa05f4b7505ed7f53a7d3fa9ab10 Mon Sep 17 00:00:00 2001 From: savynorem Date: Fri, 5 Jul 2024 12:40:45 -0400 Subject: [PATCH 01/11] added return_fields function, attempting to optionally limit fields returned by find --- aredis_om/model/model.py | 26 +++++++++++++++++++++++++- tests/test_json_model.py | 14 +++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/aredis_om/model/model.py b/aredis_om/model/model.py index f95d4ce5..2e45b801 100644 --- a/aredis_om/model/model.py +++ b/aredis_om/model/model.py @@ -421,6 +421,7 @@ def __init__( limit: Optional[int] = None, page_size: int = DEFAULT_PAGE_SIZE, sort_fields: Optional[List[str]] = None, + return_fields: Optional[List[str]] = None, nocontent: bool = False, ): if not has_redisearch(model.db()): @@ -445,6 +446,11 @@ def __init__( else: self.sort_fields = [] + if return_fields: + self.return_fields = self.validate_return_fields(return_fields) + else: + self.return_fields = [] + self._expression = None self._query: Optional[str] = None self._pagination: List[str] = [] @@ -502,8 +508,19 @@ def query(self): if self._query.startswith("(") or self._query == "*" else f"({self._query})" ) + f"=>[{self.knn}]" + if self.return_fields: + self._query += f" RETURN {','.join(self.return_fields)}" return self._query + def validate_return_fields(self, return_fields: List[str]): + for field in return_fields: + if field not in self.model.__fields__: # type: ignore + raise QueryNotSupportedError( + f"You tried to return the field {field}, but that field " + f"does not exist on the model {self.model}" + ) + return return_fields + @property def query_params(self): params: List[Union[str, bytes]] = [] @@ -956,6 +973,11 @@ def sort_by(self, *fields: str): if not fields: return self return self.copy(sort_fields=list(fields)) + + def return_fields(self, *fields: str): + if not fields: + return self + return self.copy(return_fields=list(fields)) async def update(self, use_transaction=True, **field_values): """ @@ -1531,7 +1553,9 @@ def find( *expressions: Union[Any, Expression], knn: Optional[KNNExpression] = None, ) -> FindQuery: - return FindQuery(expressions=expressions, knn=knn, model=cls) + return FindQuery( + expressions=expressions, knn=knn, model=cls + ) @classmethod def from_redis(cls, res: Any): diff --git a/tests/test_json_model.py b/tests/test_json_model.py index 267185a5..0c1db1de 100644 --- a/tests/test_json_model.py +++ b/tests/test_json_model.py @@ -935,9 +935,21 @@ class TypeWithUuid(JsonModel): await item.save() +@py_test_mark_asyncio +async def test_return_specified_fields(members, m): + member1, member2, member3 = members + actual = await m.Member.find( + (m.Member.first_name == "Andrew") & (m.Member.last_name == "Brookins") + | (m.Member.last_name == "Smith") + ).all() + assert actual == [ + {"first_name": "Andrew", "last_name": "Brookins"}, + {"first_name": "Andrew", "last_name": "Smith"}, + ] + @py_test_mark_asyncio -async def test_xfix_queries(m): +async def test_xfix_queries(m):4 await m.Member( first_name="Steve", last_name="Lorello", From b989e425cb8621adb7707be07c02334a80d0f640 Mon Sep 17 00:00:00 2001 From: savynorem Date: Tue, 23 Jul 2024 16:04:43 -0400 Subject: [PATCH 02/11] added call to get query, adding tests --- aredis_om/model/model.py | 16 +- tests/test_find_query.py | 356 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 364 insertions(+), 8 deletions(-) create mode 100644 tests/test_find_query.py diff --git a/aredis_om/model/model.py b/aredis_om/model/model.py index 2e45b801..93e8c358 100644 --- a/aredis_om/model/model.py +++ b/aredis_om/model/model.py @@ -508,8 +508,6 @@ def query(self): if self._query.startswith("(") or self._query == "*" else f"({self._query})" ) + f"=>[{self.knn}]" - if self.return_fields: - self._query += f" RETURN {','.join(self.return_fields)}" return self._query def validate_return_fields(self, return_fields: List[str]): @@ -888,7 +886,7 @@ def resolve_redisearch_query(cls, expression: ExpressionOrNegated) -> str: return result - async def execute(self, exhaust_results=True, return_raw_result=False): + async def execute(self, exhaust_results=True, return_raw_result=False, return_query_args=False): args: List[Union[str, bytes]] = [ "FT.SEARCH", self.model.Meta.index_name, @@ -912,6 +910,9 @@ async def execute(self, exhaust_results=True, return_raw_result=False): if self.nocontent: args.append("NOCONTENT") + + if return_query_args: + return self.model.Meta.index_name, args # Reset the cache if we're executing from offset 0. if self.offset == 0: @@ -945,6 +946,10 @@ async def execute(self, exhaust_results=True, return_raw_result=False): break self._model_cache += _results return self._model_cache + + async def get_query(self): + query = self.copy() + return await query.execute(return_query_args=True) async def first(self): query = self.copy(offset=0, limit=1, sort_fields=self.sort_fields) @@ -973,11 +978,6 @@ def sort_by(self, *fields: str): if not fields: return self return self.copy(sort_fields=list(fields)) - - def return_fields(self, *fields: str): - if not fields: - return self - return self.copy(return_fields=list(fields)) async def update(self, use_transaction=True, **field_values): """ diff --git a/tests/test_find_query.py b/tests/test_find_query.py new file mode 100644 index 00000000..82ff1397 --- /dev/null +++ b/tests/test_find_query.py @@ -0,0 +1,356 @@ +# type: ignore + +import abc +import dataclasses +import datetime +import decimal +import uuid +from collections import namedtuple +from typing import Dict, List, Optional, Set, Union +from unittest import mock + +import pytest +import pytest_asyncio + +from aredis_om import ( + EmbeddedJsonModel, + Field, + JsonModel, + Migrator, + NotFoundError, + QueryNotSupportedError, + RedisModelError, + FindQuery, +) + +# We need to run this check as sync code (during tests) even in async mode +# because we call it in the top-level module scope. +from redis_om import has_redis_json +from tests._compat import EmailStr, PositiveInt, ValidationError + +from .conftest import py_test_mark_asyncio + + +if not has_redis_json(): + pytestmark = pytest.mark.skip + +today = datetime.date.today() + +@pytest_asyncio.fixture +async def m(key_prefix, redis): + class BaseJsonModel(JsonModel, abc.ABC): + class Meta: + global_key_prefix = key_prefix + + class Note(EmbeddedJsonModel): + # TODO: This was going to be a full-text search example, but + # we can't index embedded documents for full-text search in + # the preview release. + description: str = Field(index=True) + created_on: datetime.datetime + + class Address(EmbeddedJsonModel): + address_line_1: str + address_line_2: Optional[str] = None + city: str = Field(index=True) + state: str + country: str + postal_code: str = Field(index=True) + note: Optional[Note] = None + + class Item(EmbeddedJsonModel): + price: decimal.Decimal + name: str = Field(index=True) + + class Order(EmbeddedJsonModel): + items: List[Item] + created_on: datetime.datetime + + class Member(BaseJsonModel): + first_name: str = Field(index=True, case_sensitive=True) + last_name: str = Field(index=True) + email: Optional[EmailStr] = Field(index=True, default=None) + join_date: datetime.date + age: Optional[PositiveInt] = Field(index=True, default=None) + bio: Optional[str] = Field(index=True, full_text_search=True, default="") + + # Creates an embedded model. + address: Address + + # Creates an embedded list of models. + orders: Optional[List[Order]] = None + + await Migrator().run() + + return namedtuple( + "Models", ["BaseJsonModel", "Note", "Address", "Item", "Order", "Member"] + )(BaseJsonModel, Note, Address, Item, Order, Member) + + +@pytest.fixture() +def address(m): + try: + yield m.Address( + address_line_1="1 Main St.", + city="Portland", + state="OR", + country="USA", + postal_code="11111", + ) + except Exception as e: + raise e + + +@pytest_asyncio.fixture() +async def members(address, m): + member1 = m.Member( + first_name="Andrew", + last_name="Brookins", + email="a@example.com", + age=38, + join_date=today, + address=address, + bio="Andrew is a software engineer", + ) + + member2 = m.Member( + first_name="Kim", + last_name="Brookins", + email="k@example.com", + age=34, + join_date=today, + address=address, + bio="Kim does not work in tech", + ) + + member3 = m.Member( + first_name="Andrew", + last_name="Smith", + email="as@example.com", + age=100, + join_date=today, + address=address, + bio="Andrew is old", + ) + + await member1.save() + await member2.save() + await member3.save() + + yield member1, member2, member3 + +# test model class and instantiate FindQuery +# 20 queries / expressions +""" +@py_test_mark_asyncio +async def test_find_query1(members, m): + member1, member2, member3 = members + x = m.Member.find() + # print(x.query) + # result is "*" + +@py_test_mark_asyncio +async def test_find_query2(members, m): + member1, member2, member3 = members + x = m.Member.find() + # print(x._query) + # result is "None" + + +@py_test_mark_asyncio +async def test_find_query3(members, m): + member1, member2, member3 = members + fq = FindQuery(expressions=[m.Member.pk >> [member2.pk, member3.pk]], model=m.Member) + # print(fq) + # result is "" + +@py_test_mark_asyncio +async def test_find_query4(members, m): + member1, member2, member3 = members + fq = FindQuery(expressions=[m.Member.pk << [member1.pk, member2.pk, member3.pk]], model=m.Member) + # print(fq.query) + # result is "(@pk:{01J33M1FMX4DHRMX16E4YAYCM3|01J33M1FN087RZVRZP6GN3BZZT|01J33M1FN1JNP0MXBRNANV5C88})" + +@py_test_mark_asyncio +async def test_find_query5(members, m): + member1, member2, member3 = members + fq = FindQuery(expressions=[m.Member.pk << [member1.pk, member2.pk, member3.pk]], model=m.Member) + # print(fq._query) + # result is "None" + +@py_test_mark_asyncio +async def test_find_query6(members, m): + member1, member2, member3 = members + fq = FindQuery(expressions=[m.Member.pk << [member1.pk, member2.pk, member3.pk]], model=m.Member) + # print(fq.command_str_list) + # result is [] + +@py_test_mark_asyncio +async def test_find_query7(members, m): + member1, member2, member3 = members + fq = await FindQuery(expressions=[m.Member.pk << [member1.pk, member2.pk, member3.pk]], model=m.Member).all() + # print(fq.query) + # result is AttributeError: 'list' object has no attribute 'query' """ + +# added get_query method and optional return_query_args to execute() +# now that we can actually get to the query, let's test what the query is when we add a filter + +@py_test_mark_asyncio +async def test_find_query_in(members, m): + member1, member2, member3 = members + model_name, fq = await FindQuery(expressions=[m.Member.pk << [member1.pk, member2.pk, member3.pk]], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.6121599113607783:tests.test_find_query.Member:index', '(@pk:{01J361ZHQQWHN9JTZD2FNX7E2P|01J361ZHQQG62Q2P19KW3CFHET|01J361ZHQQ03HH0WSH4NTM6T95})', 'LIMIT', 0, 1000] + in_str = "(@pk:{" + str(member1.pk) + "|" + str(member2.pk) + "|" + str(member3.pk) + "})" + assert fq == ['FT.SEARCH', model_name, in_str, 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_not_in(members, m): + member1, member2, member3 = members + model_name, fq = await FindQuery(expressions=[m.Member.pk >> [member2.pk, member3.pk]], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.6121599113607783:tests.test_find_query.Member:index', '-(@pk:{01J361ZHQQG62Q2P19KW3CFHET|01J361ZHQQ03HH0WSH4NTM6T95})', 'LIMIT', 0, 1000] + not_in_str = "-(@pk:{" + str(member2.pk) + "|" + str(member3.pk) + "})" + assert fq == ['FT.SEARCH', model_name, not_in_str, 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_eq(m): + model_name, fq = await FindQuery(expressions=[m.Member.first_name == "Andrew"], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.6121599113607783:tests.test_find_query.Member:index', '@first_name:{Andrew}', 'LIMIT', 0, 1000] + assert fq == ['FT.SEARCH', model_name, '@first_name:{Andrew}', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_ne(m): + model_name, fq = await FindQuery(expressions=[m.Member.first_name != "Andrew"], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '-(@first_name:{Andrew})', 'LIMIT', 0, 1000] + assert fq == ['FT.SEARCH', model_name, '-(@first_name:{Andrew})', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_lt(m): + model_name, fq = await FindQuery(expressions=[m.Member.age < 40], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '@age:[0 40}', 'LIMIT', 0, 1000] + assert fq == ['FT.SEARCH', model_name, '@age:[-inf (40]', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_le(m): + model_name, fq = await FindQuery(expressions=[m.Member.age <= 38], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '@age:[0 38]', 'LIMIT', 0, 1000] + assert fq == ['FT.SEARCH', model_name, '@age:[-inf 38]', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_gt(m): + model_name, fq = await FindQuery(expressions=[m.Member.age > 38], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '@age:[(38 +inf}', 'LIMIT', 0, 1000] + assert fq == ['FT.SEARCH', model_name, '@age:[(38 +inf]', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_ge(m): + model_name, fq = await FindQuery(expressions=[m.Member.age >= 38], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '@age:[38 +inf]', 'LIMIT', 0, 1000] + assert fq == ['FT.SEARCH', model_name, '@age:[38 +inf]', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_sort(m): + model_name, fq = await FindQuery(expressions=[m.Member.age > 0], model=m.Member, sort_fields=["age"]).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '@age:[(0 +inf]', 'LIMIT', 0, 1000, 'SORTBY', 'age', 'asc'] + assert fq == ['FT.SEARCH', model_name, '@age:[(0 +inf]', 'LIMIT', 0, 1000, 'SORTBY', 'age', 'asc'] + +@py_test_mark_asyncio +async def test_find_query_sort_desc(m): + model_name, fq = await FindQuery(expressions=[m.Member.age > 0], model=m.Member, sort_fields=["-age"]).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '@age:[(0 +inf]', 'LIMIT', 0, 1000, 'SORTBY', 'age', 'desc'] + assert fq == ['FT.SEARCH', model_name, '@age:[(0 +inf]', 'LIMIT', 0, 1000, 'SORTBY', 'age', 'desc'] + +@py_test_mark_asyncio +async def test_find_query_text_search(m): + model_name, fq = await FindQuery(expressions=[m.Member.bio == "test"], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '@bio:{test}', 'LIMIT', 0, 1000] + assert fq == ['FT.SEARCH', model_name, '@bio:{test}', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_text_search_and(m, members): + model_name, fq = await FindQuery(expressions=[m.Member.age < 40, m.Member.first_name == "Andrew"], model=m.Member).get_query() + # member1, member2, member3 = members + # query = m.Member.find( + # (m.Member.first_name == "Andrew") + # & (m.Member.age < 40) + # ) + # assert await query.all() == [member1] + + # res = await m.Member.find((m.Member.age < 40) & (m.Member.first_name == "Andrew")).all() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '(@age:[-inf (40]) @first_name:{Andrew}', 'LIMIT', 0, 1000] + # print(res) + assert fq == ['FT.SEARCH', model_name, '(@age:[-inf (40]) (@first_name:{Andrew})', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_text_search_or(m, members): + model_name, fq = await FindQuery(expressions=[(m.Member.age < 40) | (m.Member.first_name == "Andrew")], model=m.Member).get_query() + # print(fq) + # member1, member2, member3 = members + # query = m.Member.find( + # (m.Member.first_name == "Andrew") + # | (m.Member.age < 40) + # ) + # assert await query.all() == [member1, member2, member3] + # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '@bio:{test}', 'LIMIT', 0, 1000] + assert fq == ['FT.SEARCH', model_name, '(@age:[-inf (40])| (@first_name:{Andrew})', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_text_search_not(m): + model_name, fq = await FindQuery(expressions=[~(m.Member.first_name == "Andrew")], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '-(@first_name:{Andrew})', 'LIMIT', 0, 1000] + assert fq == ['FT.SEARCH', model_name, '-(@first_name:{Andrew})', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_text_search_not_and(m, members): + model_name, fq = await FindQuery(expressions=[~((m.Member.first_name == "Andrew") & (m.Member.age < 40))], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '-(@age:[-inf (40]) @first_name:{Andrew}', 'LIMIT', 0, 1000] + assert fq == ['FT.SEARCH', model_name, '-((@first_name:{Andrew}) (@age:[-inf (40]))', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_text_search_not_or(m, members): + model_name, fq = await FindQuery(expressions=[~((m.Member.first_name == "Andrew") | (m.Member.age < 40))], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '-(@age:[-inf (40])| (@first_name:{Andrew})', 'LIMIT', 0, 1000] + assert fq == ['FT.SEARCH', model_name, '-((@first_name:{Andrew})| (@age:[-inf (40]))', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_text_search_not_or_and(m, members): + model_name, fq = await FindQuery(expressions=[~(((m.Member.first_name == "Andrew") | (m.Member.age < 40)) & (m.Member.last_name == "Brookins"))], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '-((@first_name:{Andrew})| (@age:[-inf (40]) (@last_name:{Brookins}))', 'LIMIT', 0, 1000] + assert fq == ['FT.SEARCH', model_name, '-(((@first_name:{Andrew})| (@age:[-inf (40])) (@last_name:{Brookins}))', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_text_contains(m): + model_name, fq = await FindQuery(expressions=[m.Member.first_name.contains("drew")], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '@first_name:{*Andrew*}', 'LIMIT', 0, 1000] + assert fq == ['FT.SEARCH', model_name, '(@first_name:{*drew*})', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_text_startswith(m): + model_name, fq = await FindQuery(expressions=[m.Member.first_name.startswith("An")], model=m.Member).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '@first_name:{An*}', 'LIMIT', 0, 1000] + assert fq == ['FT.SEARCH', model_name, '(@first_name:{An*})', 'LIMIT', 0, 1000] + +# test that return_fields limits the fields returned +@py_test_mark_asyncio +async def test_find_query_return_fields(m): + model_name, fq = await FindQuery(expressions=[m.Member.first_name == "Andrew"], model=m.Member, return_fields=["first_name"]).get_query() + # print(fq) + # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '@first_name:{Andrew}', 'LIMIT', 0, 1000, 'RETURN', 1, 'first_name'] + # assert fq == ['FT.SEARCH', model_name, '@first_name:{Andrew}', 'LIMIT', 0, 1000, 'RETURN', 1, 'first_name'] \ No newline at end of file From e65127021a3642c4d198e0c9200c83328bd5c6ca Mon Sep 17 00:00:00 2001 From: savynorem Date: Tue, 23 Jul 2024 16:10:11 -0400 Subject: [PATCH 03/11] cleaned up test file, added endswith test --- tests/test_find_query.py | 117 +-------------------------------------- 1 file changed, 3 insertions(+), 114 deletions(-) diff --git a/tests/test_find_query.py b/tests/test_find_query.py index 82ff1397..9751d246 100644 --- a/tests/test_find_query.py +++ b/tests/test_find_query.py @@ -139,68 +139,11 @@ async def members(address, m): yield member1, member2, member3 -# test model class and instantiate FindQuery -# 20 queries / expressions -""" -@py_test_mark_asyncio -async def test_find_query1(members, m): - member1, member2, member3 = members - x = m.Member.find() - # print(x.query) - # result is "*" - -@py_test_mark_asyncio -async def test_find_query2(members, m): - member1, member2, member3 = members - x = m.Member.find() - # print(x._query) - # result is "None" - - -@py_test_mark_asyncio -async def test_find_query3(members, m): - member1, member2, member3 = members - fq = FindQuery(expressions=[m.Member.pk >> [member2.pk, member3.pk]], model=m.Member) - # print(fq) - # result is "" - -@py_test_mark_asyncio -async def test_find_query4(members, m): - member1, member2, member3 = members - fq = FindQuery(expressions=[m.Member.pk << [member1.pk, member2.pk, member3.pk]], model=m.Member) - # print(fq.query) - # result is "(@pk:{01J33M1FMX4DHRMX16E4YAYCM3|01J33M1FN087RZVRZP6GN3BZZT|01J33M1FN1JNP0MXBRNANV5C88})" - -@py_test_mark_asyncio -async def test_find_query5(members, m): - member1, member2, member3 = members - fq = FindQuery(expressions=[m.Member.pk << [member1.pk, member2.pk, member3.pk]], model=m.Member) - # print(fq._query) - # result is "None" - -@py_test_mark_asyncio -async def test_find_query6(members, m): - member1, member2, member3 = members - fq = FindQuery(expressions=[m.Member.pk << [member1.pk, member2.pk, member3.pk]], model=m.Member) - # print(fq.command_str_list) - # result is [] - -@py_test_mark_asyncio -async def test_find_query7(members, m): - member1, member2, member3 = members - fq = await FindQuery(expressions=[m.Member.pk << [member1.pk, member2.pk, member3.pk]], model=m.Member).all() - # print(fq.query) - # result is AttributeError: 'list' object has no attribute 'query' """ - -# added get_query method and optional return_query_args to execute() -# now that we can actually get to the query, let's test what the query is when we add a filter @py_test_mark_asyncio async def test_find_query_in(members, m): member1, member2, member3 = members model_name, fq = await FindQuery(expressions=[m.Member.pk << [member1.pk, member2.pk, member3.pk]], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.6121599113607783:tests.test_find_query.Member:index', '(@pk:{01J361ZHQQWHN9JTZD2FNX7E2P|01J361ZHQQG62Q2P19KW3CFHET|01J361ZHQQ03HH0WSH4NTM6T95})', 'LIMIT', 0, 1000] in_str = "(@pk:{" + str(member1.pk) + "|" + str(member2.pk) + "|" + str(member3.pk) + "})" assert fq == ['FT.SEARCH', model_name, in_str, 'LIMIT', 0, 1000] @@ -208,149 +151,95 @@ async def test_find_query_in(members, m): async def test_find_query_not_in(members, m): member1, member2, member3 = members model_name, fq = await FindQuery(expressions=[m.Member.pk >> [member2.pk, member3.pk]], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.6121599113607783:tests.test_find_query.Member:index', '-(@pk:{01J361ZHQQG62Q2P19KW3CFHET|01J361ZHQQ03HH0WSH4NTM6T95})', 'LIMIT', 0, 1000] not_in_str = "-(@pk:{" + str(member2.pk) + "|" + str(member3.pk) + "})" assert fq == ['FT.SEARCH', model_name, not_in_str, 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_eq(m): model_name, fq = await FindQuery(expressions=[m.Member.first_name == "Andrew"], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.6121599113607783:tests.test_find_query.Member:index', '@first_name:{Andrew}', 'LIMIT', 0, 1000] assert fq == ['FT.SEARCH', model_name, '@first_name:{Andrew}', 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_ne(m): model_name, fq = await FindQuery(expressions=[m.Member.first_name != "Andrew"], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '-(@first_name:{Andrew})', 'LIMIT', 0, 1000] assert fq == ['FT.SEARCH', model_name, '-(@first_name:{Andrew})', 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_lt(m): model_name, fq = await FindQuery(expressions=[m.Member.age < 40], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '@age:[0 40}', 'LIMIT', 0, 1000] assert fq == ['FT.SEARCH', model_name, '@age:[-inf (40]', 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_le(m): model_name, fq = await FindQuery(expressions=[m.Member.age <= 38], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '@age:[0 38]', 'LIMIT', 0, 1000] assert fq == ['FT.SEARCH', model_name, '@age:[-inf 38]', 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_gt(m): model_name, fq = await FindQuery(expressions=[m.Member.age > 38], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '@age:[(38 +inf}', 'LIMIT', 0, 1000] assert fq == ['FT.SEARCH', model_name, '@age:[(38 +inf]', 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_ge(m): model_name, fq = await FindQuery(expressions=[m.Member.age >= 38], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '@age:[38 +inf]', 'LIMIT', 0, 1000] assert fq == ['FT.SEARCH', model_name, '@age:[38 +inf]', 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_sort(m): model_name, fq = await FindQuery(expressions=[m.Member.age > 0], model=m.Member, sort_fields=["age"]).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '@age:[(0 +inf]', 'LIMIT', 0, 1000, 'SORTBY', 'age', 'asc'] assert fq == ['FT.SEARCH', model_name, '@age:[(0 +inf]', 'LIMIT', 0, 1000, 'SORTBY', 'age', 'asc'] @py_test_mark_asyncio async def test_find_query_sort_desc(m): model_name, fq = await FindQuery(expressions=[m.Member.age > 0], model=m.Member, sort_fields=["-age"]).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '@age:[(0 +inf]', 'LIMIT', 0, 1000, 'SORTBY', 'age', 'desc'] assert fq == ['FT.SEARCH', model_name, '@age:[(0 +inf]', 'LIMIT', 0, 1000, 'SORTBY', 'age', 'desc'] @py_test_mark_asyncio async def test_find_query_text_search(m): model_name, fq = await FindQuery(expressions=[m.Member.bio == "test"], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '@bio:{test}', 'LIMIT', 0, 1000] assert fq == ['FT.SEARCH', model_name, '@bio:{test}', 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_text_search_and(m, members): model_name, fq = await FindQuery(expressions=[m.Member.age < 40, m.Member.first_name == "Andrew"], model=m.Member).get_query() - # member1, member2, member3 = members - # query = m.Member.find( - # (m.Member.first_name == "Andrew") - # & (m.Member.age < 40) - # ) - # assert await query.all() == [member1] - - # res = await m.Member.find((m.Member.age < 40) & (m.Member.first_name == "Andrew")).all() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.491862029445422:tests.test_find_query.Member:index', '(@age:[-inf (40]) @first_name:{Andrew}', 'LIMIT', 0, 1000] - # print(res) assert fq == ['FT.SEARCH', model_name, '(@age:[-inf (40]) (@first_name:{Andrew})', 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_text_search_or(m, members): model_name, fq = await FindQuery(expressions=[(m.Member.age < 40) | (m.Member.first_name == "Andrew")], model=m.Member).get_query() - # print(fq) - # member1, member2, member3 = members - # query = m.Member.find( - # (m.Member.first_name == "Andrew") - # | (m.Member.age < 40) - # ) - # assert await query.all() == [member1, member2, member3] - # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '@bio:{test}', 'LIMIT', 0, 1000] assert fq == ['FT.SEARCH', model_name, '(@age:[-inf (40])| (@first_name:{Andrew})', 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_text_search_not(m): model_name, fq = await FindQuery(expressions=[~(m.Member.first_name == "Andrew")], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '-(@first_name:{Andrew})', 'LIMIT', 0, 1000] assert fq == ['FT.SEARCH', model_name, '-(@first_name:{Andrew})', 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_text_search_not_and(m, members): model_name, fq = await FindQuery(expressions=[~((m.Member.first_name == "Andrew") & (m.Member.age < 40))], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '-(@age:[-inf (40]) @first_name:{Andrew}', 'LIMIT', 0, 1000] assert fq == ['FT.SEARCH', model_name, '-((@first_name:{Andrew}) (@age:[-inf (40]))', 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_text_search_not_or(m, members): model_name, fq = await FindQuery(expressions=[~((m.Member.first_name == "Andrew") | (m.Member.age < 40))], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '-(@age:[-inf (40])| (@first_name:{Andrew})', 'LIMIT', 0, 1000] assert fq == ['FT.SEARCH', model_name, '-((@first_name:{Andrew})| (@age:[-inf (40]))', 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_text_search_not_or_and(m, members): model_name, fq = await FindQuery(expressions=[~(((m.Member.first_name == "Andrew") | (m.Member.age < 40)) & (m.Member.last_name == "Brookins"))], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '-((@first_name:{Andrew})| (@age:[-inf (40]) (@last_name:{Brookins}))', 'LIMIT', 0, 1000] assert fq == ['FT.SEARCH', model_name, '-(((@first_name:{Andrew})| (@age:[-inf (40])) (@last_name:{Brookins}))', 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_text_contains(m): model_name, fq = await FindQuery(expressions=[m.Member.first_name.contains("drew")], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '@first_name:{*Andrew*}', 'LIMIT', 0, 1000] assert fq == ['FT.SEARCH', model_name, '(@first_name:{*drew*})', 'LIMIT', 0, 1000] @py_test_mark_asyncio async def test_find_query_text_startswith(m): model_name, fq = await FindQuery(expressions=[m.Member.first_name.startswith("An")], model=m.Member).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '@first_name:{An*}', 'LIMIT', 0, 1000] assert fq == ['FT.SEARCH', model_name, '(@first_name:{An*})', 'LIMIT', 0, 1000] -# test that return_fields limits the fields returned @py_test_mark_asyncio -async def test_find_query_return_fields(m): - model_name, fq = await FindQuery(expressions=[m.Member.first_name == "Andrew"], model=m.Member, return_fields=["first_name"]).get_query() - # print(fq) - # result is ['FT.SEARCH', 'redis-om:testing:0.6510151538425774:tests.test_find_query.Member:index', '@first_name:{Andrew}', 'LIMIT', 0, 1000, 'RETURN', 1, 'first_name'] - # assert fq == ['FT.SEARCH', model_name, '@first_name:{Andrew}', 'LIMIT', 0, 1000, 'RETURN', 1, 'first_name'] \ No newline at end of file +async def test_find_query_text_endswith(m): + model_name, fq = await FindQuery(expressions=[m.Member.first_name.endswith("ew")], model=m.Member).get_query() + assert fq == ['FT.SEARCH', model_name, '(@first_name:{*ew})', 'LIMIT', 0, 1000] \ No newline at end of file From 8f1294cb4165299689c5005582cd6b47462a41e9 Mon Sep 17 00:00:00 2001 From: savynorem Date: Mon, 29 Jul 2024 11:50:40 -0400 Subject: [PATCH 04/11] cleaned up one more return fields line, added fuzzy matching and cleaned up some tests --- aredis_om/model/model.py | 6 ------ tests/test_find_query.py | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/aredis_om/model/model.py b/aredis_om/model/model.py index 93e8c358..6561bd4d 100644 --- a/aredis_om/model/model.py +++ b/aredis_om/model/model.py @@ -421,7 +421,6 @@ def __init__( limit: Optional[int] = None, page_size: int = DEFAULT_PAGE_SIZE, sort_fields: Optional[List[str]] = None, - return_fields: Optional[List[str]] = None, nocontent: bool = False, ): if not has_redisearch(model.db()): @@ -446,11 +445,6 @@ def __init__( else: self.sort_fields = [] - if return_fields: - self.return_fields = self.validate_return_fields(return_fields) - else: - self.return_fields = [] - self._expression = None self._query: Optional[str] = None self._pagination: List[str] = [] diff --git a/tests/test_find_query.py b/tests/test_find_query.py index 9751d246..715d79e8 100644 --- a/tests/test_find_query.py +++ b/tests/test_find_query.py @@ -21,6 +21,7 @@ QueryNotSupportedError, RedisModelError, FindQuery, + HashModel ) # We need to run this check as sync code (during tests) even in async mode @@ -120,7 +121,7 @@ async def members(address, m): age=34, join_date=today, address=address, - bio="Kim does not work in tech", + bio="Kim is a newer hire", ) member3 = m.Member( @@ -142,6 +143,7 @@ async def members(address, m): @py_test_mark_asyncio async def test_find_query_in(members, m): + # << means "in" member1, member2, member3 = members model_name, fq = await FindQuery(expressions=[m.Member.pk << [member1.pk, member2.pk, member3.pk]], model=m.Member).get_query() in_str = "(@pk:{" + str(member1.pk) + "|" + str(member2.pk) + "|" + str(member3.pk) + "})" @@ -149,11 +151,13 @@ async def test_find_query_in(members, m): @py_test_mark_asyncio async def test_find_query_not_in(members, m): + # >> means "not in" member1, member2, member3 = members model_name, fq = await FindQuery(expressions=[m.Member.pk >> [member2.pk, member3.pk]], model=m.Member).get_query() not_in_str = "-(@pk:{" + str(member2.pk) + "|" + str(member3.pk) + "})" assert fq == ['FT.SEARCH', model_name, not_in_str, 'LIMIT', 0, 1000] +# experssion testing; (==, !=, <, <=, >, >=, |, &, ~) @py_test_mark_asyncio async def test_find_query_eq(m): model_name, fq = await FindQuery(expressions=[m.Member.first_name == "Andrew"], model=m.Member).get_query() @@ -184,6 +188,7 @@ async def test_find_query_ge(m): model_name, fq = await FindQuery(expressions=[m.Member.age >= 38], model=m.Member).get_query() assert fq == ['FT.SEARCH', model_name, '@age:[38 +inf]', 'LIMIT', 0, 1000] +# tests for sorting and text search with and, or, not @py_test_mark_asyncio async def test_find_query_sort(m): model_name, fq = await FindQuery(expressions=[m.Member.age > 0], model=m.Member, sort_fields=["age"]).get_query() @@ -229,6 +234,7 @@ async def test_find_query_text_search_not_or_and(m, members): model_name, fq = await FindQuery(expressions=[~(((m.Member.first_name == "Andrew") | (m.Member.age < 40)) & (m.Member.last_name == "Brookins"))], model=m.Member).get_query() assert fq == ['FT.SEARCH', model_name, '-(((@first_name:{Andrew})| (@age:[-inf (40])) (@last_name:{Brookins}))', 'LIMIT', 0, 1000] +# text search operators; contains, startswith, endswith, fuzzy @py_test_mark_asyncio async def test_find_query_text_contains(m): model_name, fq = await FindQuery(expressions=[m.Member.first_name.contains("drew")], model=m.Member).get_query() @@ -242,4 +248,34 @@ async def test_find_query_text_startswith(m): @py_test_mark_asyncio async def test_find_query_text_endswith(m): model_name, fq = await FindQuery(expressions=[m.Member.first_name.endswith("ew")], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '(@first_name:{*ew})', 'LIMIT', 0, 1000] \ No newline at end of file + assert fq == ['FT.SEARCH', model_name, '(@first_name:{*ew})', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_test_fuzzy(m): + model_name, fq = await FindQuery(expressions=[m.Member.bio % '%newb%'], model=m.Member).get_query() + assert fq == ['FT.SEARCH', model_name, '@bio_fts:%newb%', 'LIMIT', 0, 1000] + +# limit, offset, page_size +@py_test_mark_asyncio +async def test_find_query_limit_one(m): + model_name, fq = await FindQuery(expressions=[m.Member.first_name == "Andrew"], model=m.Member, limit=1).get_query() + assert fq == ['FT.SEARCH', model_name, '@first_name:{Andrew}', 'LIMIT', 0, 1] + +@py_test_mark_asyncio +async def test_find_query_limit_offset(m): + model_name, fq = await FindQuery(expressions=[m.Member.first_name == "Andrew"], model=m.Member, limit=1, offset=1).get_query() + assert fq == ['FT.SEARCH', model_name, '@first_name:{Andrew}', 'LIMIT', 1, 1] + +@py_test_mark_asyncio +async def test_find_query_page_size(m): + # note that this test in unintuitive. + # page_size gets resolved in a while True loop that makes copies of the intial query and adds the limit and offset each time + model_name, fq = await FindQuery(expressions=[m.Member.first_name == "Andrew"], model=m.Member, page_size=1).get_query() + assert fq == ['FT.SEARCH', model_name, '@first_name:{Andrew}', 'LIMIT', 0, 1000] + +@py_test_mark_asyncio +async def test_find_query_monster(m): +# test monster query with everything everywhere all at once +# including ors, nots, ands, less thans, greater thans, text search + model_name, fq = await FindQuery(expressions=[~(((m.Member.first_name == "Andrew") | (m.Member.age < 40)) & ((m.Member.last_name.contains("oo") | ~(m.Member.email.startswith("z")))))], model=m.Member, limit=1, offset=1).get_query() + assert fq == ['FT.SEARCH', model_name, '-(((@first_name:{Andrew})| (@age:[-inf (40])) (((@last_name:{*oo*}))| -((@email:{z*}))))', 'LIMIT', 1, 1] From 6f1f4f941bdde3c575f45bf73e4e0cec305b4e17 Mon Sep 17 00:00:00 2001 From: Savannah Norem Date: Mon, 29 Jul 2024 12:11:02 -0400 Subject: [PATCH 05/11] remove changes - return_fields doesn't exist here, that'll be it's own branch --- tests/test_json_model.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/tests/test_json_model.py b/tests/test_json_model.py index 3ad7b5d1..47cfd2f8 100644 --- a/tests/test_json_model.py +++ b/tests/test_json_model.py @@ -950,21 +950,9 @@ class TypeWithUuid(JsonModel): await item.save() -@py_test_mark_asyncio -async def test_return_specified_fields(members, m): - member1, member2, member3 = members - actual = await m.Member.find( - (m.Member.first_name == "Andrew") & (m.Member.last_name == "Brookins") - | (m.Member.last_name == "Smith") - ).all() - assert actual == [ - {"first_name": "Andrew", "last_name": "Brookins"}, - {"first_name": "Andrew", "last_name": "Smith"}, - ] - @py_test_mark_asyncio -async def test_xfix_queries(m):4 +async def test_xfix_queries(m): await m.Member( first_name="Steve", last_name="Lorello", From 5430b48b75fc866843f6fde84fd3d3da93873dbb Mon Sep 17 00:00:00 2001 From: Savannah Norem Date: Mon, 29 Jul 2024 12:34:09 -0400 Subject: [PATCH 06/11] removing whitespace from blank lines for linter --- aredis_om/model/model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aredis_om/model/model.py b/aredis_om/model/model.py index 925ccb27..87fbbf52 100644 --- a/aredis_om/model/model.py +++ b/aredis_om/model/model.py @@ -905,7 +905,7 @@ async def execute(self, exhaust_results=True, return_raw_result=False, return_qu if self.nocontent: args.append("NOCONTENT") - + if return_query_args: return self.model.Meta.index_name, args @@ -941,7 +941,7 @@ async def execute(self, exhaust_results=True, return_raw_result=False, return_qu break self._model_cache += _results return self._model_cache - + async def get_query(self): query = self.copy() return await query.execute(return_query_args=True) From bd451d6b1ce363fac10260957e20d0a8e9ff11a7 Mon Sep 17 00:00:00 2001 From: slorello89 Date: Mon, 29 Jul 2024 12:47:37 -0400 Subject: [PATCH 07/11] fixing linter issues --- aredis_om/model/model.py | 8 +- tests/test_find_query.py | 280 +++++++++++++++++++++++++++++++-------- tests/test_json_model.py | 1 + 3 files changed, 229 insertions(+), 60 deletions(-) diff --git a/aredis_om/model/model.py b/aredis_om/model/model.py index 87fbbf52..3342f5f1 100644 --- a/aredis_om/model/model.py +++ b/aredis_om/model/model.py @@ -881,7 +881,9 @@ def resolve_redisearch_query(cls, expression: ExpressionOrNegated) -> str: return result - async def execute(self, exhaust_results=True, return_raw_result=False, return_query_args=False): + async def execute( + self, exhaust_results=True, return_raw_result=False, return_query_args=False + ): args: List[Union[str, bytes]] = [ "FT.SEARCH", self.model.Meta.index_name, @@ -1557,9 +1559,7 @@ def find( *expressions: Union[Any, Expression], knn: Optional[KNNExpression] = None, ) -> FindQuery: - return FindQuery( - expressions=expressions, knn=knn, model=cls - ) + return FindQuery(expressions=expressions, knn=knn, model=cls) @classmethod def from_redis(cls, res: Any): diff --git a/tests/test_find_query.py b/tests/test_find_query.py index 715d79e8..ecd14e4b 100644 --- a/tests/test_find_query.py +++ b/tests/test_find_query.py @@ -15,13 +15,13 @@ from aredis_om import ( EmbeddedJsonModel, Field, + FindQuery, + HashModel, JsonModel, Migrator, NotFoundError, QueryNotSupportedError, RedisModelError, - FindQuery, - HashModel ) # We need to run this check as sync code (during tests) even in async mode @@ -37,6 +37,7 @@ today = datetime.date.today() + @pytest_asyncio.fixture async def m(key_prefix, redis): class BaseJsonModel(JsonModel, abc.ABC): @@ -145,137 +146,304 @@ async def members(address, m): async def test_find_query_in(members, m): # << means "in" member1, member2, member3 = members - model_name, fq = await FindQuery(expressions=[m.Member.pk << [member1.pk, member2.pk, member3.pk]], model=m.Member).get_query() - in_str = "(@pk:{" + str(member1.pk) + "|" + str(member2.pk) + "|" + str(member3.pk) + "})" - assert fq == ['FT.SEARCH', model_name, in_str, 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[m.Member.pk << [member1.pk, member2.pk, member3.pk]], + model=m.Member, + ).get_query() + in_str = ( + "(@pk:{" + + str(member1.pk) + + "|" + + str(member2.pk) + + "|" + + str(member3.pk) + + "})" + ) + assert fq == ["FT.SEARCH", model_name, in_str, "LIMIT", 0, 1000] + @py_test_mark_asyncio async def test_find_query_not_in(members, m): # >> means "not in" member1, member2, member3 = members - model_name, fq = await FindQuery(expressions=[m.Member.pk >> [member2.pk, member3.pk]], model=m.Member).get_query() + model_name, fq = await FindQuery( + expressions=[m.Member.pk >> [member2.pk, member3.pk]], model=m.Member + ).get_query() not_in_str = "-(@pk:{" + str(member2.pk) + "|" + str(member3.pk) + "})" - assert fq == ['FT.SEARCH', model_name, not_in_str, 'LIMIT', 0, 1000] + assert fq == ["FT.SEARCH", model_name, not_in_str, "LIMIT", 0, 1000] + # experssion testing; (==, !=, <, <=, >, >=, |, &, ~) @py_test_mark_asyncio async def test_find_query_eq(m): - model_name, fq = await FindQuery(expressions=[m.Member.first_name == "Andrew"], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '@first_name:{Andrew}', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[m.Member.first_name == "Andrew"], model=m.Member + ).get_query() + assert fq == ["FT.SEARCH", model_name, "@first_name:{Andrew}", "LIMIT", 0, 1000] + @py_test_mark_asyncio async def test_find_query_ne(m): - model_name, fq = await FindQuery(expressions=[m.Member.first_name != "Andrew"], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '-(@first_name:{Andrew})', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[m.Member.first_name != "Andrew"], model=m.Member + ).get_query() + assert fq == ["FT.SEARCH", model_name, "-(@first_name:{Andrew})", "LIMIT", 0, 1000] + @py_test_mark_asyncio async def test_find_query_lt(m): - model_name, fq = await FindQuery(expressions=[m.Member.age < 40], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '@age:[-inf (40]', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[m.Member.age < 40], model=m.Member + ).get_query() + assert fq == ["FT.SEARCH", model_name, "@age:[-inf (40]", "LIMIT", 0, 1000] + @py_test_mark_asyncio async def test_find_query_le(m): - model_name, fq = await FindQuery(expressions=[m.Member.age <= 38], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '@age:[-inf 38]', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[m.Member.age <= 38], model=m.Member + ).get_query() + assert fq == ["FT.SEARCH", model_name, "@age:[-inf 38]", "LIMIT", 0, 1000] + @py_test_mark_asyncio async def test_find_query_gt(m): - model_name, fq = await FindQuery(expressions=[m.Member.age > 38], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '@age:[(38 +inf]', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[m.Member.age > 38], model=m.Member + ).get_query() + assert fq == ["FT.SEARCH", model_name, "@age:[(38 +inf]", "LIMIT", 0, 1000] + @py_test_mark_asyncio async def test_find_query_ge(m): - model_name, fq = await FindQuery(expressions=[m.Member.age >= 38], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '@age:[38 +inf]', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[m.Member.age >= 38], model=m.Member + ).get_query() + assert fq == ["FT.SEARCH", model_name, "@age:[38 +inf]", "LIMIT", 0, 1000] + # tests for sorting and text search with and, or, not @py_test_mark_asyncio async def test_find_query_sort(m): - model_name, fq = await FindQuery(expressions=[m.Member.age > 0], model=m.Member, sort_fields=["age"]).get_query() - assert fq == ['FT.SEARCH', model_name, '@age:[(0 +inf]', 'LIMIT', 0, 1000, 'SORTBY', 'age', 'asc'] + model_name, fq = await FindQuery( + expressions=[m.Member.age > 0], model=m.Member, sort_fields=["age"] + ).get_query() + assert fq == [ + "FT.SEARCH", + model_name, + "@age:[(0 +inf]", + "LIMIT", + 0, + 1000, + "SORTBY", + "age", + "asc", + ] + @py_test_mark_asyncio async def test_find_query_sort_desc(m): - model_name, fq = await FindQuery(expressions=[m.Member.age > 0], model=m.Member, sort_fields=["-age"]).get_query() - assert fq == ['FT.SEARCH', model_name, '@age:[(0 +inf]', 'LIMIT', 0, 1000, 'SORTBY', 'age', 'desc'] + model_name, fq = await FindQuery( + expressions=[m.Member.age > 0], model=m.Member, sort_fields=["-age"] + ).get_query() + assert fq == [ + "FT.SEARCH", + model_name, + "@age:[(0 +inf]", + "LIMIT", + 0, + 1000, + "SORTBY", + "age", + "desc", + ] + @py_test_mark_asyncio async def test_find_query_text_search(m): - model_name, fq = await FindQuery(expressions=[m.Member.bio == "test"], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '@bio:{test}', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[m.Member.bio == "test"], model=m.Member + ).get_query() + assert fq == ["FT.SEARCH", model_name, "@bio:{test}", "LIMIT", 0, 1000] + @py_test_mark_asyncio async def test_find_query_text_search_and(m, members): - model_name, fq = await FindQuery(expressions=[m.Member.age < 40, m.Member.first_name == "Andrew"], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '(@age:[-inf (40]) (@first_name:{Andrew})', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[m.Member.age < 40, m.Member.first_name == "Andrew"], model=m.Member + ).get_query() + assert fq == [ + "FT.SEARCH", + model_name, + "(@age:[-inf (40]) (@first_name:{Andrew})", + "LIMIT", + 0, + 1000, + ] + @py_test_mark_asyncio async def test_find_query_text_search_or(m, members): - model_name, fq = await FindQuery(expressions=[(m.Member.age < 40) | (m.Member.first_name == "Andrew")], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '(@age:[-inf (40])| (@first_name:{Andrew})', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[(m.Member.age < 40) | (m.Member.first_name == "Andrew")], + model=m.Member, + ).get_query() + assert fq == [ + "FT.SEARCH", + model_name, + "(@age:[-inf (40])| (@first_name:{Andrew})", + "LIMIT", + 0, + 1000, + ] + @py_test_mark_asyncio async def test_find_query_text_search_not(m): - model_name, fq = await FindQuery(expressions=[~(m.Member.first_name == "Andrew")], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '-(@first_name:{Andrew})', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[~(m.Member.first_name == "Andrew")], model=m.Member + ).get_query() + assert fq == ["FT.SEARCH", model_name, "-(@first_name:{Andrew})", "LIMIT", 0, 1000] + @py_test_mark_asyncio async def test_find_query_text_search_not_and(m, members): - model_name, fq = await FindQuery(expressions=[~((m.Member.first_name == "Andrew") & (m.Member.age < 40))], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '-((@first_name:{Andrew}) (@age:[-inf (40]))', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[~((m.Member.first_name == "Andrew") & (m.Member.age < 40))], + model=m.Member, + ).get_query() + assert fq == [ + "FT.SEARCH", + model_name, + "-((@first_name:{Andrew}) (@age:[-inf (40]))", + "LIMIT", + 0, + 1000, + ] + @py_test_mark_asyncio async def test_find_query_text_search_not_or(m, members): - model_name, fq = await FindQuery(expressions=[~((m.Member.first_name == "Andrew") | (m.Member.age < 40))], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '-((@first_name:{Andrew})| (@age:[-inf (40]))', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[~((m.Member.first_name == "Andrew") | (m.Member.age < 40))], + model=m.Member, + ).get_query() + assert fq == [ + "FT.SEARCH", + model_name, + "-((@first_name:{Andrew})| (@age:[-inf (40]))", + "LIMIT", + 0, + 1000, + ] + @py_test_mark_asyncio async def test_find_query_text_search_not_or_and(m, members): - model_name, fq = await FindQuery(expressions=[~(((m.Member.first_name == "Andrew") | (m.Member.age < 40)) & (m.Member.last_name == "Brookins"))], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '-(((@first_name:{Andrew})| (@age:[-inf (40])) (@last_name:{Brookins}))', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[ + ~( + ((m.Member.first_name == "Andrew") | (m.Member.age < 40)) + & (m.Member.last_name == "Brookins") + ) + ], + model=m.Member, + ).get_query() + assert fq == [ + "FT.SEARCH", + model_name, + "-(((@first_name:{Andrew})| (@age:[-inf (40])) (@last_name:{Brookins}))", + "LIMIT", + 0, + 1000, + ] + # text search operators; contains, startswith, endswith, fuzzy @py_test_mark_asyncio async def test_find_query_text_contains(m): - model_name, fq = await FindQuery(expressions=[m.Member.first_name.contains("drew")], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '(@first_name:{*drew*})', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[m.Member.first_name.contains("drew")], model=m.Member + ).get_query() + assert fq == ["FT.SEARCH", model_name, "(@first_name:{*drew*})", "LIMIT", 0, 1000] + @py_test_mark_asyncio async def test_find_query_text_startswith(m): - model_name, fq = await FindQuery(expressions=[m.Member.first_name.startswith("An")], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '(@first_name:{An*})', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[m.Member.first_name.startswith("An")], model=m.Member + ).get_query() + assert fq == ["FT.SEARCH", model_name, "(@first_name:{An*})", "LIMIT", 0, 1000] + @py_test_mark_asyncio async def test_find_query_text_endswith(m): - model_name, fq = await FindQuery(expressions=[m.Member.first_name.endswith("ew")], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '(@first_name:{*ew})', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[m.Member.first_name.endswith("ew")], model=m.Member + ).get_query() + assert fq == ["FT.SEARCH", model_name, "(@first_name:{*ew})", "LIMIT", 0, 1000] + @py_test_mark_asyncio async def test_find_query_test_fuzzy(m): - model_name, fq = await FindQuery(expressions=[m.Member.bio % '%newb%'], model=m.Member).get_query() - assert fq == ['FT.SEARCH', model_name, '@bio_fts:%newb%', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[m.Member.bio % "%newb%"], model=m.Member + ).get_query() + assert fq == ["FT.SEARCH", model_name, "@bio_fts:%newb%", "LIMIT", 0, 1000] + # limit, offset, page_size @py_test_mark_asyncio async def test_find_query_limit_one(m): - model_name, fq = await FindQuery(expressions=[m.Member.first_name == "Andrew"], model=m.Member, limit=1).get_query() - assert fq == ['FT.SEARCH', model_name, '@first_name:{Andrew}', 'LIMIT', 0, 1] + model_name, fq = await FindQuery( + expressions=[m.Member.first_name == "Andrew"], model=m.Member, limit=1 + ).get_query() + assert fq == ["FT.SEARCH", model_name, "@first_name:{Andrew}", "LIMIT", 0, 1] + @py_test_mark_asyncio async def test_find_query_limit_offset(m): - model_name, fq = await FindQuery(expressions=[m.Member.first_name == "Andrew"], model=m.Member, limit=1, offset=1).get_query() - assert fq == ['FT.SEARCH', model_name, '@first_name:{Andrew}', 'LIMIT', 1, 1] + model_name, fq = await FindQuery( + expressions=[m.Member.first_name == "Andrew"], model=m.Member, limit=1, offset=1 + ).get_query() + assert fq == ["FT.SEARCH", model_name, "@first_name:{Andrew}", "LIMIT", 1, 1] + @py_test_mark_asyncio async def test_find_query_page_size(m): - # note that this test in unintuitive. + # note that this test in unintuitive. # page_size gets resolved in a while True loop that makes copies of the intial query and adds the limit and offset each time - model_name, fq = await FindQuery(expressions=[m.Member.first_name == "Andrew"], model=m.Member, page_size=1).get_query() - assert fq == ['FT.SEARCH', model_name, '@first_name:{Andrew}', 'LIMIT', 0, 1000] + model_name, fq = await FindQuery( + expressions=[m.Member.first_name == "Andrew"], model=m.Member, page_size=1 + ).get_query() + assert fq == ["FT.SEARCH", model_name, "@first_name:{Andrew}", "LIMIT", 0, 1000] + @py_test_mark_asyncio async def test_find_query_monster(m): -# test monster query with everything everywhere all at once -# including ors, nots, ands, less thans, greater thans, text search - model_name, fq = await FindQuery(expressions=[~(((m.Member.first_name == "Andrew") | (m.Member.age < 40)) & ((m.Member.last_name.contains("oo") | ~(m.Member.email.startswith("z")))))], model=m.Member, limit=1, offset=1).get_query() - assert fq == ['FT.SEARCH', model_name, '-(((@first_name:{Andrew})| (@age:[-inf (40])) (((@last_name:{*oo*}))| -((@email:{z*}))))', 'LIMIT', 1, 1] + # test monster query with everything everywhere all at once + # including ors, nots, ands, less thans, greater thans, text search + model_name, fq = await FindQuery( + expressions=[ + ~( + ((m.Member.first_name == "Andrew") | (m.Member.age < 40)) + & ( + ( + m.Member.last_name.contains("oo") + | ~(m.Member.email.startswith("z")) + ) + ) + ) + ], + model=m.Member, + limit=1, + offset=1, + ).get_query() + assert fq == [ + "FT.SEARCH", + model_name, + "-(((@first_name:{Andrew})| (@age:[-inf (40])) (((@last_name:{*oo*}))| -((@email:{z*}))))", + "LIMIT", + 1, + 1, + ] diff --git a/tests/test_json_model.py b/tests/test_json_model.py index 47cfd2f8..dcc9b2b9 100644 --- a/tests/test_json_model.py +++ b/tests/test_json_model.py @@ -1098,6 +1098,7 @@ class ModelWithIntPk(JsonModel): m = await ModelWithIntPk.find(ModelWithIntPk.my_id == 42).first() assert m.my_id == 42 + @py_test_mark_asyncio async def test_pagination(): class Test(JsonModel): From aa3c4dc1ef3c3d0e519c7da76f78ee79b0b41c57 Mon Sep 17 00:00:00 2001 From: slorello89 Date: Mon, 29 Jul 2024 13:12:42 -0400 Subject: [PATCH 08/11] ignorning erroneous error --- aredis_om/model/encoders.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aredis_om/model/encoders.py b/aredis_om/model/encoders.py index f097a35d..93142f4f 100644 --- a/aredis_om/model/encoders.py +++ b/aredis_om/model/encoders.py @@ -90,7 +90,7 @@ def jsonable_encoder( sqlalchemy_safe=sqlalchemy_safe, ) if dataclasses.is_dataclass(obj): - return dataclasses.asdict(obj) + return dataclasses.asdict(obj) # type: ignore[call-overload] if isinstance(obj, Enum): return obj.value if isinstance(obj, PurePath): From 26db531400d92060ddc70b0c35bbc980427fd374 Mon Sep 17 00:00:00 2001 From: slorello89 Date: Mon, 29 Jul 2024 13:27:37 -0400 Subject: [PATCH 09/11] making xfix tests more specific --- tests/test_hash_model.py | 12 ++++++------ tests/test_json_model.py | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/test_hash_model.py b/tests/test_hash_model.py index de4bdb89..51ad55bc 100644 --- a/tests/test_hash_model.py +++ b/tests/test_hash_model.py @@ -860,22 +860,22 @@ class TypeWithUuid(HashModel): async def test_xfix_queries(members, m): member1, member2, member3 = members - result = await m.Member.find(m.Member.first_name.startswith("And")).first() + result = await m.Member.find(m.Member.first_name.startswith("And") and m.Member.last_name == "Brookins").first() assert result.last_name == "Brookins" - result = await m.Member.find(m.Member.last_name.endswith("ins")).first() + result = await m.Member.find(m.Member.last_name.endswith("ins") and m.Member.last_name == "Brookins").first() assert result.last_name == "Brookins" - result = await m.Member.find(m.Member.last_name.contains("ook")).first() + result = await m.Member.find(m.Member.last_name.contains("ook") and m.Member.last_name == "Brookins").first() assert result.last_name == "Brookins" - result = await m.Member.find(m.Member.bio % "great*").first() + result = await m.Member.find(m.Member.bio % "great*" and m.Member.first_name == "Andrew").first() assert result.first_name == "Andrew" - result = await m.Member.find(m.Member.bio % "*rty").first() + result = await m.Member.find(m.Member.bio % "*rty" and m.Member.first_name == "Andrew").first() assert result.first_name == "Andrew" - result = await m.Member.find(m.Member.bio % "*eat*").first() + result = await m.Member.find(m.Member.bio % "*eat*" and m.Member.first_name == "Andrew").first() assert result.first_name == "Andrew" diff --git a/tests/test_json_model.py b/tests/test_json_model.py index dcc9b2b9..78a2f3c7 100644 --- a/tests/test_json_model.py +++ b/tests/test_json_model.py @@ -969,22 +969,22 @@ async def test_xfix_queries(m): age=34, ).save() - result = await m.Member.find(m.Member.first_name.startswith("Ste")).first() + result = await m.Member.find(m.Member.first_name.startswith("Ste") and m.Member.first_name == "Steve").first() assert result.first_name == "Steve" - result = await m.Member.find(m.Member.last_name.endswith("llo")).first() + result = await m.Member.find(m.Member.last_name.endswith("llo") and m.Member.first_name == "Steve").first() assert result.first_name == "Steve" - result = await m.Member.find(m.Member.address.city.contains("llite")).first() + result = await m.Member.find(m.Member.address.city.contains("llite") and m.Member.first_name == "Steve").first() assert result.first_name == "Steve" - result = await m.Member.find(m.Member.bio % "tw*").first() + result = await m.Member.find(m.Member.bio % "tw*" and m.Member.first_name == "Steve").first() assert result.first_name == "Steve" - result = await m.Member.find(m.Member.bio % "*cker").first() + result = await m.Member.find(m.Member.bio % "*cker" and m.Member.first_name == "Steve").first() assert result.first_name == "Steve" - result = await m.Member.find(m.Member.bio % "*ack*").first() + result = await m.Member.find(m.Member.bio % "*ack*" and m.Member.first_name == "Steve").first() assert result.first_name == "Steve" From d90813af12c7ea023428f22ceccf29e0866d117f Mon Sep 17 00:00:00 2001 From: slorello89 Date: Mon, 29 Jul 2024 13:28:56 -0400 Subject: [PATCH 10/11] linting fixes --- tests/test_hash_model.py | 24 ++++++++++++++++++------ tests/test_json_model.py | 24 ++++++++++++++++++------ 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/tests/test_hash_model.py b/tests/test_hash_model.py index 51ad55bc..4743e75a 100644 --- a/tests/test_hash_model.py +++ b/tests/test_hash_model.py @@ -860,22 +860,34 @@ class TypeWithUuid(HashModel): async def test_xfix_queries(members, m): member1, member2, member3 = members - result = await m.Member.find(m.Member.first_name.startswith("And") and m.Member.last_name == "Brookins").first() + result = await m.Member.find( + m.Member.first_name.startswith("And") and m.Member.last_name == "Brookins" + ).first() assert result.last_name == "Brookins" - result = await m.Member.find(m.Member.last_name.endswith("ins") and m.Member.last_name == "Brookins").first() + result = await m.Member.find( + m.Member.last_name.endswith("ins") and m.Member.last_name == "Brookins" + ).first() assert result.last_name == "Brookins" - result = await m.Member.find(m.Member.last_name.contains("ook") and m.Member.last_name == "Brookins").first() + result = await m.Member.find( + m.Member.last_name.contains("ook") and m.Member.last_name == "Brookins" + ).first() assert result.last_name == "Brookins" - result = await m.Member.find(m.Member.bio % "great*" and m.Member.first_name == "Andrew").first() + result = await m.Member.find( + m.Member.bio % "great*" and m.Member.first_name == "Andrew" + ).first() assert result.first_name == "Andrew" - result = await m.Member.find(m.Member.bio % "*rty" and m.Member.first_name == "Andrew").first() + result = await m.Member.find( + m.Member.bio % "*rty" and m.Member.first_name == "Andrew" + ).first() assert result.first_name == "Andrew" - result = await m.Member.find(m.Member.bio % "*eat*" and m.Member.first_name == "Andrew").first() + result = await m.Member.find( + m.Member.bio % "*eat*" and m.Member.first_name == "Andrew" + ).first() assert result.first_name == "Andrew" diff --git a/tests/test_json_model.py b/tests/test_json_model.py index 78a2f3c7..2d3524e1 100644 --- a/tests/test_json_model.py +++ b/tests/test_json_model.py @@ -969,22 +969,34 @@ async def test_xfix_queries(m): age=34, ).save() - result = await m.Member.find(m.Member.first_name.startswith("Ste") and m.Member.first_name == "Steve").first() + result = await m.Member.find( + m.Member.first_name.startswith("Ste") and m.Member.first_name == "Steve" + ).first() assert result.first_name == "Steve" - result = await m.Member.find(m.Member.last_name.endswith("llo") and m.Member.first_name == "Steve").first() + result = await m.Member.find( + m.Member.last_name.endswith("llo") and m.Member.first_name == "Steve" + ).first() assert result.first_name == "Steve" - result = await m.Member.find(m.Member.address.city.contains("llite") and m.Member.first_name == "Steve").first() + result = await m.Member.find( + m.Member.address.city.contains("llite") and m.Member.first_name == "Steve" + ).first() assert result.first_name == "Steve" - result = await m.Member.find(m.Member.bio % "tw*" and m.Member.first_name == "Steve").first() + result = await m.Member.find( + m.Member.bio % "tw*" and m.Member.first_name == "Steve" + ).first() assert result.first_name == "Steve" - result = await m.Member.find(m.Member.bio % "*cker" and m.Member.first_name == "Steve").first() + result = await m.Member.find( + m.Member.bio % "*cker" and m.Member.first_name == "Steve" + ).first() assert result.first_name == "Steve" - result = await m.Member.find(m.Member.bio % "*ack*" and m.Member.first_name == "Steve").first() + result = await m.Member.find( + m.Member.bio % "*ack*" and m.Member.first_name == "Steve" + ).first() assert result.first_name == "Steve" From 94702acdb9e8c140ac80652d2218511de970c51c Mon Sep 17 00:00:00 2001 From: savynorem Date: Fri, 2 Aug 2024 15:21:26 -0400 Subject: [PATCH 11/11] removing validate return fields function as return_fields don't exist here --- aredis_om/model/model.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/aredis_om/model/model.py b/aredis_om/model/model.py index 3342f5f1..7284e717 100644 --- a/aredis_om/model/model.py +++ b/aredis_om/model/model.py @@ -505,15 +505,6 @@ def query(self): ) + f"=>[{self.knn}]" return self._query - def validate_return_fields(self, return_fields: List[str]): - for field in return_fields: - if field not in self.model.__fields__: # type: ignore - raise QueryNotSupportedError( - f"You tried to return the field {field}, but that field " - f"does not exist on the model {self.model}" - ) - return return_fields - @property def query_params(self): params: List[Union[str, bytes]] = []