Skip to content

Commit 37ed7ed

Browse files
committed
---
yaml --- r: 61 b: refs/heads/master c: 86625f8 h: refs/heads/master i: 59: c02f8d4 v: v3
1 parent 057c717 commit 37ed7ed

5 files changed

Lines changed: 99 additions & 28 deletions

File tree

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/master: 0e4ec0896bdf7893cc946e9a8209fa2f69f6eb9d
2+
refs/heads/master: 86625f83b117123a1ef8d793796910029a0842f0

trunk/src/main/java/com/google/gcloud/datastore/BaseEntity.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,6 @@ public B set(String name, Value<?> value) {
6868
return self();
6969
}
7070

71-
public B setNull(String name) {
72-
properties.put(name, of());
73-
return self();
74-
}
75-
7671
public B set(String name, String value) {
7772
properties.put(name, of(value));
7873
return self();
@@ -123,6 +118,11 @@ public B set(String name, Blob value) {
123118
return self();
124119
}
125120

121+
public B setNull(String name) {
122+
properties.put(name, of());
123+
return self();
124+
}
125+
126126
public E build() {
127127
return build(ImmutableSortedMap.copyOf(properties));
128128
}

trunk/src/main/java/com/google/gcloud/datastore/GqlQuery.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*
2727
* <h3>A usage example:</h3>
2828
*
29-
* When the type of the results is known the preferred usage would be:
29+
* <p>When the type of the results is known the preferred usage would be:
3030
* <pre> {@code
3131
* Query<Entity> query = GqlQuery.builder(ResultClass.full(), "select * from kind").build();
3232
* QueryResult<Entity> results = datastore.runQuery(query);
@@ -36,7 +36,7 @@
3636
* }
3737
* } </pre>
3838
*
39-
* When the type of the results is unknown you can use this approach:
39+
* <p>When the type of the results is unknown you can use this approach:
4040
* <pre> {@code
4141
* Query<?> query = GqlQuery.builder("select __key__ from kind").build();
4242
* QueryResult<?> results = datastore.runQuery(query);
@@ -48,6 +48,8 @@
4848
* }
4949
* }
5050
* } </pre>
51+
*
52+
* @param <V> the type of the result values this query will produce
5153
* @see <a href="https://cloud.google.com/datastore/docs/apis/gql/gql_reference">GQL Reference</a>
5254
*/
5355
public final class GqlQuery<V> extends Query<V> {

trunk/src/main/java/com/google/gcloud/datastore/StructuredQuery.java

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,40 @@
2222
import java.util.List;
2323
import java.util.Objects;
2424

25+
/**
26+
* An implementation of a Google Cloud Datastore Query that can be constructed by providing
27+
* all the specific query elements.
28+
*
29+
* <h3>A usage example:</h3>
30+
*
31+
* <p>A simple query that returns all entities for a specific kind
32+
* <pre> {@code
33+
* StructuredQuery<Entity> query = StructuredQuery.builder().kind(kind).build();
34+
* QueryResult<Entity> results = datastore.runQuery(query);
35+
* while (results.hasNext()) {
36+
* Entity entity = results.next();
37+
* ...
38+
* }
39+
* } </pre>
40+
*
41+
* <p>A less trivial example of a projection query that returns the first 10 results
42+
* of "age" and "name" properties (sorted and grouped by "age") with an age greater than 18
43+
* <pre> {@code
44+
* StructuredQuery<PartialEntity> query = StructuredQuery.projectionBuilder()
45+
* .kind(kind)
46+
* .projection(Projection.property("age"), Projection.first("name"))
47+
* .filter(PropertyFilter.gt("age", 18))
48+
* .groupBy("age")
49+
* .orderBy(OrderBy.asc("age"))
50+
* .limit(10)
51+
* .build();
52+
* QueryResult<PartialEntity> results = datastore.runQuery(query);
53+
* ...
54+
* } </pre>
55+
*
56+
* @param <V> the type of the result values this query will produce
57+
* @see <a href="https://cloud.google.com/appengine/docs/java/datastore/queries">Datastore queries</a>
58+
*/
2559
public class StructuredQuery<V> extends Query<V> {
2660

2761
private static final long serialVersionUID = 546838955624019594L;
@@ -361,8 +395,8 @@ public static PropertyFilter eq(String property, Blob value) {
361395
return new PropertyFilter(property, Operator.EQUAL, of(value));
362396
}
363397

364-
public static PropertyFilter hasAncestor(String property, Key key) {
365-
return new PropertyFilter(property, Operator.HAS_ANCESTOR, of(key));
398+
public static PropertyFilter hasAncestor(Key key) {
399+
return new PropertyFilter(KEY_PROPERTY_NAME, Operator.HAS_ANCESTOR, of(key));
366400
}
367401

368402
public static PropertyFilter isNull(String property) {
@@ -897,12 +931,6 @@ protected StructuredQuery<V> nextQuery(DatastoreV1.QueryResultBatch responsePb)
897931
return builder.build();
898932
}
899933

900-
@Override
901-
protected Object fromPb(ResultClass<V> resultClass, String namespace, byte[] bytesPb)
902-
throws InvalidProtocolBufferException {
903-
return fromPb(resultClass, namespace, DatastoreV1.Query.parseFrom(bytesPb));
904-
}
905-
906934
@Override
907935
protected DatastoreV1.Query toPb() {
908936
DatastoreV1.Query.Builder queryPb = DatastoreV1.Query.newBuilder();
@@ -936,6 +964,12 @@ protected DatastoreV1.Query toPb() {
936964
return queryPb.build();
937965
}
938966

967+
@Override
968+
protected Object fromPb(ResultClass<V> resultClass, String namespace, byte[] bytesPb)
969+
throws InvalidProtocolBufferException {
970+
return fromPb(resultClass, namespace, DatastoreV1.Query.parseFrom(bytesPb));
971+
}
972+
939973
static StructuredQuery<?> fromPb(ResultClass<?> resultClass, String namespace,
940974
DatastoreV1.Query queryPb) {
941975
BaseBuilder<?, ?> builder;

trunk/src/test/java/com/google/gcloud/datastore/DatastoreServiceTest.java

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
import com.google.gcloud.datastore.Query.ResultClass;
1212
import com.google.gcloud.datastore.StructuredQuery.OrderBy;
13+
import com.google.gcloud.datastore.StructuredQuery.Projection;
14+
import com.google.gcloud.datastore.StructuredQuery.PropertyFilter;
1315

1416
import org.junit.Before;
1517
import org.junit.Test;
@@ -48,7 +50,7 @@ public class DatastoreServiceTest {
4850
.set("bool", BOOL_VALUE).set("partial1", EntityValue.of(PARTIAL_ENTITY1))
4951
.set("list", LIST_VALUE2).build();
5052
private static final Entity ENTITY2 = Entity.builder(ENTITY1).key(KEY2).remove("str")
51-
.setNull("null").build();
53+
.set("name", "koko").setNull("null").set("age", 20).build();
5254
private static final Entity ENTITY3 = Entity.builder(ENTITY1).key(KEY3).remove("str")
5355
.set("null", NULL_VALUE).set("partial1", PARTIAL_ENTITY2).set("partial2", ENTITY2).build();
5456

@@ -138,7 +140,29 @@ public void testTransactionWithRead() {
138140

139141
@Test
140142
public void testTransactionWithQuery() {
141-
fail("not implemented");
143+
Query<Entity> query =
144+
StructuredQuery.builder().kind(KIND2).filter(PropertyFilter.hasAncestor(KEY2)).build();
145+
Transaction transaction = datastore.newTransaction();
146+
QueryResult<Entity> results = transaction.runQuery(query);
147+
assertEquals(ENTITY2, results.next());
148+
assertFalse(results.hasNext());
149+
transaction.add(ENTITY3);
150+
transaction.commit();
151+
assertEquals(ENTITY3, datastore.get(KEY3));
152+
153+
transaction = datastore.newTransaction();
154+
results = transaction.runQuery(query);
155+
assertEquals(ENTITY2, results.next());
156+
transaction.delete(ENTITY3.key());
157+
// update entity2 during the transaction
158+
datastore.put(Entity.builder(ENTITY2).clear().build());
159+
try {
160+
transaction.commit();
161+
fail("Expecting a failure");
162+
} catch (DatastoreServiceException expected) {
163+
expected.printStackTrace();
164+
assertEquals(DatastoreServiceException.Code.ABORTED, expected.code());
165+
}
142166
}
143167

144168
@Test
@@ -311,19 +335,30 @@ public void testRunStructuredQuery() {
311335
assertFalse(results1.hasNext());
312336

313337
StructuredQuery<Key> keyOnlyQuery = StructuredQuery.keyOnlyBuilder().kind(KIND1).build();
338+
QueryResult<Key> results2 = datastore.runQuery(keyOnlyQuery);
339+
assertTrue(results2.hasNext());
340+
assertEquals(ENTITY1.key(), results2.next());
341+
assertFalse(results2.hasNext());
314342

343+
StructuredQuery<PartialEntity> projectionQuery = StructuredQuery.projectionBuilder()
344+
.kind(KIND2)
345+
.projection(Projection.property("age"), Projection.first("name"))
346+
.filter(PropertyFilter.gt("age", 18))
347+
.groupBy("age")
348+
.orderBy(OrderBy.asc("age"))
349+
.limit(10)
350+
.build();
315351

316-
// todo(ozarov): construct a test to very nextQuery/pagination
317-
}
318-
319-
@Test
320-
public void testRunStructuredQueryProjection() {
321-
fail("Not yet implemented");
322-
}
352+
QueryResult<PartialEntity> results3 = datastore.runQuery(projectionQuery);
353+
assertTrue(results3.hasNext());
354+
PartialEntity entity = results3.next();
355+
assertEquals(ENTITY2.key(), entity.key());
356+
assertEquals(20, entity.getLong("age"));
357+
assertEquals("koko", entity.getString("name"));
358+
assertEquals(2, entity.properties().size());
359+
assertFalse(results3.hasNext());
323360

324-
@Test
325-
public void testRunStructuredQueryKeysOnly() {
326-
fail("Not yet implemented");
361+
// TODO(ozarov): construct a test to very nextQuery/pagination
327362
}
328363

329364
@Test

0 commit comments

Comments
 (0)