Skip to content

Commit 9417675

Browse files
Port QueryEngine (#6153)
1 parent b538312 commit 9417675

18 files changed

+537
-136
lines changed

packages/firestore/src/core/query.ts

+2-11
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import { compareDocumentsByField, Document } from '../model/document';
1919
import { DocumentKey } from '../model/document_key';
2020
import { FieldPath, ResourcePath } from '../model/path';
2121
import { debugAssert, debugCast, fail } from '../util/assert';
22-
import { isNullOrUndefined } from '../util/types';
2322

2423
import {
2524
Bound,
@@ -155,7 +154,7 @@ export function asCollectionQueryAtPath(
155154
* Returns true if this query does not specify any query constraints that
156155
* could remove results.
157156
*/
158-
export function matchesAllDocuments(query: Query): boolean {
157+
export function queryMatchesAllDocuments(query: Query): boolean {
159158
return (
160159
query.filters.length === 0 &&
161160
query.limit === null &&
@@ -167,14 +166,6 @@ export function matchesAllDocuments(query: Query): boolean {
167166
);
168167
}
169168

170-
export function hasLimitToFirst(query: Query): boolean {
171-
return !isNullOrUndefined(query.limit) && query.limitType === LimitType.First;
172-
}
173-
174-
export function hasLimitToLast(query: Query): boolean {
175-
return !isNullOrUndefined(query.limit) && query.limitType === LimitType.Last;
176-
}
177-
178169
export function getFirstOrderByField(query: Query): FieldPath | null {
179170
return query.explicitOrderBy.length > 0
180171
? query.explicitOrderBy[0].field
@@ -393,7 +384,7 @@ export function queryWithAddedOrderBy(query: Query, orderBy: OrderBy): Query {
393384

394385
export function queryWithLimit(
395386
query: Query,
396-
limit: number,
387+
limit: number | null,
397388
limitType: LimitType
398389
): Query {
399390
return new QueryImpl(

packages/firestore/src/core/view.ts

+10-13
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,7 @@ import { DocumentSet } from '../model/document_set';
2727
import { TargetChange } from '../remote/remote_event';
2828
import { debugAssert, fail } from '../util/assert';
2929

30-
import {
31-
hasLimitToFirst,
32-
hasLimitToLast,
33-
newQueryComparator,
34-
Query,
35-
queryMatches
36-
} from './query';
30+
import { LimitType, newQueryComparator, Query, queryMatches } from './query';
3731
import { OnlineState } from './types';
3832
import {
3933
ChangeType,
@@ -146,11 +140,13 @@ export class View {
146140
// Note that this should never get used in a refill (when previousChanges is
147141
// set), because there will only be adds -- no deletes or updates.
148142
const lastDocInLimit =
149-
hasLimitToFirst(this.query) && oldDocumentSet.size === this.query.limit
143+
this.query.limitType === LimitType.First &&
144+
oldDocumentSet.size === this.query.limit
150145
? oldDocumentSet.last()
151146
: null;
152147
const firstDocInLimit =
153-
hasLimitToLast(this.query) && oldDocumentSet.size === this.query.limit
148+
this.query.limitType === LimitType.Last &&
149+
oldDocumentSet.size === this.query.limit
154150
? oldDocumentSet.first()
155151
: null;
156152

@@ -228,11 +224,12 @@ export class View {
228224
});
229225

230226
// Drop documents out to meet limit/limitToLast requirement.
231-
if (hasLimitToFirst(this.query) || hasLimitToLast(this.query)) {
227+
if (this.query.limit !== null) {
232228
while (newDocumentSet.size > this.query.limit!) {
233-
const oldDoc = hasLimitToFirst(this.query)
234-
? newDocumentSet.last()
235-
: newDocumentSet.first();
229+
const oldDoc =
230+
this.query.limitType === LimitType.First
231+
? newDocumentSet.last()
232+
: newDocumentSet.first();
236233
newDocumentSet = newDocumentSet.delete(oldDoc!.key);
237234
newMutatedKeys = newMutatedKeys.delete(oldDoc!.key);
238235
changeSet.track({ type: ChangeType.Removed, doc: oldDoc! });

packages/firestore/src/lite-api/query.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import {
2222
findFilterOperator,
2323
getFirstOrderByField,
2424
getInequalityFilterField,
25-
hasLimitToLast,
2625
isCollectionGroupQuery,
2726
LimitType,
2827
Query as InternalQuery,
@@ -66,7 +65,10 @@ import {
6665
export function validateHasExplicitOrderByForLimitToLast(
6766
query: InternalQuery
6867
): void {
69-
if (hasLimitToLast(query) && query.explicitOrderBy.length === 0) {
68+
if (
69+
query.limitType === LimitType.Last &&
70+
query.explicitOrderBy.length === 0
71+
) {
7072
throw new FirestoreError(
7173
Code.UNIMPLEMENTED,
7274
'limitToLast() queries require specifying at least one orderBy() clause'

packages/firestore/src/lite-api/reference_impl.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {
2121
} from '@firebase/firestore-types';
2222
import { getModularInstance } from '@firebase/util';
2323

24-
import { hasLimitToLast } from '../core/query';
24+
import { LimitType } from '../core/query';
2525
import { DeleteMutation, Precondition } from '../model/mutation';
2626
import {
2727
invokeBatchGetDocumentsRpc,
@@ -172,7 +172,7 @@ export function getDocs<T>(query: Query<T>): Promise<QuerySnapshot<T>> {
172172
)
173173
);
174174

175-
if (hasLimitToLast(query._query)) {
175+
if (query._query.limitType === LimitType.Last) {
176176
// Limit to last queries reverse the orderBy constraint that was
177177
// specified by the user. As such, we need to reverse the order of the
178178
// results to return the documents in the expected order.

packages/firestore/src/local/index_manager.ts

+9
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,13 @@ export interface IndexManager {
155155
transaction: PersistenceTransaction,
156156
documents: DocumentMap
157157
): PersistencePromise<void>;
158+
159+
/**
160+
* Iterates over all field indexes that are used to serve the given target,
161+
* and returns the minimum offset of them all.
162+
*/
163+
getMinOffset(
164+
transaction: PersistenceTransaction,
165+
target: Target
166+
): PersistencePromise<IndexOffset>;
158167
}

packages/firestore/src/local/indexeddb_index_manager.ts

+38-8
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
fieldIndexToString,
4545
IndexKind,
4646
IndexOffset,
47+
indexOffsetComparator,
4748
IndexSegment
4849
} from '../model/field_index';
4950
import { FieldPath, ResourcePath } from '../model/path';
@@ -462,15 +463,22 @@ export class IndexedDbIndexManager implements IndexManager {
462463
transaction: PersistenceTransaction,
463464
target: Target
464465
): PersistencePromise<IndexType> {
465-
// TODO(orqueries): We should look at the subtargets here
466-
return this.getFieldIndex(transaction, target).next(index => {
467-
if (!index) {
468-
return IndexType.NONE as IndexType;
466+
let indexType = IndexType.FULL;
467+
return PersistencePromise.forEach(
468+
this.getSubTargets(target),
469+
(target: Target) => {
470+
return this.getFieldIndex(transaction, target).next(index => {
471+
if (!index) {
472+
indexType = IndexType.NONE;
473+
} else if (
474+
indexType !== IndexType.NONE &&
475+
index.fields.length < targetGetSegmentCount(target)
476+
) {
477+
indexType = IndexType.PARTIAL;
478+
}
479+
});
469480
}
470-
return index.fields.length < targetGetSegmentCount(target)
471-
? IndexType.PARTIAL
472-
: IndexType.FULL;
473-
});
481+
).next(() => indexType);
474482
}
475483

476484
/**
@@ -965,6 +973,28 @@ export class IndexedDbIndexManager implements IndexManager {
965973
}
966974
return ranges;
967975
}
976+
977+
getMinOffset(
978+
transaction: PersistenceTransaction,
979+
target: Target
980+
): PersistencePromise<IndexOffset> {
981+
let offset: IndexOffset | undefined;
982+
return PersistencePromise.forEach(
983+
this.getSubTargets(target),
984+
(target: Target) => {
985+
return this.getFieldIndex(transaction, target).next(index => {
986+
if (!index) {
987+
offset = IndexOffset.min();
988+
} else if (
989+
!offset ||
990+
indexOffsetComparator(index.indexState.offset, offset) < 0
991+
) {
992+
offset = index.indexState.offset;
993+
}
994+
});
995+
}
996+
).next(() => offset!);
997+
}
968998
}
969999

9701000
/**

packages/firestore/src/local/indexeddb_schema.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { EncodedResourcePath } from './encoded_resource_path';
2929
import { DbTimestampKey } from './indexeddb_sentinels';
3030

3131
// TODO(indexing): Remove this constant
32-
const INDEXING_ENABLED = false;
32+
export const INDEXING_ENABLED = false;
3333

3434
export const INDEXING_SCHEMA_VERSION = 14;
3535

packages/firestore/src/local/local_documents_view.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export class LocalDocumentsView {
5252
constructor(
5353
readonly remoteDocumentCache: RemoteDocumentCache,
5454
readonly mutationQueue: MutationQueue,
55-
readonly indexManager: IndexManager
55+
private readonly indexManager: IndexManager
5656
) {}
5757

5858
/**

packages/firestore/src/local/local_store_impl.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ class LocalStoreImpl implements LocalStore {
203203
this.indexManager
204204
);
205205
this.remoteDocuments.setIndexManager(this.indexManager);
206-
this.queryEngine.setLocalDocumentsView(this.localDocuments);
206+
this.queryEngine.initialize(this.localDocuments, this.indexManager);
207207
}
208208

209209
collectGarbage(garbageCollector: LruGarbageCollector): Promise<LruResults> {

packages/firestore/src/local/memory_index_manager.ts

+7
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ export class MemoryIndexManager implements IndexManager {
9797
return PersistencePromise.resolve<string | null>(null);
9898
}
9999

100+
getMinOffset(
101+
transaction: PersistenceTransaction,
102+
target: Target
103+
): PersistencePromise<IndexOffset> {
104+
return PersistencePromise.resolve(IndexOffset.min());
105+
}
106+
100107
updateCollectionGroup(
101108
transaction: PersistenceTransaction,
102109
collectionGroup: string,

0 commit comments

Comments
 (0)