Iterators QuerySet Method (#688)
* feat: add iterator function with sample docstring * feat: implement the iterator queryset method * feat: completed the docstring of iterator method * test: write test function to check iterator result * refactor: use iterate method instead fetch_all * fix: debuging syntax error in kwargs of iterator * feat: write a base sample doc for iterator method * refactor: add ouput comment iterator docs example * refactor: check change pk yield ormar model * test: write new test to coverage iterator queryset * fix: debuging new user model class 3 number * fix: iterate on user3 model class * fix: debug id field in user3 model by main user * fix: remove prefetch_related for iterator method * fix: debug mypy test for type annotation * fix: added type annotation for rows variable * simplify row checks as processing is expensive, raise exception on prefetch_related with iterator * fix coverage * fix mypy, bump mypy in pre-commit to newest version * refactor: update document and test uuid pk type * feat: write docs of iterate in quesrysetproxy * feat: write iterate method querysetproxy tests * fix: debuging new test written uuid pk * refactor: seperate iterate test modules * refactor: change description and handle empty set * feat: added iterate method in readme files * fix: set pragma: no cover for raised test Co-authored-by: collerek <collerek@gmail.com>
This commit is contained in:
@ -12,6 +12,7 @@ from typing import (
|
||||
TypeVar,
|
||||
Union,
|
||||
cast,
|
||||
AsyncGenerator,
|
||||
)
|
||||
|
||||
import databases
|
||||
@ -1055,6 +1056,55 @@ class QuerySet(Generic[T]):
|
||||
|
||||
return result_rows
|
||||
|
||||
async def iterate( # noqa: A003
|
||||
self,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> AsyncGenerator["T", None]:
|
||||
"""
|
||||
Return async iterable generator for all rows from a database for given model.
|
||||
|
||||
Passing args and/or kwargs is a shortcut and equals to calling
|
||||
`filter(*args, **kwargs).iterate()`.
|
||||
|
||||
If there are no rows meeting the criteria an empty async generator is returned.
|
||||
|
||||
:param kwargs: fields names and proper value types
|
||||
:type kwargs: Any
|
||||
:return: asynchronous iterable generator of returned models
|
||||
:rtype: AsyncGenerator[Model]
|
||||
"""
|
||||
|
||||
if self._prefetch_related:
|
||||
raise QueryDefinitionError(
|
||||
"Prefetch related queries are not supported in iterators"
|
||||
)
|
||||
|
||||
if kwargs or args:
|
||||
async for result in self.filter(*args, **kwargs).iterate():
|
||||
yield result
|
||||
return
|
||||
|
||||
expr = self.build_select_expression()
|
||||
|
||||
rows: list = []
|
||||
last_primary_key = None
|
||||
pk_alias = self.model.get_column_alias(self.model_meta.pkname)
|
||||
|
||||
async for row in self.database.iterate(query=expr):
|
||||
current_primary_key = row[pk_alias]
|
||||
if last_primary_key == current_primary_key or last_primary_key is None:
|
||||
last_primary_key = current_primary_key
|
||||
rows.append(row)
|
||||
continue
|
||||
|
||||
yield self._process_query_result_rows(rows)[0]
|
||||
last_primary_key = current_primary_key
|
||||
rows = [row]
|
||||
|
||||
if rows:
|
||||
yield self._process_query_result_rows(rows)[0]
|
||||
|
||||
async def create(self, **kwargs: Any) -> "T":
|
||||
"""
|
||||
Creates the model instance, saves it in a database and returns the updates model
|
||||
|
||||
@ -14,6 +14,7 @@ from typing import ( # noqa: I100, I201
|
||||
TypeVar,
|
||||
Union,
|
||||
cast,
|
||||
AsyncGenerator,
|
||||
)
|
||||
|
||||
import ormar # noqa: I100, I202
|
||||
@ -431,6 +432,28 @@ class QuerysetProxy(Generic[T]):
|
||||
self._register_related(all_items)
|
||||
return all_items
|
||||
|
||||
async def iterate( # noqa: A003
|
||||
self,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> AsyncGenerator["T", None]:
|
||||
"""
|
||||
Return async iterable generator for all rows from a database for given model.
|
||||
|
||||
Passing args and/or kwargs is a shortcut and equals to calling
|
||||
`filter(*args, **kwargs).iterate()`.
|
||||
|
||||
If there are no rows meeting the criteria an empty async generator is returned.
|
||||
|
||||
:param kwargs: fields names and proper value types
|
||||
:type kwargs: Any
|
||||
:return: asynchronous iterable generator of returned models
|
||||
:rtype: AsyncGenerator[Model]
|
||||
"""
|
||||
|
||||
async for item in self.queryset.iterate(*args, **kwargs):
|
||||
yield item
|
||||
|
||||
async def create(self, **kwargs: Any) -> "T":
|
||||
"""
|
||||
Creates the model instance, saves it in a database and returns the updates model
|
||||
|
||||
Reference in New Issue
Block a user