Skip to content
This repository was archived by the owner on May 8, 2026. It is now read-only.
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,104 @@ public int hashCode() {
}
}

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 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 ArrayUnionFieldValue extends FieldValue {
final List<Object> elements;

Expand Down Expand Up @@ -289,6 +387,62 @@ 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 set the field to the numeric minimum of the field's current and the given value.
*
* <p>If the current field value is not of type 'number', 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 set the field to the numeric minimum of the field's current and the given value.
*
* <p>If the current field value is not of type 'number', 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 set the field to the numeric maximum of the field's current and the given value.
*
* <p>If the current field value is not of type 'number', 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 set the field to the numeric maximum of the field's current and the given value.
*
* <p>If the current field value is not of type 'number', 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 union the given elements with any array value that already exists on the server. Each
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -530,6 +532,56 @@ public void setWithIncrement() throws Exception {
assertCommitEquals(set, commitRequest);
}

@Test
public void setWithMinimum() throws Exception {
doReturn(FIELD_TRANSFORM_COMMIT_RESPONSE)
.when(firestoreMock)
.sendRequest(
commitCapture.capture(),
ArgumentMatchers.<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 setWithMaximum() throws Exception {
doReturn(FIELD_TRANSFORM_COMMIT_RESPONSE)
.when(firestoreMock)
.sendRequest(
commitCapture.capture(),
ArgumentMatchers.<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 setWithArrayUnion() throws Exception {
doReturn(FIELD_TRANSFORM_COMMIT_RESPONSE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,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)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1970,6 +1970,60 @@ public void floatIncrement() throws ExecutionException, InterruptedException {
assertEquals(3.3, (Double) docSnap.get("sum"), DOUBLE_EPSILON);
}

@Test
public void integerMinimum() throws ExecutionException, InterruptedException {
DocumentReference docRef = randomColl.document();
docRef.set(Collections.singletonMap("min", 2L)).get();
docRef.update("min", FieldValue.minimum(1)).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", 2.2)).get();
docRef.update("min", FieldValue.minimum(1.1)).get();
DocumentSnapshot docSnap = docRef.get().get();
assertEquals(1.1, (Double) docSnap.get("min"), DOUBLE_EPSILON);
}

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

@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 maximumAgainstNonNumeric() throws ExecutionException, InterruptedException {
DocumentReference docRef = randomColl.document();
docRef.set(Collections.singletonMap("max", "any string")).get();
docRef.update("max", FieldValue.maximum(2)).get();
DocumentSnapshot docSnap = docRef.get().get();
assertEquals(2L, docSnap.get("max"));
}

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