Skip to content

Commit 99a91e5

Browse files
Add ordering to Index implementation
1 parent 9b67604 commit 99a91e5

File tree

10 files changed

+293
-166
lines changed

10 files changed

+293
-166
lines changed

firebase-firestore/src/main/java/com/google/firebase/firestore/core/OrderBy.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,25 @@
2424
public class OrderBy {
2525
/** The direction of the ordering */
2626
public enum Direction {
27-
ASCENDING(1),
28-
DESCENDING(-1);
27+
ASCENDING(1, "asc"),
28+
DESCENDING(-1, "desc");
2929

3030
private final int comparisonModifier;
31+
private final String shorthand;
3132

32-
Direction(int comparisonModifier) {
33+
Direction(int comparisonModifier, String canonicalString) {
3334
this.comparisonModifier = comparisonModifier;
35+
this.shorthand = canonicalString;
3436
}
3537

3638
int getComparisonModifier() {
3739
return comparisonModifier;
3840
}
41+
42+
/** Returns "asc" for ascending or "desc" for descending. */
43+
public String canonicalString() {
44+
return shorthand;
45+
}
3946
}
4047

4148
public static OrderBy getInstance(Direction direction, FieldPath path) {

firebase-firestore/src/main/java/com/google/firebase/firestore/core/Target.java

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

1717
import static com.google.firebase.firestore.model.Values.max;
1818
import static com.google.firebase.firestore.model.Values.min;
19+
import static com.google.firebase.firestore.util.Assert.fail;
1920

2021
import androidx.annotation.Nullable;
21-
import com.google.firebase.firestore.core.OrderBy.Direction;
2222
import com.google.firebase.firestore.model.DocumentKey;
2323
import com.google.firebase.firestore.model.FieldIndex;
2424
import com.google.firebase.firestore.model.ResourcePath;
2525
import com.google.firebase.firestore.model.Values;
26-
import com.google.firestore.v1.ArrayValue;
2726
import com.google.firestore.v1.Value;
2827
import java.util.ArrayList;
28+
import java.util.Collections;
2929
import java.util.List;
3030

3131
/**
@@ -115,6 +115,27 @@ public boolean hasLimit() {
115115
return endAt;
116116
}
117117

118+
/** Returns the list of values that are used in ARRAY_CONTAINS and ARRAY_CONTAINS_ANY filter. */
119+
public List<Value> getArrayValues(FieldIndex fieldIndex) {
120+
for (FieldIndex.Segment segment : fieldIndex.getArraySegments()) {
121+
for (Filter filter : filters) {
122+
if (filter.getField().equals(segment.getFieldPath())) {
123+
FieldFilter fieldFilter = (FieldFilter) filter;
124+
switch (fieldFilter.getOperator()) {
125+
case ARRAY_CONTAINS_ANY:
126+
return fieldFilter.getValue().getArrayValue().getValuesList();
127+
case ARRAY_CONTAINS:
128+
return Collections.singletonList(fieldFilter.getValue());
129+
default:
130+
fail("Unexpected operator: " + fieldFilter.getOperator());
131+
}
132+
}
133+
}
134+
}
135+
136+
return Collections.emptyList();
137+
}
138+
118139
/**
119140
* Returns a lower bound of field values that can be used as a starting point to scan the index
120141
* defined by {@code fieldIndex}.
@@ -127,7 +148,7 @@ public Bound getLowerBound(FieldIndex fieldIndex) {
127148
boolean inclusive = true;
128149

129150
// Go through all filters to find a value for the current field segment
130-
for (FieldIndex.Segment segment : fieldIndex) {
151+
for (FieldIndex.Segment segment : fieldIndex.getDirectionalSegments()) {
131152
Value segmentValue = Values.NULL_VALUE;
132153
boolean segmentInclusive = true;
133154

@@ -143,25 +164,19 @@ public Bound getLowerBound(FieldIndex fieldIndex) {
143164
filterValue = Values.getLowerBound(fieldFilter.getValue().getValueTypeCase());
144165
break;
145166
case NOT_EQUAL:
146-
filterValue = Values.NULL_VALUE;
147-
break;
148167
case NOT_IN:
149-
filterValue =
150-
Value.newBuilder()
151-
.setArrayValue(ArrayValue.newBuilder().addValues(Values.NULL_VALUE))
152-
.build();
153168
break;
154169
case EQUAL:
155170
case IN:
156-
case ARRAY_CONTAINS_ANY:
157-
case ARRAY_CONTAINS:
158171
case GREATER_THAN_OR_EQUAL:
159172
filterValue = fieldFilter.getValue();
160173
break;
161174
case GREATER_THAN:
162175
filterValue = fieldFilter.getValue();
163176
filterInclusive = false;
164177
break;
178+
default:
179+
fail("Unexpected operator: " + fieldFilter.getOperator());
165180
}
166181

167182
if (max(segmentValue, filterValue) == filterValue) {
@@ -206,7 +221,7 @@ public Bound getLowerBound(FieldIndex fieldIndex) {
206221
List<Value> values = new ArrayList<>();
207222
boolean inclusive = true;
208223

209-
for (FieldIndex.Segment segment : fieldIndex) {
224+
for (FieldIndex.Segment segment : fieldIndex.getDirectionalSegments()) {
210225
@Nullable Value segmentValue = null;
211226
boolean segmentInclusive = true;
212227

@@ -229,15 +244,15 @@ public Bound getLowerBound(FieldIndex fieldIndex) {
229244
break;
230245
case EQUAL:
231246
case IN:
232-
case ARRAY_CONTAINS_ANY:
233-
case ARRAY_CONTAINS:
234247
case LESS_THAN_OR_EQUAL:
235248
filterValue = fieldFilter.getValue();
236249
break;
237250
case LESS_THAN:
238251
filterValue = fieldFilter.getValue();
239252
filterInclusive = false;
240253
break;
254+
default:
255+
fail("Unexpected operator: " + fieldFilter.getOperator());
241256
}
242257

243258
if (min(segmentValue, filterValue) == filterValue) {
@@ -283,6 +298,11 @@ public List<OrderBy> getOrderBy() {
283298
return this.orderBys;
284299
}
285300

301+
/** Returns the first order by (which always exists). */
302+
public OrderBy getFirstOrderBy() {
303+
return this.orderBys.get(0);
304+
}
305+
286306
/** Returns a canonical string representing this target. */
287307
public String getCanonicalId() {
288308
if (memoizedCannonicalId != null) {
@@ -307,7 +327,7 @@ public String getCanonicalId() {
307327
builder.append("|ob:");
308328
for (OrderBy orderBy : getOrderBy()) {
309329
builder.append(orderBy.getField().canonicalString());
310-
builder.append(orderBy.getDirection().equals(Direction.ASCENDING) ? "asc" : "desc");
330+
builder.append(orderBy.getDirection().canonicalString());
311331
}
312332

313333
// Add limit.

firebase-firestore/src/main/java/com/google/firebase/firestore/index/IndexEntry.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@
2121
// TODO(indexing)
2222
public class IndexEntry {
2323
private final int indexId;
24-
private final byte[] indexValue;
24+
private final byte[] arrayValue;
25+
private final byte[] directionalValue;
2526
private final String uid;
2627
private final String documentName;
2728

28-
public IndexEntry(int indexId, byte[] indexValue, String uid, String documentName) {
29+
public IndexEntry(
30+
int indexId, byte[] arrayValue, byte[] directionalValue, String uid, String documentName) {
2931
this.indexId = indexId;
30-
this.indexValue = indexValue;
32+
this.arrayValue = arrayValue;
33+
this.directionalValue = directionalValue;
3134
this.uid = uid;
3235
this.documentName = documentName;
3336
}
@@ -36,8 +39,12 @@ public int getIndexId() {
3639
return indexId;
3740
}
3841

39-
public byte[] getIndexValue() {
40-
return indexValue;
42+
public byte[] getArrayValue() {
43+
return arrayValue;
44+
}
45+
46+
public byte[] getDirectionalValue() {
47+
return directionalValue;
4148
}
4249

4350
public String getUid() {

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,13 @@ void addIndexEntry(IndexEntry entry) {
115115
persistence.execute(
116116
"INSERT OR IGNORE INTO index_entries ("
117117
+ "index_id, "
118-
+ "index_value, "
118+
+ "array_index, "
119+
+ "directional_index, "
119120
+ "uid, "
120121
+ "document_name) VALUES(?, ?, ?, ?)",
121122
entry.getIndexId(),
122-
entry.getIndexValue(),
123+
entry.getArrayValue(),
124+
entry.getDirectionalValue(),
123125
entry.getUid(),
124126
entry.getDocumentName());
125127
}
@@ -141,12 +143,18 @@ void removeIndexEntry(int indexId, String uid, String documentName) {
141143
@VisibleForTesting
142144
IndexEntry getIndexEntry(int indexId) {
143145
return persistence
144-
.query("SELECT index_value, uid, document_name FROM index_entries WHERE index_id = ?")
146+
.query(
147+
"SELECT array_index, directional_index, uid, document_name FROM index_entries WHERE index_id = ?")
145148
.binding(indexId)
146149
.firstValue(
147150
row ->
148151
row == null
149152
? null
150-
: new IndexEntry(indexId, row.getBlob(0), row.getString(1), row.getString(2)));
153+
: new IndexEntry(
154+
indexId,
155+
row.getBlob(0),
156+
row.getBlob(1),
157+
row.getString(2),
158+
row.getString(3)));
151159
}
152160
}

0 commit comments

Comments
 (0)