Skip to content

Commit

Permalink
Using ancestor queries for strong consistency.
Browse files Browse the repository at this point in the history
Integrates changes from googleapis/google-cloud-node#267
  • Loading branch information
dhermes committed Oct 23, 2014
1 parent c729e4c commit 592b1ba
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 31 deletions.
12 changes: 12 additions & 0 deletions regression/data/index.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
indexes:

- kind: Character
ancestor: yes
properties:
- name: appearances

- kind: Character
ancestor: yes
properties:
- name: alive

- kind: Character
ancestor: yes
properties:
- name: family
- name: appearances

- kind: Character
ancestor: yes
properties:
- name: name
- name: family
45 changes: 23 additions & 22 deletions regression/datastore.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from gcloud import datastore
# This assumes the command is being run via tox hence the
# repository root is the current directory.
from regression.populate_datastore import CHARACTERS
from regression import populate_datastore
from regression import regression_utils


Expand Down Expand Up @@ -115,11 +115,16 @@ class TestDatastoreQuery(TestDatastore):
@classmethod
def setUpClass(cls):
super(TestDatastoreQuery, cls).setUpClass()
cls.CHARACTERS = CHARACTERS
cls.CHARACTERS = populate_datastore.CHARACTERS
cls.ANCESTOR_KEY = datastore.key.Key(
path=[populate_datastore.ANCESTOR])

def _base_query(self):
return self.dataset.query('Character').ancestor(self.ANCESTOR_KEY)

def test_limit_queries(self):
limit = 5
query = self.dataset.query('Character').limit(limit)
query = self._base_query().limit(limit)
# Verify there is not cursor before fetch().
self.assertRaises(RuntimeError, query.cursor)

Expand All @@ -132,49 +137,46 @@ def test_limit_queries(self):
self.assertTrue(cursor is not None)

# Fetch next batch of characters.
new_query = self.dataset.query('Character').with_cursor(cursor)
new_query = self._base_query().with_cursor(cursor)
new_character_entities = new_query.fetch()
characters_remaining = len(self.CHARACTERS) - limit
self.assertEqual(len(new_character_entities), characters_remaining)

def test_query_simple_filter(self):
query = self.dataset.query('Character')
query = query.filter('appearances >=', 20)
query = self._base_query().filter('appearances >=', 20)
expected_matches = 6
# We expect 6, but allow the query to get 1 extra.
entities = query.fetch(limit=expected_matches + 1)
self.assertEqual(len(entities), expected_matches)

def test_query_multiple_filters(self):
query = self.dataset.query('Character')
query = query.filter('appearances >=', 26).filter('family =', 'Stark')
query = self._base_query().filter(
'appearances >=', 26).filter('family =', 'Stark')
expected_matches = 4
# We expect 4, but allow the query to get 1 extra.
entities = query.fetch(limit=expected_matches + 1)
self.assertEqual(len(entities), expected_matches)

def test_ancestor_query(self):
query = self.dataset.query('Character')
filtered_query = query.ancestor(['Character', 'Eddard'])
filtered_query = self._base_query()

expected_matches = 5
# We expect 5, but allow the query to get 1 extra.
expected_matches = 8
# We expect 8, but allow the query to get 1 extra.
entities = filtered_query.fetch(limit=expected_matches + 1)
self.assertEqual(len(entities), expected_matches)

def test_query___key___filter(self):
rickard_key = datastore.key.Key(
path=[{'kind': 'Character', 'name': 'Rickard'}])
path=[populate_datastore.ANCESTOR, populate_datastore.RICKARD])

query = self.dataset.query('Character').filter(
'__key__ =', rickard_key)
query = self._base_query().filter('__key__ =', rickard_key)
expected_matches = 1
# We expect 1, but allow the query to get 1 extra.
entities = query.fetch(limit=expected_matches + 1)
self.assertEqual(len(entities), expected_matches)

def test_ordered_query(self):
query = self.dataset.query('Character').order('appearances')
query = self._base_query().order('appearances')
expected_matches = 8
# We expect 8, but allow the query to get 1 extra.
entities = query.fetch(limit=expected_matches + 1)
Expand All @@ -185,8 +187,7 @@ def test_ordered_query(self):
self.assertEqual(entities[7]['name'], self.CHARACTERS[3]['name'])

def test_projection_query(self):
query = self.dataset.query('Character')
filtered_query = query.projection(['name', 'family'])
filtered_query = self._base_query().projection(['name', 'family'])

# NOTE: There are 9 responses because of Catelyn. She has both
# Stark and Tully as her families, hence occurs twice in
Expand Down Expand Up @@ -220,7 +221,7 @@ def test_projection_query(self):
self.assertEqual(sansa_dict, {'name': 'Sansa', 'family': 'Stark'})

def test_query_paginate_with_offset(self):
query = self.dataset.query('Character')
query = self._base_query()
offset = 2
limit = 3
page_query = query.offset(offset).limit(limit).order('appearances')
Expand All @@ -246,7 +247,7 @@ def test_query_paginate_with_offset(self):
self.assertEqual(entities[2]['name'], 'Arya')

def test_query_paginate_with_start_cursor(self):
query = self.dataset.query('Character')
query = self._base_query()
offset = 2
limit = 2
page_query = query.offset(offset).limit(limit).order('appearances')
Expand All @@ -259,7 +260,7 @@ def test_query_paginate_with_start_cursor(self):

# Use cursor to create a fresh query.
cursor = page_query.cursor()
fresh_query = self.dataset.query('Character')
fresh_query = self._base_query()
fresh_query = fresh_query.order('appearances').with_cursor(cursor)

new_entities = fresh_query.fetch()
Expand All @@ -269,7 +270,7 @@ def test_query_paginate_with_start_cursor(self):
self.assertEqual(new_entities[3]['name'], 'Arya')

def test_query_group_by(self):
query = self.dataset.query('Character').group_by(['alive'])
query = self._base_query().group_by(['alive'])

expected_matches = 2
# We expect 2, but allow the query to get 1 extra.
Expand Down
21 changes: 12 additions & 9 deletions regression/populate_datastore.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,23 @@
from regression import regression_utils


ANCESTOR = {'kind': 'Book', 'name': 'GoT'}
RICKARD = {'kind': 'Character', 'name': 'Rickard'}
EDDARD = {'kind': 'Character', 'name': 'Eddard'}
KEY_PATHS = [
[{'kind': 'Character', 'name': 'Rickard'}],
[{'kind': 'Character', 'name': 'Rickard'},
{'kind': 'Character', 'name': 'Eddard'}],
[{'kind': 'Character', 'name': 'Catelyn'}],
[{'kind': 'Character', 'name': 'Eddard'},
[ANCESTOR, RICKARD],
[ANCESTOR, RICKARD, EDDARD],
[ANCESTOR,
{'kind': 'Character', 'name': 'Catelyn'}],
[ANCESTOR, RICKARD, EDDARD,
{'kind': 'Character', 'name': 'Arya'}],
[{'kind': 'Character', 'name': 'Eddard'},
[ANCESTOR, RICKARD, EDDARD,
{'kind': 'Character', 'name': 'Sansa'}],
[{'kind': 'Character', 'name': 'Eddard'},
[ANCESTOR, RICKARD, EDDARD,
{'kind': 'Character', 'name': 'Robb'}],
[{'kind': 'Character', 'name': 'Eddard'},
[ANCESTOR, RICKARD, EDDARD,
{'kind': 'Character', 'name': 'Bran'}],
[{'kind': 'Character', 'name': 'Eddard'},
[ANCESTOR, RICKARD, EDDARD,
{'kind': 'Character', 'name': 'Jon Snow'}],
]
CHARACTERS = [
Expand Down

0 comments on commit 592b1ba

Please sign in to comment.