use of com.google.firebase.firestore.model.FieldIndex in project firebase-android-sdk by firebase.
the class SQLiteLocalStoreTest method testIndexesServerTimestamps.
@Test
public void testIndexesServerTimestamps() {
FieldIndex index = fieldIndex("coll", 0, FieldIndex.INITIAL_STATE, "time", FieldIndex.Segment.Kind.ASCENDING);
configureFieldIndexes(singletonList(index));
writeMutation(setMutation("coll/a", map("time", FieldValue.serverTimestamp())));
backfillIndexes();
Query query = query("coll").orderBy(orderBy("time", "asc"));
executeQuery(query);
assertOverlaysRead(/* byKey= */
1, /* byCollection= */
0);
assertQueryReturned("coll/a");
}
use of com.google.firebase.firestore.model.FieldIndex in project firebase-android-sdk by firebase.
the class SQLiteLocalStoreTest method testDoesNotResetIndexWhenSameIndexIsAdded.
@Test
public void testDoesNotResetIndexWhenSameIndexIsAdded() {
FieldIndex indexA = fieldIndex("coll", 0, FieldIndex.INITIAL_STATE, "a", FieldIndex.Segment.Kind.ASCENDING);
configureFieldIndexes(singletonList(indexA));
Collection<FieldIndex> fieldIndexes = getFieldIndexes();
assertThat(fieldIndexes).containsExactly(indexA);
Query query = query("coll").filter(filter("a", "==", 1));
int targetId = allocateQuery(query);
applyRemoteEvent(addedRemoteEvent(doc("coll/a", 10, map("a", 1)), targetId));
backfillIndexes();
FieldIndex updatedIndexA = fieldIndex("coll", 0, FieldIndex.IndexState.create(1, version(10), key("coll/a"), -1), "a", FieldIndex.Segment.Kind.ASCENDING);
fieldIndexes = getFieldIndexes();
assertThat(fieldIndexes).containsExactly(updatedIndexA);
// Re-add the same index. We do not reset the index to its initial state.
configureFieldIndexes(singletonList(indexA));
fieldIndexes = getFieldIndexes();
assertThat(fieldIndexes).containsExactly(updatedIndexA);
}
use of com.google.firebase.firestore.model.FieldIndex in project firebase-android-sdk by firebase.
the class SQLiteLocalStoreTest method testRemovesIndexes.
@Test
public void testRemovesIndexes() {
FieldIndex indexA = fieldIndex("coll", 0, FieldIndex.INITIAL_STATE, "a", FieldIndex.Segment.Kind.ASCENDING);
FieldIndex indexB = fieldIndex("coll", 1, FieldIndex.INITIAL_STATE, "b", FieldIndex.Segment.Kind.DESCENDING);
configureFieldIndexes(Arrays.asList(indexA, indexB));
Collection<FieldIndex> fieldIndexes = getFieldIndexes();
assertThat(fieldIndexes).containsExactly(indexA, indexB);
configureFieldIndexes(singletonList(indexA));
fieldIndexes = getFieldIndexes();
assertThat(fieldIndexes).containsExactly(indexA);
}
use of com.google.firebase.firestore.model.FieldIndex in project firebase-android-sdk by firebase.
the class SQLiteLocalStoreTest method testDeletedDocumentRemovesIndex.
@Test
public void testDeletedDocumentRemovesIndex() {
FieldIndex index = fieldIndex("coll", 0, FieldIndex.INITIAL_STATE, "matches", FieldIndex.Segment.Kind.ASCENDING);
configureFieldIndexes(singletonList(index));
Query query = query("coll").filter(filter("matches", "==", true));
int targetId = allocateQuery(query);
applyRemoteEvent(addedRemoteEvent(doc("coll/a", 10, map("matches", true)), targetId));
// Add the document to the index
backfillIndexes();
executeQuery(query);
assertRemoteDocumentsRead(/* byKey= */
1, /* byQuery= */
0);
assertQueryReturned("coll/a");
applyRemoteEvent(updateRemoteEvent(deletedDoc("coll/a", 0), singletonList(targetId), emptyList()));
// No backfill needed for deleted document.
executeQuery(query);
assertRemoteDocumentsRead(/* byKey= */
0, /* byQuery= */
0);
assertQueryReturned();
}
use of com.google.firebase.firestore.model.FieldIndex in project firebase-android-sdk by firebase.
the class SQLiteIndexManager method getDocumentsMatchingTarget.
@Override
public Set<DocumentKey> getDocumentsMatchingTarget(Target target) {
hardAssert(started, "IndexManager not started");
List<String> subQueries = new ArrayList<>();
List<Object> bindings = new ArrayList<>();
for (Target subTarget : getSubTargets(target)) {
FieldIndex fieldIndex = getFieldIndex(subTarget);
if (fieldIndex == null) {
return null;
}
@Nullable List<Value> arrayValues = subTarget.getArrayValues(fieldIndex);
@Nullable Collection<Value> notInValues = subTarget.getNotInValues(fieldIndex);
@Nullable Bound lowerBound = subTarget.getLowerBound(fieldIndex);
@Nullable Bound upperBound = subTarget.getUpperBound(fieldIndex);
if (Logger.isDebugEnabled()) {
Logger.debug(TAG, "Using index '%s' to execute '%s' (Arrays: %s, Lower bound: %s, Upper bound: %s)", fieldIndex, subTarget, arrayValues, lowerBound, upperBound);
}
Object[] lowerBoundEncoded = encodeBound(fieldIndex, subTarget, lowerBound);
String lowerBoundOp = lowerBound != null && lowerBound.isInclusive() ? ">=" : ">";
Object[] upperBoundEncoded = encodeBound(fieldIndex, subTarget, upperBound);
String upperBoundOp = upperBound != null && upperBound.isInclusive() ? "<=" : "<";
Object[] notInEncoded = encodeValues(fieldIndex, subTarget, notInValues);
Object[] subQueryAndBindings = generateQueryAndBindings(subTarget, fieldIndex.getIndexId(), arrayValues, lowerBoundEncoded, lowerBoundOp, upperBoundEncoded, upperBoundOp, notInEncoded);
subQueries.add(String.valueOf(subQueryAndBindings[0]));
bindings.addAll(Arrays.asList(subQueryAndBindings).subList(1, subQueryAndBindings.length));
}
String queryString;
if (subQueries.size() == 1) {
// If there's only one subQuery, just execute the one subQuery.
queryString = subQueries.get(0);
} else {
// Construct "SELECT * FROM (subQuery1 UNION subQuery2 UNION ...) LIMIT N"
queryString = "SELECT * FROM (" + TextUtils.join(" UNION ", subQueries) + ")";
if (target.getLimit() != -1) {
queryString = queryString + " LIMIT " + target.getLimit();
}
}
hardAssert(bindings.size() < 1000, "Cannot perform query with more than 999 bind elements");
SQLitePersistence.Query query = db.query(queryString).binding(bindings.toArray());
Set<DocumentKey> result = new HashSet<>();
query.forEach(row -> result.add(DocumentKey.fromPath(ResourcePath.fromString(row.getString(0)))));
Logger.debug(TAG, "Index scan returned %s documents", result.size());
return result;
}
Aggregations