Skip to content

Commit e4c11c0

Browse files
schmidt-sebastiansduskis
authored andcommitted
Adding FieldValue.increment() (#4018)
* DO NOT MERGE: Adding FieldValue.increment() * Use "increment" Proto naming
1 parent abf4f93 commit e4c11c0

6 files changed

Lines changed: 153 additions & 10 deletions

File tree

google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FieldValue.java

Lines changed: 91 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,55 @@ FieldTransform toProto(FieldPath path) {
7777
}
7878
};
7979

80+
static class NumericIncrementFieldValue extends FieldValue {
81+
final Number operand;
82+
83+
NumericIncrementFieldValue(Number operand) {
84+
this.operand = operand;
85+
}
86+
87+
@Override
88+
boolean includeInDocumentMask() {
89+
return false;
90+
}
91+
92+
@Override
93+
boolean includeInDocumentTransform() {
94+
return true;
95+
}
96+
97+
@Override
98+
String getMethodName() {
99+
return "FieldValue.increment()";
100+
}
101+
102+
@Override
103+
FieldTransform toProto(FieldPath path) {
104+
FieldTransform.Builder fieldTransform = FieldTransform.newBuilder();
105+
fieldTransform.setFieldPath(path.getEncodedPath());
106+
fieldTransform.setIncrement(
107+
UserDataConverter.encodeValue(path, operand, UserDataConverter.ARGUMENT));
108+
return fieldTransform.build();
109+
}
110+
111+
@Override
112+
public boolean equals(Object o) {
113+
if (this == o) {
114+
return true;
115+
}
116+
if (o == null || getClass() != o.getClass()) {
117+
return false;
118+
}
119+
NumericIncrementFieldValue that = (NumericIncrementFieldValue) o;
120+
return Objects.equals(operand, that.operand);
121+
}
122+
123+
@Override
124+
public int hashCode() {
125+
return Objects.hash(operand);
126+
}
127+
}
128+
80129
static class ArrayUnionFieldValue extends FieldValue {
81130
final List<Object> elements;
82131

@@ -205,11 +254,44 @@ public static FieldValue delete() {
205254
}
206255

207256
/**
208-
* Returns a special value that can be used with set() or update() that tells the server to union
209-
* the given elements with any array value that already exists on the server. Each specified
210-
* element that doesn't already exist in the array will be added to the end. If the field being
211-
* modified is not already an array it will be overwritten with an array containing exactly the
212-
* specified elements.
257+
* Returns a special value that can be used with set(), create() or update() that tells the server
258+
* to increment the field's current value by the given value.
259+
*
260+
* <p>If the current field value is an integer, possible integer overflows are resolved to
261+
* Long.MAX_VALUE or Long.MIN_VALUE. If the current field value is a double, both values will be
262+
* interpreted as doubles and the arithmetic will follow IEEE 754 semantics.
263+
*
264+
* <p>If the current field is not an integer or double, or if the field does not yet exist, the
265+
* transformation will set the field to the given value.
266+
*
267+
* @return The FieldValue sentinel for use in a call to set(), create() or update().
268+
*/
269+
@Nonnull
270+
public static FieldValue increment(long l) {
271+
return new NumericIncrementFieldValue(l);
272+
}
273+
274+
/**
275+
* Returns a special value that can be used with set(), create() or update() that tells the server
276+
* to increment the field's current value by the given value.
277+
*
278+
* <p>If the current value is an integer or a double, both the current and the given value will be
279+
* interpreted as doubles and all arithmetic will follow IEEE 754 semantics. Otherwise, the
280+
* transformation will set the field to the given value.
281+
*
282+
* @return The FieldValue sentinel for use in a call to set(), create() or update().
283+
*/
284+
@Nonnull
285+
public static FieldValue increment(double d) {
286+
return new NumericIncrementFieldValue(d);
287+
}
288+
289+
/**
290+
* Returns a special value that can be used with set(), create() or update() that tells the server
291+
* to union the given elements with any array value that already exists on the server. Each
292+
* specified element that doesn't already exist in the array will be added to the end. If the
293+
* field being modified is not already an array it will be overwritten with an array containing
294+
* exactly the specified elements.
213295
*
214296
* @param elements The elements to union into the array.
215297
* @return The FieldValue sentinel for use in a call to set() or update().
@@ -221,10 +303,10 @@ public static FieldValue arrayUnion(@Nonnull Object... elements) {
221303
}
222304

223305
/**
224-
* Returns a special value that can be used with set() or update() that tells the server to remove
225-
* the given elements from any array value that already exists on the server. All instances of
226-
* each element specified will be removed from the array. If the field being modified is not
227-
* already an array it will be overwritten with an empty array.
306+
* Returns a special value that can be used with set(), create() or update() that tells the server
307+
* to remove the given elements from any array value that already exists on the server. All
308+
* instances of each element specified will be removed from the array. If the field being modified
309+
* is not already an array it will be overwritten with an empty array.
228310
*
229311
* @param elements The elements to remove from the array.
230312
* @return The FieldValue sentinel for use in a call to set() or update().

google-cloud-clients/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UserDataConverter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ private UserDataConverter() {}
9090
* @param path path THe field path of the object to encode.
9191
* @param sanitizedObject An Object that has been sanitized by CustomClassMapper and only contains
9292
* valid types.
93-
* @param options Encoding opions to use for this value.
93+
* @param options Encoding options to use for this value.
9494
* @return The Value proto.
9595
*/
9696
@Nullable

google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/DocumentReferenceTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import static com.google.cloud.firestore.LocalFirestoreHelper.delete;
4545
import static com.google.cloud.firestore.LocalFirestoreHelper.get;
4646
import static com.google.cloud.firestore.LocalFirestoreHelper.getAllResponse;
47+
import static com.google.cloud.firestore.LocalFirestoreHelper.increment;
4748
import static com.google.cloud.firestore.LocalFirestoreHelper.map;
4849
import static com.google.cloud.firestore.LocalFirestoreHelper.object;
4950
import static com.google.cloud.firestore.LocalFirestoreHelper.serverTimestamp;
@@ -408,6 +409,30 @@ public void mergeWithServerTimestamps() throws Exception {
408409
assertCommitEquals(set, commitRequests.get(1));
409410
}
410411

412+
@Test
413+
public void setWithIncrement() throws Exception {
414+
doReturn(FIELD_TRANSFORM_COMMIT_RESPONSE)
415+
.when(firestoreMock)
416+
.sendRequest(
417+
commitCapture.capture(), Matchers.<UnaryCallable<CommitRequest, CommitResponse>>any());
418+
419+
documentReference
420+
.set(map("integer", FieldValue.increment(1), "double", FieldValue.increment(1.1)))
421+
.get();
422+
423+
CommitRequest set =
424+
commit(
425+
set(Collections.<String, Value>emptyMap()),
426+
transform(
427+
"integer",
428+
increment(Value.newBuilder().setIntegerValue(1).build()),
429+
"double",
430+
increment(Value.newBuilder().setDoubleValue(1.1).build())));
431+
432+
CommitRequest commitRequest = commitCapture.getValue();
433+
assertCommitEquals(set, commitRequest);
434+
}
435+
411436
@Test
412437
public void setWithArrayUnion() throws Exception {
413438
doReturn(FIELD_TRANSFORM_COMMIT_RESPONSE)

google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/FirestoreTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,16 @@ public void arrayRemoveEquals() {
157157
assertNotEquals(arrayRemove1, arrayRemove3);
158158
assertNotEquals(arrayRemove1, arrayUnion);
159159
}
160+
161+
@Test
162+
public void incrementEquals() {
163+
FieldValue increment1 = FieldValue.increment(42);
164+
FieldValue increment2 = FieldValue.increment(42);
165+
FieldValue increment3 = FieldValue.increment(42.0);
166+
FieldValue increment4 = FieldValue.increment(42.0);
167+
assertEquals(increment1, increment2);
168+
assertEquals(increment3, increment4);
169+
assertNotEquals(increment1, increment3);
170+
assertNotEquals(increment2, increment4);
171+
}
160172
}

google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,10 @@ public static FieldTransform serverTimestamp() {
272272
.build();
273273
}
274274

275+
public static FieldTransform increment(Value value) {
276+
return FieldTransform.newBuilder().setIncrement(value).build();
277+
}
278+
275279
public static FieldTransform arrayUnion(Value... values) {
276280
return FieldTransform.newBuilder()
277281
.setAppendMissingElements(ArrayValue.newBuilder().addAllValues(Arrays.asList(values)))

google-cloud-clients/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171

7272
public class ITSystemTest {
7373

74+
private static final double DOUBLE_EPSILON = 0.000001;
75+
7476
private final Map<String, Object> SINGLE_FIELD_MAP = LocalFirestoreHelper.SINGLE_FIELD_MAP;
7577
private final Map<String, Object> ALL_SUPPORTED_TYPES_MAP =
7678
LocalFirestoreHelper.ALL_SUPPORTED_TYPES_MAP;
@@ -977,4 +979,22 @@ public void arrayOperators() throws ExecutionException, InterruptedException {
977979

978980
assertTrue(containsQuery.get().get().isEmpty());
979981
}
982+
983+
@Test
984+
public void integerIncrement() throws ExecutionException, InterruptedException {
985+
DocumentReference docRef = randomColl.document();
986+
docRef.set(Collections.singletonMap("sum", (Object) 1L)).get();
987+
docRef.update("sum", FieldValue.increment(2)).get();
988+
DocumentSnapshot docSnap = docRef.get().get();
989+
assertEquals(3L, docSnap.get("sum"));
990+
}
991+
992+
@Test
993+
public void floatIncrement() throws ExecutionException, InterruptedException {
994+
DocumentReference docRef = randomColl.document();
995+
docRef.set(Collections.singletonMap("sum", (Object) 1.1)).get();
996+
docRef.update("sum", FieldValue.increment(2.2)).get();
997+
DocumentSnapshot docSnap = docRef.get().get();
998+
assertEquals(3.3, (Double) docSnap.get("sum"), DOUBLE_EPSILON);
999+
}
9801000
}

0 commit comments

Comments
 (0)