Skip to content

Commit 8d758bd

Browse files
committed
Add App Engine Cloud Datastore metadata queries samples.
From https://cloud.google.com/appengine/docs/java/datastore/metadataqueries.
1 parent 09ceb9c commit 8d758bd

File tree

4 files changed

+671
-0
lines changed

4 files changed

+671
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* Copyright 2016 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.appengine;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
21+
import com.google.appengine.api.datastore.DatastoreService;
22+
import com.google.appengine.api.datastore.DatastoreServiceFactory;
23+
import com.google.appengine.api.datastore.Entities;
24+
import com.google.appengine.api.datastore.Entity;
25+
import com.google.appengine.api.datastore.EntityNotFoundException;
26+
import com.google.appengine.api.datastore.FetchOptions;
27+
import com.google.appengine.api.datastore.Key;
28+
import com.google.appengine.api.datastore.PreparedQuery;
29+
import com.google.appengine.api.datastore.Query;
30+
import com.google.appengine.api.datastore.Transaction;
31+
import com.google.appengine.api.memcache.MemcacheService;
32+
import com.google.appengine.api.memcache.MemcacheServiceFactory;
33+
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
34+
import com.google.appengine.tools.development.testing.LocalMemcacheServiceTestConfig;
35+
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
36+
import org.junit.After;
37+
import org.junit.Before;
38+
import org.junit.Test;
39+
import org.junit.runner.RunWith;
40+
import org.junit.runners.JUnit4;
41+
42+
import java.io.PrintWriter;
43+
import java.io.Serializable;
44+
import java.io.StringWriter;
45+
46+
/**
47+
* Unit tests to demonstrate App Engine Datastore entity group metadata.
48+
*/
49+
@RunWith(JUnit4.class)
50+
public class MetadataEntityGroupTest {
51+
52+
private final LocalServiceTestHelper helper =
53+
new LocalServiceTestHelper(
54+
// Set no eventual consistency, that way queries return all results.
55+
// https://cloud.google.com/appengine/docs/java/tools/localunittesting#Java_Writing_High_Replication_Datastore_tests
56+
new LocalDatastoreServiceTestConfig().setDefaultHighRepJobPolicyUnappliedJobPercentage(0),
57+
new LocalMemcacheServiceTestConfig());
58+
59+
private DatastoreService datastore;
60+
61+
@Before
62+
public void setUp() {
63+
helper.setUp();
64+
datastore = DatastoreServiceFactory.getDatastoreService();
65+
}
66+
67+
@After
68+
public void tearDown() {
69+
helper.tearDown();
70+
}
71+
72+
// [START entity_group_1]
73+
private static long getEntityGroupVersion(DatastoreService ds, Transaction tx, Key entityKey) {
74+
try {
75+
return Entities.getVersionProperty(ds.get(tx, Entities.createEntityGroupKey(entityKey)));
76+
} catch (EntityNotFoundException e) {
77+
// No entity group information, return a value strictly smaller than any
78+
// possible version
79+
return 0;
80+
}
81+
}
82+
83+
private static void printEntityGroupVersions(DatastoreService ds, PrintWriter writer) {
84+
Entity entity1 = new Entity("Simple");
85+
Key key1 = ds.put(entity1);
86+
Key entityGroupKey = Entities.createEntityGroupKey(key1);
87+
88+
// Print entity1's entity group version
89+
writer.println("version " + getEntityGroupVersion(ds, null, key1));
90+
91+
// Write to a different entity group
92+
Entity entity2 = new Entity("Simple");
93+
ds.put(entity2);
94+
95+
// Will print the same version, as entity1's entity group has not changed
96+
writer.println("version " + getEntityGroupVersion(ds, null, key1));
97+
98+
// Change entity1's entity group by adding a new child entity
99+
Entity entity3 = new Entity("Simple", entity1.getKey());
100+
ds.put(entity3);
101+
102+
// Will print a higher version, as entity1's entity group has changed
103+
writer.println("version " + getEntityGroupVersion(ds, null, key1));
104+
}
105+
// [END entity_group_1]
106+
107+
@Test
108+
public void printEntityGroupVersions_printsVersions() throws Exception {
109+
StringWriter responseWriter = new StringWriter();
110+
printEntityGroupVersions(datastore, new PrintWriter(responseWriter));
111+
assertThat(responseWriter.toString()).contains("version");
112+
}
113+
114+
// [START entity_group_2]
115+
// A simple class for tracking consistent entity group counts.
116+
private static class EntityGroupCount implements Serializable {
117+
long version; // Version of the entity group whose count we are tracking
118+
int count;
119+
120+
EntityGroupCount(long version, int count) {
121+
this.version = version;
122+
this.count = count;
123+
}
124+
125+
// Display count of entities in an entity group, with consistent caching
126+
void showEntityGroupCount(
127+
DatastoreService ds, MemcacheService cache, PrintWriter writer, Key entityGroupKey) {
128+
EntityGroupCount egCount = (EntityGroupCount) cache.get(entityGroupKey);
129+
// Reuses getEntityGroupVersion method from the previous example.
130+
if (egCount != null && egCount.version == getEntityGroupVersion(ds, null, entityGroupKey)) {
131+
// Cached value matched current entity group version, use that
132+
writer.println(egCount.count + " entities (cached)");
133+
} else {
134+
// Need to actually count entities. Using a transaction to get a consistent count
135+
// and entity group version.
136+
Transaction tx = ds.beginTransaction();
137+
PreparedQuery pq = ds.prepare(tx, new Query(entityGroupKey));
138+
int count = pq.countEntities(FetchOptions.Builder.withLimit(5000));
139+
cache.put(
140+
entityGroupKey,
141+
new EntityGroupCount(getEntityGroupVersion(ds, tx, entityGroupKey), count));
142+
tx.rollback();
143+
writer.println(count + " entities");
144+
}
145+
}
146+
}
147+
// [END entity_group_2]
148+
149+
@Test
150+
public void entityGroupCount_printsCount() throws Exception {
151+
StringWriter responseWriter = new StringWriter();
152+
MemcacheService cache = MemcacheServiceFactory.getMemcacheService();
153+
Entity entity1 = new Entity("Simple");
154+
Key key1 = datastore.put(entity1);
155+
Key entityGroupKey = Entities.createEntityGroupKey(key1);
156+
157+
EntityGroupCount groupCount = new EntityGroupCount(0, 0);
158+
groupCount.showEntityGroupCount(
159+
datastore, cache, new PrintWriter(responseWriter), entityGroupKey);
160+
161+
assertThat(responseWriter.toString()).contains(" entities");
162+
}
163+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Copyright 2016 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.appengine;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
21+
import com.google.appengine.api.datastore.DatastoreService;
22+
import com.google.appengine.api.datastore.DatastoreServiceFactory;
23+
import com.google.appengine.api.datastore.Entities;
24+
import com.google.appengine.api.datastore.Entity;
25+
import com.google.appengine.api.datastore.Query;
26+
import com.google.appengine.api.datastore.Query.CompositeFilterOperator;
27+
import com.google.appengine.api.datastore.Query.Filter;
28+
import com.google.appengine.api.datastore.Query.FilterOperator;
29+
import com.google.appengine.api.datastore.Query.FilterPredicate;
30+
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
31+
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
32+
import org.junit.After;
33+
import org.junit.Before;
34+
import org.junit.Test;
35+
import org.junit.runner.RunWith;
36+
import org.junit.runners.JUnit4;
37+
38+
import java.io.PrintWriter;
39+
import java.io.StringWriter;
40+
import java.util.ArrayList;
41+
import java.util.List;
42+
43+
/**
44+
* Unit tests to demonstrate App Engine Datastore kinds metadata.
45+
*/
46+
@RunWith(JUnit4.class)
47+
public class MetadataKindsTest {
48+
49+
private final LocalServiceTestHelper helper =
50+
new LocalServiceTestHelper(
51+
// Set no eventual consistency, that way queries return all results.
52+
// https://cloud.google.com/appengine/docs/java/tools/localunittesting#Java_Writing_High_Replication_Datastore_tests
53+
new LocalDatastoreServiceTestConfig()
54+
.setDefaultHighRepJobPolicyUnappliedJobPercentage(0));
55+
56+
private StringWriter responseWriter;
57+
private DatastoreService datastore;
58+
59+
@Before
60+
public void setUp() {
61+
helper.setUp();
62+
datastore = DatastoreServiceFactory.getDatastoreService();
63+
responseWriter = new StringWriter();
64+
}
65+
66+
@After
67+
public void tearDown() {
68+
helper.tearDown();
69+
}
70+
71+
// [START kind_query_example]
72+
void printLowercaseKinds(DatastoreService ds, PrintWriter writer) {
73+
74+
// Start with unrestricted kind query
75+
Query q = new Query(Entities.KIND_METADATA_KIND);
76+
77+
List<Filter> subFils = new ArrayList();
78+
79+
// Limit to lowercase initial letters
80+
subFils.add(
81+
new FilterPredicate(
82+
Entity.KEY_RESERVED_PROPERTY,
83+
FilterOperator.GREATER_THAN_OR_EQUAL,
84+
Entities.createKindKey("a")));
85+
86+
String endChar = Character.toString((char) ('z' + 1)); // Character after 'z'
87+
88+
subFils.add(
89+
new FilterPredicate(
90+
Entity.KEY_RESERVED_PROPERTY,
91+
FilterOperator.LESS_THAN,
92+
Entities.createKindKey(endChar)));
93+
94+
q.setFilter(CompositeFilterOperator.and(subFils));
95+
96+
// Print heading
97+
writer.println("Lowercase kinds:");
98+
99+
// Print query results
100+
for (Entity e : ds.prepare(q).asIterable()) {
101+
writer.println(" " + e.getKey().getName());
102+
}
103+
}
104+
// [END kind_query_example]
105+
106+
@Test
107+
public void printLowercaseKinds_printsKinds() throws Exception {
108+
datastore.put(new Entity("alpha"));
109+
datastore.put(new Entity("beta"));
110+
datastore.put(new Entity("NotIncluded"));
111+
datastore.put(new Entity("zed"));
112+
113+
printLowercaseKinds(datastore, new PrintWriter(responseWriter));
114+
115+
String response = responseWriter.toString();
116+
assertThat(response).contains("alpha");
117+
assertThat(response).contains("beta");
118+
assertThat(response).contains("zed");
119+
assertThat(response).doesNotContain("NotIncluded");
120+
}
121+
}

0 commit comments

Comments
 (0)