From 96509abadf6190b7886d57fdd9b090da55f5171c Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Sun, 18 Nov 2018 18:50:07 -0800 Subject: [PATCH 1/2] DO NOT MERGE: Adding FieldValue.increment() --- .../google/cloud/firestore/FieldValue.java | 100 ++++++++++++++++-- .../cloud/firestore/UserDataConverter.java | 2 +- .../firestore/DocumentReferenceTest.java | 31 +++++- .../google/cloud/firestore/FirestoreTest.java | 12 +++ .../cloud/firestore/LocalFirestoreHelper.java | 4 + .../cloud/firestore/it/ITSystemTest.java | 20 ++++ 6 files changed, 154 insertions(+), 15 deletions(-) diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FieldValue.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FieldValue.java index c7480ce653b4..f268cec54469 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FieldValue.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FieldValue.java @@ -77,6 +77,55 @@ FieldTransform toProto(FieldPath path) { } }; + static class NumericIncrementFieldValue extends FieldValue { + final Number operand; + + NumericIncrementFieldValue(Number operand) { + this.operand = operand; + } + + @Override + boolean includeInDocumentMask() { + return false; + } + + @Override + boolean includeInDocumentTransform() { + return true; + } + + @Override + String getMethodName() { + return "FieldValue.increment()"; + } + + @Override + FieldTransform toProto(FieldPath path) { + FieldTransform.Builder fieldTransform = FieldTransform.newBuilder(); + fieldTransform.setFieldPath(path.getEncodedPath()); + fieldTransform.setNumericAdd( + UserDataConverter.encodeValue(FieldPath.of(""), operand, UserDataConverter.ARGUMENT)); + return fieldTransform.build(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + NumericIncrementFieldValue that = (NumericIncrementFieldValue) o; + return Objects.equals(operand, that.operand); + } + + @Override + public int hashCode() { + return Objects.hash(operand); + } + } + static class ArrayUnionFieldValue extends FieldValue { final List elements; @@ -205,11 +254,44 @@ public static FieldValue delete() { } /** - * Returns a special value that can be used with set() or update() that tells the server to union - * the given elements with any array value that already exists on the server. Each specified - * element that doesn't already exist in the array will be added to the end. If the field being - * modified is not already an array it will be overwritten with an array containing exactly the - * specified elements. + * Returns a special value that can be used with set(), create() or update() that tells the server + * to increment the field's current value by the given value. + * + *

If the current field value is an integer, possible integer overflows are resolved to + * Long.MAX_VALUE or Long.MIN_VALUE. If the current field value is a double, both values will be + * interpreted as doubles and the arithmetic will follow IEEE 754 semantics. + * + *

If the current field is not an integer or double, or if the field does not yet exist, the + * transformation will set the field to the given value. + * + * @return The FieldValue sentinel for use in a call to set(), create() or update(). + */ + @Nonnull + public static FieldValue increment(long l) { + return new NumericIncrementFieldValue(l); + } + + /** + * Returns a special value that can be used with set(), create() or update() that tells the server + * to increment the field's current value by the given value. + * + *

If the current value is an integer or a double, both the current and the given value will be + * interpreted as doubles and all arithmetic will follow IEEE 754 semantics. Otherwise, the + * transformation will set the field to the given value. + * + * @return The FieldValue sentinel for use in a call to set(), create() or update(). + */ + @Nonnull + public static FieldValue increment(double d) { + return new NumericIncrementFieldValue(d); + } + + /** + * Returns a special value that can be used with set(), create() or update() that tells the server + * to union the given elements with any array value that already exists on the server. Each + * specified element that doesn't already exist in the array will be added to the end. If the + * field being modified is not already an array it will be overwritten with an array containing + * exactly the specified elements. * * @param elements The elements to union into the array. * @return The FieldValue sentinel for use in a call to set() or update(). @@ -221,10 +303,10 @@ public static FieldValue arrayUnion(@Nonnull Object... elements) { } /** - * Returns a special value that can be used with set() or update() that tells the server to remove - * the given elements from any array value that already exists on the server. All instances of - * each element specified will be removed from the array. If the field being modified is not - * already an array it will be overwritten with an empty array. + * Returns a special value that can be used with set(), create() or update() that tells the server + * to remove the given elements from any array value that already exists on the server. All + * instances of each element specified will be removed from the array. If the field being modified + * is not already an array it will be overwritten with an empty array. * * @param elements The elements to remove from the array. * @return The FieldValue sentinel for use in a call to set() or update(). diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UserDataConverter.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UserDataConverter.java index bda5ad48f0f7..d789f01c5b3f 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UserDataConverter.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UserDataConverter.java @@ -90,7 +90,7 @@ private UserDataConverter() {} * @param path path THe field path of the object to encode. * @param sanitizedObject An Object that has been sanitized by CustomClassMapper and only contains * valid types. - * @param options Encoding opions to use for this value. + * @param options Encoding options to use for this value. * @return The Value proto. */ @Nullable diff --git a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/DocumentReferenceTest.java b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/DocumentReferenceTest.java index 59dab2fea2d8..654a32ae696b 100644 --- a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/DocumentReferenceTest.java +++ b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/DocumentReferenceTest.java @@ -44,6 +44,7 @@ import static com.google.cloud.firestore.LocalFirestoreHelper.delete; import static com.google.cloud.firestore.LocalFirestoreHelper.get; import static com.google.cloud.firestore.LocalFirestoreHelper.getAllResponse; +import static com.google.cloud.firestore.LocalFirestoreHelper.increment; import static com.google.cloud.firestore.LocalFirestoreHelper.map; import static com.google.cloud.firestore.LocalFirestoreHelper.object; import static com.google.cloud.firestore.LocalFirestoreHelper.serverTimestamp; @@ -418,9 +419,7 @@ public void setWithArrayUnion() throws Exception { .sendRequest( commitCapture.capture(), Matchers.>any()); - documentReference - .set(map("foo", FieldValue.arrayUnion("bar", map("foo", "baz")))) - .get(); + documentReference.set(map("foo", FieldValue.arrayUnion("bar", map("foo", "baz")))).get(); CommitRequest set = commit( @@ -432,16 +431,38 @@ public void setWithArrayUnion() throws Exception { } @Test - public void setWithArrayRemove() throws Exception { + public void setWithIncrement() throws Exception { doReturn(FIELD_TRANSFORM_COMMIT_RESPONSE) .when(firestoreMock) .sendRequest( commitCapture.capture(), Matchers.>any()); documentReference - .set(map("foo", FieldValue.arrayRemove("bar", map("foo", "baz")))) + .set(map("integer", FieldValue.increment(1), "double", FieldValue.increment(1.1))) .get(); + CommitRequest set = + commit( + set(Collections.emptyMap()), + transform( + "integer", + increment(Value.newBuilder().setIntegerValue(1).build()), + "double", + increment(Value.newBuilder().setDoubleValue(1.1).build()))); + + CommitRequest commitRequest = commitCapture.getValue(); + assertCommitEquals(set, commitRequest); + } + + @Test + public void setWithArrayRemove() throws Exception { + doReturn(FIELD_TRANSFORM_COMMIT_RESPONSE) + .when(firestoreMock) + .sendRequest( + commitCapture.capture(), Matchers.>any()); + + documentReference.set(map("foo", FieldValue.arrayRemove("bar", map("foo", "baz")))).get(); + CommitRequest set = commit( set(Collections.emptyMap()), diff --git a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/FirestoreTest.java b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/FirestoreTest.java index 68798058a068..13faab323af6 100644 --- a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/FirestoreTest.java +++ b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/FirestoreTest.java @@ -141,4 +141,16 @@ public void arrayRemoveEquals() { assertNotEquals(arrayRemove1, arrayRemove3); assertNotEquals(arrayRemove1, arrayUnion); } + + @Test + public void incrementEquals() { + FieldValue increment1 = FieldValue.increment(42); + FieldValue increment2 = FieldValue.increment(42); + FieldValue increment3 = FieldValue.increment(42.0); + FieldValue increment4 = FieldValue.increment(42.0); + assertEquals(increment1, increment2); + assertEquals(increment3, increment4); + assertNotEquals(increment1, increment3); + assertNotEquals(increment2, increment4); + } } diff --git a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java index 8876fa83cf64..d09735add8d3 100644 --- a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java +++ b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java @@ -272,6 +272,10 @@ public static FieldTransform serverTimestamp() { .build(); } + public static FieldTransform increment(Value value) { + return FieldTransform.newBuilder().setNumericAdd(value).build(); + } + public static FieldTransform arrayUnion(Value... values) { return FieldTransform.newBuilder() .setAppendMissingElements(ArrayValue.newBuilder().addAllValues(Arrays.asList(values))) diff --git a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java index d05adfe11f23..88e2b0da69af 100644 --- a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java +++ b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java @@ -70,6 +70,8 @@ public class ITSystemTest { + private static final double DOUBLE_EPSILON = 0.000001; + private final Map SINGLE_FIELD_MAP = LocalFirestoreHelper.SINGLE_FIELD_MAP; private final Map ALL_SUPPORTED_TYPES_MAP = LocalFirestoreHelper.ALL_SUPPORTED_TYPES_MAP; @@ -968,4 +970,22 @@ public void arrayOperators() throws ExecutionException, InterruptedException { assertTrue(containsQuery.get().get().isEmpty()); } + + @Test + public void integerIncrement() throws ExecutionException, InterruptedException { + DocumentReference docRef = randomColl.document(); + docRef.set(Collections.singletonMap("sum", (Object) 1L)).get(); + docRef.update("sum", FieldValue.increment(2)); + DocumentSnapshot docSnap = docRef.get().get(); + assertEquals(3L, docSnap.get("sum")); + } + + @Test + public void floatIncrement() throws ExecutionException, InterruptedException { + DocumentReference docRef = randomColl.document(); + docRef.set(Collections.singletonMap("sum", (Object) 1.1)).get(); + docRef.update("sum", FieldValue.increment(2.2)); + DocumentSnapshot docSnap = docRef.get().get(); + assertEquals(3.3, (Double) docSnap.get("sum"), DOUBLE_EPSILON); + } } From cda050ac98e649d5d19afb6f216d9c2f811288b9 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Wed, 26 Dec 2018 11:07:37 -0800 Subject: [PATCH 2/2] Use "increment" Proto naming --- .../src/main/java/com/google/cloud/firestore/FieldValue.java | 2 +- .../java/com/google/cloud/firestore/LocalFirestoreHelper.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FieldValue.java b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FieldValue.java index f268cec54469..f1176c850a7e 100644 --- a/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FieldValue.java +++ b/google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FieldValue.java @@ -103,7 +103,7 @@ String getMethodName() { FieldTransform toProto(FieldPath path) { FieldTransform.Builder fieldTransform = FieldTransform.newBuilder(); fieldTransform.setFieldPath(path.getEncodedPath()); - fieldTransform.setNumericAdd( + fieldTransform.setIncrement( UserDataConverter.encodeValue(FieldPath.of(""), operand, UserDataConverter.ARGUMENT)); return fieldTransform.build(); } diff --git a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java index d09735add8d3..d42fda179143 100644 --- a/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java +++ b/google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java @@ -273,7 +273,7 @@ public static FieldTransform serverTimestamp() { } public static FieldTransform increment(Value value) { - return FieldTransform.newBuilder().setNumericAdd(value).build(); + return FieldTransform.newBuilder().setIncrement(value).build(); } public static FieldTransform arrayUnion(Value... values) {