Skip to content

Commit 81f3b0c

Browse files
committed
Using ancestor queries for strong consistency.
Integrates changes from googleapis/google-cloud-node#267
1 parent 87012d8 commit 81f3b0c

File tree

3 files changed

+47
-31
lines changed

3 files changed

+47
-31
lines changed

regression/data/index.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
11
indexes:
22

33
- kind: Character
4+
ancestor: yes
5+
properties:
6+
- name: appearances
7+
8+
- kind: Character
9+
ancestor: yes
10+
properties:
11+
- name: alive
12+
13+
- kind: Character
14+
ancestor: yes
415
properties:
516
- name: family
617
- name: appearances
718

819
- kind: Character
20+
ancestor: yes
921
properties:
1022
- name: name
1123
- name: family

regression/datastore.py

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from gcloud import datastore
66
# This assumes the command is being run via tox hence the
77
# repository root is the current directory.
8-
from regression.populate_datastore import CHARACTERS
8+
from regression import populate_datastore
99
from regression import regression_utils
1010

1111

@@ -115,11 +115,16 @@ class TestDatastoreQuery(TestDatastore):
115115
@classmethod
116116
def setUpClass(cls):
117117
super(TestDatastoreQuery, cls).setUpClass()
118-
cls.CHARACTERS = CHARACTERS
118+
cls.CHARACTERS = populate_datastore.CHARACTERS
119+
cls.ANCESTOR_KEY = datastore.key.Key(
120+
path=[populate_datastore.ANCESTOR])
121+
122+
def _base_query(self):
123+
return self.dataset.query('Character').ancestor(self.ANCESTOR_KEY)
119124

120125
def test_limit_queries(self):
121126
limit = 5
122-
query = self.dataset.query('Character').limit(limit)
127+
query = self._base_query().limit(limit)
123128
# Verify there is not cursor before fetch().
124129
self.assertRaises(RuntimeError, query.cursor)
125130

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

134139
# Fetch next batch of characters.
135-
new_query = self.dataset.query('Character').with_cursor(cursor)
140+
new_query = self._base_query().with_cursor(cursor)
136141
new_character_entities = new_query.fetch()
137142
characters_remaining = len(self.CHARACTERS) - limit
138143
self.assertEqual(len(new_character_entities), characters_remaining)
139144

140145
def test_query_simple_filter(self):
141-
query = self.dataset.query('Character')
142-
query = query.filter('appearances >=', 20)
146+
query = self._base_query().filter('appearances >=', 20)
143147
expected_matches = 6
144148
# We expect 6, but allow the query to get 1 extra.
145149
entities = query.fetch(limit=expected_matches + 1)
146150
self.assertEqual(len(entities), expected_matches)
147151

148152
def test_query_multiple_filters(self):
149-
query = self.dataset.query('Character')
150-
query = query.filter('appearances >=', 26).filter('family =', 'Stark')
153+
query = self._base_query().filter(
154+
'appearances >=', 26).filter('family =', 'Stark')
151155
expected_matches = 4
152156
# We expect 4, but allow the query to get 1 extra.
153157
entities = query.fetch(limit=expected_matches + 1)
154158
self.assertEqual(len(entities), expected_matches)
155159

156160
def test_ancestor_query(self):
157-
query = self.dataset.query('Character')
158-
filtered_query = query.ancestor(['Character', 'Eddard'])
161+
filtered_query = self._base_query()
159162

160-
expected_matches = 5
161-
# We expect 5, but allow the query to get 1 extra.
163+
expected_matches = 8
164+
# We expect 8, but allow the query to get 1 extra.
162165
entities = filtered_query.fetch(limit=expected_matches + 1)
163166
self.assertEqual(len(entities), expected_matches)
164167

165168
def test_query___key___filter(self):
166169
rickard_key = datastore.key.Key(
167-
path=[{'kind': 'Character', 'name': 'Rickard'}])
170+
path=[populate_datastore.ANCESTOR, populate_datastore.RICKARD])
168171

169-
query = self.dataset.query('Character').filter(
170-
'__key__ =', rickard_key)
172+
query = self._base_query().filter('__key__ =', rickard_key)
171173
expected_matches = 1
172174
# We expect 1, but allow the query to get 1 extra.
173175
entities = query.fetch(limit=expected_matches + 1)
174176
self.assertEqual(len(entities), expected_matches)
175177

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

187189
def test_projection_query(self):
188-
query = self.dataset.query('Character')
189-
filtered_query = query.projection(['name', 'family'])
190+
filtered_query = self._base_query().projection(['name', 'family'])
190191

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

222223
def test_query_paginate_with_offset(self):
223-
query = self.dataset.query('Character')
224+
query = self._base_query()
224225
offset = 2
225226
limit = 3
226227
page_query = query.offset(offset).limit(limit).order('appearances')
@@ -246,7 +247,7 @@ def test_query_paginate_with_offset(self):
246247
self.assertEqual(entities[2]['name'], 'Arya')
247248

248249
def test_query_paginate_with_start_cursor(self):
249-
query = self.dataset.query('Character')
250+
query = self._base_query()
250251
offset = 2
251252
limit = 2
252253
page_query = query.offset(offset).limit(limit).order('appearances')
@@ -259,7 +260,7 @@ def test_query_paginate_with_start_cursor(self):
259260

260261
# Use cursor to create a fresh query.
261262
cursor = page_query.cursor()
262-
fresh_query = self.dataset.query('Character')
263+
fresh_query = self._base_query()
263264
fresh_query = fresh_query.order('appearances').with_cursor(cursor)
264265

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

271272
def test_query_group_by(self):
272-
query = self.dataset.query('Character').group_by(['alive'])
273+
query = self._base_query().group_by(['alive'])
273274

274275
expected_matches = 2
275276
# We expect 2, but allow the query to get 1 extra.

regression/populate_datastore.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,23 @@
77
from regression import regression_utils
88

99

10+
ANCESTOR = {'kind': 'Book', 'name': 'GoT'}
11+
RICKARD = {'kind': 'Character', 'name': 'Rickard'}
12+
EDDARD = {'kind': 'Character', 'name': 'Eddard'}
1013
KEY_PATHS = [
11-
[{'kind': 'Character', 'name': 'Rickard'}],
12-
[{'kind': 'Character', 'name': 'Rickard'},
13-
{'kind': 'Character', 'name': 'Eddard'}],
14-
[{'kind': 'Character', 'name': 'Catelyn'}],
15-
[{'kind': 'Character', 'name': 'Eddard'},
14+
[ANCESTOR, RICKARD],
15+
[ANCESTOR, RICKARD, EDDARD],
16+
[ANCESTOR,
17+
{'kind': 'Character', 'name': 'Catelyn'}],
18+
[ANCESTOR, RICKARD, EDDARD,
1619
{'kind': 'Character', 'name': 'Arya'}],
17-
[{'kind': 'Character', 'name': 'Eddard'},
20+
[ANCESTOR, RICKARD, EDDARD,
1821
{'kind': 'Character', 'name': 'Sansa'}],
19-
[{'kind': 'Character', 'name': 'Eddard'},
22+
[ANCESTOR, RICKARD, EDDARD,
2023
{'kind': 'Character', 'name': 'Robb'}],
21-
[{'kind': 'Character', 'name': 'Eddard'},
24+
[ANCESTOR, RICKARD, EDDARD,
2225
{'kind': 'Character', 'name': 'Bran'}],
23-
[{'kind': 'Character', 'name': 'Eddard'},
26+
[ANCESTOR, RICKARD, EDDARD,
2427
{'kind': 'Character', 'name': 'Jon Snow'}],
2528
]
2629
CHARACTERS = [

0 commit comments

Comments
 (0)