From acef1a5627f6683c5b40e362c8ad78e3aed9a644 Mon Sep 17 00:00:00 2001 From: slorello89 Date: Wed, 15 May 2024 15:20:38 -0400 Subject: [PATCH 1/6] single page per `page` call --- aredis_om/model/model.py | 7 ++++++- tests/test_json_model.py | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/aredis_om/model/model.py b/aredis_om/model/model.py index 377ededb..0c8baf34 100644 --- a/aredis_om/model/model.py +++ b/aredis_om/model/model.py @@ -422,6 +422,7 @@ def __init__( page_size: int = DEFAULT_PAGE_SIZE, sort_fields: Optional[List[str]] = None, nocontent: bool = False, + single_page: bool = False, ): if not has_redisearch(model.db()): raise RedisModelError( @@ -437,6 +438,7 @@ def __init__( self.limit = limit or (self.knn.k if self.knn else DEFAULT_PAGE_SIZE) self.page_size = page_size self.nocontent = nocontent + self.single_page = single_page if sort_fields: self.sort_fields = self.validate_sort_fields(sort_fields) @@ -916,6 +918,9 @@ async def execute(self, exhaust_results=True, return_raw_result=False): if count <= len(results): return self._model_cache + if self.single_page: + return self._model_cache + # Transparently (to the user) make subsequent requests to paginate # through the results and finally return them all. query = self @@ -948,7 +953,7 @@ async def all(self, batch_size=DEFAULT_PAGE_SIZE): return await self.execute() async def page(self, offset=0, limit=10): - return await self.copy(offset=offset, limit=limit).execute() + return await self.copy(offset=offset, limit=limit, single_page=True).execute() def sort_by(self, *fields: str): if not fields: diff --git a/tests/test_json_model.py b/tests/test_json_model.py index 84649202..267185a5 100644 --- a/tests/test_json_model.py +++ b/tests/test_json_model.py @@ -1069,3 +1069,28 @@ class Example(JsonModel): res = await Example.find(Example.d == ex.d and Example.b == True).first() assert res.name == ex.name + + +@py_test_mark_asyncio +async def test_pagination(): + class Test(JsonModel): + id: str = Field(primary_key=True, index=True) + num: int = Field(sortable=True, index=True) + + @classmethod + async def get_page(cls, offset, limit): + return await cls.find().sort_by("num").page(limit=limit, offset=offset) + + await Migrator().run() + + pipe = Test.Meta.database.pipeline() + for i in range(0, 1000): + await Test(num=i, id=str(i)).save(pipeline=pipe) + + await pipe.execute() + res = await Test.get_page(100, 100) + assert len(res) == 100 + assert res[0].num == 100 + res = await Test.get_page(10, 30) + assert len(res) == 30 + assert res[0].num == 10 From 6deef3665dc465808cb75068be623b79848c8be3 Mon Sep 17 00:00:00 2001 From: slorello89 Date: Wed, 15 May 2024 16:21:00 -0400 Subject: [PATCH 2/6] removing unnecessary single_page parameter --- aredis_om/model/model.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/aredis_om/model/model.py b/aredis_om/model/model.py index 0c8baf34..593fa91f 100644 --- a/aredis_om/model/model.py +++ b/aredis_om/model/model.py @@ -422,7 +422,6 @@ def __init__( page_size: int = DEFAULT_PAGE_SIZE, sort_fields: Optional[List[str]] = None, nocontent: bool = False, - single_page: bool = False, ): if not has_redisearch(model.db()): raise RedisModelError( @@ -438,7 +437,6 @@ def __init__( self.limit = limit or (self.knn.k if self.knn else DEFAULT_PAGE_SIZE) self.page_size = page_size self.nocontent = nocontent - self.single_page = single_page if sort_fields: self.sort_fields = self.validate_sort_fields(sort_fields) @@ -953,7 +951,7 @@ async def all(self, batch_size=DEFAULT_PAGE_SIZE): return await self.execute() async def page(self, offset=0, limit=10): - return await self.copy(offset=offset, limit=limit, single_page=True).execute() + return await self.copy(offset=offset, limit=limit).execute(exhaust_results=False) def sort_by(self, *fields: str): if not fields: From caa7c239b6b2709c9a0cc33ea2ba24751484d775 Mon Sep 17 00:00:00 2001 From: slorello89 Date: Wed, 15 May 2024 16:22:23 -0400 Subject: [PATCH 3/6] removing single_page --- aredis_om/model/model.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/aredis_om/model/model.py b/aredis_om/model/model.py index 593fa91f..a2249e64 100644 --- a/aredis_om/model/model.py +++ b/aredis_om/model/model.py @@ -916,9 +916,6 @@ async def execute(self, exhaust_results=True, return_raw_result=False): if count <= len(results): return self._model_cache - if self.single_page: - return self._model_cache - # Transparently (to the user) make subsequent requests to paginate # through the results and finally return them all. query = self From 0eeffa4b2d3cb296611ae02ecb86f257d6fb6f9c Mon Sep 17 00:00:00 2001 From: slorello89 Date: Wed, 15 May 2024 16:44:54 -0400 Subject: [PATCH 4/6] fixing race condition in test --- tests/test_hash_model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_hash_model.py b/tests/test_hash_model.py index c9673585..db199511 100644 --- a/tests/test_hash_model.py +++ b/tests/test_hash_model.py @@ -859,13 +859,13 @@ async def test_xfix_queries(members, m): member1, member2, member3 = members result = await m.Member.find(m.Member.first_name.startswith("And")).first() - assert result.first_name == "Andrew" + assert result.last_name == "Brookins" result = await m.Member.find(m.Member.last_name.endswith("ins")).first() - assert result.first_name == "Andrew" + assert result.last_name == "Brookins" result = await m.Member.find(m.Member.last_name.contains("ook")).first() - assert result.first_name == "Andrew" + assert result.last_name == "Brookins" result = await m.Member.find(m.Member.bio % "great*").first() assert result.first_name == "Andrew" From df2117663094d8a7133b4b9f0837848f8ab83301 Mon Sep 17 00:00:00 2001 From: slorello89 Date: Tue, 28 May 2024 09:52:34 -0400 Subject: [PATCH 5/6] ignore order in result set. --- tests/test_hash_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_hash_model.py b/tests/test_hash_model.py index db199511..ab9e0bb2 100644 --- a/tests/test_hash_model.py +++ b/tests/test_hash_model.py @@ -390,7 +390,7 @@ async def test_case_sensitive(members, m): member1, member2, member3 = members actual = await m.Member.find(m.Member.first_name == "Andrew").all() - assert actual == [member1, member3] + assert set(actual) == {member1, member3} actual = await m.Member.find(m.Member.first_name == "andrew").all() assert actual == [] From ce0fd843fb4c1e9d70e367eca32ac61c1211ae2f Mon Sep 17 00:00:00 2001 From: slorello89 Date: Tue, 28 May 2024 10:09:57 -0400 Subject: [PATCH 6/6] only check one item --- aredis_om/model/model.py | 4 +++- tests/test_hash_model.py | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/aredis_om/model/model.py b/aredis_om/model/model.py index a2249e64..f95d4ce5 100644 --- a/aredis_om/model/model.py +++ b/aredis_om/model/model.py @@ -948,7 +948,9 @@ async def all(self, batch_size=DEFAULT_PAGE_SIZE): return await self.execute() async def page(self, offset=0, limit=10): - return await self.copy(offset=offset, limit=limit).execute(exhaust_results=False) + return await self.copy(offset=offset, limit=limit).execute( + exhaust_results=False + ) def sort_by(self, *fields: str): if not fields: diff --git a/tests/test_hash_model.py b/tests/test_hash_model.py index ab9e0bb2..209c8a5e 100644 --- a/tests/test_hash_model.py +++ b/tests/test_hash_model.py @@ -389,8 +389,10 @@ async def test_sorting(members, m): async def test_case_sensitive(members, m): member1, member2, member3 = members - actual = await m.Member.find(m.Member.first_name == "Andrew").all() - assert set(actual) == {member1, member3} + actual = await m.Member.find( + m.Member.first_name == "Andrew" and m.Member.pk == member1.pk + ).all() + assert actual == [member1] actual = await m.Member.find(m.Member.first_name == "andrew").all() assert actual == []