Skip to content

Commit 1111906

Browse files
author
Chris Rossi
authored
feat: allow Query.fetch_page for queries with post filters (#463)
Closes #270
1 parent b39af47 commit 1111906

File tree

5 files changed

+49
-51
lines changed

5 files changed

+49
-51
lines changed

packages/google-cloud-ndb/google/cloud/ndb/_datastore_query.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,10 @@ def cursor_after(self):
494494

495495
return self._cursor_after
496496

497+
@property
498+
def _more_results_after_limit(self):
499+
return self._result_set._more_results_after_limit
500+
497501

498502
class _MultiQueryIteratorImpl(QueryIterator):
499503
"""Multiple Query Iterator

packages/google-cloud-ndb/google/cloud/ndb/query.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2319,15 +2319,6 @@ def fetch_page_async(self, page_size, **kwargs):
23192319
"that uses 'OR', '!=', or 'IN'."
23202320
)
23212321

2322-
post_filters = _options.filters._post_filters()
2323-
if post_filters:
2324-
raise TypeError(
2325-
"Can't use 'fetch_page' or 'fetch_page_async' with a "
2326-
"post-filter. (An in-memory filter.) This probably means "
2327-
"you're querying a repeated structured property which "
2328-
"requires post-filtering."
2329-
)
2330-
23312322
iterator = _datastore_query.iterate(_options, raw=True)
23322323
results = []
23332324
cursor = None

packages/google-cloud-ndb/tests/system/test_query.py

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,59 +1516,49 @@ def test_fetch_page_with_repeated_structured_property(dispose_of):
15161516
class OtherKind(ndb.Model):
15171517
one = ndb.StringProperty()
15181518
two = ndb.StringProperty()
1519-
three = ndb.StringProperty()
1519+
three = ndb.IntegerProperty()
15201520

15211521
class SomeKind(ndb.Model):
15221522
foo = ndb.IntegerProperty()
15231523
bar = ndb.StructuredProperty(OtherKind, repeated=True)
15241524

1525+
N = 30
1526+
15251527
@ndb.synctasklet
15261528
def make_entities():
1527-
entity1 = SomeKind(
1528-
foo=1,
1529-
bar=[
1530-
OtherKind(one="pish", two="posh", three="pash"),
1531-
OtherKind(one="bish", two="bosh", three="bash"),
1532-
],
1533-
)
1534-
entity2 = SomeKind(
1535-
foo=2,
1536-
bar=[
1537-
OtherKind(one="bish", two="bosh", three="bass"),
1538-
OtherKind(one="pish", two="posh", three="pass"),
1539-
],
1540-
)
1541-
entity3 = SomeKind(
1542-
foo=3,
1543-
bar=[
1544-
OtherKind(one="pish", two="fosh", three="fash"),
1545-
OtherKind(one="bish", two="posh", three="bash"),
1546-
],
1547-
)
1548-
1549-
keys = yield (
1550-
entity1.put_async(),
1551-
entity2.put_async(),
1552-
entity3.put_async(),
1553-
)
1529+
futures = [
1530+
SomeKind(
1531+
foo=i,
1532+
bar=[
1533+
OtherKind(one="pish", two="posh", three=i % 2),
1534+
OtherKind(one="bish", two="bosh", three=i % 2),
1535+
],
1536+
).put_async()
1537+
for i in range(N)
1538+
]
1539+
1540+
keys = yield futures
15541541
raise ndb.Return(keys)
15551542

15561543
keys = make_entities()
15571544
for key in keys:
15581545
dispose_of(key._key)
15591546

1560-
eventually(SomeKind.query().fetch, length_equals(3))
1547+
eventually(SomeKind.query().fetch, length_equals(N))
15611548
query = (
15621549
SomeKind.query()
15631550
.filter(
15641551
SomeKind.bar == OtherKind(one="pish", two="posh"),
1565-
SomeKind.bar == OtherKind(two="posh", three="pash"),
1552+
SomeKind.bar == OtherKind(two="bosh", three=0),
15661553
)
15671554
.order(SomeKind.foo)
15681555
)
15691556

1570-
with pytest.raises(TypeError):
1571-
query.fetch_page(page_size=10)
1557+
results, cursor, more = query.fetch_page(page_size=5)
1558+
assert [entity.foo for entity in results] == [0, 2, 4, 6, 8]
1559+
1560+
results, cursor, more = query.fetch_page(page_size=5, start_cursor=cursor)
1561+
assert [entity.foo for entity in results] == [10, 12, 14, 16, 18]
15721562

15731563

15741564
@pytest.mark.usefixtures("client_context")

packages/google-cloud-ndb/tests/unit/test__datastore_query.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,29 @@ def test_cursor_after_no_cursor():
680680
with pytest.raises(exceptions.BadArgumentError):
681681
iterator.cursor_after()
682682

683+
@staticmethod
684+
def test__more_results_after_limit():
685+
foo = model.StringProperty("foo")
686+
query = query_module.QueryOptions(
687+
offset=20, limit=10, filters=foo == u"this"
688+
)
689+
predicate = object()
690+
iterator = _datastore_query._PostFilterQueryIteratorImpl(
691+
query, predicate
692+
)
693+
assert iterator._result_set._query == query_module.QueryOptions(
694+
filters=foo == u"this"
695+
)
696+
assert iterator._offset == 20
697+
assert iterator._limit == 10
698+
assert iterator._predicate is predicate
699+
700+
iterator._result_set._more_results_after_limit = False
701+
assert iterator._more_results_after_limit is False
702+
703+
iterator._result_set._more_results_after_limit = True
704+
assert iterator._more_results_after_limit is True
705+
683706

684707
class Test_MultiQueryIteratorImpl:
685708
@staticmethod

packages/google-cloud-ndb/tests/unit/test_query.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2198,16 +2198,6 @@ def test_fetch_page_multiquery():
21982198
with pytest.raises(TypeError):
21992199
query.fetch_page(5)
22002200

2201-
@staticmethod
2202-
@pytest.mark.usefixtures("in_context")
2203-
def test_fetch_page_post_filter():
2204-
query = query_module.Query()
2205-
query.filters = mock.Mock(
2206-
_multiquery=False, _post_filters=mock.Mock(return_value=True)
2207-
)
2208-
with pytest.raises(TypeError):
2209-
query.fetch_page(5)
2210-
22112201
@staticmethod
22122202
@pytest.mark.usefixtures("in_context")
22132203
@mock.patch("google.cloud.ndb._datastore_query")

0 commit comments

Comments
 (0)