From c029c378fd2d09928802c75f8ca9c21e2aafb477 Mon Sep 17 00:00:00 2001 From: Ajay Kannan Date: Mon, 5 Oct 2015 15:55:10 -0700 Subject: [PATCH 1/5] Update query-related datastore code to v1beta3 --- .../com/google/gcloud/datastore/Blob.java | 10 +- .../com/google/gcloud/datastore/Cursor.java | 15 +- .../gcloud/datastore/DatastoreImpl.java | 4 +- .../com/google/gcloud/datastore/GqlQuery.java | 129 ++++++------ .../com/google/gcloud/datastore/Query.java | 59 +++--- .../google/gcloud/datastore/QueryResults.java | 1 - .../gcloud/datastore/QueryResultsImpl.java | 44 ++-- .../gcloud/datastore/StructuredQuery.java | 191 ++++++++---------- .../gcloud/datastore/DatastoreTest.java | 19 +- .../gcloud/datastore/SerializationTest.java | 12 +- 10 files changed, 221 insertions(+), 263 deletions(-) diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Blob.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Blob.java index 5a759240be38..fbe2887d9b35 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Blob.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Blob.java @@ -18,8 +18,6 @@ import static com.google.common.base.Preconditions.checkNotNull; -import com.google.api.services.datastore.DatastoreV1; -import com.google.api.services.datastore.DatastoreV1.Value; import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects.ToStringHelper; import com.google.protobuf.ByteString; @@ -37,7 +35,7 @@ * * @see Google Cloud Datastore Entities, Properties, and Keys */ -public final class Blob extends Serializable { +public final class Blob extends Serializable { private static final long serialVersionUID = 3835421019618247721L; @@ -146,12 +144,12 @@ public static Blob copyFrom(InputStream input) throws IOException { } @Override - protected Value toPb() { - return DatastoreV1.Value.newBuilder().setBlobValue(byteString).build(); + protected com.google.datastore.v1beta3.Value toPb() { + return com.google.datastore.v1beta3.Value.newBuilder().setBlobValue(byteString).build(); } @Override protected Object fromPb(byte[] bytesPb) throws InvalidProtocolBufferException { - return new Blob(DatastoreV1.Value.parseFrom(bytesPb).getBlobValue()); + return new Blob(com.google.datastore.v1beta3.Value.parseFrom(bytesPb).getBlobValue()); } } diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Cursor.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Cursor.java index 42a8cee8e5a2..df237e4d897c 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Cursor.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Cursor.java @@ -19,8 +19,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import static java.nio.charset.StandardCharsets.UTF_8; -import com.google.api.services.datastore.DatastoreV1; -import com.google.api.services.datastore.DatastoreV1.Value; import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects.ToStringHelper; import com.google.common.base.Preconditions; @@ -37,7 +35,7 @@ * A Google Cloud Datastore cursor. * The cursor can be used to as a starting point or an ending point for a {@link Query} */ -public final class Cursor extends Serializable { +public final class Cursor extends Serializable { private static final long serialVersionUID = -1423744878777486541L; @@ -89,7 +87,8 @@ public String toUrlSafe() { public static Cursor fromUrlSafe(String urlSafe) { try { String utf8Str = URLDecoder.decode(urlSafe, UTF_8.name()); - DatastoreV1.Value.Builder builder = DatastoreV1.Value.newBuilder(); + com.google.datastore.v1beta3.Value.Builder builder = + com.google.datastore.v1beta3.Value.newBuilder(); TextFormat.merge(utf8Str, builder); return fromPb(builder.build()); } catch (UnsupportedEncodingException | ParseException e) { @@ -102,16 +101,16 @@ public static Cursor copyFrom(byte[] bytes) { } @Override - protected Value toPb() { - return DatastoreV1.Value.newBuilder().setBlobValue(byteString).build(); + protected com.google.datastore.v1beta3.Value toPb() { + return com.google.datastore.v1beta3.Value.newBuilder().setBlobValue(byteString).build(); } @Override protected Object fromPb(byte[] bytesPb) throws InvalidProtocolBufferException { - return fromPb(DatastoreV1.Value.parseFrom(bytesPb)); + return fromPb(com.google.datastore.v1beta3.Value.parseFrom(bytesPb)); } - static Cursor fromPb(DatastoreV1.Value valuePb) { + static Cursor fromPb(com.google.datastore.v1beta3.Value valuePb) { return new Cursor(valuePb.getBlobValue()); } } diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/DatastoreImpl.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/DatastoreImpl.java index 59804831872c..fdd8917d11e2 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/DatastoreImpl.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/DatastoreImpl.java @@ -99,9 +99,7 @@ public QueryResults run(Query query) { } QueryResults run(com.google.datastore.v1beta3.ReadOptions readOptionsPb, Query query) { - // TODO(ajaykannan): fix me! - //return new QueryResultsImpl<>(this, readOptionsPb, query); - return null; // TODO(ajaykannan): fix me! + return new QueryResultsImpl<>(this, readOptionsPb, query); } com.google.datastore.v1beta3.RunQueryResponse runQuery( diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/GqlQuery.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/GqlQuery.java index 54110a89c3e0..2c02aa7b970c 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/GqlQuery.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/GqlQuery.java @@ -19,7 +19,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.gcloud.datastore.Validator.validateNamespace; -import com.google.api.services.datastore.DatastoreV1; import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -75,25 +74,22 @@ public final class GqlQuery extends Query { private final transient String queryString; private final transient boolean allowLiteral; - private final transient ImmutableList namedBindings; + private final transient ImmutableMap namedBindings; private final transient ImmutableList positionalBindings; - static final class Binding extends Serializable { + static final class Binding extends Serializable { private static final long serialVersionUID = 1976895435257636275L; - private final transient String name; private final transient Cursor cursor; private final transient Value value; - Binding(String name, Cursor cursor) { - this.name = name; + Binding(Cursor cursor) { this.cursor = checkNotNull(cursor); value = null; } - Binding(String name, Value value) { - this.name = name; + Binding(Value value) { this.value = checkNotNull(value); cursor = null; } @@ -102,13 +98,9 @@ Object cursorOrValue() { return MoreObjects.firstNonNull(cursor, value); } - String name() { - return name; - } - @Override public int hashCode() { - return Objects.hash(name, cursor, value); + return Objects.hash(cursor, value); } @Override @@ -120,40 +112,36 @@ public boolean equals(Object obj) { return false; } Binding other = (Binding) obj; - return Objects.equals(name, other.name) - && Objects.equals(cursor, other.cursor) - && Objects.equals(value, other.value); + return Objects.equals(cursor, other.cursor) && Objects.equals(value, other.value); } @Override - protected DatastoreV1.GqlQueryArg toPb() { - DatastoreV1.GqlQueryArg.Builder argPb = DatastoreV1.GqlQueryArg.newBuilder(); - if (name != null) { - argPb.setName(name); - } + protected com.google.datastore.v1beta3.GqlQueryParameter toPb() { + com.google.datastore.v1beta3.GqlQueryParameter.Builder argPb = + com.google.datastore.v1beta3.GqlQueryParameter.newBuilder(); if (cursor != null) { argPb.setCursor(cursor.byteString()); } if (value != null) { - // TODO(ajaykannan): fix me! - //argPb.setValue(value.toPb()); + argPb.setValue(value.toPb()); } return argPb.build(); } @Override protected Object fromPb(byte[] bytesPb) throws InvalidProtocolBufferException { - return fromPb(DatastoreV1.GqlQueryArg.parseFrom(bytesPb)); + return fromPb(com.google.datastore.v1beta3.GqlQueryParameter.parseFrom(bytesPb)); } - static Binding fromPb(DatastoreV1.GqlQueryArg argPb) { - String name = argPb.hasName() ? argPb.getName() : null; - if (argPb.hasCursor()) { - return new Binding(name, new Cursor(argPb.getCursor())); + static Binding fromPb(com.google.datastore.v1beta3.GqlQueryParameter argPb) { + switch (argPb.getParameterTypeCase()) { + case CURSOR: + return new Binding(new Cursor(argPb.getCursor())); + case VALUE: + return new Binding(Value.fromPb(argPb.getValue())); + default: + return null; } - // TODO(ajaykannan): fix me! - //return new Binding(name, Value.fromPb(argPb.getValue())); - return new Binding(name, new Cursor(null)); // TODO(ajaykannan): fix me! } } @@ -196,52 +184,52 @@ public Builder clearBindings() { } public Builder setBinding(String name, Cursor cursor) { - namedBindings.put(name, new Binding(name, cursor)); + namedBindings.put(name, new Binding(cursor)); return this; } public Builder setBinding(String name, String... value) { - namedBindings.put(name, toBinding(name, StringValue.MARSHALLER, Arrays.asList(value))); + namedBindings.put(name, toBinding(StringValue.MARSHALLER, Arrays.asList(value))); return this; } public Builder setBinding(String name, long... value) { - namedBindings.put(name, toBinding(name, LongValue.MARSHALLER, Longs.asList(value))); + namedBindings.put(name, toBinding(LongValue.MARSHALLER, Longs.asList(value))); return this; } public Builder setBinding(String name, double... value) { - namedBindings.put(name, toBinding(name, DoubleValue.MARSHALLER, Doubles.asList(value))); + namedBindings.put(name, toBinding(DoubleValue.MARSHALLER, Doubles.asList(value))); return this; } public Builder setBinding(String name, boolean... value) { - namedBindings.put(name, toBinding(name, BooleanValue.MARSHALLER, Booleans.asList(value))); + namedBindings.put(name, toBinding(BooleanValue.MARSHALLER, Booleans.asList(value))); return this; } public Builder setBinding(String name, DateTime... value) { - namedBindings.put(name, toBinding(name, DateTimeValue.MARSHALLER, Arrays.asList(value))); + namedBindings.put(name, toBinding(DateTimeValue.MARSHALLER, Arrays.asList(value))); return this; } public Builder setBinding(String name, Key... value) { - namedBindings.put(name, toBinding(name, KeyValue.MARSHALLER, Arrays.asList(value))); + namedBindings.put(name, toBinding(KeyValue.MARSHALLER, Arrays.asList(value))); return this; } public Builder setBinding(String name, FullEntity... value) { - namedBindings.put(name, toBinding(name, EntityValue.MARSHALLER, Arrays.asList(value))); + namedBindings.put(name, toBinding(EntityValue.MARSHALLER, Arrays.asList(value))); return this; } public Builder setBinding(String name, Blob... value) { - namedBindings.put(name, toBinding(name, BlobValue.MARSHALLER, Arrays.asList(value))); + namedBindings.put(name, toBinding(BlobValue.MARSHALLER, Arrays.asList(value))); return this; } public Builder addBinding(Cursor cursor) { - positionalBindings.add(new Binding(null, cursor)); + positionalBindings.add(new Binding(cursor)); return this; } @@ -289,11 +277,7 @@ public GqlQuery build() { return new GqlQuery<>(this); } - private static Binding toBinding(Value.BuilderFactory builderFactory, List values) { - return toBinding(null, builderFactory, values); - } - - private static Binding toBinding(String name, Value.BuilderFactory builderFactory, + private static Binding toBinding(Value.BuilderFactory builderFactory, List values) { List> list = new ArrayList<>(values.size()); for (Object object : values) { @@ -309,7 +293,7 @@ private static Binding toBinding(String name, Value.BuilderFactory } else { value = new ListValue(list); } - return new Binding(name, value); + return new Binding(value); } } @@ -317,7 +301,7 @@ private GqlQuery(Builder builder) { super(builder.resultType, builder.namespace); queryString = builder.queryString; allowLiteral = builder.allowLiteral; - namedBindings = ImmutableList.copyOf(builder.namedBindings.values()); + namedBindings = ImmutableMap.copyOf(builder.namedBindings); positionalBindings = ImmutableList.copyOf(builder.positionalBindings); } @@ -334,8 +318,8 @@ public boolean allowLiteral() { */ public Map namedBindings() { ImmutableMap.Builder builder = ImmutableSortedMap.naturalOrder(); - for (Binding binding : namedBindings) { - builder.put(binding.name(), binding.cursorOrValue()); + for (Map.Entry binding : namedBindings.entrySet()) { + builder.put(binding.getKey(), binding.getValue().cursorOrValue()); } return builder.build(); } @@ -373,26 +357,29 @@ public boolean equals(Object obj) { } @Override - protected DatastoreV1.GqlQuery toPb() { - DatastoreV1.GqlQuery.Builder queryPb = DatastoreV1.GqlQuery.newBuilder(); + protected com.google.datastore.v1beta3.GqlQuery toPb() { + com.google.datastore.v1beta3.GqlQuery.Builder queryPb = + com.google.datastore.v1beta3.GqlQuery.newBuilder(); queryPb.setQueryString(queryString); - queryPb.setAllowLiteral(allowLiteral); - for (Binding argument : namedBindings) { - queryPb.addNameArg(argument.toPb()); + queryPb.setAllowLiterals(allowLiteral); + Map namedBindingsPb = + queryPb.getMutableNamedBindings(); + for (Map.Entry entry : namedBindings.entrySet()) { + namedBindingsPb.put(entry.getKey(), entry.getValue().toPb()); } for (Binding argument : positionalBindings) { - queryPb.addNumberArg(argument.toPb()); + queryPb.addPositionalBindings(argument.toPb()); } return queryPb.build(); } @Override - protected void populatePb(DatastoreV1.RunQueryRequest.Builder requestPb) { + protected void populatePb(com.google.datastore.v1beta3.RunQueryRequest.Builder requestPb) { requestPb.setGqlQuery(toPb()); } @Override - protected GqlQuery nextQuery(DatastoreV1.QueryResultBatch responsePb) { + protected GqlQuery nextQuery(com.google.datastore.v1beta3.QueryResultBatch responsePb) { // See issue #17 throw new UnsupportedOperationException("paging for this query is not implemented yet"); } @@ -400,23 +387,27 @@ protected GqlQuery nextQuery(DatastoreV1.QueryResultBatch responsePb) { @Override protected Object fromPb(ResultType resultType, String namespace, byte[] bytesPb) throws InvalidProtocolBufferException { - return fromPb(resultType, namespace, DatastoreV1.GqlQuery.parseFrom(bytesPb)); + return fromPb(resultType, namespace, com.google.datastore.v1beta3.GqlQuery.parseFrom(bytesPb)); } private static GqlQuery fromPb( - ResultType resultType, String ns, DatastoreV1.GqlQuery queryPb) { + ResultType resultType, String ns, com.google.datastore.v1beta3.GqlQuery queryPb) { Builder builder = new Builder<>(resultType, queryPb.getQueryString()); builder.namespace(ns); - if (queryPb.hasAllowLiteral()) { - builder.allowLiteral = queryPb.getAllowLiteral(); - } - for (DatastoreV1.GqlQueryArg nameArg : queryPb.getNameArgList()) { - Binding argument = Binding.fromPb(nameArg); - builder.namedBindings.put(argument.name(), argument); + builder.allowLiteral = queryPb.getAllowLiterals(); + for (Map.Entry nameArg + : queryPb.getNamedBindings().entrySet()) { + Binding currBinding = Binding.fromPb(nameArg.getValue()); + if (currBinding != null) { + builder.namedBindings.put(nameArg.getKey(), currBinding); + } } - for (DatastoreV1.GqlQueryArg numberArg : queryPb.getNumberArgList()) { - Binding argument = Binding.fromPb(numberArg); - builder.positionalBindings.add(argument); + for (com.google.datastore.v1beta3.GqlQueryParameter numberArg + : queryPb.getPositionalBindingsList()) { + Binding currBinding = Binding.fromPb(numberArg); + if (currBinding != null) { + builder.positionalBindings.add(currBinding); + } } return builder.build(); } diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Query.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Query.java index 7fae120dd402..6e962d92fb2f 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Query.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Query.java @@ -18,7 +18,6 @@ import static com.google.common.base.Preconditions.checkNotNull; -import com.google.api.services.datastore.DatastoreV1; import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects.ToStringHelper; import com.google.common.collect.Maps; @@ -54,68 +53,65 @@ public abstract class Query extends Serializable { public abstract static class ResultType implements java.io.Serializable { private static final long serialVersionUID = 2104157695425806623L; - private static final Map> - PB_TO_INSTANCE = Maps.newEnumMap(DatastoreV1.EntityResult.ResultType.class); + private static final Map> + PB_TO_INSTANCE = Maps.newEnumMap( + com.google.datastore.v1beta3.EntityResult.ResultType.class); static final ResultType UNKNOWN = new ResultType(null, Object.class) { private static final long serialVersionUID = 1602329532153860907L; - @Override protected Object convert(DatastoreV1.Entity entityPb) { - if (entityPb.getPropertyCount() == 0) { + @Override protected Object convert(com.google.datastore.v1beta3.Entity entityPb) { + if (entityPb.getProperties().size() == 0) { if (!entityPb.hasKey()) { return null; } - //TODO(ajaykannan): fix me! - //return Key.fromPb(entityPb.getKey()); + return Key.fromPb(entityPb.getKey()); } - // TODO(ajaykannan): fix me! - //return ProjectionEntity.fromPb(entityPb); - return ProjectionEntity.fromPb((com.google.datastore.v1beta3.Entity) null); // TODO(ajaykannan): fix me! + return ProjectionEntity.fromPb(entityPb); } }; public static final ResultType ENTITY = - new ResultType(DatastoreV1.EntityResult.ResultType.FULL, Entity.class) { + new ResultType( + com.google.datastore.v1beta3.EntityResult.ResultType.FULL, Entity.class) { private static final long serialVersionUID = 7712959777507168274L; - @Override protected Entity convert(DatastoreV1.Entity entityPb) { - // TODO(ajaykannan): fix me! - //return Entity.fromPb(entityPb); - return Entity.fromPb((com.google.datastore.v1beta3.Entity) null); // TODO(ajaykannan): fix me! + @Override protected Entity convert(com.google.datastore.v1beta3.Entity entityPb) { + return Entity.fromPb(entityPb); } }; public static final ResultType KEY = - new ResultType(DatastoreV1.EntityResult.ResultType.KEY_ONLY, Key.class) { + new ResultType( + com.google.datastore.v1beta3.EntityResult.ResultType.KEY_ONLY, Key.class) { private static final long serialVersionUID = -8514289244104446252L; - @Override protected Key convert(DatastoreV1.Entity entityPb) { - //TODO(ajaykannan): fix me! - //return Key.fromPb(entityPb.getKey()); - return Key.builder(null).build(); // TODO(ajaykannan): fix me! + @Override protected Key convert(com.google.datastore.v1beta3.Entity entityPb) { + return Key.fromPb(entityPb.getKey()); } }; public static final ResultType PROJECTION_ENTITY = - new ResultType(DatastoreV1.EntityResult.ResultType.PROJECTION, + new ResultType( + com.google.datastore.v1beta3.EntityResult.ResultType.PROJECTION, ProjectionEntity.class) { private static final long serialVersionUID = -7591409419690650246L; - @Override protected ProjectionEntity convert(DatastoreV1.Entity entityPb) { - // TODO(ajaykannan): fix me! - //return ProjectionEntity.fromPb(entityPb); - return ProjectionEntity.fromPb((com.google.datastore.v1beta3.Entity) null); // TODO(ajaykannan): fix me! + @Override protected ProjectionEntity convert( + com.google.datastore.v1beta3.Entity entityPb) { + return ProjectionEntity.fromPb(entityPb); } }; private final Class resultClass; - private final DatastoreV1.EntityResult.ResultType queryType; + private final com.google.datastore.v1beta3.EntityResult.ResultType queryType; - private ResultType(DatastoreV1.EntityResult.ResultType queryType, Class resultClass) { + private ResultType(com.google.datastore.v1beta3.EntityResult.ResultType queryType, + Class resultClass) { this.queryType = queryType; this.resultClass = resultClass; if (queryType != null) { @@ -156,9 +152,9 @@ boolean isAssignableFrom(ResultType otherResultType) { return resultClass.isAssignableFrom(otherResultType.resultClass); } - protected abstract V convert(DatastoreV1.Entity entityPb); + protected abstract V convert(com.google.datastore.v1beta3.Entity entityPb); - static ResultType fromPb(DatastoreV1.EntityResult.ResultType typePb) { + static ResultType fromPb(com.google.datastore.v1beta3.EntityResult.ResultType typePb) { return MoreObjects.firstNonNull(PB_TO_INSTANCE.get(typePb), UNKNOWN); } } @@ -193,9 +189,10 @@ protected Object fromPb(byte[] bytesPb) throws InvalidProtocolBufferException { protected abstract Object fromPb(ResultType resultType, String namespace, byte[] bytesPb) throws InvalidProtocolBufferException; - protected abstract void populatePb(DatastoreV1.RunQueryRequest.Builder requestPb); + protected abstract void populatePb( + com.google.datastore.v1beta3.RunQueryRequest.Builder requestPb); - protected abstract Query nextQuery(DatastoreV1.QueryResultBatch responsePb); + protected abstract Query nextQuery(com.google.datastore.v1beta3.QueryResultBatch responsePb); /** * Returns a new {@link GqlQuery} builder. diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResults.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResults.java index b23c56a7c395..5b4f71da3963 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResults.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResults.java @@ -36,7 +36,6 @@ public interface QueryResults extends Iterator { /** * Returns the Cursor for point after the value returned in the last {@link #next} call. - * Not currently implemented (depends on v1beta3). */ Cursor cursorAfter(); } diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java index caf5d7f8a84f..b3c51ceb9eeb 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java @@ -16,11 +16,11 @@ package com.google.gcloud.datastore; -import com.google.api.services.datastore.DatastoreV1; -import com.google.api.services.datastore.DatastoreV1.QueryResultBatch.MoreResultsType; +import com.google.datastore.v1beta3.QueryResultBatch.MoreResultsType; import com.google.common.base.Preconditions; import com.google.common.collect.AbstractIterator; import com.google.gcloud.datastore.Query.ResultType; +import com.google.protobuf.ByteString; import java.util.Iterator; import java.util.Objects; @@ -28,46 +28,49 @@ class QueryResultsImpl extends AbstractIterator implements QueryResults { private final DatastoreImpl datastore; - private final DatastoreV1.ReadOptions readOptionsPb; - private final DatastoreV1.PartitionId partitionIdPb; + private final com.google.datastore.v1beta3.ReadOptions readOptionsPb; + private final com.google.datastore.v1beta3.PartitionId partitionIdPb; private final ResultType queryResultType; private Query query; private ResultType actualResultType; - private DatastoreV1.QueryResultBatch queryResultBatchPb; + private com.google.datastore.v1beta3.QueryResultBatch queryResultBatchPb; private boolean lastBatch; - private Iterator entityResultPbIter; - //private ByteString cursor; // only available in v1beta3 + private Iterator entityResultPbIter; + private ByteString cursor; - QueryResultsImpl(DatastoreImpl datastore, DatastoreV1.ReadOptions readOptionsPb, + QueryResultsImpl(DatastoreImpl datastore, com.google.datastore.v1beta3.ReadOptions readOptionsPb, Query query) { this.datastore = datastore; this.readOptionsPb = readOptionsPb; this.query = query; queryResultType = query.type(); - DatastoreV1.PartitionId.Builder pbBuilder = DatastoreV1.PartitionId.newBuilder(); - pbBuilder.setDatasetId(datastore.options().projectId()); + com.google.datastore.v1beta3.PartitionId.Builder pbBuilder = + com.google.datastore.v1beta3.PartitionId.newBuilder(); + pbBuilder.setProjectId(datastore.options().projectId()); if (query.namespace() != null) { - pbBuilder.setNamespace(query.namespace()); + pbBuilder.setNamespaceId(query.namespace()); } else if (datastore.options().namespace() != null) { - pbBuilder.setNamespace(datastore.options().namespace()); + pbBuilder.setNamespaceId(datastore.options().namespace()); } partitionIdPb = pbBuilder.build(); sendRequest(); } private void sendRequest() { - DatastoreV1.RunQueryRequest.Builder requestPb = DatastoreV1.RunQueryRequest.newBuilder(); + com.google.datastore.v1beta3.RunQueryRequest.Builder requestPb = + com.google.datastore.v1beta3.RunQueryRequest.newBuilder(); if (readOptionsPb != null) { requestPb.setReadOptions(readOptionsPb); } requestPb.setPartitionId(partitionIdPb); query.populatePb(requestPb); - // TODO(ajaykannan): fix me! - //queryResultBatchPb = datastore.runQuery(requestPb.build()).getBatch(); + queryResultBatchPb = datastore.runQuery(requestPb.build()).getBatch(); lastBatch = queryResultBatchPb.getMoreResults() != MoreResultsType.NOT_FINISHED; - entityResultPbIter = queryResultBatchPb.getEntityResultList().iterator(); - // cursor = resultPb.getSkippedCursor(); // available in v1beta3, use startCursor if not skipped + entityResultPbIter = queryResultBatchPb.getEntityResultsList().iterator(); + if (queryResultBatchPb.getSkippedResults() > 0) { + cursor = queryResultBatchPb.getSkippedCursor(); + } actualResultType = ResultType.fromPb(queryResultBatchPb.getEntityResultType()); if (Objects.equals(queryResultType, ResultType.PROJECTION_ENTITY)) { // projection entity can represent all type of results @@ -86,8 +89,8 @@ protected T computeNext() { if (!entityResultPbIter.hasNext()) { return endOfData(); } - DatastoreV1.EntityResult entityResultPb = entityResultPbIter.next(); - //cursor = entityResultPb.getCursor(); // only available in v1beta3 + com.google.datastore.v1beta3.EntityResult entityResultPb = entityResultPbIter.next(); + cursor = entityResultPb.getCursor(); @SuppressWarnings("unchecked") T result = (T) actualResultType.convert(entityResultPb.getEntity()); return result; @@ -100,7 +103,6 @@ public Class resultClass() { @Override public Cursor cursorAfter() { - //return new Cursor(cursor); // only available in v1beta3 - return null; + return new Cursor(cursor); } } diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java index 1dd35cb4f191..7c1cf815879e 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java @@ -25,7 +25,6 @@ import static com.google.gcloud.datastore.LongValue.of; import static com.google.gcloud.datastore.StringValue.of; -import com.google.api.services.datastore.DatastoreV1; import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects.ToStringHelper; import com.google.common.base.Preconditions; @@ -103,13 +102,17 @@ public abstract static class Filter implements Serializable { Filter() { } - protected abstract DatastoreV1.Filter toPb(); + protected abstract com.google.datastore.v1beta3.Filter toPb(); - static Filter fromPb(DatastoreV1.Filter filterPb) { - if (filterPb.hasCompositeFilter()) { - return CompositeFilter.fromPb(filterPb.getCompositeFilter()); + static Filter fromPb(com.google.datastore.v1beta3.Filter filterPb) { + switch (filterPb.getFilterTypeCase()) { + case COMPOSITE_FILTER: + return CompositeFilter.fromPb(filterPb.getCompositeFilter()); + case PROPERTY_FILTER: + return PropertyFilter.fromPb(filterPb.getPropertyFilter()); + default: + return null; } - return PropertyFilter.fromPb(filterPb.getPropertyFilter()); } } @@ -122,11 +125,11 @@ public static final class CompositeFilter extends Filter { enum Operator { AND; - DatastoreV1.CompositeFilter.Operator toPb() { - return DatastoreV1.CompositeFilter.Operator.valueOf(name()); + com.google.datastore.v1beta3.CompositeFilter.Operator toPb() { + return com.google.datastore.v1beta3.CompositeFilter.Operator.valueOf(name()); } - static Operator fromPb(DatastoreV1.CompositeFilter.Operator operatorPb) { + static Operator fromPb(com.google.datastore.v1beta3.CompositeFilter.Operator operatorPb) { return valueOf(operatorPb.name()); } } @@ -169,11 +172,14 @@ public boolean equals(Object obj) { && filters.equals(other.filters); } - static CompositeFilter fromPb(DatastoreV1.CompositeFilter compositeFilterPb) { - Operator operator = Operator.fromPb(compositeFilterPb.getOperator()); + static CompositeFilter fromPb(com.google.datastore.v1beta3.CompositeFilter compositeFilterPb) { + Operator operator = Operator.fromPb(compositeFilterPb.getOp()); ImmutableList.Builder filters = ImmutableList.builder(); - for (DatastoreV1.Filter filterPb : compositeFilterPb.getFilterList()) { - filters.add(Filter.fromPb(filterPb)); + for (com.google.datastore.v1beta3.Filter filterPb : compositeFilterPb.getFiltersList()) { + Filter currFilter = Filter.fromPb(filterPb); + if (currFilter != null) { + filters.add(currFilter); + } } return new CompositeFilter(operator, filters.build()); } @@ -183,12 +189,14 @@ public static CompositeFilter and(Filter first, Filter... other) { } @Override - protected DatastoreV1.Filter toPb() { - DatastoreV1.Filter.Builder filterPb = DatastoreV1.Filter.newBuilder(); - DatastoreV1.CompositeFilter.Builder compositeFilterPb = filterPb.getCompositeFilterBuilder(); - compositeFilterPb.setOperator(operator.toPb()); + protected com.google.datastore.v1beta3.Filter toPb() { + com.google.datastore.v1beta3.Filter.Builder filterPb = + com.google.datastore.v1beta3.Filter.newBuilder(); + com.google.datastore.v1beta3.CompositeFilter.Builder compositeFilterPb = + filterPb.getCompositeFilterBuilder(); + compositeFilterPb.setOp(operator.toPb()); for (Filter filter : filters) { - compositeFilterPb.addFilter(filter.toPb()); + compositeFilterPb.addFilters(filter.toPb()); } return filterPb.build(); } @@ -210,11 +218,11 @@ enum Operator { EQUAL, HAS_ANCESTOR; - DatastoreV1.PropertyFilter.Operator toPb() { - return DatastoreV1.PropertyFilter.Operator.valueOf(name()); + com.google.datastore.v1beta3.PropertyFilter.Operator toPb() { + return com.google.datastore.v1beta3.PropertyFilter.Operator.valueOf(name()); } - static Operator fromPb(DatastoreV1.PropertyFilter.Operator operatorPb) { + static Operator fromPb(com.google.datastore.v1beta3.PropertyFilter.Operator operatorPb) { return valueOf(operatorPb.name()); } } @@ -225,13 +233,11 @@ private PropertyFilter(String property, Operator operator, Value value) { this.value = checkNotNull(value); } - public static PropertyFilter fromPb(DatastoreV1.PropertyFilter propertyFilterPb) { + public static PropertyFilter fromPb(com.google.datastore.v1beta3.PropertyFilter propertyFilterPb) { String property = propertyFilterPb.getProperty().getName(); - Operator operator = Operator.fromPb(propertyFilterPb.getOperator()); - // TODO(ajaykannan): fix me! - //Value value = Value.fromPb(propertyFilterPb.getValue()); - //return new PropertyFilter(property, operator, value); - return new PropertyFilter(property, operator, null); // TODO(ajaykannan): fix me! + Operator operator = Operator.fromPb(propertyFilterPb.getOp()); + Value value = Value.fromPb(propertyFilterPb.getValue()); + return new PropertyFilter(property, operator, value); } @Override @@ -431,14 +437,15 @@ public static PropertyFilter isNull(String property) { } @Override - protected DatastoreV1.Filter toPb() { - DatastoreV1.Filter.Builder filterPb = DatastoreV1.Filter.newBuilder(); - DatastoreV1.PropertyFilter.Builder propertyFilterPb = filterPb.getPropertyFilterBuilder(); + protected com.google.datastore.v1beta3.Filter toPb() { + com.google.datastore.v1beta3.Filter.Builder filterPb = + com.google.datastore.v1beta3.Filter.newBuilder(); + com.google.datastore.v1beta3.PropertyFilter.Builder propertyFilterPb = + filterPb.getPropertyFilterBuilder(); propertyFilterPb.getPropertyBuilder().setName(property); - propertyFilterPb.setOperator(operator.toPb()); + propertyFilterPb.setOp(operator.toPb()); if (value != null) { - // TODO(ajaykannan): fix me! - //propertyFilterPb.setValue(value.toPb()); + propertyFilterPb.setValue(value.toPb()); } return filterPb.build(); } @@ -455,11 +462,11 @@ public enum Direction { ASCENDING, DESCENDING; - DatastoreV1.PropertyOrder.Direction toPb() { - return DatastoreV1.PropertyOrder.Direction.valueOf(name()); + com.google.datastore.v1beta3.PropertyOrder.Direction toPb() { + return com.google.datastore.v1beta3.PropertyOrder.Direction.valueOf(name()); } - static Direction fromPb(DatastoreV1.PropertyOrder.Direction directionPb) { + static Direction fromPb(com.google.datastore.v1beta3.PropertyOrder.Direction directionPb) { return valueOf(directionPb.name()); } } @@ -495,10 +502,11 @@ public Direction direction() { return direction; } - DatastoreV1.PropertyOrder toPb() { - return DatastoreV1.PropertyOrder.newBuilder() + com.google.datastore.v1beta3.PropertyOrder toPb() { + return com.google.datastore.v1beta3.PropertyOrder.newBuilder() .setDirection(direction.toPb()) - .setProperty(DatastoreV1.PropertyReference.newBuilder().setName(property).build()) + .setProperty(com.google.datastore.v1beta3.PropertyReference.newBuilder() + .setName(property).build()) .build(); } @@ -510,7 +518,7 @@ public static OrderBy desc(String property) { return new OrderBy(property, OrderBy.Direction.DESCENDING); } - static OrderBy fromPb(DatastoreV1.PropertyOrder propertyOrderPb) { + static OrderBy fromPb(com.google.datastore.v1beta3.PropertyOrder propertyOrderPb) { String property = propertyOrderPb.getProperty().getName(); Direction direction = Direction.fromPb(propertyOrderPb.getDirection()); return new OrderBy(property, direction); @@ -521,30 +529,15 @@ public static final class Projection implements Serializable { private static final long serialVersionUID = 3083707957256279470L; - private final Aggregate aggregate; private final String property; - public enum Aggregate { - - FIRST; - - DatastoreV1.PropertyExpression.AggregationFunction toPb() { - return DatastoreV1.PropertyExpression.AggregationFunction.valueOf(name()); - } - - static Aggregate fromPb(DatastoreV1.PropertyExpression.AggregationFunction aggregatePb) { - return valueOf(aggregatePb.name()); - } - } - - private Projection(Aggregate aggregate, String property) { - this.aggregate = aggregate; + private Projection(String property) { this.property = property; } @Override public int hashCode() { - return Objects.hash(property, aggregate); + return Objects.hash(property); } @Override @@ -555,51 +548,31 @@ public boolean equals(Object obj) { if (!(obj instanceof Projection)) { return false; } - Projection other = (Projection) obj; - return Objects.equals(property, other.property) - && Objects.equals(aggregate, other.aggregate); + return Objects.equals(property, ((Projection) obj).property); } @Override public String toString() { ToStringHelper toStringHelper = MoreObjects.toStringHelper(this); toStringHelper.add("property", property); - if (aggregate != null) { - toStringHelper.add("aggregate", aggregate); - } return toStringHelper.toString(); } - DatastoreV1.PropertyExpression toPb() { - DatastoreV1.PropertyExpression.Builder expressionPb = - DatastoreV1.PropertyExpression.newBuilder(); - if (aggregate != null) { - expressionPb.setAggregationFunction(aggregate.toPb()); - } + com.google.datastore.v1beta3.Projection toPb() { + com.google.datastore.v1beta3.Projection.Builder expressionPb = + com.google.datastore.v1beta3.Projection.newBuilder(); expressionPb.setProperty( - DatastoreV1.PropertyReference.newBuilder().setName(property).build()); + com.google.datastore.v1beta3.PropertyReference.newBuilder().setName(property).build()); return expressionPb.build(); } - public static Projection fromPb(DatastoreV1.PropertyExpression propertyExpressionPb) { - String property = propertyExpressionPb.getProperty().getName(); - Aggregate aggregate = null; - if (propertyExpressionPb.hasAggregationFunction()) { - aggregate = Aggregate.fromPb(propertyExpressionPb.getAggregationFunction()); - } - return new Projection(aggregate, property); + public static Projection fromPb( + com.google.datastore.v1beta3.Projection projectionPb) { + return new Projection(projectionPb.getProperty().getName()); } public static Projection property(String property) { - return new Projection(null, property); - } - - public static Projection aggregate(Aggregate aggregate, String property) { - return new Projection(aggregate, property); - } - - public static Projection first(String property) { - return new Projection(Aggregate.FIRST, property); + return new Projection(property); } } @@ -714,32 +687,34 @@ B addGroupBy(String property, String... others) { return self(); } - B mergeFrom(DatastoreV1.Query queryPb) { + B mergeFrom(com.google.datastore.v1beta3.Query queryPb) { if (queryPb.getKindCount() > 0) { kind(queryPb.getKind(0).getName()); } - if (queryPb.hasStartCursor()) { + if (!queryPb.getStartCursor().isEmpty()) { startCursor(new Cursor(queryPb.getStartCursor())); } - if (queryPb.hasEndCursor()) { + if (!queryPb.getEndCursor().isEmpty()) { endCursor(new Cursor(queryPb.getEndCursor())); } - if (queryPb.hasOffset()) { - offset(queryPb.getOffset()); - } + offset(queryPb.getOffset()); if (queryPb.hasLimit()) { - limit(queryPb.getLimit()); + limit(queryPb.getLimit().getValue()); } if (queryPb.hasFilter()) { - filter(Filter.fromPb(queryPb.getFilter())); + Filter currFilter = Filter.fromPb(queryPb.getFilter()); + if (currFilter != null) { + filter(currFilter); + } } - for (DatastoreV1.PropertyOrder orderByPb : queryPb.getOrderList()) { + for (com.google.datastore.v1beta3.PropertyOrder orderByPb : queryPb.getOrderList()) { addOrderBy(OrderBy.fromPb(orderByPb)); } - for (DatastoreV1.PropertyExpression projectionPb : queryPb.getProjectionList()) { + for (com.google.datastore.v1beta3.Projection projectionPb + : queryPb.getProjectionList()) { addProjection(Projection.fromPb(projectionPb)); } - for (DatastoreV1.PropertyReference groupByPb : queryPb.getGroupByList()) { + for (com.google.datastore.v1beta3.PropertyReference groupByPb : queryPb.getDistinctOnList()) { addGroupBy(groupByPb.getName()); } return self(); @@ -777,7 +752,7 @@ public static final class KeyQueryBuilder extends BaseBuilder nextQuery(DatastoreV1.QueryResultBatch responsePb) { + protected StructuredQuery nextQuery(com.google.datastore.v1beta3.QueryResultBatch responsePb) { Builder builder = new Builder<>(type()); builder.mergeFrom(toPb()); builder.startCursor(new Cursor(responsePb.getEndCursor())); @@ -929,15 +904,16 @@ protected StructuredQuery nextQuery(DatastoreV1.QueryResultBatch responsePb) } else { builder.offset(0); if (limit != null) { - builder.limit(limit - responsePb.getEntityResultCount()); + builder.limit(limit - responsePb.getEntityResultsCount()); } } return builder.build(); } @Override - protected DatastoreV1.Query toPb() { - DatastoreV1.Query.Builder queryPb = DatastoreV1.Query.newBuilder(); + protected com.google.datastore.v1beta3.Query toPb() { + com.google.datastore.v1beta3.Query.Builder queryPb = + com.google.datastore.v1beta3.Query.newBuilder(); if (kind != null) { queryPb.addKindBuilder().setName(kind); } @@ -951,7 +927,7 @@ protected DatastoreV1.Query toPb() { queryPb.setOffset(offset); } if (limit != null) { - queryPb.setLimit(limit); + queryPb.setLimit(com.google.protobuf.Int32Value.newBuilder().setValue(limit.intValue())); } if (filter != null) { queryPb.setFilter(filter.toPb()); @@ -960,7 +936,8 @@ protected DatastoreV1.Query toPb() { queryPb.addOrder(value.toPb()); } for (String value : groupBy) { - queryPb.addGroupBy(DatastoreV1.PropertyReference.newBuilder().setName(value).build()); + queryPb.addDistinctOn(com.google.datastore.v1beta3.PropertyReference.newBuilder() + .setName(value).build()); } for (Projection value : projection) { queryPb.addProjection(value.toPb()); @@ -971,11 +948,11 @@ protected DatastoreV1.Query toPb() { @Override protected Object fromPb(ResultType resultType, String namespace, byte[] bytesPb) throws InvalidProtocolBufferException { - return fromPb(resultType, namespace, DatastoreV1.Query.parseFrom(bytesPb)); + return fromPb(resultType, namespace, com.google.datastore.v1beta3.Query.parseFrom(bytesPb)); } private static StructuredQuery fromPb(ResultType resultType, String namespace, - DatastoreV1.Query queryPb) { + com.google.datastore.v1beta3.Query queryPb) { BaseBuilder builder; if (resultType.equals(ResultType.ENTITY)) { builder = new EntityQueryBuilder(); diff --git a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java index 689d2a7b8b6b..e3a71d8a8aa2 100644 --- a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java +++ b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java @@ -115,9 +115,9 @@ public void setUp() throws IOException, InterruptedException { .host("localhost:" + LocalGcdHelper.PORT) .build(); datastore = DatastoreFactory.instance().get(options); - //StructuredQuery query = Query.keyQueryBuilder().build(); - //QueryResults result = datastore.run(query); - //datastore.delete(Iterators.toArray(result, Key.class)); + StructuredQuery query = Query.keyQueryBuilder().build(); + QueryResults result = datastore.run(query); + datastore.delete(Iterators.toArray(result, Key.class)); datastore.add(ENTITY1, ENTITY2); } @@ -188,7 +188,7 @@ public void testTransactionWithRead() { assertEquals(DatastoreException.Code.ABORTED, expected.code()); } } - /* TODO(ajaykannan): fix me! + @Test public void testTransactionWithQuery() { Query query = Query.entityQueryBuilder() @@ -216,7 +216,7 @@ public void testTransactionWithQuery() { assertEquals(DatastoreException.Code.ABORTED, expected.code()); } } - */ + @Test public void testNewTransactionRollback() { Transaction transaction = datastore.newTransaction(); @@ -331,7 +331,7 @@ public void testNewBatch() { assertNull(entities.get(4)); assertEquals(5, entities.size()); } - /* TODO(ajaykannan): fix me! + @Test public void testRunGqlQueryNoCasting() { Query query1 = Query.gqlQueryBuilder(ResultType.ENTITY, "select * from " + KIND1).build(); @@ -431,7 +431,7 @@ public void testRunStructuredQuery() { StructuredQuery projectionQuery = Query.projectionEntityQueryBuilder() .kind(KIND2) - .projection(Projection.property("age"), Projection.first("name")) + .projection(Projection.property("age")) .filter(PropertyFilter.gt("age", 18)) .groupBy("age") .orderBy(OrderBy.asc("age")) @@ -443,12 +443,11 @@ public void testRunStructuredQuery() { ProjectionEntity entity = results4.next(); assertEquals(ENTITY2.key(), entity.key()); assertEquals(20, entity.getLong("age")); - assertEquals("Dan", entity.getString("name")); - assertEquals(2, entity.properties().size()); + assertEquals(1, entity.properties().size()); assertFalse(results4.hasNext()); // TODO(ozarov): construct a test to verify nextQuery/pagination } - */ + @Test public void testAllocateId() { KeyFactory keyFactory = datastore.newKeyFactory().kind(KIND1); diff --git a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/SerializationTest.java b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/SerializationTest.java index bd4a683f9c9c..0c65ab76c681 100644 --- a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/SerializationTest.java +++ b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/SerializationTest.java @@ -122,9 +122,8 @@ public class SerializationTest { .put(ValueType.NULL, NULL_VALUE) .put(ValueType.KEY, KEY_VALUE) .put(ValueType.STRING, STRING_VALUE) - // TODO(ajaykannan): fix me! - //.putAll(ValueType.ENTITY, EMBEDDED_ENTITY_VALUE1, EMBEDDED_ENTITY_VALUE2, - // EMBEDDED_ENTITY_VALUE3) + .putAll(ValueType.ENTITY, EMBEDDED_ENTITY_VALUE1, EMBEDDED_ENTITY_VALUE2, + EMBEDDED_ENTITY_VALUE3) .put(ValueType.LIST, LIST_VALUE) .put(ValueType.LONG, LONG_VALUE) .put(ValueType.DOUBLE, DOUBLE_VALUE) @@ -169,10 +168,9 @@ public void testValues() throws Exception { @Test public void testTypes() throws Exception { - // TODO(ajaykannan): fix me! - Serializable[] types = { KEY1, KEY2, INCOMPLETE_KEY1, INCOMPLETE_KEY2, /*ENTITY1, ENTITY2, - ENTITY3, EMBEDDED_ENTITY, PROJECTION_ENTITY,*/ DATE_TIME1, BLOB1/*, CURSOR1, GQL1, GQL2, - QUERY1, QUERY2, QUERY3*/}; + Serializable[] types = { KEY1, KEY2, INCOMPLETE_KEY1, INCOMPLETE_KEY2, ENTITY1, ENTITY2, + ENTITY3, EMBEDDED_ENTITY, PROJECTION_ENTITY, DATE_TIME1, BLOB1, CURSOR1, GQL1, GQL2, + QUERY1, QUERY2, QUERY3}; for (Serializable obj : types) { Object copy = serializeAndDeserialize(obj); assertEquals(obj, obj); From 16afb0d0ba2f67f61f8027391440b9686479423f Mon Sep 17 00:00:00 2001 From: Ajay Kannan Date: Tue, 13 Oct 2015 12:11:55 -0700 Subject: [PATCH 2/5] fix distinct and cursor code --- .../com/google/gcloud/datastore/GqlQuery.java | 15 +- .../com/google/gcloud/datastore/Query.java | 2 +- .../gcloud/datastore/QueryResultsImpl.java | 4 + .../gcloud/datastore/StructuredQuery.java | 150 +++++++----------- .../gcloud/datastore/DatastoreTest.java | 7 +- .../gcloud/datastore/SerializationTest.java | 5 +- 6 files changed, 73 insertions(+), 110 deletions(-) diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/GqlQuery.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/GqlQuery.java index 2c02aa7b970c..8e023c0c224e 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/GqlQuery.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/GqlQuery.java @@ -20,6 +20,7 @@ import static com.google.gcloud.datastore.Validator.validateNamespace; import com.google.common.base.MoreObjects; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedMap; @@ -137,10 +138,8 @@ static Binding fromPb(com.google.datastore.v1beta3.GqlQueryParameter argPb) { switch (argPb.getParameterTypeCase()) { case CURSOR: return new Binding(new Cursor(argPb.getCursor())); - case VALUE: - return new Binding(Value.fromPb(argPb.getValue())); default: - return null; + return new Binding(Value.fromPb(argPb.getValue())); } } } @@ -398,16 +397,14 @@ private static GqlQuery fromPb( for (Map.Entry nameArg : queryPb.getNamedBindings().entrySet()) { Binding currBinding = Binding.fromPb(nameArg.getValue()); - if (currBinding != null) { - builder.namedBindings.put(nameArg.getKey(), currBinding); - } + Preconditions.checkState(currBinding != null); + builder.namedBindings.put(nameArg.getKey(), currBinding); } for (com.google.datastore.v1beta3.GqlQueryParameter numberArg : queryPb.getPositionalBindingsList()) { Binding currBinding = Binding.fromPb(numberArg); - if (currBinding != null) { - builder.positionalBindings.add(currBinding); - } + Preconditions.checkState(currBinding != null); + builder.positionalBindings.add(currBinding); } return builder.build(); } diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Query.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Query.java index 6e962d92fb2f..c45efde3e30d 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Query.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/Query.java @@ -62,7 +62,7 @@ public abstract static class ResultType implements java.io.Serializable { private static final long serialVersionUID = 1602329532153860907L; @Override protected Object convert(com.google.datastore.v1beta3.Entity entityPb) { - if (entityPb.getProperties().size() == 0) { + if (entityPb.getProperties().isEmpty()) { if (!entityPb.hasKey()) { return null; } diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java index b3c51ceb9eeb..40f1aee9dc5e 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java @@ -70,6 +70,10 @@ private void sendRequest() { entityResultPbIter = queryResultBatchPb.getEntityResultsList().iterator(); if (queryResultBatchPb.getSkippedResults() > 0) { cursor = queryResultBatchPb.getSkippedCursor(); + } else if (entityResultPbIter.hasNext()) { + cursor = queryResultBatchPb.getEntityResults(0).getCursor(); + } else { + cursor = queryResultBatchPb.getEndCursor(); } actualResultType = ResultType.fromPb(queryResultBatchPb.getEntityResultType()); if (Objects.equals(queryResultType, ResultType.PROJECTION_ENTITY)) { diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java index 7c1cf815879e..4151ae4b462c 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java @@ -68,7 +68,7 @@ * .kind(kind) * .projection(Projection.property("age"), Projection.first("name")) * .filter(PropertyFilter.gt("age", 18)) - * .groupBy("age") + * .distinct("age") * .orderBy(OrderBy.asc("age")) * .limit(10) * .build(); @@ -86,9 +86,9 @@ public class StructuredQuery extends Query { private static final String KEY_PROPERTY_NAME = "__key__"; private final transient String kind; - private final ImmutableList projection; + private final ImmutableList projection; private final transient Filter filter; - private final ImmutableList groupBy; + private final ImmutableList distinctOn; private final transient ImmutableList orderBy; private final transient Cursor startCursor; private final transient Cursor endCursor; @@ -108,10 +108,8 @@ static Filter fromPb(com.google.datastore.v1beta3.Filter filterPb) { switch (filterPb.getFilterTypeCase()) { case COMPOSITE_FILTER: return CompositeFilter.fromPb(filterPb.getCompositeFilter()); - case PROPERTY_FILTER: - return PropertyFilter.fromPb(filterPb.getPropertyFilter()); default: - return null; + return PropertyFilter.fromPb(filterPb.getPropertyFilter()); } } } @@ -525,65 +523,15 @@ static OrderBy fromPb(com.google.datastore.v1beta3.PropertyOrder propertyOrderPb } } - public static final class Projection implements Serializable { - - private static final long serialVersionUID = 3083707957256279470L; - - private final String property; - - private Projection(String property) { - this.property = property; - } - - @Override - public int hashCode() { - return Objects.hash(property); - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof Projection)) { - return false; - } - return Objects.equals(property, ((Projection) obj).property); - } - - @Override - public String toString() { - ToStringHelper toStringHelper = MoreObjects.toStringHelper(this); - toStringHelper.add("property", property); - return toStringHelper.toString(); - } - - com.google.datastore.v1beta3.Projection toPb() { - com.google.datastore.v1beta3.Projection.Builder expressionPb = - com.google.datastore.v1beta3.Projection.newBuilder(); - expressionPb.setProperty( - com.google.datastore.v1beta3.PropertyReference.newBuilder().setName(property).build()); - return expressionPb.build(); - } - - public static Projection fromPb( - com.google.datastore.v1beta3.Projection projectionPb) { - return new Projection(projectionPb.getProperty().getName()); - } - - public static Projection property(String property) { - return new Projection(property); - } - } - static class BaseBuilder> { private final ResultType resultType; private String namespace; private String kind; - private final List projection = new LinkedList<>(); + private final List projection = new LinkedList<>(); private Filter filter; - private final List groupBy = new LinkedList<>(); + private boolean distinctOnAll = false; + private final List distinctOn = new LinkedList<>(); private final List orderBy = new LinkedList<>(); private Cursor startCursor; private Cursor endCursor; @@ -658,32 +606,39 @@ B clearProjection() { return self(); } - B projection(Projection projection, Projection... others) { + B projection(String projection, String... others) { clearProjection(); addProjection(projection, others); return self(); } - B addProjection(Projection projection, Projection... others) { + B addProjection(String projection, String... others) { this.projection.add(projection); Collections.addAll(this.projection, others); return self(); } - B clearGroupBy() { - groupBy.clear(); + B clearDistinct() { + distinctOn.clear(); + distinctOnAll = false; return self(); } - B groupBy(String property, String... others) { - clearGroupBy(); - addGroupBy(property, others); + B distinct(String... properties) { + clearDistinct(); + if (properties.length == 0) { + this.distinctOnAll = true; + } else if (properties.length == 1) { + addDistinct(properties[0]); + } else { + addDistinct(properties[0], Arrays.copyOfRange(properties, 1, properties.length)); + } return self(); } - B addGroupBy(String property, String... others) { - this.groupBy.add(property); - Collections.addAll(this.groupBy, others); + B addDistinct(String property, String... others) { + this.distinctOn.add(property); + Collections.addAll(this.distinctOn, others); return self(); } @@ -712,15 +667,20 @@ B mergeFrom(com.google.datastore.v1beta3.Query queryPb) { } for (com.google.datastore.v1beta3.Projection projectionPb : queryPb.getProjectionList()) { - addProjection(Projection.fromPb(projectionPb)); + addProjection(projectionPb.getProperty().getName()); } - for (com.google.datastore.v1beta3.PropertyReference groupByPb : queryPb.getDistinctOnList()) { - addGroupBy(groupByPb.getName()); + for (com.google.datastore.v1beta3.PropertyReference distinctOnPb : queryPb.getDistinctOnList()) { + addDistinct(distinctOnPb.getName()); } + distinctOnAll = false; return self(); } public StructuredQuery build() { + if (distinctOnAll) { + clearDistinct(); + this.distinctOn.addAll(this.projection); + } return new StructuredQuery<>(this); } } @@ -748,14 +708,14 @@ public static final class KeyQueryBuilder extends BaseBuilder projection() { + public List projection() { return projection; } @@ -865,8 +825,8 @@ public Filter filter() { return filter; } - public List groupBy() { - return groupBy; + public List distinct() { + return distinctOn; } public ImmutableList orderBy() { @@ -935,12 +895,16 @@ protected com.google.datastore.v1beta3.Query toPb() { for (OrderBy value : orderBy) { queryPb.addOrder(value.toPb()); } - for (String value : groupBy) { + for (String value : distinctOn) { queryPb.addDistinctOn(com.google.datastore.v1beta3.PropertyReference.newBuilder() .setName(value).build()); } - for (Projection value : projection) { - queryPb.addProjection(value.toPb()); + for (String value : projection) { + com.google.datastore.v1beta3.Projection.Builder expressionPb = + com.google.datastore.v1beta3.Projection.newBuilder(); + expressionPb.setProperty( + com.google.datastore.v1beta3.PropertyReference.newBuilder().setName(value).build()); + queryPb.addProjection(expressionPb.build()); } return queryPb.build(); } diff --git a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java index e3a71d8a8aa2..41f0c4df8d92 100644 --- a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java +++ b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java @@ -29,7 +29,6 @@ import com.google.gcloud.RetryParams; import com.google.gcloud.datastore.Query.ResultType; import com.google.gcloud.datastore.StructuredQuery.OrderBy; -import com.google.gcloud.datastore.StructuredQuery.Projection; import com.google.gcloud.datastore.StructuredQuery.PropertyFilter; import com.google.gcloud.spi.DatastoreRpc; import com.google.gcloud.spi.DatastoreRpc.DatastoreRpcException.Reason; @@ -421,7 +420,7 @@ public void testRunStructuredQuery() { StructuredQuery keyOnlyProjectionQuery = Query.projectionEntityQueryBuilder() - .kind(KIND1).projection(Projection.property("__key__")).build(); + .kind(KIND1).projection("__key__").build(); QueryResults results3 = datastore.run(keyOnlyProjectionQuery); assertTrue(results3.hasNext()); ProjectionEntity projectionEntity = results3.next(); @@ -431,9 +430,9 @@ public void testRunStructuredQuery() { StructuredQuery projectionQuery = Query.projectionEntityQueryBuilder() .kind(KIND2) - .projection(Projection.property("age")) + .projection("age") .filter(PropertyFilter.gt("age", 18)) - .groupBy("age") + .distinct("age") .orderBy(OrderBy.asc("age")) .limit(10) .build(); diff --git a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/SerializationTest.java b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/SerializationTest.java index 0c65ab76c681..d946246db279 100644 --- a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/SerializationTest.java +++ b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/SerializationTest.java @@ -26,7 +26,6 @@ import com.google.gcloud.RetryParams; import com.google.gcloud.datastore.StructuredQuery.CompositeFilter; import com.google.gcloud.datastore.StructuredQuery.OrderBy; -import com.google.gcloud.datastore.StructuredQuery.Projection; import com.google.gcloud.datastore.StructuredQuery.PropertyFilter; import org.junit.Test; @@ -71,13 +70,13 @@ public class SerializationTest { private static final Query QUERY3 = Query.projectionEntityQueryBuilder() .kind("k") .namespace("ns1") - .projection(Projection.property("p")) + .projection("p") .limit(100) .offset(5) .startCursor(CURSOR1) .endCursor(CURSOR2) .filter(CompositeFilter.and(PropertyFilter.gt("p1", 10), PropertyFilter.eq("a", "v"))) - .addGroupBy("p") + .addDistinct("p") .addOrderBy(OrderBy.asc("p")) .build(); private static final KeyValue KEY_VALUE = KeyValue.of(KEY1); From acf2c4207f384d9e4d8f7ce958a1d7ac2263ff7a Mon Sep 17 00:00:00 2001 From: Ajay Kannan Date: Wed, 14 Oct 2015 18:55:30 -0700 Subject: [PATCH 3/5] Include cursor workaround, fix distinct in StructuredQuery, and remove extra checks --- .../com/google/gcloud/datastore/GqlQuery.java | 7 +++---- .../gcloud/datastore/QueryResultsImpl.java | 14 ++++++------- .../gcloud/datastore/StructuredQuery.java | 20 ++++++++++--------- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/GqlQuery.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/GqlQuery.java index 8e023c0c224e..7fcb562fea89 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/GqlQuery.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/GqlQuery.java @@ -20,7 +20,6 @@ import static com.google.gcloud.datastore.Validator.validateNamespace; import com.google.common.base.MoreObjects; -import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedMap; @@ -138,8 +137,10 @@ static Binding fromPb(com.google.datastore.v1beta3.GqlQueryParameter argPb) { switch (argPb.getParameterTypeCase()) { case CURSOR: return new Binding(new Cursor(argPb.getCursor())); - default: + case VALUE: return new Binding(Value.fromPb(argPb.getValue())); + default: + throw new AssertionError("Unexpected enum value " + argPb.getParameterTypeCase()); } } } @@ -397,13 +398,11 @@ private static GqlQuery fromPb( for (Map.Entry nameArg : queryPb.getNamedBindings().entrySet()) { Binding currBinding = Binding.fromPb(nameArg.getValue()); - Preconditions.checkState(currBinding != null); builder.namedBindings.put(nameArg.getKey(), currBinding); } for (com.google.datastore.v1beta3.GqlQueryParameter numberArg : queryPb.getPositionalBindingsList()) { Binding currBinding = Binding.fromPb(numberArg); - Preconditions.checkState(currBinding != null); builder.positionalBindings.add(currBinding); } return builder.build(); diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java index 40f1aee9dc5e..38eb3dd1c393 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java @@ -16,9 +16,9 @@ package com.google.gcloud.datastore; -import com.google.datastore.v1beta3.QueryResultBatch.MoreResultsType; import com.google.common.base.Preconditions; import com.google.common.collect.AbstractIterator; +import com.google.datastore.v1beta3.QueryResultBatch.MoreResultsType; import com.google.gcloud.datastore.Query.ResultType; import com.google.protobuf.ByteString; @@ -55,6 +55,11 @@ class QueryResultsImpl extends AbstractIterator implements QueryResults } partitionIdPb = pbBuilder.build(); sendRequest(); + if (queryResultBatchPb.getSkippedResults() > 0) { + cursor = queryResultBatchPb.getSkippedCursor(); + } else { + cursor = ByteString.EMPTY; + } } private void sendRequest() { @@ -68,13 +73,6 @@ private void sendRequest() { queryResultBatchPb = datastore.runQuery(requestPb.build()).getBatch(); lastBatch = queryResultBatchPb.getMoreResults() != MoreResultsType.NOT_FINISHED; entityResultPbIter = queryResultBatchPb.getEntityResultsList().iterator(); - if (queryResultBatchPb.getSkippedResults() > 0) { - cursor = queryResultBatchPb.getSkippedCursor(); - } else if (entityResultPbIter.hasNext()) { - cursor = queryResultBatchPb.getEntityResults(0).getCursor(); - } else { - cursor = queryResultBatchPb.getEndCursor(); - } actualResultType = ResultType.fromPb(queryResultBatchPb.getEntityResultType()); if (Objects.equals(queryResultType, ResultType.PROJECTION_ENTITY)) { // projection entity can represent all type of results diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java index 4151ae4b462c..c49ddddc9c02 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java @@ -108,8 +108,10 @@ static Filter fromPb(com.google.datastore.v1beta3.Filter filterPb) { switch (filterPb.getFilterTypeCase()) { case COMPOSITE_FILTER: return CompositeFilter.fromPb(filterPb.getCompositeFilter()); - default: + case PROPERTY_FILTER: return PropertyFilter.fromPb(filterPb.getPropertyFilter()); + default: + throw new AssertionError("Unexpected enum value " + filterPb.getFilterTypeCase()); } } } @@ -530,7 +532,7 @@ static class BaseBuilder> { private String kind; private final List projection = new LinkedList<>(); private Filter filter; - private boolean distinctOnAll = false; + private boolean distinct = false; private final List distinctOn = new LinkedList<>(); private final List orderBy = new LinkedList<>(); private Cursor startCursor; @@ -620,14 +622,16 @@ B addProjection(String projection, String... others) { B clearDistinct() { distinctOn.clear(); - distinctOnAll = false; + distinct = false; return self(); } B distinct(String... properties) { clearDistinct(); if (properties.length == 0) { - this.distinctOnAll = true; + clearDistinct(); + this.distinct = true; + this.distinctOn.addAll(this.projection); } else if (properties.length == 1) { addDistinct(properties[0]); } else { @@ -637,6 +641,9 @@ B distinct(String... properties) { } B addDistinct(String property, String... others) { + if (this.distinct) { + throw new IllegalStateException("\"distinct()\" is currently set."); + } this.distinctOn.add(property); Collections.addAll(this.distinctOn, others); return self(); @@ -672,15 +679,10 @@ B mergeFrom(com.google.datastore.v1beta3.Query queryPb) { for (com.google.datastore.v1beta3.PropertyReference distinctOnPb : queryPb.getDistinctOnList()) { addDistinct(distinctOnPb.getName()); } - distinctOnAll = false; return self(); } public StructuredQuery build() { - if (distinctOnAll) { - clearDistinct(); - this.distinctOn.addAll(this.projection); - } return new StructuredQuery<>(this); } } From 0c2f9e93ffb78aadb55c3abf558e47c616336c18 Mon Sep 17 00:00:00 2001 From: Ajay Kannan Date: Thu, 15 Oct 2015 15:52:50 -0700 Subject: [PATCH 4/5] standardize distinctOn naming --- .../gcloud/datastore/StructuredQuery.java | 45 +++++++------------ .../gcloud/datastore/DatastoreTest.java | 17 +++---- .../gcloud/datastore/SerializationTest.java | 25 ++++++----- 3 files changed, 38 insertions(+), 49 deletions(-) diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java index c49ddddc9c02..1b82991cb8c8 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/StructuredQuery.java @@ -68,7 +68,7 @@ * .kind(kind) * .projection(Projection.property("age"), Projection.first("name")) * .filter(PropertyFilter.gt("age", 18)) - * .distinct("age") + * .distinctOn("age") * .orderBy(OrderBy.asc("age")) * .limit(10) * .build(); @@ -532,7 +532,6 @@ static class BaseBuilder> { private String kind; private final List projection = new LinkedList<>(); private Filter filter; - private boolean distinct = false; private final List distinctOn = new LinkedList<>(); private final List orderBy = new LinkedList<>(); private Cursor startCursor; @@ -620,30 +619,18 @@ B addProjection(String projection, String... others) { return self(); } - B clearDistinct() { + B clearDistinctOn() { distinctOn.clear(); - distinct = false; return self(); } - B distinct(String... properties) { - clearDistinct(); - if (properties.length == 0) { - clearDistinct(); - this.distinct = true; - this.distinctOn.addAll(this.projection); - } else if (properties.length == 1) { - addDistinct(properties[0]); - } else { - addDistinct(properties[0], Arrays.copyOfRange(properties, 1, properties.length)); - } + B distinctOn(String property, String... others) { + clearDistinctOn(); + addDistinctOn(property, others); return self(); } - B addDistinct(String property, String... others) { - if (this.distinct) { - throw new IllegalStateException("\"distinct()\" is currently set."); - } + B addDistinctOn(String property, String... others) { this.distinctOn.add(property); Collections.addAll(this.distinctOn, others); return self(); @@ -677,7 +664,7 @@ B mergeFrom(com.google.datastore.v1beta3.Query queryPb) { addProjection(projectionPb.getProperty().getName()); } for (com.google.datastore.v1beta3.PropertyReference distinctOnPb : queryPb.getDistinctOnList()) { - addDistinct(distinctOnPb.getName()); + addDistinctOn(distinctOnPb.getName()); } return self(); } @@ -717,7 +704,7 @@ public static final class KeyQueryBuilder extends BaseBuilder distinct() { + public List distinctOn() { return distinctOn; } diff --git a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java index 41f0c4df8d92..f0fbd4ab96c0 100644 --- a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java +++ b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java @@ -428,14 +428,15 @@ public void testRunStructuredQuery() { assertTrue(projectionEntity.names().isEmpty()); assertFalse(results2.hasNext()); - StructuredQuery projectionQuery = Query.projectionEntityQueryBuilder() - .kind(KIND2) - .projection("age") - .filter(PropertyFilter.gt("age", 18)) - .distinct("age") - .orderBy(OrderBy.asc("age")) - .limit(10) - .build(); + StructuredQuery projectionQuery = + Query.projectionEntityQueryBuilder() + .kind(KIND2) + .projection("age") + .filter(PropertyFilter.gt("age", 18)) + .distinctOn("age") + .orderBy(OrderBy.asc("age")) + .limit(10) + .build(); QueryResults results4 = datastore.run(projectionQuery); assertTrue(results4.hasNext()); diff --git a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/SerializationTest.java b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/SerializationTest.java index d946246db279..2e083250f35e 100644 --- a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/SerializationTest.java +++ b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/SerializationTest.java @@ -67,18 +67,19 @@ public class SerializationTest { .kind("k") .filter(PropertyFilter.eq("p1", "hello")) .build(); - private static final Query QUERY3 = Query.projectionEntityQueryBuilder() - .kind("k") - .namespace("ns1") - .projection("p") - .limit(100) - .offset(5) - .startCursor(CURSOR1) - .endCursor(CURSOR2) - .filter(CompositeFilter.and(PropertyFilter.gt("p1", 10), PropertyFilter.eq("a", "v"))) - .addDistinct("p") - .addOrderBy(OrderBy.asc("p")) - .build(); + private static final Query QUERY3 = + Query.projectionEntityQueryBuilder() + .kind("k") + .namespace("ns1") + .projection("p") + .limit(100) + .offset(5) + .startCursor(CURSOR1) + .endCursor(CURSOR2) + .filter(CompositeFilter.and(PropertyFilter.gt("p1", 10), PropertyFilter.eq("a", "v"))) + .addDistinctOn("p") + .addOrderBy(OrderBy.asc("p")) + .build(); private static final KeyValue KEY_VALUE = KeyValue.of(KEY1); private static final NullValue NULL_VALUE = NullValue.builder().excludeFromIndexes(true).build(); private static final StringValue STRING_VALUE = StringValue.of("hello"); From 35ea69a5a4102de920f7732b52e29ebc8372d974 Mon Sep 17 00:00:00 2001 From: Ajay Kannan Date: Fri, 16 Oct 2015 11:06:08 -0700 Subject: [PATCH 5/5] Add missing case for start_cursor --- .../com/google/gcloud/datastore/QueryResultsImpl.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java index 38eb3dd1c393..bb2b65fcc646 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/QueryResultsImpl.java @@ -34,6 +34,7 @@ class QueryResultsImpl extends AbstractIterator implements QueryResults private Query query; private ResultType actualResultType; private com.google.datastore.v1beta3.QueryResultBatch queryResultBatchPb; + private com.google.datastore.v1beta3.Query mostRecentQueryPb; private boolean lastBatch; private Iterator entityResultPbIter; private ByteString cursor; @@ -58,7 +59,7 @@ class QueryResultsImpl extends AbstractIterator implements QueryResults if (queryResultBatchPb.getSkippedResults() > 0) { cursor = queryResultBatchPb.getSkippedCursor(); } else { - cursor = ByteString.EMPTY; + cursor = mostRecentQueryPb.getStartCursor(); } } @@ -70,7 +71,13 @@ private void sendRequest() { } requestPb.setPartitionId(partitionIdPb); query.populatePb(requestPb); - queryResultBatchPb = datastore.runQuery(requestPb.build()).getBatch(); + com.google.datastore.v1beta3.RunQueryResponse runQueryResponsePb = + datastore.runQuery(requestPb.build()); + queryResultBatchPb = runQueryResponsePb.getBatch(); + mostRecentQueryPb = runQueryResponsePb.getQuery(); + if (mostRecentQueryPb == null) { + mostRecentQueryPb = requestPb.getQuery(); + } lastBatch = queryResultBatchPb.getMoreResults() != MoreResultsType.NOT_FINISHED; entityResultPbIter = queryResultBatchPb.getEntityResultsList().iterator(); actualResultType = ResultType.fromPb(queryResultBatchPb.getEntityResultType());