Skip to content

Commit

Permalink
Merge pull request googleapis#425 from tseaver/423-expose_query_more_…
Browse files Browse the repository at this point in the history
…results

Fix googleapis#423:  Expose the 'more_results' value fetched from the back-end.
  • Loading branch information
tseaver committed Dec 17, 2014
2 parents ac999e8 + 5743370 commit 1b9f1c2
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 9 deletions.
38 changes: 31 additions & 7 deletions gcloud/datastore/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def __init__(self, kind=None, dataset=None, namespace=None):
self._dataset = dataset
self._namespace = namespace
self._pb = datastore_pb.Query()
self._cursor = None
self._cursor = self._more_results = None
self._offset = 0

if kind:
Expand All @@ -85,6 +85,7 @@ def _clone(self):
namespace=self._namespace)
clone._pb.CopyFrom(self._pb)
clone._cursor = self._cursor
clone._more_results = self._more_results
return clone

def namespace(self):
Expand Down Expand Up @@ -347,21 +348,22 @@ def fetch(self, limit=None):
dataset_id=self.dataset().id(),
namespace=self._namespace,
)
# NOTE: `query_results` contains two extra values that we don't use,
# namely `more_results` and `skipped_results`. The value of
# `more_results` is unusable because it always returns an enum
# NOTE: `query_results` contains an extra value that we don't use,
# namely `skipped_results`.
#
# NOTE: The value of `more_results` is not currently useful because
# the back-end always returns an enum
# value of MORE_RESULTS_AFTER_LIMIT even if there are no more
# results. See
# https://github.com/GoogleCloudPlatform/gcloud-python/issues/280
# for discussion.
entity_pbs, end_cursor = query_results[:2]
entity_pbs, self._cursor, self._more_results = query_results[:3]

self._cursor = end_cursor
return [helpers.entity_from_protobuf(entity, dataset=self.dataset())
for entity in entity_pbs]

def cursor(self):
"""Returns cursor ID
"""Returns cursor ID from most recent ``fetch()``.
.. warning:: Invoking this method on a query that has not yet
been executed will raise a RuntimeError.
Expand All @@ -374,6 +376,28 @@ def cursor(self):
raise RuntimeError('No cursor')
return base64.b64encode(self._cursor)

def more_results(self):
"""Returns ``more_results`` flag from most recent ``fetch()``.
.. warning:: Invoking this method on a query that has not yet
been executed will raise a RuntimeError.
.. note::
The `more_results` is not currently useful because it is
always returned by the back-end as ``MORE_RESULTS_AFTER_LIMIT``
even if there are no more results. See
https://github.com/GoogleCloudPlatform/gcloud-python/issues/280
for discussion.
:rtype: :class:`gcloud.datastore.datastore_v1_pb2.
QueryResultBatch.MoreResultsType`
:returns: enumerated value: are there more results available.
"""
if self._more_results is None:
raise RuntimeError('No results')
return self._more_results

def with_cursor(self, start_cursor, end_cursor=None):
"""Specifies the starting / ending positions in a query's result set.
Expand Down
27 changes: 25 additions & 2 deletions gcloud/datastore/test_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ def test__clone(self):
_DATASET = 'DATASET'
_KIND = 'KIND'
_CURSOR = 'DEADBEEF'
_MORE_RESULTS = 2
_NAMESPACE = 'NAMESPACE'
dataset = Dataset(_DATASET)
query = self._makeOne(_KIND, dataset, _NAMESPACE)
query._cursor = _CURSOR
query._more_results = _MORE_RESULTS
clone = query._clone()
self.assertFalse(clone is query)
self.assertTrue(isinstance(clone, self._getTargetClass()))
Expand All @@ -63,6 +65,7 @@ def test__clone(self):
kq_pb, = list(clone.kind())
self.assertEqual(kq_pb.name, _KIND)
self.assertEqual(clone._cursor, _CURSOR)
self.assertEqual(clone._more_results, _MORE_RESULTS)

def test_to_protobuf_empty(self):
query = self._makeOne()
Expand Down Expand Up @@ -317,6 +320,7 @@ def test_fetch_default_limit(self):
self.assertEqual(connection._called_with, expected_called_with)

def test_fetch_explicit_limit(self):
import base64
from gcloud.datastore.datastore_v1_pb2 import Entity
_CURSOR = 'CURSOR'
_DATASET = 'DATASET'
Expand All @@ -336,7 +340,8 @@ def test_fetch_explicit_limit(self):
query = self._makeOne(_KIND, dataset, _NAMESPACE)
limited = query.limit(13)
entities = query.fetch(13)
self.assertEqual(query._cursor, _CURSOR)
self.assertEqual(query.cursor(), base64.b64encode(_CURSOR))
self.assertEqual(query.more_results(), connection._more)
self.assertEqual(len(entities), 1)
self.assertEqual(entities[0].key().path(),
[{'kind': _KIND, 'id': _ID}])
Expand All @@ -347,6 +352,24 @@ def test_fetch_explicit_limit(self):
}
self.assertEqual(connection._called_with, expected_called_with)

def test_more_results_not_fetched(self):
_DATASET = 'DATASET'
_KIND = 'KIND'
connection = _Connection()
dataset = _Dataset(_DATASET, connection)
query = self._makeOne(_KIND, dataset)
self.assertRaises(RuntimeError, query.more_results)

def test_more_results_fetched(self):
_MORE_RESULTS = 2
_DATASET = 'DATASET'
_KIND = 'KIND'
connection = _Connection()
dataset = _Dataset(_DATASET, connection)
query = self._makeOne(_KIND, dataset)
query._more_results = _MORE_RESULTS
self.assertEqual(query.more_results(), _MORE_RESULTS)

def test_cursor_not_fetched(self):
_DATASET = 'DATASET'
_KIND = 'KIND'
Expand Down Expand Up @@ -564,7 +587,7 @@ def connection(self):
class _Connection(object):
_called_with = None
_cursor = ''
_more = True
_more = 2
_skipped = 0

def __init__(self, *result):
Expand Down

0 comments on commit 1b9f1c2

Please sign in to comment.