Skip to content

Commit 0803d13

Browse files
author
Chris Rossi
authored
fix: make sure keys_only ordered multiquery returns keys not entities (#527)
Fixes #526
1 parent 66bc3fa commit 0803d13

File tree

3 files changed

+66
-3
lines changed

3 files changed

+66
-3
lines changed

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ class _MultiQueryIteratorImpl(QueryIterator):
580580
"""
581581

582582
_extra_projections = None
583+
_coerce_keys_only = False
583584

584585
def __init__(self, query, raw=False):
585586
projection = query.projection
@@ -592,10 +593,12 @@ def __init__(self, query, raw=False):
592593
extra_projections = []
593594
for order in query.order_by:
594595
if order.name not in projection:
595-
projection.append(order.name)
596596
extra_projections.append(order.name)
597597

598598
if extra_projections:
599+
if projection == ["__key__"]:
600+
self._coerce_keys_only = True
601+
projection.extend(extra_projections)
599602
self._extra_projections = extra_projections
600603

601604
queries = [
@@ -707,7 +710,10 @@ def next(self):
707710
if self._raw:
708711
return next_result
709712
else:
710-
return next_result.entity()
713+
entity = next_result.entity()
714+
if self._coerce_keys_only:
715+
return entity._key
716+
return entity
711717

712718
__next__ = next
713719

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ class SomeKind(ndb.Model):
673673
results = eventually(
674674
functools.partial(query.fetch, keys_only=True), length_equals(5)
675675
)
676-
assert keys == [entity.key for entity in results]
676+
assert keys == results
677677

678678

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

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

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,30 @@ def test_constructor_sortable_with_projection_needs_extra():
910910
projection=["bar", "foo"],
911911
)
912912
assert iterator._sortable
913+
assert not iterator._coerce_keys_only
914+
915+
@staticmethod
916+
def test_constructor_sortable_with_projection_needs_extra_keys_only():
917+
foo = model.StringProperty("foo")
918+
order_by = [query_module.PropertyOrder("foo")]
919+
query = query_module.QueryOptions(
920+
filters=query_module.OR(foo == "this", foo == "that"),
921+
order_by=order_by,
922+
projection=("__key__",),
923+
)
924+
iterator = _datastore_query._MultiQueryIteratorImpl(query)
925+
assert iterator._result_sets[0]._query == query_module.QueryOptions(
926+
filters=foo == "this",
927+
order_by=order_by,
928+
projection=["__key__", "foo"],
929+
)
930+
assert iterator._result_sets[1]._query == query_module.QueryOptions(
931+
filters=foo == "that",
932+
order_by=order_by,
933+
projection=["__key__", "foo"],
934+
)
935+
assert iterator._sortable
936+
assert iterator._coerce_keys_only
913937

914938
@staticmethod
915939
def test_iter():
@@ -981,6 +1005,39 @@ def test_next_with_extra_projections():
9811005
assert iterator.next() is next_result
9821006
assert "foo" not in next_result.result_pb.entity.properties
9831007

1008+
@staticmethod
1009+
@pytest.mark.usefixtures("in_context")
1010+
def test_next_coerce_keys_only():
1011+
foo = model.StringProperty("foo")
1012+
order_by = [
1013+
query_module.PropertyOrder("foo"),
1014+
query_module.PropertyOrder("food"),
1015+
]
1016+
query = query_module.QueryOptions(
1017+
filters=query_module.OR(foo == "this", foo == "that"),
1018+
order_by=order_by,
1019+
projection=["__key__"],
1020+
)
1021+
iterator = _datastore_query._MultiQueryIteratorImpl(query)
1022+
iterator._next_result = next_result = mock.Mock(
1023+
result_pb=mock.Mock(
1024+
entity=mock.Mock(
1025+
properties={"foo": 1, "bar": "two"},
1026+
spec=("properties",),
1027+
),
1028+
spec=("entity",),
1029+
),
1030+
entity=mock.Mock(
1031+
return_value=mock.Mock(
1032+
_key="thekey",
1033+
)
1034+
),
1035+
spec=("result_pb", "entity"),
1036+
)
1037+
1038+
assert iterator.next() == "thekey"
1039+
assert "foo" not in next_result.result_pb.entity.properties
1040+
9841041
@staticmethod
9851042
@pytest.mark.usefixtures("in_context")
9861043
def test_iterate_async():

0 commit comments

Comments
 (0)