Skip to content

Commit 91b40a5

Browse files
Migrate transforms to use Values (#1205)
1 parent f988c70 commit 91b40a5

File tree

23 files changed

+166
-164
lines changed

23 files changed

+166
-164
lines changed

firebase-firestore/ktx/src/test/kotlin/com/google/firebase/firestore/ktx/FirestoreTests.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ import com.google.firebase.firestore.FieldPath
2222
import com.google.firebase.firestore.FirebaseFirestore
2323
import com.google.firebase.firestore.FirebaseFirestoreSettings
2424
import com.google.firebase.firestore.TestUtil
25-
import com.google.firebase.firestore.model.value.IntegerValue
2625
import com.google.firebase.firestore.model.value.ObjectValue
26+
import com.google.firebase.firestore.testutil.TestUtil.wrap
2727
import com.google.firebase.ktx.Firebase
2828
import com.google.firebase.ktx.app
2929
import com.google.firebase.ktx.initialize
@@ -171,7 +171,7 @@ class QuerySnapshotTests {
171171
val qs = TestUtil.querySnapshot(
172172
"rooms",
173173
mapOf(),
174-
mapOf("id" to ObjectValue.fromMap(mapOf("a" to IntegerValue.valueOf(1).proto, "b" to IntegerValue.valueOf(2).proto))),
174+
mapOf("id" to ObjectValue.fromMap(mapOf("a" to wrap(1).proto, "b" to wrap(2).proto))),
175175
false,
176176
false)
177177

firebase-firestore/src/main/java/com/google/firebase/firestore/Query.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import com.google.firebase.firestore.model.value.ServerTimestampValue;
4646
import com.google.firebase.firestore.util.Executors;
4747
import com.google.firebase.firestore.util.Util;
48+
import com.google.firestore.v1.Value;
4849
import java.util.ArrayList;
4950
import java.util.Arrays;
5051
import java.util.List;
@@ -336,9 +337,9 @@ private Query whereHelper(@NonNull FieldPath fieldPath, Operator op, Object valu
336337
+ "' queries on FieldPath.documentId().");
337338
} else if (op == Operator.IN) {
338339
validateDisjunctiveFilterElements(value, op);
339-
List<FieldValue> referenceList = new ArrayList<>();
340+
List<Value> referenceList = new ArrayList<>();
340341
for (Object arrayValue : (List) value) {
341-
referenceList.add(parseDocumentIdValue(arrayValue));
342+
referenceList.add(parseDocumentIdValue(arrayValue).getProto());
342343
}
343344
fieldValue = ArrayValue.fromList(referenceList);
344345
} else {

firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,13 +357,13 @@ private void parseSentinelFieldValue(
357357
context.addToFieldTransforms(context.getPath(), ServerTimestampOperation.getInstance());
358358

359359
} else if (value instanceof ArrayUnionFieldValue) {
360-
List<FieldValue> parsedElements =
360+
List<Value> parsedElements =
361361
parseArrayTransformElements(((ArrayUnionFieldValue) value).getElements());
362362
ArrayTransformOperation arrayUnion = new ArrayTransformOperation.Union(parsedElements);
363363
context.addToFieldTransforms(context.getPath(), arrayUnion);
364364

365365
} else if (value instanceof ArrayRemoveFieldValue) {
366-
List<FieldValue> parsedElements =
366+
List<Value> parsedElements =
367367
parseArrayTransformElements(((ArrayRemoveFieldValue) value).getElements());
368368
ArrayTransformOperation arrayRemove = new ArrayTransformOperation.Remove(parsedElements);
369369
context.addToFieldTransforms(context.getPath(), arrayRemove);
@@ -464,17 +464,17 @@ private Value parseTimestamp(Timestamp timestamp) {
464464
.build();
465465
}
466466

467-
private List<FieldValue> parseArrayTransformElements(List<Object> elements) {
467+
private List<Value> parseArrayTransformElements(List<Object> elements) {
468468
ParseAccumulator accumulator = new ParseAccumulator(UserData.Source.Argument);
469469

470-
ArrayList<FieldValue> result = new ArrayList<>(elements.size());
470+
List<Value> result = new ArrayList<>(elements.size());
471471
for (int i = 0; i < elements.size(); i++) {
472472
Object element = elements.get(i);
473473
// Although array transforms are used with writes, the actual elements
474474
// being unioned or removed are not considered writes since they cannot
475475
// contain any FieldValue sentinels, etc.
476476
ParseContext context = accumulator.rootContext();
477-
result.add(FieldValue.valueOf(convertAndParseFieldData(element, context.childContext(i))));
477+
result.add(convertAndParseFieldData(element, context.childContext(i)));
478478
}
479479
return result;
480480
}

firebase-firestore/src/main/java/com/google/firebase/firestore/model/Document.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import androidx.annotation.Nullable;
1919
import com.google.firebase.firestore.model.value.FieldValue;
2020
import com.google.firebase.firestore.model.value.ObjectValue;
21+
import com.google.firestore.v1.Value;
2122
import java.util.Comparator;
2223

2324
/**
@@ -66,6 +67,11 @@ public ObjectValue getData() {
6667
return objectValue.get(path);
6768
}
6869

70+
public @Nullable Value getFieldProto(FieldPath path) {
71+
FieldValue fieldValue = getField(path);
72+
return fieldValue != null ? fieldValue.getProto() : null;
73+
}
74+
6975
public boolean hasLocalMutations() {
7076
return documentState.equals(DocumentState.LOCAL_MUTATIONS);
7177
}

firebase-firestore/src/main/java/com/google/firebase/firestore/model/mutation/ArrayTransformOperation.java

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616

1717
import androidx.annotation.Nullable;
1818
import com.google.firebase.Timestamp;
19-
import com.google.firebase.firestore.model.value.ArrayValue;
20-
import com.google.firebase.firestore.model.value.FieldValue;
21-
import java.util.ArrayList;
19+
import com.google.firebase.firestore.model.value.ProtoValues;
20+
import com.google.firestore.v1.ArrayValue;
21+
import com.google.firestore.v1.Value;
2222
import java.util.Collections;
2323
import java.util.List;
2424

@@ -28,32 +28,31 @@
2828
* <p>Implementations are: ArrayTransformOperation.Union and ArrayTransformOperation.Remove
2929
*/
3030
public abstract class ArrayTransformOperation implements TransformOperation {
31-
private final List<FieldValue> elements;
31+
private final List<Value> elements;
3232

33-
ArrayTransformOperation(List<FieldValue> elements) {
33+
ArrayTransformOperation(List<Value> elements) {
3434
this.elements = Collections.unmodifiableList(elements);
3535
}
3636

37-
public List<FieldValue> getElements() {
37+
public List<Value> getElements() {
3838
return elements;
3939
}
4040

4141
@Override
42-
public FieldValue applyToLocalView(@Nullable FieldValue previousValue, Timestamp localWriteTime) {
42+
public Value applyToLocalView(@Nullable Value previousValue, Timestamp localWriteTime) {
4343
return apply(previousValue);
4444
}
4545

4646
@Override
47-
public FieldValue applyToRemoteDocument(
48-
@Nullable FieldValue previousValue, FieldValue transformResult) {
47+
public Value applyToRemoteDocument(@Nullable Value previousValue, Value transformResult) {
4948
// The server just sends null as the transform result for array operations, so we have to
5049
// calculate a result the same as we do for local applications.
5150
return apply(previousValue);
5251
}
5352

5453
@Override
5554
@Nullable
56-
public FieldValue computeBaseValue(@Nullable FieldValue currentValue) {
55+
public Value computeBaseValue(@Nullable Value currentValue) {
5756
return null; // Array transforms are idempotent and don't require a base value.
5857
}
5958

@@ -80,53 +79,58 @@ public int hashCode() {
8079
}
8180

8281
/** Applies this ArrayTransformOperation against the specified previousValue. */
83-
protected abstract ArrayValue apply(@Nullable FieldValue previousValue);
82+
protected abstract Value apply(@Nullable Value previousValue);
8483

8584
/**
86-
* Inspects the provided value, returning an ArrayList copy of the internal array if it's an
87-
* ArrayValue and an empty ArrayList if it's null or any other type of FSTFieldValue.
85+
* Inspects the provided value, returning an ArrayValue.Builder containing the existing array
86+
* elements or an empty builder if `value` is not an array.
8887
*/
89-
static List<FieldValue> coercedFieldValuesArray(@Nullable FieldValue value) {
90-
if (value instanceof ArrayValue) {
91-
return ((ArrayValue) value).getValues();
88+
static ArrayValue.Builder coercedFieldValuesArray(@Nullable Value value) {
89+
if (ProtoValues.isArray(value)) {
90+
return value.getArrayValue().toBuilder();
9291
} else {
9392
// coerce to empty array.
94-
return new ArrayList<>();
93+
return ArrayValue.newBuilder();
9594
}
9695
}
9796

9897
/** An array union transform operation. */
9998
public static class Union extends ArrayTransformOperation {
100-
// TODO(mrschmidt): Migrate to list of Value protos
101-
public Union(List<FieldValue> elements) {
99+
public Union(List<Value> elements) {
102100
super(elements);
103101
}
104102

105103
@Override
106-
protected ArrayValue apply(@Nullable FieldValue previousValue) {
107-
List<FieldValue> result = coercedFieldValuesArray(previousValue);
108-
for (FieldValue element : getElements()) {
109-
if (!result.contains(element)) {
110-
result.add(element);
104+
protected Value apply(@Nullable Value previousValue) {
105+
ArrayValue.Builder result = coercedFieldValuesArray(previousValue);
106+
for (Value unionElement : getElements()) {
107+
if (!ProtoValues.contains(result.getValuesList(), unionElement)) {
108+
result.addValues(unionElement);
111109
}
112110
}
113-
return ArrayValue.fromList(result);
111+
return Value.newBuilder().setArrayValue(result).build();
114112
}
115113
}
116114

117115
/** An array remove transform operation. */
118116
public static class Remove extends ArrayTransformOperation {
119-
public Remove(List<FieldValue> elements) {
117+
public Remove(List<Value> elements) {
120118
super(elements);
121119
}
122120

123121
@Override
124-
protected ArrayValue apply(@Nullable FieldValue previousValue) {
125-
List<FieldValue> result = coercedFieldValuesArray(previousValue);
126-
for (FieldValue element : getElements()) {
127-
result.removeAll(Collections.singleton(element));
122+
protected Value apply(@Nullable Value previousValue) {
123+
ArrayValue.Builder result = coercedFieldValuesArray(previousValue);
124+
for (Value removeElement : getElements()) {
125+
for (int i = 0; i < result.getValuesCount(); ) {
126+
if (ProtoValues.equals(result.getValues(i), removeElement)) {
127+
result.removeValues(i);
128+
} else {
129+
++i;
130+
}
131+
}
128132
}
129-
return ArrayValue.fromList(result);
133+
return Value.newBuilder().setArrayValue(result).build();
130134
}
131135
}
132136
}

firebase-firestore/src/main/java/com/google/firebase/firestore/model/mutation/MutationResult.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import androidx.annotation.Nullable;
2020
import com.google.firebase.firestore.model.SnapshotVersion;
21-
import com.google.firebase.firestore.model.value.FieldValue;
21+
import com.google.firestore.v1.Value;
2222
import java.util.List;
2323

2424
/**
@@ -31,9 +31,9 @@
3131
*/
3232
public final class MutationResult {
3333
private final SnapshotVersion version;
34-
@Nullable private final List<FieldValue> transformResults;
34+
@Nullable private final List<Value> transformResults;
3535

36-
public MutationResult(SnapshotVersion version, @Nullable List<FieldValue> transformResults) {
36+
public MutationResult(SnapshotVersion version, @Nullable List<Value> transformResults) {
3737
this.version = checkNotNull(version);
3838
this.transformResults = transformResults;
3939
}
@@ -56,12 +56,12 @@ public SnapshotVersion getVersion() {
5656

5757
/**
5858
* The resulting fields returned from the backend after a TransformMutation has been committed.
59-
* Contains one FieldValue for each FieldTransform that was in the mutation.
59+
* Contains one Value for each FieldTransform that was in the mutation.
6060
*
6161
* <p>Will be null if the mutation was not a TransformMutation.
6262
*/
6363
@Nullable
64-
public List<FieldValue> getTransformResults() {
64+
public List<Value> getTransformResults() {
6565
return transformResults;
6666
}
6767
}

firebase-firestore/src/main/java/com/google/firebase/firestore/model/mutation/NumericIncrementTransformOperation.java

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
package com.google.firebase.firestore.model.mutation;
1616

17+
import static com.google.firebase.firestore.model.value.ProtoValues.isDouble;
18+
import static com.google.firebase.firestore.model.value.ProtoValues.isInteger;
1719
import static com.google.firebase.firestore.util.Assert.fail;
1820
import static com.google.firebase.firestore.util.Assert.hardAssert;
1921

@@ -23,6 +25,8 @@
2325
import com.google.firebase.firestore.model.value.FieldValue;
2426
import com.google.firebase.firestore.model.value.IntegerValue;
2527
import com.google.firebase.firestore.model.value.NumberValue;
28+
import com.google.firebase.firestore.model.value.ProtoValues;
29+
import com.google.firestore.v1.Value;
2630

2731
/**
2832
* Implements the backend semantics for locally computed NUMERIC_ADD (increment) transforms.
@@ -37,29 +41,28 @@ public NumericIncrementTransformOperation(NumberValue operand) {
3741
}
3842

3943
@Override
40-
public FieldValue applyToLocalView(@Nullable FieldValue previousValue, Timestamp localWriteTime) {
41-
NumberValue baseValue = computeBaseValue(previousValue);
44+
public Value applyToLocalView(@Nullable Value previousValue, Timestamp localWriteTime) {
45+
Value baseValue = computeBaseValue(previousValue);
4246

4347
// Return an integer value only if the previous value and the operand is an integer.
44-
if (baseValue instanceof IntegerValue && operand instanceof IntegerValue) {
45-
long sum = safeIncrement(((IntegerValue) baseValue).getIntegerValue(), operandAsLong());
46-
return IntegerValue.valueOf(sum);
47-
} else if (baseValue instanceof IntegerValue) {
48-
double sum = ((IntegerValue) baseValue).getIntegerValue() + operandAsDouble();
49-
return DoubleValue.valueOf(sum);
48+
if (isInteger(baseValue) && operand instanceof IntegerValue) {
49+
long sum = safeIncrement(baseValue.getIntegerValue(), operandAsLong());
50+
return Value.newBuilder().setIntegerValue(sum).build();
51+
} else if (isInteger(baseValue)) {
52+
double sum = baseValue.getIntegerValue() + operandAsDouble();
53+
return Value.newBuilder().setDoubleValue(sum).build();
5054
} else {
5155
hardAssert(
52-
baseValue instanceof DoubleValue,
56+
isDouble(baseValue),
5357
"Expected NumberValue to be of type DoubleValue, but was ",
5458
previousValue.getClass().getCanonicalName());
55-
double sum = ((DoubleValue) baseValue).getDoubleValue() + operandAsDouble();
56-
return DoubleValue.valueOf(sum);
59+
double sum = baseValue.getDoubleValue() + operandAsDouble();
60+
return Value.newBuilder().setDoubleValue(sum).build();
5761
}
5862
}
5963

6064
@Override
61-
public FieldValue applyToRemoteDocument(
62-
@Nullable FieldValue previousValue, FieldValue transformResult) {
65+
public Value applyToRemoteDocument(@Nullable Value previousValue, Value transformResult) {
6366
return transformResult;
6467
}
6568

@@ -72,10 +75,10 @@ public FieldValue getOperand() {
7275
* otherwise returning a coerced IntegerValue of 0.
7376
*/
7477
@Override
75-
public NumberValue computeBaseValue(@Nullable FieldValue previousValue) {
76-
return previousValue instanceof NumberValue
77-
? (NumberValue) previousValue
78-
: IntegerValue.valueOf(0L);
78+
public Value computeBaseValue(@Nullable Value previousValue) {
79+
return ProtoValues.isNumber(previousValue)
80+
? previousValue
81+
: Value.newBuilder().setIntegerValue(0).build();
7982
}
8083

8184
/**

firebase-firestore/src/main/java/com/google/firebase/firestore/model/mutation/ServerTimestampOperation.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
import androidx.annotation.Nullable;
1818
import com.google.firebase.Timestamp;
19-
import com.google.firebase.firestore.model.value.FieldValue;
2019
import com.google.firebase.firestore.model.value.ServerTimestampValue;
20+
import com.google.firestore.v1.Value;
2121

2222
/** Transforms a value into a server-generated timestamp. */
2323
public class ServerTimestampOperation implements TransformOperation {
@@ -30,19 +30,18 @@ public static ServerTimestampOperation getInstance() {
3030
}
3131

3232
@Override
33-
public FieldValue applyToLocalView(@Nullable FieldValue previousValue, Timestamp localWriteTime) {
34-
return ServerTimestampValue.valueOf(localWriteTime, previousValue);
33+
public Value applyToLocalView(@Nullable Value previousValue, Timestamp localWriteTime) {
34+
return ServerTimestampValue.valueOf(localWriteTime, previousValue).getProto();
3535
}
3636

3737
@Override
38-
public FieldValue applyToRemoteDocument(
39-
@Nullable FieldValue previousValue, FieldValue transformResult) {
38+
public Value applyToRemoteDocument(@Nullable Value previousValue, Value transformResult) {
4039
return transformResult;
4140
}
4241

4342
@Nullable
4443
@Override
45-
public FieldValue computeBaseValue(@Nullable FieldValue currentValue) {
44+
public Value computeBaseValue(@Nullable Value currentValue) {
4645
return null; // Server timestamps are idempotent and don't require a base value.
4746
}
4847

0 commit comments

Comments
 (0)