Skip to content

Commit 9e4692d

Browse files
committed
Merge pull request #270 from ajkannan/geopoint-value
Add GeoPoint value
2 parents 8245607 + 241960f commit 9e4692d

File tree

10 files changed

+393
-53
lines changed

10 files changed

+393
-53
lines changed

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

+17
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.LatLngValue.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, LatLng 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 LatLng.
331+
*
332+
* @throws DatastoreException if not such property.
333+
* @throws ClassCastException if value is not a LatLng.
334+
*/
335+
@SuppressWarnings("unchecked")
336+
public LatLng getLatLng(String name) {
337+
return ((Value<LatLng>) getValue(name)).get();
338+
}
339+
323340
/**
324341
* Returns the property value as a Key.
325342
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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 LatLng (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 LatLng 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+
LatLng(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+
public double latitude() {
50+
return latitude;
51+
}
52+
53+
public double longitude() {
54+
return longitude;
55+
}
56+
57+
@Override
58+
public String toString() {
59+
return Double.toString(latitude) + ", " + Double.toString(longitude);
60+
}
61+
62+
@Override
63+
public int hashCode() {
64+
return Objects.hash(latitude, longitude);
65+
}
66+
67+
@Override
68+
public boolean equals(Object obj) {
69+
return obj == this || (obj instanceof LatLng && this.latitude == ((LatLng) obj).latitude
70+
&& this.longitude == ((LatLng) obj).longitude);
71+
}
72+
73+
public static LatLng of(double latitude, double longitude) {
74+
return new LatLng(latitude, longitude);
75+
}
76+
77+
@Override
78+
protected com.google.type.LatLng toPb() {
79+
return com.google.type.LatLng.newBuilder()
80+
.setLatitude(latitude)
81+
.setLongitude(longitude)
82+
.build();
83+
}
84+
85+
@Override
86+
protected Object fromPb(byte[] bytesPb) throws InvalidProtocolBufferException {
87+
com.google.type.LatLng parsedLatLng = com.google.type.LatLng.parseFrom(bytesPb);
88+
return new LatLng(parsedLatLng.getLatitude(), parsedLatLng.getLongitude());
89+
}
90+
}
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 LatLngValue extends Value<LatLng> {
22+
23+
private static final long serialVersionUID = -5810614280642405898L;
24+
25+
static final BaseMarshaller<LatLng, LatLngValue, Builder> MARSHALLER =
26+
new BaseMarshaller<LatLng, LatLngValue, 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(LatLng value) {
37+
return builder(value);
38+
}
39+
40+
@Override
41+
protected LatLng getValue(com.google.datastore.v1beta3.Value from) {
42+
return new LatLng(
43+
from.getGeoPointValue().getLatitude(), from.getGeoPointValue().getLongitude());
44+
}
45+
46+
@Override
47+
protected void setValue(LatLngValue 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<LatLng, LatLngValue, Builder> {
53+
54+
private Builder() {
55+
super(ValueType.LAT_LNG);
56+
}
57+
58+
@Override
59+
public LatLngValue build() {
60+
return new LatLngValue(this);
61+
}
62+
}
63+
64+
public LatLngValue(LatLng value) {
65+
this(builder(value));
66+
}
67+
68+
private LatLngValue(Builder builder) {
69+
super(builder);
70+
}
71+
72+
@Override
73+
public Builder toBuilder() {
74+
return new Builder().mergeFrom(this);
75+
}
76+
77+
public static LatLngValue of(LatLng value) {
78+
return new LatLngValue(value);
79+
}
80+
81+
public static Builder builder(LatLng value) {
82+
return new Builder().set(value);
83+
}
84+
}

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

+3-3
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 LatLng} value
8685
*/
86+
LAT_LNG(LatLngValue.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

+15-6
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 LatLng LAT_LNG = new LatLng(37.422035, -122.084124);
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("latLng", LAT_LNG);
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"), LatLngValue.of(LAT_LNG));
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 testGetLatLng() throws Exception {
155+
BaseEntity<Key> entity = builder.build();
156+
assertEquals(LAT_LNG, entity.getLatLng("latLng"));
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(LAT_LNG, 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", "latLng", "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

+18-11
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ 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 LatLngValue LAT_LNG_VALUE =
78+
new LatLngValue(new LatLng(37.422035, -122.084124));
7779
private static final FullEntity<IncompleteKey> PARTIAL_ENTITY1 =
7880
FullEntity.builder(INCOMPLETE_KEY2).set("str", STR_VALUE).set("bool", BOOL_VALUE)
7981
.set("list", LIST_VALUE1).build();
@@ -83,13 +85,15 @@ public class DatastoreTest {
8385
private static final FullEntity<IncompleteKey> PARTIAL_ENTITY3 =
8486
FullEntity.builder(PARTIAL_ENTITY1).key(IncompleteKey.builder(PROJECT_ID, KIND3).build())
8587
.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();
88+
private static final Entity ENTITY1 =
89+
Entity.builder(KEY1)
90+
.set("str", STR_VALUE)
91+
.set("date", DATE_TIME_VALUE)
92+
.set("latLng", LAT_LNG_VALUE)
93+
.set("bool", BOOL_VALUE)
94+
.set("partial1", EntityValue.of(PARTIAL_ENTITY1))
95+
.set("list", LIST_VALUE2)
96+
.build();
9397
private static final Entity ENTITY2 = Entity.builder(ENTITY1).key(KEY2).remove("str")
9498
.set("name", "Dan").setNull("null").set("age", 20).build();
9599
private static final Entity ENTITY3 = Entity.builder(ENTITY1).key(KEY3).remove("str")
@@ -504,9 +508,11 @@ public void testGet() {
504508
assertEquals(LIST_VALUE2, value3);
505509
DateTimeValue value4 = entity.getValue("date");
506510
assertEquals(DATE_TIME_VALUE, value4);
507-
FullEntity<IncompleteKey> value5 = entity.getEntity("partial1");
508-
assertEquals(PARTIAL_ENTITY1, value5);
509-
assertEquals(5, entity.names().size());
511+
LatLngValue value5 = entity.getValue("latLng");
512+
assertEquals(LAT_LNG_VALUE, value5);
513+
FullEntity<IncompleteKey> value6 = entity.getEntity("partial1");
514+
assertEquals(PARTIAL_ENTITY1, value6);
515+
assertEquals(6, entity.names().size());
510516
assertFalse(entity.contains("bla"));
511517
}
512518

@@ -528,7 +534,8 @@ public void testGetArray() {
528534
assertEquals(PARTIAL_ENTITY2, partial1);
529535
assertEquals(ENTITY2, partial2);
530536
assertEquals(ValueType.BOOLEAN, entity3.getValue("bool").type());
531-
assertEquals(6, entity3.names().size());
537+
assertEquals(LAT_LNG_VALUE, entity3.getValue("latLng"));
538+
assertEquals(7, entity3.names().size());
532539
assertFalse(entity3.contains("bla"));
533540
try {
534541
entity3.getString("str");

0 commit comments

Comments
 (0)