def test_fetch_page(dispose_of): page_size = 5 n_entities = page_size * 2 class SomeKind(ndb.Model): foo = ndb.IntegerProperty() @ndb.toplevel def make_entities(): entities = [SomeKind(foo=i) for i in range(n_entities)] keys = yield [entity.put_async() for entity in entities] raise ndb.Return(keys) for key in make_entities(): dispose_of(key._key) query = SomeKind.query().order(SomeKind.foo) eventually(query.fetch, _length_equals(n_entities)) results, cursor, more = query.fetch_page(page_size) assert [entity.foo for entity in results] == [0, 1, 2, 3, 4] assert more safe_cursor = cursor.urlsafe() next_cursor = ndb.Cursor(urlsafe=safe_cursor) results, cursor, more = query.fetch_page(page_size, start_cursor=next_cursor) assert [entity.foo for entity in results] == [5, 6, 7, 8, 9] results, cursor, more = query.fetch_page(page_size, start_cursor=cursor) assert not results assert not more
def get_list(limit: int, cursor: str, sort: str, is_published: bool, category_resource_id: Optional[str]) -> ArticleModelPagedResult: models: List[ArticleModel] = [] # Query Options opts = {} if (cursor): opts = {'start_cursor': ndb.Cursor(urlsafe=cursor)} # Run Query with client.context(): q = ArticleEntity.query() q = q.filter(ArticleEntity.is_published == is_published) # If there is a category resource_id, filter by it if (category_resource_id): category_key = get_key_from_resource_id(category_resource_id) q = q.filter(ArticleEntity.categories == category_key) # TODO: Support custom sorting... requires some additional indexes... q = q.order(-ArticleEntity.published_date) [results, nextCursor, more] = q.fetch_page(limit, **opts) # Bulk Dereference Entities derefenced_entities = bulk_dereference(results) # [logging.error(getattr(e, LEGACY_IMAGE_PROP, None)) for e in derefenced_entities] # Map Results to Domain Model models = [map_entity_to_model(e) for e in derefenced_entities] return ArticleModelPagedResult(models=models, cursor=nextCursor.urlsafe(), more=more)
def retrieve_cats(limit: int = 2, cursor: str = None): """Retrieves cats from datastore.""" logger.info('Retrieving all cats') with client.context(): query = models.CatNDB.query() res, cursor, _ = query.fetch_page( limit=limit, start_cursor=ndb.Cursor(urlsafe=cursor)) return ([_ndb_to_cat(c) for c in res], cursor.urlsafe() if cursor is not None else '')
def get_list(limit: int, cursor: str, sort: str) -> CategoryModelPagedResult: models: List[CategoryModel] = [] # Query Options opts = {} if (cursor): opts = {'start_cursor': ndb.Cursor(urlsafe=cursor)} # Run Query with client.context(): q = CategoryEntity.query() q = q.order(CategoryEntity.name) [results, nextCursor, more] = q.fetch_page(limit, **opts) # Map Results to Domain Model models = [map_entity_to_model(e) for e in results] return CategoryModelPagedResult(models=models, cursor=nextCursor.urlsafe(), more=more)
def make_cursor(urlsafe_cursor=None): # type: (Optional[Text]) -> datastore_query.Cursor """Makes an immutable cursor that points to a relative position in a query. The position denoted by a Cursor is relative to the result of a query, even if the result is removed later on. Usually, the position points to whatever immediately follows the last result of a batch. A cursor should only be used on a query with an identical signature to the one that produced it, or on a query with its sort order reversed. A Cursor constructed with no arguments points to the first result of any query. If such a Cursor is used as an end_cursor, no results will be returned. Args: urlsafe_cursor: str | None. The base64-encoded serialization of a cursor. When None, the cursor returned will point to the first result of any query. Returns: datastore_query.Cursor. A cursor into an arbitrary query. """ return ndb.Cursor(urlsafe=urlsafe_cursor)