Skip to content

Commit a45f274

Browse files
Renames and comments
1 parent 4aa3ec6 commit a45f274

File tree

9 files changed

+121
-97
lines changed

9 files changed

+121
-97
lines changed

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

Lines changed: 67 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import com.google.firestore.v1.Value;
1919
import java.util.Comparator;
2020

21-
public class MutableDocument implements Cloneable {
21+
public final class MutableDocument implements Cloneable {
2222
private static final Comparator<MutableDocument> KEY_COMPARATOR =
2323
(left, right) -> left.getKey().compareTo(right.getKey());
2424

@@ -27,81 +27,99 @@ public static Comparator<MutableDocument> keyComparator() {
2727
return KEY_COMPARATOR;
2828
}
2929

30-
private enum Type {
30+
private enum DocumentType {
31+
/**
32+
* Represents the initial state of a MutableDocument when only the document key is known.
33+
* Invalid documents transition to other states as mutations are applied. If a document remain
34+
* invalids after applying mutations, it should be discarded.
35+
*/
3136
INVALID,
37+
/**
38+
* Represents a document in Firestore with a key, version, data and whether the data has local
39+
* mutations applied to it.
40+
*/
3241
FOUND_DOCUMENT,
42+
/** Represents that no documents exists for the key at the given version. */
3343
NO_DOCUMENT,
44+
/**
45+
* Represents an existing document whose data is unknown (e.g. a document that was updated
46+
* without a known base document).
47+
*/
3448
UNKNOWN_DOCUMENT;
3549
}
3650

51+
/** Describes the `hasPendingWrites` state of a document. */
52+
private enum DocumentState {
53+
/** Local mutations applied via the mutation queue. Document is potentially inconsistent. */
54+
LOCAL_MUTATIONS,
55+
/** Mutations applied based on a write acknowledgment. Document is potentially inconsistent. */
56+
COMMITTED_MUTATIONS,
57+
/** No mutations applied. Document was sent to us by Watch. */
58+
SYNCED
59+
}
60+
3761
private final DocumentKey key;
38-
private Type type;
62+
private DocumentType documentType;
3963
private SnapshotVersion version;
4064
private ObjectValue value;
41-
boolean hasLocalMutations;
42-
boolean hasCommittedMutations;
65+
private DocumentState documentState;
4366

4467
public MutableDocument(DocumentKey key) {
45-
this.key = key;
46-
this.version = SnapshotVersion.NONE;
47-
this.type = Type.INVALID;
48-
this.value = new ObjectValue();
68+
this(key, DocumentType.INVALID, SnapshotVersion.NONE, new ObjectValue(), DocumentState.SYNCED);
4969
}
5070

5171
private MutableDocument(
5272
DocumentKey key,
53-
Type type,
73+
DocumentType documentType,
5474
SnapshotVersion version,
5575
ObjectValue value,
56-
boolean hasLocalMutations,
57-
boolean hasCommittedMutations) {
76+
DocumentState documentState) {
5877
this.key = key;
5978
this.version = version;
60-
this.type = type;
61-
this.hasLocalMutations = hasLocalMutations;
62-
this.hasCommittedMutations = hasCommittedMutations;
79+
this.documentType = documentType;
80+
this.documentState = documentState;
6381
this.value = value;
6482
}
6583

66-
/** Changes the document type to FOUND_DOCUMENT and sets the given version and data. */
84+
/**
85+
* Changes the document type to indicate that it exists and that its version and data are known.
86+
*/
6787
public MutableDocument setFoundDocument(SnapshotVersion version, ObjectValue value) {
6888
this.version = version;
69-
this.type = Type.FOUND_DOCUMENT;
89+
this.documentType = DocumentType.FOUND_DOCUMENT;
7090
this.value = value;
71-
this.hasLocalMutations = false;
72-
this.hasCommittedMutations = false;
91+
this.documentState = DocumentState.SYNCED;
7392
return this;
7493
}
7594

76-
/** Changes the document type to NO_DOCUMENT and sets the given version. */
95+
/** Changes the document type to indicate that it doesn't exist at the given version. */
7796
public MutableDocument setNoDocument(SnapshotVersion version) {
7897
this.version = version;
79-
this.type = Type.NO_DOCUMENT;
98+
this.documentType = DocumentType.NO_DOCUMENT;
8099
this.value = new ObjectValue();
81-
this.hasLocalMutations = false;
82-
this.hasCommittedMutations = false;
100+
this.documentState = DocumentState.SYNCED;
83101
return this;
84102
}
85103

86-
/** Changes the document type to UNKNOWN_DOCUMENT and sets the given version. */
104+
/**
105+
* Changes the document type to indicate that it exists at a given version but that is data is not
106+
* known (e.g. a document that was updated without a known base document).
107+
*/
87108
public MutableDocument setUnknownDocument(SnapshotVersion version) {
88109
this.version = version;
89-
this.type = Type.UNKNOWN_DOCUMENT;
110+
this.documentType = DocumentType.UNKNOWN_DOCUMENT;
90111
this.value = new ObjectValue();
91-
this.hasLocalMutations = false;
92-
this.hasCommittedMutations = true;
112+
this.documentState = DocumentState.COMMITTED_MUTATIONS;
93113
return this;
94114
}
95115

96116
public MutableDocument setCommittedMutations() {
97-
this.hasLocalMutations = false;
98-
this.hasCommittedMutations = true;
117+
this.documentState = DocumentState.COMMITTED_MUTATIONS;
99118
return this;
100119
}
101120

102121
public MutableDocument setLocalMutations() {
103-
this.hasLocalMutations = true;
104-
this.hasCommittedMutations = true;
122+
this.documentState = DocumentState.LOCAL_MUTATIONS;
105123
return this;
106124
}
107125

@@ -120,12 +138,12 @@ public SnapshotVersion getVersion() {
120138

121139
/** Returns whether local mutations were applied via the mutation queue. */
122140
public boolean hasLocalMutations() {
123-
return hasLocalMutations;
141+
return documentState.equals(DocumentState.LOCAL_MUTATIONS);
124142
}
125143

126144
/** Returns whether mutations were applied based on a write acknowledgment. */
127145
public boolean hasCommittedMutations() {
128-
return hasCommittedMutations;
146+
return documentState.equals(DocumentState.COMMITTED_MUTATIONS);
129147
}
130148

131149
/**
@@ -143,27 +161,33 @@ public Value getField(FieldPath field) {
143161
return getData().get(field);
144162
}
145163

164+
/**
165+
* Returns whether this document is valid (i.e. it is an entry in the RemoteDocumentCache, was
166+
* created by a mutation or read from the backend).
167+
*/
146168
public boolean isValidDocument() {
147-
return !type.equals(Type.INVALID);
169+
return !documentType.equals(DocumentType.INVALID);
148170
}
149171

172+
/** Returns whether the document exists and its data is known at the current version. */
150173
public boolean isFoundDocument() {
151-
return type.equals(Type.FOUND_DOCUMENT);
174+
return documentType.equals(DocumentType.FOUND_DOCUMENT);
152175
}
153176

177+
/** Returns whether the document is known to not exist at the current version. */
154178
public boolean isNoDocument() {
155-
return type.equals(Type.NO_DOCUMENT);
179+
return documentType.equals(DocumentType.NO_DOCUMENT);
156180
}
157181

182+
/** Returns whether the document exists and its data is unknown at the current version. */
158183
public boolean isUnknownDocument() {
159-
return type.equals(Type.UNKNOWN_DOCUMENT);
184+
return documentType.equals(DocumentType.UNKNOWN_DOCUMENT);
160185
}
161186

162187
@Override
163188
@NonNull
164189
public MutableDocument clone() {
165-
return new MutableDocument(
166-
key, type, version, value.clone(), hasLocalMutations, hasCommittedMutations);
190+
return new MutableDocument(key, documentType, version, value.clone(), documentState);
167191
}
168192

169193
@Override
@@ -173,11 +197,9 @@ public boolean equals(Object o) {
173197

174198
MutableDocument document = (MutableDocument) o;
175199

176-
if (hasLocalMutations != document.hasLocalMutations) return false;
177-
if (hasCommittedMutations != document.hasCommittedMutations) return false;
178200
if (!key.equals(document.key)) return false;
179201
if (!version.equals(document.version)) return false;
180-
if (type != document.type) return false;
202+
if (documentType != document.documentType) return false;
181203
return value.equals(document.value);
182204
}
183205

@@ -194,11 +216,9 @@ public String toString() {
194216
+ ", version="
195217
+ version
196218
+ ", type="
197-
+ type
198-
+ ", hasLocalMutations="
199-
+ hasLocalMutations
200-
+ ", hasCommittedMutations="
201-
+ hasCommittedMutations
219+
+ documentType
220+
+ ", documentState="
221+
+ documentState
202222
+ ", value="
203223
+ value
204224
+ '}';

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

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,17 @@
2727
import java.util.Set;
2828

2929
/** A structured object value stored in Firestore. */
30-
public class ObjectValue implements Cloneable {
30+
public final class ObjectValue implements Cloneable {
3131
/**
32-
* The immutable Value proto for this object. Local mutations are stored in `overlayMap` and and
33-
* only applied when `memoize` is invoked.
32+
* The immutable Value proto for this object. Local mutations are stored in `overlayMap` and only
33+
* applied when {@link #buildProto()} is invoked.
3434
*/
3535
private Value partialValue;
3636

3737
/**
38-
* A nested map that contains the accumulated changes that haven't yet been applied to
39-
* `partialValue`. Values can either be `Value` protos, `Map<String, Object>` values (to represent
40-
* additional nesting) or `null` (to represent field deletes).
38+
* A nested map that contains the accumulated changes that haven't yet been applied to {@link
39+
* #partialValue}. Values can either be {@link Value} protos, {@code Map<String, Object>} values
40+
* (to represent additional nesting) or {@code null} (to represent field deletes).
4141
*/
4242
private Map<String, Object> overlayMap = new HashMap<>();
4343

@@ -61,12 +61,12 @@ public ObjectValue() {
6161
}
6262

6363
public Map<String, Value> getFieldsMap() {
64-
return getProto().getMapValue().getFieldsMap();
64+
return buildProto().getMapValue().getFieldsMap();
6565
}
6666

6767
/** Recursively extracts the FieldPaths that are set in this ObjectValue. */
6868
public FieldMask getFieldMask() {
69-
return extractFieldMask(getProto().getMapValue());
69+
return extractFieldMask(buildProto().getMapValue());
7070
}
7171

7272
private FieldMask extractFieldMask(MapValue value) {
@@ -99,11 +99,11 @@ private FieldMask extractFieldMask(MapValue value) {
9999
* @return The value at the path or null if it doesn't exist.
100100
*/
101101
public @Nullable Value get(FieldPath fieldPath) {
102-
return get(getProto(), fieldPath);
102+
return extractNestedValue(buildProto(), fieldPath);
103103
}
104104

105105
@Nullable
106-
Value get(Value value, FieldPath fieldPath) {
106+
private Value extractNestedValue(Value value, FieldPath fieldPath) {
107107
if (fieldPath.isEmpty()) {
108108
return value;
109109
} else {
@@ -117,9 +117,18 @@ Value get(Value value, FieldPath fieldPath) {
117117
}
118118
}
119119

120-
/** Returns the Protobuf that backs this ObjectValue. */
121-
public Value getProto() {
122-
memoize();
120+
/**
121+
* Returns the Protobuf that backs this ObjectValue.
122+
*
123+
* <p>This method applies any outstanding modifications and memoizes the result. Further
124+
* invocations are based on this memoized result.
125+
*/
126+
private Value buildProto() {
127+
MapValue mergedResult = applyOverlay(FieldPath.EMPTY_PATH, overlayMap);
128+
if (mergedResult != null) {
129+
partialValue = Value.newBuilder().setMapValue(mergedResult).build();
130+
overlayMap.clear();
131+
}
123132
return partialValue;
124133
}
125134

@@ -145,7 +154,7 @@ public void set(FieldPath path, Value value) {
145154
setOverlay(path, value);
146155
}
147156

148-
public void set(Map<FieldPath, Value> data) {
157+
public void setAll(Map<FieldPath, Value> data) {
149158
for (Map.Entry<FieldPath, Value> entry : data.entrySet()) {
150159
FieldPath path = entry.getKey();
151160
if (entry.getValue() == null) {
@@ -156,7 +165,9 @@ public void set(Map<FieldPath, Value> data) {
156165
}
157166
}
158167

159-
/** Adds `value` to the overlay map at `path`. Creates nested map entries if needed. */
168+
/**
169+
* Adds {@code value} to the overlay map at {@code path}. Creates nested map entries if needed.
170+
*/
160171
private void setOverlay(FieldPath path, @Nullable Value value) {
161172
Map<String, Object> currentLevel = overlayMap;
162173

@@ -185,30 +196,21 @@ private void setOverlay(FieldPath path, @Nullable Value value) {
185196
currentLevel.put(path.getLastSegment(), value);
186197
}
187198

188-
/** Returns an ObjectValue with all mutations applied. */
189-
void memoize() {
190-
MapValue mergedResult = applyOverlay(FieldPath.EMPTY_PATH, overlayMap);
191-
if (mergedResult != null) {
192-
partialValue = Value.newBuilder().setMapValue(mergedResult).build();
193-
overlayMap.clear();
194-
}
195-
}
196-
197199
/**
198-
* Applies any overlays from `currentOverlays` that exist at `currentPath` and returns the merged
199-
* data at `currentPath` (or null if there were no changes).
200+
* Applies any overlays from {@code currentOverlays} that exist at `currentPath` and returns the
201+
* merged data at {@code currentPath} (or {@code null} if there were no changes).
200202
*
201-
* @param currentPath The path at the current nesting level. Can be set toFieldValue.EMPTY_PATH to
202-
* represent the root.
203-
* @param currentOverlays The overlays at the current nesting level in the same format as
204-
* `overlayMap`.
203+
* @param currentPath The path at the current nesting level. Can be set to {@code
204+
* FieldValue.EMPTY_PATH} to represent the root.
205+
* @param currentOverlays The overlays at the current nesting level in the same format as {@code
206+
* overlayMap}.
205207
* @return The merged data at `currentPath` or null if no modifications were applied.
206208
*/
207209
private @Nullable MapValue applyOverlay(
208210
FieldPath currentPath, Map<String, Object> currentOverlays) {
209211
boolean modified = false;
210212

211-
@Nullable Value existingValue = get(partialValue, currentPath);
213+
@Nullable Value existingValue = extractNestedValue(partialValue, currentPath);
212214
MapValue.Builder resultAtPath =
213215
Values.isMapValue(existingValue)
214216
// If there is already data at the current path, base our modifications on top
@@ -246,24 +248,24 @@ public boolean equals(Object o) {
246248
if (this == o) {
247249
return true;
248250
} else if (o instanceof ObjectValue) {
249-
return Values.equals(getProto(), ((ObjectValue) o).getProto());
251+
return Values.equals(buildProto(), ((ObjectValue) o).buildProto());
250252
}
251253
return false;
252254
}
253255

254256
@Override
255257
public int hashCode() {
256-
return getProto().hashCode();
258+
return buildProto().hashCode();
257259
}
258260

259261
@Override
260262
@NonNull
261263
public String toString() {
262-
return "ObjectValue{" + "internalValue=" + getProto() + '}';
264+
return "ObjectValue{" + "internalValue=" + buildProto() + '}';
263265
}
264266

265267
@NonNull
266268
public ObjectValue clone() {
267-
return new ObjectValue(getProto());
269+
return new ObjectValue(buildProto());
268270
}
269271
}

0 commit comments

Comments
 (0)