Skip to content
Open
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
28 changes: 24 additions & 4 deletions firebase-firestore/firebase-firestore.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -91,28 +91,40 @@ android {
}
}

testFixtures {
enable = true
}

sourceSets {
main {
proto {
srcDir 'src/proto'
}
}
test {
testFixtures {
java {
srcDir 'src/testUtil/java'
srcDir 'src/roboUtil/java'
}
}
androidTest {
test {
java {
srcDir 'src/testUtil/java'
srcDir 'src/roboUtil/java'
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lint {
lintConfig file("lint.xml")
ignoreTestFixturesSources true
}
packagingOptions {
resources {
excludes += "**/*.proto"
}
}
testOptions.unitTests.includeAndroidResources = true

}
Expand Down Expand Up @@ -156,6 +168,14 @@ dependencies {

androidTestAnnotationProcessor libs.autovalue

testFixturesImplementation libs.androidx.annotation
testFixturesImplementation libs.truth
testFixturesImplementation libs.junit
testFixturesImplementation libs.mockito.core
testFixturesImplementation libs.jackson.databind
testFixturesImplementation libs.grpc.protobuf.lite
testFixturesCompileOnly libs.protobuf.java
testFixturesCompileOnly libs.javax.annotation.jsr250
testImplementation project(':firebase-database-collection')
testImplementation project(':firebase-firestore')
testProtobuf(libs.proto.google.common.protos)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -790,4 +790,48 @@ public void canRunTransactionsOnDocumentsWithBsonTypes() throws Exception {
assertEquals(
getSnapshot.getDocuments().get(1).getRegexValue("key"), new RegexValue("^bar", "i"));
}

@Test
public void numericIncrementWithBsonTypes() throws Exception {
DocumentReference docRef = testCollection().document();

waitFor(docRef.set(map("val", new Decimal128Value("10.5"))));
waitFor(docRef.update("val", FieldValue.increment(5.0)));
DocumentSnapshot actual = waitFor(docRef.get());
assertEquals(new Decimal128Value("15.5"), actual.get("val"));

waitFor(docRef.set(map("val", new Int32Value(10))));
waitFor(docRef.update("val", FieldValue.increment(5L)));
actual = waitFor(docRef.get());
assertEquals(15L, actual.get("val"));
}

@Test
public void numericMinimumAndMaximumWithBsonTypes() throws Exception {
DocumentReference docRef = testCollection().document();

// Minimum: Base wins
waitFor(docRef.set(map("val", new Decimal128Value("10.5"))));
waitFor(docRef.update("val", FieldValue.minimum(20.0)));
DocumentSnapshot actual = waitFor(docRef.get());
assertEquals(new Decimal128Value("10.5"), actual.get("val"));

// Minimum: Operand wins
waitFor(docRef.set(map("val", new Decimal128Value("10.5"))));
waitFor(docRef.update("val", FieldValue.minimum(5.0)));
actual = waitFor(docRef.get());
assertEquals(5.0, actual.get("val"));

// Maximum: Base wins
waitFor(docRef.set(map("val", new Int32Value(10))));
waitFor(docRef.update("val", FieldValue.maximum(5L)));
actual = waitFor(docRef.get());
assertEquals(new Int32Value(10), actual.get("val"));

// Maximum: Operand wins
waitFor(docRef.set(map("val", new Int32Value(10))));
waitFor(docRef.update("val", FieldValue.maximum(20L)));
actual = waitFor(docRef.get());
assertEquals(20L, actual.get("val"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import androidx.annotation.NonNull;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
* Sentinel values that can be used when writing document fields with {@code set()} or {@code
Expand Down Expand Up @@ -100,6 +101,23 @@ String getMethodName() {
Number getOperand() {
return operand;
}

@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);
}
}

/** {@code FieldValue} class for {@link #minimum()} transforms. */
Expand All @@ -118,6 +136,23 @@ String getMethodName() {
Number getOperand() {
return operand;
}

@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);
}
}

/** {@code FieldValue} class for {@link #maximum()} transforms. */
Expand All @@ -136,6 +171,23 @@ String getMethodName() {
Number getOperand() {
return operand;
}

@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);
}
}

private static final DeleteFieldValue DELETE_INSTANCE = new DeleteFieldValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -545,18 +545,11 @@ private Value parseRegexValue(RegexValue regex) {
}

private Value parseInteger32Value(Int32Value int32) {
MapValue.Builder mapBuilder = MapValue.newBuilder();
mapBuilder.putFields(
Values.RESERVED_INT32_KEY, Value.newBuilder().setIntegerValue(int32.value).build());
return Value.newBuilder().setMapValue(mapBuilder).build();
return Values.getInt32(int32.value);
}

private Value parseDecimal128Value(Decimal128Value decimal128) {
MapValue.Builder mapBuilder = MapValue.newBuilder();
mapBuilder.putFields(
Values.RESERVED_DECIMAL128_KEY,
Value.newBuilder().setStringValue(decimal128.stringValue).build());
return Value.newBuilder().setMapValue(mapBuilder).build();
return Values.getDecimal128(decimal128.stringValue);
}

private Value parseTimestamp(Timestamp timestamp) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ private void decodeFieldFilter(List<Filter> result, JSONObject fieldFilter) thro
fieldPath, filterOperator, decodeValue(fieldFilter.getJSONObject("value"))));
}

private Value decodeValue(JSONObject value) throws JSONException {
public Value decodeValue(JSONObject value) throws JSONException {
Value.Builder builder = Value.newBuilder();

if (value.has("nullValue")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ package com.google.firebase.firestore.model
import com.google.cloud.datastore.core.number.NumberComparisonHelper.firestoreCompareDoubleWithLong
import com.google.cloud.datastore.core.number.NumberComparisonHelper.firestoreCompareDoubles
import com.google.firebase.firestore.Blob
import com.google.firebase.firestore.Decimal128Value
import com.google.firebase.firestore.DocumentReference
import com.google.firebase.firestore.GeoPoint
import com.google.firebase.firestore.Int32Value
import com.google.firebase.firestore.Quadruple
import com.google.firebase.firestore.VectorValue
import com.google.firebase.firestore.util.Assert
Expand Down Expand Up @@ -686,10 +688,13 @@ object Values {
return value != null && value.hasDoubleValue()
}

/** Returns true if `value` is either a INTEGER_VALUE or a DOUBLE_VALUE. */
/**
* Returns true if `value` is either a INTEGER_VALUE, DOUBLE_VALUE, or BSON `Int32Value` or BSON
* `Decimal128Value`.
*/
@JvmStatic
fun isNumber(value: Value?): Boolean {
return isInteger(value) || isDouble(value)
return isInteger(value) || isDouble(value) || isInt32Value(value) || isDecimal128Value(value)
}

/** Returns true if `value` is an ARRAY_VALUE. */
Expand Down Expand Up @@ -905,6 +910,62 @@ object Values {

@JvmStatic fun encodeValue(vector: VectorValue): Value = encodeVectorValue(vector.toArray())

@JvmStatic fun encodeValue(value: Int32Value): Value = getInt32(value.value)

@JvmStatic fun encodeValue(value: Decimal128Value): Value = getDecimal128(value.stringValue)

@JvmStatic
fun getInt32(value: Int): Value =
Value.newBuilder()
.setMapValue(
MapValue.newBuilder()
.putFields(RESERVED_INT32_KEY, Value.newBuilder().setIntegerValue(value.toLong()).build())
)
.build()

@JvmStatic
fun getDecimal128(value: String): Value =
Value.newBuilder()
.setMapValue(
MapValue.newBuilder()
.putFields(RESERVED_DECIMAL128_KEY, Value.newBuilder().setStringValue(value).build())
)
.build()

@JvmStatic
fun getDouble(value: Value): Double {
if (isDouble(value)) {
return value.doubleValue
}
if (isInteger(value)) {
return value.integerValue.toDouble()
}
if (isInt32Value(value)) {
return value.mapValue.fieldsMap[RESERVED_INT32_KEY]!!.integerValue.toDouble()
}
if (isDecimal128Value(value)) {
return value.mapValue.fieldsMap[RESERVED_DECIMAL128_KEY]!!.stringValue.toDouble()
}
throw IllegalArgumentException("getDouble was called with a non-numeric argument: $value")
}

@JvmStatic
fun getLong(value: Value): Long {
if (isInteger(value)) {
return value.integerValue
}
if (isInt32Value(value)) {
return value.mapValue.fieldsMap[RESERVED_INT32_KEY]!!.integerValue
}
if (isDouble(value)) {
return value.doubleValue.toLong()
}
if (isDecimal128Value(value)) {
return value.mapValue.fieldsMap[RESERVED_DECIMAL128_KEY]!!.stringValue.toDouble().toLong()
}
throw IllegalArgumentException("getLong was called with a non-numeric argument: $value")
}

@JvmStatic
fun encodeVectorValue(vector: DoubleArray): Value {
val listBuilder = ArrayValue.newBuilder()
Expand Down Expand Up @@ -940,6 +1001,8 @@ object Values {
is GeoPoint -> encodeValue(value)
is Blob -> encodeValue(value)
is VectorValue -> encodeValue(value)
is Int32Value -> encodeValue(value)
is Decimal128Value -> encodeValue(value)
else -> throw IllegalArgumentException("Unexpected type: $value")
}

Expand Down
Loading
Loading