Skip to content

Commit f6eeddd

Browse files
author
Ajay Kannan
committed
Support GeoPoint value in Datastore v1beta3
1 parent af6ab8f commit f6eeddd

12 files changed

Lines changed: 384 additions & 39 deletions

File tree

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static com.google.gcloud.datastore.DateTimeValue.of;
2222
import static com.google.gcloud.datastore.DoubleValue.of;
2323
import static com.google.gcloud.datastore.EntityValue.of;
24+
import static com.google.gcloud.datastore.GeoPointValue.of;
2425
import static com.google.gcloud.datastore.KeyValue.of;
2526
import static com.google.gcloud.datastore.ListValue.of;
2627
import static com.google.gcloud.datastore.LongValue.of;
@@ -159,6 +160,11 @@ public B set(String name, DateTime value) {
159160
return self();
160161
}
161162

163+
public B set(String name, GeoPoint value) {
164+
properties.put(name, of(value));
165+
return self();
166+
}
167+
162168
public B set(String name, Key value) {
163169
properties.put(name, of(value));
164170
return self();
@@ -320,6 +326,17 @@ public DateTime getDateTime(String name) {
320326
return ((Value<DateTime>) getValue(name)).get();
321327
}
322328

329+
/**
330+
* Returns the property value as a GeoPoint.
331+
*
332+
* @throws DatastoreException if not such property.
333+
* @throws ClassCastException if value is not a GeoPoint.
334+
*/
335+
@SuppressWarnings("unchecked")
336+
public GeoPoint getGeoPoint(String name) {
337+
return ((Value<GeoPoint>) getValue(name)).get();
338+
}
339+
323340
/**
324341
* Returns the property value as a Key.
325342
*
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright 2015 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.google.gcloud.datastore;
18+
19+
import static com.google.common.base.Preconditions.checkArgument;
20+
21+
import com.google.protobuf.InvalidProtocolBufferException;
22+
23+
import java.util.Objects;
24+
25+
/**
26+
* A Google Cloud Datastore GeoPoint (represented by latitude and longitude in degrees).
27+
* This class is immutable.
28+
*
29+
* @see <a href="https://cloud.google.com/datastore/docs/concepts/entities">Google Cloud Datastore
30+
* Entities, Properties, and Keys</a>
31+
*/
32+
public final class GeoPoint extends Serializable<com.google.type.LatLng> {
33+
34+
private static final long serialVersionUID = 9077060962655752073L;
35+
36+
private final transient double latitude;
37+
private final transient double longitude;
38+
39+
GeoPoint(double latitude, double longitude) {
40+
checkArgument(
41+
latitude >= -90.0 && latitude <= 90.0, "latitude must be in the range [-90, 90] degrees");
42+
checkArgument(
43+
longitude >= -180.0 && longitude <= 180.0,
44+
"latitude must be in the range [-180, 180] degrees");
45+
this.latitude = latitude;
46+
this.longitude = longitude;
47+
}
48+
49+
@Override
50+
public String toString() {
51+
return Double.toString(latitude) + ", " + Double.toString(longitude);
52+
}
53+
54+
@Override
55+
public int hashCode() {
56+
return Objects.hash(latitude, longitude);
57+
}
58+
59+
@Override
60+
public boolean equals(Object obj) {
61+
return obj == this
62+
|| (obj instanceof GeoPoint && new Double(this.latitude).equals(((GeoPoint) obj).latitude))
63+
&& new Double(this.longitude).equals(((GeoPoint) obj).longitude);
64+
}
65+
66+
public static GeoPoint of(double latitude, double longitude) {
67+
return new GeoPoint(latitude, longitude);
68+
}
69+
70+
@Override
71+
protected com.google.type.LatLng toPb() {
72+
return com.google.type.LatLng.newBuilder()
73+
.setLatitude(latitude)
74+
.setLongitude(longitude)
75+
.build();
76+
}
77+
78+
@Override
79+
protected Object fromPb(byte[] bytesPb) throws InvalidProtocolBufferException {
80+
com.google.type.LatLng parsedLatLng = com.google.type.LatLng.parseFrom(bytesPb);
81+
return new GeoPoint(parsedLatLng.getLatitude(), parsedLatLng.getLongitude());
82+
}
83+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright 2015 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.google.gcloud.datastore;
18+
19+
import static com.google.datastore.v1beta3.Value.GEO_POINT_VALUE_FIELD_NUMBER;
20+
21+
public final class GeoPointValue extends Value<GeoPoint> {
22+
23+
private static final long serialVersionUID = -5810614280642405898L;
24+
25+
static final BaseMarshaller<GeoPoint, GeoPointValue, Builder> MARSHALLER =
26+
new BaseMarshaller<GeoPoint, GeoPointValue, Builder>() {
27+
28+
private static final long serialVersionUID = -3550567536035178649L;
29+
30+
@Override
31+
public int getProtoFieldId() {
32+
return GEO_POINT_VALUE_FIELD_NUMBER;
33+
}
34+
35+
@Override
36+
public Builder newBuilder(GeoPoint value) {
37+
return builder(value);
38+
}
39+
40+
@Override
41+
protected GeoPoint getValue(com.google.datastore.v1beta3.Value from) {
42+
return new GeoPoint(
43+
from.getGeoPointValue().getLatitude(), from.getGeoPointValue().getLongitude());
44+
}
45+
46+
@Override
47+
protected void setValue(GeoPointValue from, com.google.datastore.v1beta3.Value.Builder to) {
48+
to.setGeoPointValue(from.get().toPb());
49+
}
50+
};
51+
52+
public static final class Builder extends Value.BaseBuilder<GeoPoint, GeoPointValue, Builder> {
53+
54+
private Builder() {
55+
super(ValueType.GEO_POINT);
56+
}
57+
58+
@Override
59+
public GeoPointValue build() {
60+
return new GeoPointValue(this);
61+
}
62+
}
63+
64+
public GeoPointValue(GeoPoint value) {
65+
this(builder(value));
66+
}
67+
68+
private GeoPointValue(Builder builder) {
69+
super(builder);
70+
}
71+
72+
@Override
73+
public Builder toBuilder() {
74+
return new Builder().mergeFrom(this);
75+
}
76+
77+
public static GeoPointValue of(GeoPoint value) {
78+
return new GeoPointValue(value);
79+
}
80+
81+
public static Builder builder(GeoPoint value) {
82+
return new Builder().set(value);
83+
}
84+
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ public Builder<V> setBinding(String name, DateTime... value) {
212212
namedBindings.put(name, toBinding(DateTimeValue.MARSHALLER, Arrays.asList(value)));
213213
return this;
214214
}
215+
216+
public Builder<V> setBinding(String name, GeoPoint... value) {
217+
namedBindings.put(name, toBinding(GeoPointValue.MARSHALLER, Arrays.asList(value)));
218+
return this;
219+
}
215220

216221
public Builder<V> setBinding(String name, Key... value) {
217222
namedBindings.put(name, toBinding(KeyValue.MARSHALLER, Arrays.asList(value)));
@@ -258,6 +263,11 @@ public Builder<V> addBinding(DateTime... value) {
258263
return this;
259264
}
260265

266+
public Builder<V> addBinding(GeoPoint... value) {
267+
positionalBindings.add(toBinding(GeoPointValue.MARSHALLER, Arrays.asList(value)));
268+
return this;
269+
}
270+
261271
public Builder<V> addBinding(Key... value) {
262272
positionalBindings.add(toBinding(KeyValue.MARSHALLER, Arrays.asList(value)));
263273
return this;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static com.google.gcloud.datastore.BooleanValue.of;
2222
import static com.google.gcloud.datastore.DateTimeValue.of;
2323
import static com.google.gcloud.datastore.DoubleValue.of;
24+
import static com.google.gcloud.datastore.GeoPointValue.of;
2425
import static com.google.gcloud.datastore.KeyValue.of;
2526
import static com.google.gcloud.datastore.LongValue.of;
2627
import static com.google.gcloud.datastore.StringValue.of;
@@ -420,6 +421,10 @@ public static PropertyFilter eq(String property, DateTime value) {
420421
return new PropertyFilter(property, Operator.EQUAL, of(value));
421422
}
422423

424+
public static PropertyFilter eq(String property, GeoPoint value) {
425+
return new PropertyFilter(property, Operator.EQUAL, of(value));
426+
}
427+
423428
public static PropertyFilter eq(String property, Key value) {
424429
return new PropertyFilter(property, Operator.EQUAL, of(value));
425430
}

gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/ValueType.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,12 @@ public enum ValueType {
7878
/**
7979
* Represents a raw/unparsed value.
8080
*/
81-
RAW_VALUE(RawValue.MARSHALLER);
81+
RAW_VALUE(RawValue.MARSHALLER),
8282

8383
/**
84-
* TODO(ajaykannan): add GEO_POINT_VALUE
85-
* Will represent a geolocation value in latitude/longitude
84+
* Represents a {@link GeoPoint} value
8685
*/
86+
GEO_POINT(GeoPointValue.MARSHALLER);
8787

8888
private static final ImmutableMap<Integer, ValueType> DESCRIPTOR_TO_TYPE_MAP;
8989

gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/BaseEntityTest.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public class BaseEntityTest {
3535

3636
private static final Blob BLOB = Blob.copyFrom(new byte[]{1, 2});
3737
private static final DateTime DATE_TIME = DateTime.now();
38+
private static final GeoPoint GEO_POINT = new GeoPoint(30.5, -40.5);
3839
private static final Key KEY = Key.builder("ds1", "k1", "n1").build();
3940
private static final Entity ENTITY = Entity.builder(KEY).set("name", "foo").build();
4041
private static final IncompleteKey INCOMPLETE_KEY = IncompleteKey.builder("ds1", "k1").build();
@@ -62,9 +63,9 @@ public void setUp() {
6263
builder = new Builder();
6364
builder.set("blob", BLOB).set("boolean", true).set("dateTime", DATE_TIME);
6465
builder.set("double", 1.25).set("key", KEY).set("string", "hello world");
65-
builder.set("long", 125).setNull("null").set("entity", ENTITY);
66+
builder.set("long", 125).setNull("null").set("entity", ENTITY).set("geoPoint", GEO_POINT);
6667
builder.set("partialEntity", PARTIAL_ENTITY).set("stringValue", StringValue.of("bla"));
67-
builder.set("list1", NullValue.of(), StringValue.of("foo"));
68+
builder.set("list1", NullValue.of(), StringValue.of("foo"), GeoPointValue.of(GEO_POINT));
6869
builder.set("list2", ImmutableList.of(LongValue.of(10), DoubleValue.of(2)));
6970
builder.set("list3", Collections.singletonList(BooleanValue.of(true)));
7071
}
@@ -149,6 +150,12 @@ public void testGetDateTime() throws Exception {
149150
assertEquals(dateTime, entity.getDateTime("dateTime"));
150151
}
151152

153+
@Test
154+
public void testGetGeoPoint() throws Exception {
155+
BaseEntity<Key> entity = builder.build();
156+
assertEquals(GEO_POINT, entity.getGeoPoint("geoPoint"));
157+
}
158+
152159
@Test
153160
public void testGetKey() throws Exception {
154161
BaseEntity<Key> entity = builder.build();
@@ -171,9 +178,10 @@ public void testGetEntity() throws Exception {
171178
public void testGetList() throws Exception {
172179
BaseEntity<Key> entity = builder.build();
173180
List<? extends Value<?>> list = entity.getList("list1");
174-
assertEquals(2, list.size());
181+
assertEquals(3, list.size());
175182
assertEquals(NullValue.of(), list.get(0));
176183
assertEquals("foo", list.get(1).get());
184+
assertEquals(GEO_POINT, list.get(2).get());
177185
list = entity.getList("list2");
178186
assertEquals(2, list.size());
179187
assertEquals(Long.valueOf(10), list.get(0).get());
@@ -196,9 +204,10 @@ public void testGetBlob() throws Exception {
196204

197205
@Test
198206
public void testNames() throws Exception {
199-
Set<String> names = ImmutableSet.<String>builder()
200-
.add("string", "stringValue", "boolean", "double", "long", "list1", "list2", "list3")
201-
.add("entity", "partialEntity", "null", "dateTime", "blob", "key")
207+
Set<String> names =
208+
ImmutableSet.<String>builder()
209+
.add("string", "stringValue", "boolean", "double", "long", "list1", "list2", "list3")
210+
.add("entity", "partialEntity", "null", "dateTime", "geoPoint", "blob", "key")
202211
.build();
203212
BaseEntity<Key> entity = builder.build();
204213
assertEquals(names, entity.names());

gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public class DatastoreTest {
7474
.build();
7575
private static final ListValue LIST_VALUE2 = ListValue.of(Collections.singletonList(KEY_VALUE));
7676
private static final DateTimeValue DATE_TIME_VALUE = new DateTimeValue(DateTime.now());
77+
private static final GeoPointValue GEO_POINT_VALUE = new GeoPointValue(new GeoPoint(30.5, 40.5));
7778
private static final FullEntity<IncompleteKey> PARTIAL_ENTITY1 =
7879
FullEntity.builder(INCOMPLETE_KEY2).set("str", STR_VALUE).set("bool", BOOL_VALUE)
7980
.set("list", LIST_VALUE1).build();
@@ -83,13 +84,15 @@ public class DatastoreTest {
8384
private static final FullEntity<IncompleteKey> PARTIAL_ENTITY3 =
8485
FullEntity.builder(PARTIAL_ENTITY1).key(IncompleteKey.builder(PROJECT_ID, KIND3).build())
8586
.build();
86-
private static final Entity ENTITY1 = Entity.builder(KEY1)
87-
.set("str", STR_VALUE)
88-
.set("date", DATE_TIME_VALUE)
89-
.set("bool", BOOL_VALUE)
90-
.set("partial1", EntityValue.of(PARTIAL_ENTITY1))
91-
.set("list", LIST_VALUE2)
92-
.build();
87+
private static final Entity ENTITY1 =
88+
Entity.builder(KEY1)
89+
.set("str", STR_VALUE)
90+
.set("date", DATE_TIME_VALUE)
91+
.set("geoPoint", GEO_POINT_VALUE)
92+
.set("bool", BOOL_VALUE)
93+
.set("partial1", EntityValue.of(PARTIAL_ENTITY1))
94+
.set("list", LIST_VALUE2)
95+
.build();
9396
private static final Entity ENTITY2 = Entity.builder(ENTITY1).key(KEY2).remove("str")
9497
.set("name", "Dan").setNull("null").set("age", 20).build();
9598
private static final Entity ENTITY3 = Entity.builder(ENTITY1).key(KEY3).remove("str")
@@ -504,9 +507,11 @@ public void testGet() {
504507
assertEquals(LIST_VALUE2, value3);
505508
DateTimeValue value4 = entity.getValue("date");
506509
assertEquals(DATE_TIME_VALUE, value4);
507-
FullEntity<IncompleteKey> value5 = entity.getEntity("partial1");
508-
assertEquals(PARTIAL_ENTITY1, value5);
509-
assertEquals(5, entity.names().size());
510+
GeoPointValue value5 = entity.getValue("geoPoint");
511+
assertEquals(GEO_POINT_VALUE, value5);
512+
FullEntity<IncompleteKey> value6 = entity.getEntity("partial1");
513+
assertEquals(PARTIAL_ENTITY1, value6);
514+
assertEquals(6, entity.names().size());
510515
assertFalse(entity.contains("bla"));
511516
}
512517

@@ -528,7 +533,8 @@ public void testGetArray() {
528533
assertEquals(PARTIAL_ENTITY2, partial1);
529534
assertEquals(ENTITY2, partial2);
530535
assertEquals(ValueType.BOOLEAN, entity3.getValue("bool").type());
531-
assertEquals(6, entity3.names().size());
536+
assertEquals(GEO_POINT_VALUE, entity3.getValue("geoPoint"));
537+
assertEquals(7, entity3.names().size());
532538
assertFalse(entity3.contains("bla"));
533539
try {
534540
entity3.getString("str");

0 commit comments

Comments
 (0)