Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GeoPoint value #270

Merged
merged 4 commits into from
Oct 20, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import static com.google.gcloud.datastore.DateTimeValue.of;
import static com.google.gcloud.datastore.DoubleValue.of;
import static com.google.gcloud.datastore.EntityValue.of;
import static com.google.gcloud.datastore.LatLngValue.of;
import static com.google.gcloud.datastore.KeyValue.of;
import static com.google.gcloud.datastore.ListValue.of;
import static com.google.gcloud.datastore.LongValue.of;
Expand Down Expand Up @@ -159,6 +160,11 @@ public B set(String name, DateTime value) {
return self();
}

public B set(String name, LatLng value) {
properties.put(name, of(value));
return self();
}

public B set(String name, Key value) {
properties.put(name, of(value));
return self();
Expand Down Expand Up @@ -320,6 +326,17 @@ public DateTime getDateTime(String name) {
return ((Value<DateTime>) getValue(name)).get();
}

/**
* Returns the property value as a LatLng.
*
* @throws DatastoreException if not such property.
* @throws ClassCastException if value is not a LatLng.
*/
@SuppressWarnings("unchecked")
public LatLng getLatLng(String name) {
return ((Value<LatLng>) getValue(name)).get();
}

/**
* Returns the property value as a Key.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.gcloud.datastore;

import static com.google.common.base.Preconditions.checkArgument;

import com.google.protobuf.InvalidProtocolBufferException;

import java.util.Objects;

/**
* A Google Cloud Datastore LatLng (represented by latitude and longitude in degrees).
* This class is immutable.
*
* @see <a href="https://cloud.google.com/datastore/docs/concepts/entities">Google Cloud Datastore
* Entities, Properties, and Keys</a>
*/
public final class LatLng extends Serializable<com.google.type.LatLng> {

private static final long serialVersionUID = 9077060962655752073L;

private final transient double latitude;
private final transient double longitude;

LatLng(double latitude, double longitude) {
checkArgument(
latitude >= -90.0 && latitude <= 90.0, "latitude must be in the range [-90, 90] degrees");
checkArgument(
longitude >= -180.0 && longitude <= 180.0,
"latitude must be in the range [-180, 180] degrees");
this.latitude = latitude;
this.longitude = longitude;
}

public double latitude() {
return latitude;
}

public double longitude() {
return longitude;
}

@Override
public String toString() {
return Double.toString(latitude) + ", " + Double.toString(longitude);
}

@Override
public int hashCode() {
return Objects.hash(latitude, longitude);
}

@Override
public boolean equals(Object obj) {
return obj == this || (obj instanceof LatLng && this.latitude == ((LatLng) obj).latitude
&& this.longitude == ((LatLng) obj).longitude);
}

public static LatLng of(double latitude, double longitude) {
return new LatLng(latitude, longitude);
}

@Override
protected com.google.type.LatLng toPb() {
return com.google.type.LatLng.newBuilder()
.setLatitude(latitude)
.setLongitude(longitude)
.build();
}

@Override
protected Object fromPb(byte[] bytesPb) throws InvalidProtocolBufferException {
com.google.type.LatLng parsedLatLng = com.google.type.LatLng.parseFrom(bytesPb);
return new LatLng(parsedLatLng.getLatitude(), parsedLatLng.getLongitude());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.gcloud.datastore;

import static com.google.datastore.v1beta3.Value.GEO_POINT_VALUE_FIELD_NUMBER;

public final class LatLngValue extends Value<LatLng> {

private static final long serialVersionUID = -5810614280642405898L;

static final BaseMarshaller<LatLng, LatLngValue, Builder> MARSHALLER =
new BaseMarshaller<LatLng, LatLngValue, Builder>() {

private static final long serialVersionUID = -3550567536035178649L;

@Override
public int getProtoFieldId() {
return GEO_POINT_VALUE_FIELD_NUMBER;
}

@Override
public Builder newBuilder(LatLng value) {
return builder(value);
}

@Override
protected LatLng getValue(com.google.datastore.v1beta3.Value from) {
return new LatLng(
from.getGeoPointValue().getLatitude(), from.getGeoPointValue().getLongitude());
}

@Override
protected void setValue(LatLngValue from, com.google.datastore.v1beta3.Value.Builder to) {
to.setGeoPointValue(from.get().toPb());
}
};

public static final class Builder extends Value.BaseBuilder<LatLng, LatLngValue, Builder> {

private Builder() {
super(ValueType.LAT_LNG);
}

@Override
public LatLngValue build() {
return new LatLngValue(this);
}
}

public LatLngValue(LatLng value) {
this(builder(value));
}

private LatLngValue(Builder builder) {
super(builder);
}

@Override
public Builder toBuilder() {
return new Builder().mergeFrom(this);
}

public static LatLngValue of(LatLng value) {
return new LatLngValue(value);
}

public static Builder builder(LatLng value) {
return new Builder().set(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ public enum ValueType {
/**
* Represents a raw/unparsed value.
*/
RAW_VALUE(RawValue.MARSHALLER);
RAW_VALUE(RawValue.MARSHALLER),

/**
* TODO(ajaykannan): add GEO_POINT_VALUE
* Will represent a geolocation value in latitude/longitude
* Represents a {@link LatLng} value
*/
LAT_LNG(LatLngValue.MARSHALLER);

private static final ImmutableMap<Integer, ValueType> DESCRIPTOR_TO_TYPE_MAP;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class BaseEntityTest {

private static final Blob BLOB = Blob.copyFrom(new byte[]{1, 2});
private static final DateTime DATE_TIME = DateTime.now();
private static final LatLng LAT_LNG = new LatLng(37.422035, -122.084124);
private static final Key KEY = Key.builder("ds1", "k1", "n1").build();
private static final Entity ENTITY = Entity.builder(KEY).set("name", "foo").build();
private static final IncompleteKey INCOMPLETE_KEY = IncompleteKey.builder("ds1", "k1").build();
Expand Down Expand Up @@ -62,9 +63,9 @@ public void setUp() {
builder = new Builder();
builder.set("blob", BLOB).set("boolean", true).set("dateTime", DATE_TIME);
builder.set("double", 1.25).set("key", KEY).set("string", "hello world");
builder.set("long", 125).setNull("null").set("entity", ENTITY);
builder.set("long", 125).setNull("null").set("entity", ENTITY).set("latLng", LAT_LNG);
builder.set("partialEntity", PARTIAL_ENTITY).set("stringValue", StringValue.of("bla"));
builder.set("list1", NullValue.of(), StringValue.of("foo"));
builder.set("list1", NullValue.of(), StringValue.of("foo"), LatLngValue.of(LAT_LNG));
builder.set("list2", ImmutableList.of(LongValue.of(10), DoubleValue.of(2)));
builder.set("list3", Collections.singletonList(BooleanValue.of(true)));
}
Expand Down Expand Up @@ -149,6 +150,12 @@ public void testGetDateTime() throws Exception {
assertEquals(dateTime, entity.getDateTime("dateTime"));
}

@Test
public void testGetLatLng() throws Exception {
BaseEntity<Key> entity = builder.build();
assertEquals(LAT_LNG, entity.getLatLng("latLng"));
}

@Test
public void testGetKey() throws Exception {
BaseEntity<Key> entity = builder.build();
Expand All @@ -171,9 +178,10 @@ public void testGetEntity() throws Exception {
public void testGetList() throws Exception {
BaseEntity<Key> entity = builder.build();
List<? extends Value<?>> list = entity.getList("list1");
assertEquals(2, list.size());
assertEquals(3, list.size());
assertEquals(NullValue.of(), list.get(0));
assertEquals("foo", list.get(1).get());
assertEquals(LAT_LNG, list.get(2).get());
list = entity.getList("list2");
assertEquals(2, list.size());
assertEquals(Long.valueOf(10), list.get(0).get());
Expand All @@ -196,9 +204,10 @@ public void testGetBlob() throws Exception {

@Test
public void testNames() throws Exception {
Set<String> names = ImmutableSet.<String>builder()
.add("string", "stringValue", "boolean", "double", "long", "list1", "list2", "list3")
.add("entity", "partialEntity", "null", "dateTime", "blob", "key")
Set<String> names =
ImmutableSet.<String>builder()
.add("string", "stringValue", "boolean", "double", "long", "list1", "list2", "list3")
.add("entity", "partialEntity", "null", "dateTime", "latLng", "blob", "key")
.build();
BaseEntity<Key> entity = builder.build();
assertEquals(names, entity.names());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public class DatastoreTest {
.build();
private static final ListValue LIST_VALUE2 = ListValue.of(Collections.singletonList(KEY_VALUE));
private static final DateTimeValue DATE_TIME_VALUE = new DateTimeValue(DateTime.now());
private static final LatLngValue LAT_LNG_VALUE =
new LatLngValue(new LatLng(37.422035, -122.084124));
private static final FullEntity<IncompleteKey> PARTIAL_ENTITY1 =
FullEntity.builder(INCOMPLETE_KEY2).set("str", STR_VALUE).set("bool", BOOL_VALUE)
.set("list", LIST_VALUE1).build();
Expand All @@ -83,13 +85,15 @@ public class DatastoreTest {
private static final FullEntity<IncompleteKey> PARTIAL_ENTITY3 =
FullEntity.builder(PARTIAL_ENTITY1).key(IncompleteKey.builder(PROJECT_ID, KIND3).build())
.build();
private static final Entity ENTITY1 = Entity.builder(KEY1)
.set("str", STR_VALUE)
.set("date", DATE_TIME_VALUE)
.set("bool", BOOL_VALUE)
.set("partial1", EntityValue.of(PARTIAL_ENTITY1))
.set("list", LIST_VALUE2)
.build();
private static final Entity ENTITY1 =
Entity.builder(KEY1)
.set("str", STR_VALUE)
.set("date", DATE_TIME_VALUE)
.set("latLng", LAT_LNG_VALUE)
.set("bool", BOOL_VALUE)
.set("partial1", EntityValue.of(PARTIAL_ENTITY1))
.set("list", LIST_VALUE2)
.build();
private static final Entity ENTITY2 = Entity.builder(ENTITY1).key(KEY2).remove("str")
.set("name", "Dan").setNull("null").set("age", 20).build();
private static final Entity ENTITY3 = Entity.builder(ENTITY1).key(KEY3).remove("str")
Expand Down Expand Up @@ -504,9 +508,11 @@ public void testGet() {
assertEquals(LIST_VALUE2, value3);
DateTimeValue value4 = entity.getValue("date");
assertEquals(DATE_TIME_VALUE, value4);
FullEntity<IncompleteKey> value5 = entity.getEntity("partial1");
assertEquals(PARTIAL_ENTITY1, value5);
assertEquals(5, entity.names().size());
LatLngValue value5 = entity.getValue("latLng");
assertEquals(LAT_LNG_VALUE, value5);
FullEntity<IncompleteKey> value6 = entity.getEntity("partial1");
assertEquals(PARTIAL_ENTITY1, value6);
assertEquals(6, entity.names().size());
assertFalse(entity.contains("bla"));
}

Expand All @@ -528,7 +534,8 @@ public void testGetArray() {
assertEquals(PARTIAL_ENTITY2, partial1);
assertEquals(ENTITY2, partial2);
assertEquals(ValueType.BOOLEAN, entity3.getValue("bool").type());
assertEquals(6, entity3.names().size());
assertEquals(LAT_LNG_VALUE, entity3.getValue("latLng"));
assertEquals(7, entity3.names().size());
assertFalse(entity3.contains("bla"));
try {
entity3.getString("str");
Expand Down
Loading