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

feat: adds maximum and minimum FieldValue transforms #1153

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
@@ -126,6 +126,104 @@ public int hashCode() {
}
}

static class NumericMaximumFieldValue extends FieldValue {
final Number operand;

NumericMaximumFieldValue(Number operand) {
this.operand = operand;
}

@Override
boolean includeInDocumentMask() {
return false;
}

@Override
boolean includeInDocumentTransform() {
return true;
}

@Override
String getMethodName() {
return "FieldValue.maximum()";
}

@Override
FieldTransform toProto(FieldPath path) {
FieldTransform.Builder fieldTransform = FieldTransform.newBuilder();
fieldTransform.setFieldPath(path.getEncodedPath());
fieldTransform.setMaximum(
UserDataConverter.encodeValue(path, 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;
}
NumericMaximumFieldValue that = (NumericMaximumFieldValue) o;
return Objects.equals(operand, that.operand);
}

@Override
public int hashCode() {
return Objects.hash(operand);
}
}

static class NumericMinimumFieldValue extends FieldValue {
final Number operand;

NumericMinimumFieldValue(Number operand) {
this.operand = operand;
}

@Override
boolean includeInDocumentMask() {
return false;
}

@Override
boolean includeInDocumentTransform() {
return true;
}

@Override
String getMethodName() {
return "FieldValue.minimum()";
}

@Override
FieldTransform toProto(FieldPath path) {
FieldTransform.Builder fieldTransform = FieldTransform.newBuilder();
fieldTransform.setFieldPath(path.getEncodedPath());
fieldTransform.setMinimum(
UserDataConverter.encodeValue(path, 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;
}
NumericMinimumFieldValue that = (NumericMinimumFieldValue) o;
return Objects.equals(operand, that.operand);
}

@Override
public int hashCode() {
return Objects.hash(operand);
}
}

static class ArrayUnionFieldValue extends FieldValue {
final List<Object> elements;

@@ -288,6 +386,58 @@ 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 take the maximum of the field's current value and the given value.
*
* <p>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 maximum(long l) { return new NumericMaximumFieldValue(l); }

/**
* Returns a special value that can be used with set(), create() or update() that tells the server
* to take the maximum of the field's current value and the given value.
*
* <p>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 maximum(double d) {
return new NumericMaximumFieldValue(d);
}

/**
* Returns a special value that can be used with set(), create() or update() that tells the server
* to take the minimum of the field's current value and the given value.
*
* <p>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 minimum(long l) { return new NumericMinimumFieldValue(l); }

/**
* Returns a special value that can be used with set(), create() or update() that tells the server
* to take the minimum of the field's current value and the given value.
*
* <p>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 minimum(double d) {
return new NumericMinimumFieldValue(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
Original file line number Diff line number Diff line change
@@ -48,6 +48,8 @@
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.maximum;
import static com.google.cloud.firestore.LocalFirestoreHelper.minimum;
import static com.google.cloud.firestore.LocalFirestoreHelper.object;
import static com.google.cloud.firestore.LocalFirestoreHelper.serverTimestamp;
import static com.google.cloud.firestore.LocalFirestoreHelper.set;
@@ -517,6 +519,54 @@ public void setWithIncrement() throws Exception {
assertCommitEquals(set, commitRequest);
}

@Test
public void setWithMaximum() throws Exception {
doReturn(FIELD_TRANSFORM_COMMIT_RESPONSE)
.when(firestoreMock)
.sendRequest(
commitCapture.capture(), Matchers.<UnaryCallable<CommitRequest, CommitResponse>>any());

documentReference
.set(map("integer", FieldValue.maximum(1), "double", FieldValue.maximum(1.1)))
.get();

CommitRequest set =
commit(
set(Collections.emptyMap()),
transform(
"integer",
maximum(Value.newBuilder().setIntegerValue(1).build()),
"double",
maximum(Value.newBuilder().setDoubleValue(1.1).build())));

CommitRequest commitRequest = commitCapture.getValue();
assertCommitEquals(set, commitRequest);
}

@Test
public void setWithMinimum() throws Exception {
doReturn(FIELD_TRANSFORM_COMMIT_RESPONSE)
.when(firestoreMock)
.sendRequest(
commitCapture.capture(), Matchers.<UnaryCallable<CommitRequest, CommitResponse>>any());

documentReference
.set(map("integer", FieldValue.minimum(1), "double", FieldValue.minimum(1.1)))
.get();

CommitRequest set =
commit(
set(Collections.emptyMap()),
transform(
"integer",
minimum(Value.newBuilder().setIntegerValue(1).build()),
"double",
minimum(Value.newBuilder().setDoubleValue(1.1).build())));

CommitRequest commitRequest = commitCapture.getValue();
assertCommitEquals(set, commitRequest);
}

@Test
public void setWithArrayUnion() throws Exception {
doReturn(FIELD_TRANSFORM_COMMIT_RESPONSE)
Original file line number Diff line number Diff line change
@@ -185,6 +185,30 @@ public void incrementEquals() {
assertNotEquals(increment2, increment4);
}

@Test
public void maximumEquals() {
FieldValue maximum1 = FieldValue.maximum(42);
FieldValue maximum2 = FieldValue.maximum(42);
FieldValue maximum3 = FieldValue.maximum(42.0);
FieldValue maximum4 = FieldValue.maximum(42.0);
assertEquals(maximum1, maximum2);
assertEquals(maximum3, maximum4);
assertNotEquals(maximum1, maximum3);
assertNotEquals(maximum2, maximum4);
}

@Test
public void minimumEquals() {
FieldValue minimum1 = FieldValue.minimum(42);
FieldValue minimum2 = FieldValue.minimum(42);
FieldValue minimum3 = FieldValue.minimum(42.0);
FieldValue minimum4 = FieldValue.minimum(42.0);
assertEquals(minimum1, minimum2);
assertEquals(minimum3, minimum4);
assertNotEquals(minimum1, minimum3);
assertNotEquals(minimum2, minimum4);
}

@Test
public void arrayUnionWithPojo() throws ExecutionException, InterruptedException {
doReturn(commitResponse(1, 0))
Original file line number Diff line number Diff line change
@@ -486,6 +486,14 @@ public static FieldTransform increment(Value value) {
return FieldTransform.newBuilder().setIncrement(value).build();
}

public static FieldTransform minimum(Value value) {
return FieldTransform.newBuilder().setMinimum(value).build();
}

public static FieldTransform maximum(Value value) {
return FieldTransform.newBuilder().setMaximum(value).build();
}

public static FieldTransform arrayUnion(Value... values) {
return FieldTransform.newBuilder()
.setAppendMissingElements(ArrayValue.newBuilder().addAllValues(Arrays.asList(values)))
Original file line number Diff line number Diff line change
@@ -279,6 +279,24 @@ public void setWithIncrementAndMerge() throws ExecutionException, InterruptedExc
assertEquals(3L, docSnap.get("sum"));
}

@Test
public void setWithMaximumAndMerge() throws ExecutionException, InterruptedException {
DocumentReference docRef = randomColl.document();
docRef.set(Collections.singletonMap("max", 1L)).get();
docRef.set(Collections.singletonMap("max", FieldValue.maximum(2)), SetOptions.merge()).get();
DocumentSnapshot docSnap = docRef.get().get();
assertEquals(2L, docSnap.get("max"));
}

@Test
public void setWithMinimumAndMerge() throws ExecutionException, InterruptedException {
DocumentReference docRef = randomColl.document();
docRef.set(Collections.singletonMap("min", 1L)).get();
docRef.set(Collections.singletonMap("min", FieldValue.minimum(2)), SetOptions.merge()).get();
DocumentSnapshot docSnap = docRef.get().get();
assertEquals(1L, docSnap.get("min"));
}

@Test
public void mergeDocumentWithServerTimestamp() throws Exception {
Map<String, Object> originalMap = LocalFirestoreHelper.map("a", "b");
@@ -1392,6 +1410,42 @@ public void floatIncrement() throws ExecutionException, InterruptedException {
assertEquals(3.3, (Double) docSnap.get("sum"), DOUBLE_EPSILON);
}

@Test
public void integerMaximum() throws ExecutionException, InterruptedException {
DocumentReference docRef = randomColl.document();
docRef.set(Collections.singletonMap("max", 1L)).get();
docRef.update("max", FieldValue.maximum(2)).get();
DocumentSnapshot docSnap = docRef.get().get();
assertEquals(2L, docSnap.get("max"));
}

@Test
public void floatMaximum() throws ExecutionException, InterruptedException {
DocumentReference docRef = randomColl.document();
docRef.set(Collections.singletonMap("max", 1.1)).get();
docRef.update("max", FieldValue.maximum(2.2)).get();
DocumentSnapshot docSnap = docRef.get().get();
assertEquals(2.2, (Double) docSnap.get("max"), DOUBLE_EPSILON);
}

@Test
public void integerMinimum() throws ExecutionException, InterruptedException {
DocumentReference docRef = randomColl.document();
docRef.set(Collections.singletonMap("min", 1L)).get();
docRef.update("min", FieldValue.minimum(2)).get();
DocumentSnapshot docSnap = docRef.get().get();
assertEquals(1L, docSnap.get("min"));
}

@Test
public void floatMinimum() throws ExecutionException, InterruptedException {
DocumentReference docRef = randomColl.document();
docRef.set(Collections.singletonMap("min", 1.1)).get();
docRef.update("min", FieldValue.minimum(2.2)).get();
DocumentSnapshot docSnap = docRef.get().get();
assertEquals(1.1, (Double) docSnap.get("min"), DOUBLE_EPSILON);
}

@Test
public void getAllWithObserver() throws Exception {
DocumentReference ref1 = randomColl.document("doc1");