Skip to content

Commit 2a2e789

Browse files
Backport executeQuery() API changes (#822)
1 parent 5da580d commit 2a2e789

File tree

11 files changed

+122
-99
lines changed

11 files changed

+122
-99
lines changed

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

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import com.google.android.gms.tasks.TaskCompletionSource;
2323
import com.google.android.gms.tasks.Tasks;
2424
import com.google.common.base.Function;
25-
import com.google.firebase.database.collection.ImmutableSortedMap;
2625
import com.google.firebase.database.collection.ImmutableSortedSet;
2726
import com.google.firebase.firestore.EventListener;
2827
import com.google.firebase.firestore.FirebaseFirestoreException;
@@ -38,6 +37,7 @@
3837
import com.google.firebase.firestore.local.MemoryPersistence;
3938
import com.google.firebase.firestore.local.Persistence;
4039
import com.google.firebase.firestore.local.QueryEngine;
40+
import com.google.firebase.firestore.local.QueryResult;
4141
import com.google.firebase.firestore.local.SQLitePersistence;
4242
import com.google.firebase.firestore.local.SimpleQueryEngine;
4343
import com.google.firebase.firestore.model.Document;
@@ -55,7 +55,6 @@
5555
import com.google.firebase.firestore.util.AsyncQueue;
5656
import com.google.firebase.firestore.util.Logger;
5757
import io.grpc.Status;
58-
import java.util.Collections;
5958
import java.util.List;
6059
import java.util.concurrent.ExecutionException;
6160
import java.util.concurrent.atomic.AtomicBoolean;
@@ -201,14 +200,9 @@ public Task<ViewSnapshot> getDocumentsFromLocalCache(Query query) {
201200
this.verifyNotTerminated();
202201
return asyncQueue.enqueue(
203202
() -> {
204-
ImmutableSortedMap<DocumentKey, Document> docs = localStore.executeQuery(query);
205-
206-
View view =
207-
new View(
208-
query,
209-
new ImmutableSortedSet<DocumentKey>(
210-
Collections.emptyList(), DocumentKey::compareTo));
211-
View.DocumentChanges viewDocChanges = view.computeDocChanges(docs);
203+
QueryResult queryResult = localStore.executeQuery(query, /* usePreviousResults= */ true);
204+
View view = new View(query, queryResult.getRemoteKeys());
205+
View.DocumentChanges viewDocChanges = view.computeDocChanges(queryResult.getDocuments());
212206
return view.applyChanges(viewDocChanges).getSnapshot();
213207
});
214208
}

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

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
import com.google.firebase.firestore.local.LocalWriteResult;
3333
import com.google.firebase.firestore.local.QueryData;
3434
import com.google.firebase.firestore.local.QueryPurpose;
35+
import com.google.firebase.firestore.local.QueryResult;
3536
import com.google.firebase.firestore.local.ReferenceSet;
36-
import com.google.firebase.firestore.model.Document;
3737
import com.google.firebase.firestore.model.DocumentKey;
3838
import com.google.firebase.firestore.model.MaybeDocument;
3939
import com.google.firebase.firestore.model.NoDocument;
@@ -191,13 +191,10 @@ public int listen(Query query) {
191191
private ViewSnapshot initializeViewAndComputeSnapshot(QueryData queryData) {
192192
Query query = queryData.getQuery();
193193

194-
ImmutableSortedSet<DocumentKey> remoteKeys =
195-
localStore.getRemoteDocumentKeys(queryData.getTargetId());
196-
ImmutableSortedMap<DocumentKey, Document> docs =
197-
localStore.executeQuery(query, queryData, remoteKeys);
194+
QueryResult queryResult = localStore.executeQuery(query, /* usePreviousResults= */ true);
198195

199-
View view = new View(query, remoteKeys);
200-
View.DocumentChanges viewDocChanges = view.computeDocChanges(docs);
196+
View view = new View(query, queryResult.getRemoteKeys());
197+
View.DocumentChanges viewDocChanges = view.computeDocChanges(queryResult.getDocuments());
201198
ViewChange viewChange = view.applyChanges(viewDocChanges);
202199
hardAssert(
203200
view.getLimboDocuments().size() == 0,
@@ -530,10 +527,9 @@ private void emitNewSnapsAndNotifyLocalStore(
530527
// The query has a limit and some docs were removed/updated, so we need to re-run the query
531528
// against the local store to make sure we didn't lose any good docs that had been past the
532529
// limit.
533-
ImmutableSortedMap<DocumentKey, Document> docs =
534-
localStore.executeQuery(
535-
queryView.getQuery(), /* queryData= */ null, DocumentKey.emptyKeySet());
536-
viewDocChanges = view.computeDocChanges(docs, viewDocChanges);
530+
QueryResult queryResult =
531+
localStore.executeQuery(queryView.getQuery(), /* usePreviousResults= */ false);
532+
viewDocChanges = view.computeDocChanges(queryResult.getDocuments(), viewDocChanges);
537533
}
538534
TargetChange targetChange =
539535
remoteEvent == null ? null : remoteEvent.getTargetChanges().get(queryView.getTargetId());

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

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

1717
import static com.google.firebase.firestore.util.Assert.hardAssert;
1818

19-
import androidx.annotation.Nullable;
2019
import com.google.firebase.database.collection.ImmutableSortedMap;
2120
import com.google.firebase.database.collection.ImmutableSortedSet;
2221
import com.google.firebase.firestore.core.Query;
@@ -58,7 +57,9 @@ public void setLocalDocumentsView(LocalDocumentsView localDocuments) {
5857

5958
@Override
6059
public ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingQuery(
61-
Query query, @Nullable QueryData queryData, ImmutableSortedSet<DocumentKey> remoteKeys) {
60+
Query query,
61+
SnapshotVersion lastLimboFreeSnapshotVersion,
62+
ImmutableSortedSet<DocumentKey> remoteKeys) {
6263
hardAssert(localDocumentsView != null, "setLocalDocumentsView() not called");
6364

6465
// Queries that match all document don't benefit from using IndexFreeQueries. It is more
@@ -69,8 +70,7 @@ public ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingQuery(
6970

7071
// Queries that have never seen a snapshot without limbo free documents should also be run as a
7172
// full collection scan.
72-
if (queryData == null
73-
|| queryData.getLastLimboFreeSnapshotVersion().equals(SnapshotVersion.NONE)) {
73+
if (lastLimboFreeSnapshotVersion.equals(SnapshotVersion.NONE)) {
7474
return executeFullCollectionScan(query);
7575
}
7676

@@ -79,23 +79,22 @@ public ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingQuery(
7979
ImmutableSortedSet<Document> previousResults = applyQuery(query, documents);
8080

8181
if (query.hasLimit()
82-
&& needsRefill(previousResults, remoteKeys, queryData.getLastLimboFreeSnapshotVersion())) {
82+
&& needsRefill(previousResults, remoteKeys, lastLimboFreeSnapshotVersion)) {
8383
return executeFullCollectionScan(query);
8484
}
8585

8686
if (Logger.isDebugEnabled()) {
8787
Logger.debug(
8888
LOG_TAG,
8989
"Re-using previous result from %s to execute query: %s",
90-
queryData.getLastLimboFreeSnapshotVersion().toString(),
90+
lastLimboFreeSnapshotVersion.toString(),
9191
query.toString());
9292
}
9393

9494
// Retrieve all results for documents that were updated since the last limbo-document free
9595
// remote snapshot.
9696
ImmutableSortedMap<DocumentKey, Document> updatedResults =
97-
localDocumentsView.getDocumentsMatchingQuery(
98-
query, queryData.getLastLimboFreeSnapshotVersion());
97+
localDocumentsView.getDocumentsMatchingQuery(query, lastLimboFreeSnapshotVersion);
9998

10099
// We merge `previousResults` into `updateResults`, since `updateResults` is already a
101100
// ImmutableSortedMap. If a document is contained in both lists, then its contents are the same.

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,9 @@ public void setLocalDocumentsView(LocalDocumentsView localDocuments) {
103103

104104
@Override
105105
public ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingQuery(
106-
Query query, @Nullable QueryData queryData, ImmutableSortedSet<DocumentKey> remoteKeys) {
106+
Query query,
107+
SnapshotVersion lastLimboFreeSnapshotVersion,
108+
ImmutableSortedSet<DocumentKey> remoteKeys) {
107109
hardAssert(localDocuments != null, "setLocalDocumentsView() not called");
108110

109111
return query.isDocumentQuery()

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

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -598,25 +598,29 @@ public void releaseQuery(Query query) {
598598
});
599599
}
600600

601-
/** Runs the given query against all the documents in the local store and returns the results. */
602-
public ImmutableSortedMap<DocumentKey, Document> executeQuery(Query query) {
601+
/**
602+
* Runs the specified query against the local store and returns the results, potentially taking
603+
* advantage of query data from previous executions (such as the set of remote keys).
604+
*
605+
* @param usePreviousResults Whether results from previous executions can be used to optimize this
606+
* query execution.
607+
*/
608+
public QueryResult executeQuery(Query query, boolean usePreviousResults) {
603609
QueryData queryData = getQueryData(query);
610+
SnapshotVersion lastLimboFreeSnapshotVersion = SnapshotVersion.NONE;
611+
ImmutableSortedSet<DocumentKey> remoteKeys = DocumentKey.emptyKeySet();
612+
604613
if (queryData != null) {
605-
ImmutableSortedSet<DocumentKey> remoteKeys =
606-
this.queryCache.getMatchingKeysForTargetId(queryData.getTargetId());
607-
return executeQuery(query, queryData, remoteKeys);
608-
} else {
609-
return executeQuery(query, null, DocumentKey.emptyKeySet());
614+
lastLimboFreeSnapshotVersion = queryData.getLastLimboFreeSnapshotVersion();
615+
remoteKeys = this.queryCache.getMatchingKeysForTargetId(queryData.getTargetId());
610616
}
611-
}
612617

613-
/**
614-
* Runs the given query against the local store and returns the results, potentially taking
615-
* advantage of the provided query data and the set of remote document keys.
616-
*/
617-
public ImmutableSortedMap<DocumentKey, Document> executeQuery(
618-
Query query, @Nullable QueryData queryData, ImmutableSortedSet<DocumentKey> remoteKeys) {
619-
return queryEngine.getDocumentsMatchingQuery(query, queryData, remoteKeys);
618+
ImmutableSortedMap<DocumentKey, Document> documents =
619+
queryEngine.getDocumentsMatchingQuery(
620+
query,
621+
usePreviousResults ? lastLimboFreeSnapshotVersion : SnapshotVersion.NONE,
622+
usePreviousResults ? remoteKeys : DocumentKey.emptyKeySet());
623+
return new QueryResult(documents, remoteKeys);
620624
}
621625

622626
/**

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414

1515
package com.google.firebase.firestore.local;
1616

17-
import androidx.annotation.Nullable;
1817
import com.google.firebase.database.collection.ImmutableSortedMap;
1918
import com.google.firebase.database.collection.ImmutableSortedSet;
2019
import com.google.firebase.firestore.core.Query;
2120
import com.google.firebase.firestore.model.Document;
2221
import com.google.firebase.firestore.model.DocumentKey;
2322
import com.google.firebase.firestore.model.MaybeDocument;
23+
import com.google.firebase.firestore.model.SnapshotVersion;
2424

2525
/**
2626
* Represents a query engine capable of performing queries over the local document cache. You must
@@ -33,7 +33,9 @@ public interface QueryEngine {
3333

3434
/** Returns all local documents matching the specified query. */
3535
ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingQuery(
36-
Query query, @Nullable QueryData queryData, ImmutableSortedSet<DocumentKey> remoteKeys);
36+
Query query,
37+
SnapshotVersion lastLimboFreeSnapshotVersion,
38+
ImmutableSortedSet<DocumentKey> remoteKeys);
3739

3840
/**
3941
* Notifies the query engine of a document change in case it would like to update indexes and the
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2019 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.firestore.local;
16+
17+
import com.google.firebase.database.collection.ImmutableSortedMap;
18+
import com.google.firebase.database.collection.ImmutableSortedSet;
19+
import com.google.firebase.firestore.model.Document;
20+
import com.google.firebase.firestore.model.DocumentKey;
21+
22+
/** The result of executing a query against the local store. */
23+
public class QueryResult {
24+
private final ImmutableSortedMap<DocumentKey, Document> documents;
25+
private final ImmutableSortedSet<DocumentKey> remoteKeys;
26+
27+
public QueryResult(
28+
ImmutableSortedMap<DocumentKey, Document> documents,
29+
ImmutableSortedSet<DocumentKey> remoteKeys) {
30+
this.documents = documents;
31+
this.remoteKeys = remoteKeys;
32+
}
33+
34+
public ImmutableSortedMap<DocumentKey, Document> getDocuments() {
35+
return documents;
36+
}
37+
38+
public ImmutableSortedSet<DocumentKey> getRemoteKeys() {
39+
return remoteKeys;
40+
}
41+
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
import static com.google.firebase.firestore.util.Assert.hardAssert;
1818

19-
import androidx.annotation.Nullable;
2019
import com.google.firebase.database.collection.ImmutableSortedMap;
2120
import com.google.firebase.database.collection.ImmutableSortedSet;
2221
import com.google.firebase.firestore.core.Query;
@@ -40,7 +39,9 @@ public void setLocalDocumentsView(LocalDocumentsView localDocuments) {
4039

4140
@Override
4241
public ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingQuery(
43-
Query query, @Nullable QueryData queryData, ImmutableSortedSet<DocumentKey> remoteKeys) {
42+
Query query,
43+
SnapshotVersion lastLimboFreeSnapshotVersion,
44+
ImmutableSortedSet<DocumentKey> remoteKeys) {
4445
hardAssert(localDocumentsView != null, "setLocalDocumentsView() not called");
4546

4647
// TODO: Once LocalDocumentsView provides a getCollectionDocuments() method, we

firebase-firestore/src/test/java/com/google/firebase/firestore/local/CountingQueryEngine.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ public void setLocalDocumentsView(LocalDocumentsView localDocuments) {
6464

6565
@Override
6666
public ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingQuery(
67-
Query query, @Nullable QueryData queryData, ImmutableSortedSet<DocumentKey> remoteKeys) {
68-
return queryEngine.getDocumentsMatchingQuery(query, queryData, remoteKeys);
67+
Query query,
68+
SnapshotVersion lastLimboFreeSnapshotVersion,
69+
ImmutableSortedSet<DocumentKey> remoteKeys) {
70+
return queryEngine.getDocumentsMatchingQuery(query, lastLimboFreeSnapshotVersion, remoteKeys);
6971
}
7072

7173
@Override

0 commit comments

Comments
 (0)