Skip to content

Commit 710046b

Browse files
Make FieldIndex an AutoValue (#3147)
1 parent 0e5ccca commit 710046b

File tree

11 files changed

+234
-380
lines changed

11 files changed

+234
-380
lines changed

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.google.firebase.firestore.model.FieldIndex;
4545
import com.google.firebase.firestore.model.FieldPath;
4646
import com.google.firebase.firestore.model.ResourcePath;
47+
import com.google.firebase.firestore.model.SnapshotVersion;
4748
import com.google.firebase.firestore.remote.FirestoreChannel;
4849
import com.google.firebase.firestore.remote.GrpcMetadataProvider;
4950
import com.google.firebase.firestore.util.AsyncQueue;
@@ -322,21 +323,24 @@ Task<Void> configureIndices(String json) {
322323
JSONArray indices = jsonObject.getJSONArray("indexes");
323324
for (int i = 0; i < indices.length(); ++i) {
324325
JSONObject definition = indices.getJSONObject(i);
325-
FieldIndex fieldIndex = new FieldIndex(definition.getString("collectionGroup"));
326+
String collectionGroup = definition.getString("collectionGroup");
327+
List<FieldIndex.Segment> segments = new ArrayList<>();
326328

327329
JSONArray fields = definition.optJSONArray("fields");
328330
for (int f = 0; fields != null && f < fields.length(); ++f) {
329331
JSONObject field = fields.getJSONObject(f);
330332
FieldPath fieldPath = FieldPath.fromServerFormat(field.getString("fieldPath"));
331333
if ("CONTAINS".equals(field.optString("arrayConfig"))) {
332-
fieldIndex = fieldIndex.withAddedField(fieldPath, FieldIndex.Segment.Kind.CONTAINS);
334+
segments.add(FieldIndex.Segment.create(fieldPath, FieldIndex.Segment.Kind.CONTAINS));
333335
} else if ("ASCENDING".equals(field.optString("order"))) {
334-
fieldIndex = fieldIndex.withAddedField(fieldPath, FieldIndex.Segment.Kind.ASCENDING);
336+
segments.add(FieldIndex.Segment.create(fieldPath, FieldIndex.Segment.Kind.ASCENDING));
335337
} else {
336-
fieldIndex = fieldIndex.withAddedField(fieldPath, FieldIndex.Segment.Kind.DESCENDING);
338+
segments.add(
339+
FieldIndex.Segment.create(fieldPath, FieldIndex.Segment.Kind.DESCENDING));
337340
}
338-
parsedIndices.add(fieldIndex);
339341
}
342+
343+
parsedIndices.add(FieldIndex.create(-1, collectionGroup, segments, SnapshotVersion.NONE));
340344
}
341345
}
342346
} catch (JSONException e) {

firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalSerializer.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -291,14 +291,13 @@ public BundledQuery decodeBundledQuery(com.google.firestore.bundle.BundledQuery
291291
return new BundledQuery(target, limitType);
292292
}
293293

294-
public Index encodeFieldIndex(FieldIndex fieldIndex) {
294+
public Index encodeFieldIndexSegments(List<FieldIndex.Segment> segments) {
295295
Index.Builder index = Index.newBuilder();
296296
// The Mobile SDKs treat all indices as collection group indices, as we run all collection group
297297
// queries against each collection separately.
298298
index.setQueryScope(Index.QueryScope.COLLECTION_GROUP);
299299

300-
for (int i = 0; i < fieldIndex.segmentCount(); ++i) {
301-
FieldIndex.Segment segment = fieldIndex.getSegment(i);
300+
for (FieldIndex.Segment segment : segments) {
302301
Index.IndexField.Builder indexField = Index.IndexField.newBuilder();
303302
indexField.setFieldPath(segment.getFieldPath().canonicalString());
304303
if (segment.getKind() == FieldIndex.Segment.Kind.CONTAINS) {
@@ -314,9 +313,8 @@ public Index encodeFieldIndex(FieldIndex fieldIndex) {
314313
return index.build();
315314
}
316315

317-
public FieldIndex decodeFieldIndex(
318-
String collectionGroup, int indexId, Index index, int updateSeconds, int updateNanos) {
319-
FieldIndex fieldIndex = new FieldIndex(collectionGroup, indexId);
316+
public List<FieldIndex.Segment> decodeFieldIndexSegments(Index index) {
317+
List<FieldIndex.Segment> result = new ArrayList<>();
320318
for (Index.IndexField field : index.getFieldsList()) {
321319
FieldPath fieldPath = FieldPath.fromServerFormat(field.getFieldPath());
322320
FieldIndex.Segment.Kind kind =
@@ -325,11 +323,9 @@ public FieldIndex decodeFieldIndex(
325323
: (field.getOrder().equals(Index.IndexField.Order.ASCENDING)
326324
? FieldIndex.Segment.Kind.ASCENDING
327325
: FieldIndex.Segment.Kind.DESCENDING);
328-
fieldIndex = fieldIndex.withAddedField(fieldPath, kind);
326+
result.add(FieldIndex.Segment.create(fieldPath, kind));
329327
}
330-
fieldIndex =
331-
fieldIndex.withUpdateTime(new SnapshotVersion(new Timestamp(updateSeconds, updateNanos)));
332-
return fieldIndex;
328+
return result;
333329
}
334330

335331
public Mutation decodeMutation(Write mutation) {

firebase-firestore/src/main/java/com/google/firebase/firestore/local/SQLiteIndexManager.java

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,15 @@ public void start() {
9494
.forEach(
9595
row -> {
9696
try {
97+
int indexId = row.getInt(0);
98+
String collectionGroup = row.getString(1);
99+
List<FieldIndex.Segment> segments =
100+
serializer.decodeFieldIndexSegments(Index.parseFrom(row.getBlob(2)));
101+
SnapshotVersion updateTime =
102+
new SnapshotVersion(new Timestamp(row.getLong(3), row.getInt(4)));
103+
97104
FieldIndex fieldIndex =
98-
serializer.decodeFieldIndex(
99-
row.getString(1),
100-
row.getInt(0),
101-
Index.parseFrom(row.getBlob(2)),
102-
row.getInt(3),
103-
row.getInt(4));
105+
FieldIndex.create(indexId, collectionGroup, segments, updateTime);
104106
memoizeIndex(fieldIndex);
105107
} catch (InvalidProtocolBufferException e) {
106108
throw fail("Failed to decode index: " + e);
@@ -146,7 +148,9 @@ public void addFieldIndex(FieldIndex index) {
146148
hardAssert(started, "IndexManager not started");
147149

148150
int nextIndexId = memoizedMaxId + 1;
149-
index = index.withIndexId(nextIndexId);
151+
index =
152+
FieldIndex.create(
153+
nextIndexId, index.getCollectionGroup(), index.getSegments(), index.getUpdateTime());
150154

151155
db.execute(
152156
"INSERT INTO index_configuration ("
@@ -157,7 +161,7 @@ public void addFieldIndex(FieldIndex index) {
157161
+ "update_time_nanos) VALUES(?, ?, ?, ?, ?)",
158162
nextIndexId,
159163
index.getCollectionGroup(),
160-
encodeFieldIndex(index),
164+
encodeSegments(index),
161165
index.getUpdateTime().getTimestamp().getSeconds(),
162166
index.getUpdateTime().getTimestamp().getNanoseconds());
163167

@@ -188,7 +192,7 @@ private void updateFieldIndex(FieldIndex index) {
188192
+ "update_time_nanos) VALUES(?, ?, ?, ?, ?)",
189193
index.getIndexId(),
190194
index.getCollectionGroup(),
191-
encodeFieldIndex(index),
195+
encodeSegments(index),
192196
index.getUpdateTime().getTimestamp().getSeconds(),
193197
index.getUpdateTime().getTimestamp().getNanoseconds());
194198

@@ -292,7 +296,11 @@ private FieldIndex getPostUpdateIndex(FieldIndex baseIndex, SnapshotVersion newR
292296
if (baseIndex.getUpdateTime().compareTo(newReadTime) > 0) {
293297
return baseIndex;
294298
} else {
295-
return baseIndex.withUpdateTime(newReadTime);
299+
return FieldIndex.create(
300+
baseIndex.getIndexId(),
301+
baseIndex.getCollectionGroup(),
302+
baseIndex.getSegments(),
303+
newReadTime);
296304
}
297305
}
298306

@@ -545,7 +553,7 @@ public FieldIndex getFieldIndex(Target target) {
545553

546554
// Return the index with the most number of segments
547555
return Collections.max(
548-
matchingIndexes, (l, r) -> Integer.compare(l.segmentCount(), r.segmentCount()));
556+
matchingIndexes, (l, r) -> Integer.compare(l.getSegments().size(), r.getSegments().size()));
549557
}
550558

551559
/**
@@ -651,8 +659,8 @@ private boolean isInFilter(Target target, FieldPath fieldPath) {
651659
return false;
652660
}
653661

654-
private byte[] encodeFieldIndex(FieldIndex fieldIndex) {
655-
return serializer.encodeFieldIndex(fieldIndex).toByteArray();
662+
private byte[] encodeSegments(FieldIndex fieldIndex) {
663+
return serializer.encodeFieldIndexSegments(fieldIndex.getSegments()).toByteArray();
656664
}
657665

658666
@VisibleForTesting

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

Lines changed: 23 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,17 @@
3232
* group-scoped indices. Every index can be used for both single collection and collection group
3333
* queries.
3434
*/
35-
public final class FieldIndex {
35+
@AutoValue
36+
public abstract class FieldIndex {
3637

3738
/** Compares indexes by collection group and segments. Ignores update time and index ID. */
3839
public static final Comparator<FieldIndex> SEMANTIC_COMPARATOR =
3940
(left, right) -> {
40-
int cmp = left.collectionGroup.compareTo(right.collectionGroup);
41+
int cmp = left.getCollectionGroup().compareTo(right.getCollectionGroup());
4142
if (cmp != 0) return cmp;
4243

43-
Iterator<Segment> leftIt = left.segments.iterator();
44-
Iterator<Segment> rightIt = right.segments.iterator();
44+
Iterator<Segment> leftIt = left.getSegments().iterator();
45+
Iterator<Segment> rightIt = right.getSegments().iterator();
4546
while (leftIt.hasNext() && rightIt.hasNext()) {
4647
cmp = leftIt.next().compareTo(rightIt.next());
4748
if (cmp != 0) return cmp;
@@ -62,17 +63,16 @@ public enum Kind {
6263
CONTAINS
6364
}
6465

66+
public static Segment create(FieldPath fieldPath, Kind kind) {
67+
return new AutoValue_FieldIndex_Segment(fieldPath, kind);
68+
}
69+
6570
/** The field path of the component. */
6671
public abstract FieldPath getFieldPath();
6772

6873
/** The indexes sorting order. */
6974
public abstract Kind getKind();
7075

71-
@Override
72-
public String toString() {
73-
return String.format("Segment{fieldPath=%s, kind=%s}", getFieldPath(), getKind());
74-
}
75-
7676
@Override
7777
public int compareTo(Segment other) {
7878
int cmp = getFieldPath().compareTo(other.getFieldPath());
@@ -81,121 +81,45 @@ public int compareTo(Segment other) {
8181
}
8282
}
8383

84-
private final String collectionGroup;
85-
private final int indexId;
86-
private final List<Segment> segments;
87-
private final SnapshotVersion updateTime;
88-
89-
public FieldIndex(String collectionGroup, int indexId) {
90-
this.collectionGroup = collectionGroup;
91-
this.segments = new ArrayList<>();
92-
this.indexId = indexId;
93-
this.updateTime = SnapshotVersion.NONE;
94-
}
95-
96-
public FieldIndex(String collectionId) {
97-
this(collectionId, -1);
98-
}
99-
100-
FieldIndex(
101-
String collectionGroup, int indexId, List<Segment> segments, SnapshotVersion updateTime) {
102-
this.collectionGroup = collectionGroup;
103-
this.segments = segments;
104-
this.indexId = indexId;
105-
this.updateTime = updateTime;
106-
}
107-
108-
/** The collection ID this index applies to. */
109-
public String getCollectionGroup() {
110-
return collectionGroup;
84+
public static FieldIndex create(
85+
int indexId, String collectionGroup, List<Segment> segments, SnapshotVersion updateTime) {
86+
return new AutoValue_FieldIndex(indexId, collectionGroup, segments, updateTime);
11187
}
11288

11389
/**
11490
* The index ID. Returns -1 if the index ID is not available (e.g. the index has not yet been
11591
* persisted).
11692
*/
117-
public int getIndexId() {
118-
return indexId;
119-
}
93+
public abstract int getIndexId();
12094

121-
public Segment getSegment(int index) {
122-
return segments.get(index);
123-
}
95+
/** The collection ID this index applies to. */
96+
public abstract String getCollectionGroup();
12497

125-
public int segmentCount() {
126-
return segments.size();
127-
}
98+
/** Returns all field segments for this index. */
99+
public abstract List<Segment> getSegments();
128100

129-
/**
130-
* Returns the latest read time version that has been indexed by Firestore for this field index.
131-
*/
132-
public SnapshotVersion getUpdateTime() {
133-
return updateTime;
134-
}
101+
/** Returns when this index was last updated. */
102+
public abstract SnapshotVersion getUpdateTime();
135103

104+
/** Returns all directional (ascending/descending) segments for this index. */
136105
public List<Segment> getDirectionalSegments() {
137106
List<Segment> filteredSegments = new ArrayList<>();
138-
for (Segment segment : segments) {
107+
for (Segment segment : getSegments()) {
139108
if (!segment.getKind().equals(Segment.Kind.CONTAINS)) {
140109
filteredSegments.add(segment);
141110
}
142111
}
143112
return filteredSegments;
144113
}
145114

115+
/** Returns the ArrayContains/ArrayContainsAny segment for this index. */
146116
public @Nullable Segment getArraySegment() {
147-
for (Segment segment : segments) {
117+
for (Segment segment : getSegments()) {
148118
if (segment.getKind().equals(Segment.Kind.CONTAINS)) {
149119
// Firestore queries can only have a single ArrayContains/ArrayContainsAny statements.
150120
return segment;
151121
}
152122
}
153123
return null;
154124
}
155-
156-
/** Returns a new field index with additional index segment. */
157-
public FieldIndex withAddedField(FieldPath fieldPath, Segment.Kind kind) {
158-
List<Segment> newSegments = new ArrayList<>(segments);
159-
newSegments.add(new AutoValue_FieldIndex_Segment(fieldPath, kind));
160-
return new FieldIndex(collectionGroup, indexId, newSegments, updateTime);
161-
}
162-
163-
/** Returns a new field index with the updated version. */
164-
public FieldIndex withUpdateTime(SnapshotVersion updateTime) {
165-
return new FieldIndex(collectionGroup, indexId, segments, updateTime);
166-
}
167-
168-
/** Returns a new field index with the provided index id. */
169-
public FieldIndex withIndexId(int indexId) {
170-
return new FieldIndex(collectionGroup, indexId, segments, updateTime);
171-
}
172-
173-
@Override
174-
public boolean equals(Object o) {
175-
if (this == o) return true;
176-
if (o == null || getClass() != o.getClass()) return false;
177-
178-
FieldIndex fieldIndex = (FieldIndex) o;
179-
180-
if (indexId != fieldIndex.indexId) return false;
181-
if (!segments.equals(fieldIndex.segments)) return false;
182-
if (!updateTime.equals(fieldIndex.updateTime)) return false;
183-
return collectionGroup.equals(fieldIndex.collectionGroup);
184-
}
185-
186-
@Override
187-
public int hashCode() {
188-
int result = collectionGroup.hashCode();
189-
result = 31 * result + indexId;
190-
result = 31 * result + segments.hashCode();
191-
result = 31 * result + updateTime.hashCode();
192-
return result;
193-
}
194-
195-
@Override
196-
public String toString() {
197-
return String.format(
198-
"FieldIndex{indexId=%s, collectionGroup='%s', segments=%s, updateTime=%s}",
199-
indexId, collectionGroup, segments, updateTime);
200-
}
201125
}

0 commit comments

Comments
 (0)