Skip to content

Commit e52e401

Browse files
authored
Merge 1d5a4a6 into 15b96a9
2 parents 15b96a9 + 1d5a4a6 commit e52e401

File tree

12 files changed

+244
-55
lines changed

12 files changed

+244
-55
lines changed

packages/firestore/exp/src/api/database.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ import {
4646
indexedDbStoragePrefix
4747
} from '../../../src/local/indexeddb_persistence';
4848
import { LoadBundleTask } from '../../../src/api/bundle';
49-
import { Query } from '../../../lite';
5049
import {
5150
getLocalStore,
5251
getPersistence,
@@ -332,9 +331,17 @@ export function loadBundle(
332331
const firestoreImpl = cast(firestore, Firestore);
333332
const resultTask = new LoadBundleTask();
334333
// eslint-disable-next-line @typescript-eslint/no-floating-promises
335-
getSyncEngine(firestoreImpl).then(syncEngine =>
336-
enqueueLoadBundle(firestoreImpl._queue, syncEngine, bundleData, resultTask)
337-
);
334+
getSyncEngine(firestoreImpl).then(async syncEngine => {
335+
const databaseId = (await firestoreImpl._getConfiguration()).databaseInfo
336+
.databaseId;
337+
enqueueLoadBundle(
338+
databaseId,
339+
firestoreImpl._queue,
340+
syncEngine,
341+
bundleData,
342+
resultTask
343+
);
344+
});
338345

339346
return resultTask;
340347
}

packages/firestore/src/core/bundle.ts

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ import {
3535
saveNamedQuery
3636
} from '../local/local_store';
3737
import { SizedBundleElement } from '../util/bundle_reader';
38-
import { MaybeDocumentMap } from '../model/collections';
38+
import {
39+
documentKeySet,
40+
DocumentKeySet,
41+
MaybeDocumentMap
42+
} from '../model/collections';
3943
import { BundleMetadata } from '../protos/firestore_bundle_proto';
4044

4145
/**
@@ -79,7 +83,7 @@ export type BundledDocuments = BundledDocument[];
7983
* Helper to convert objects from bundles to model objects in the SDK.
8084
*/
8185
export class BundleConverter {
82-
constructor(private serializer: JsonProtoSerializer) {}
86+
constructor(private readonly serializer: JsonProtoSerializer) {}
8387

8488
toDocumentKey(name: string): DocumentKey {
8589
return fromName(this.serializer, name);
@@ -161,7 +165,8 @@ export class BundleLoader {
161165

162166
constructor(
163167
private metadata: bundleProto.BundleMetadata,
164-
private localStore: LocalStore
168+
private localStore: LocalStore,
169+
private serializer: JsonProtoSerializer
165170
) {
166171
this.progress = bundleInitialProgress(metadata);
167172
}
@@ -208,6 +213,28 @@ export class BundleLoader {
208213
return null;
209214
}
210215

216+
private getQueryDocumentMapping(
217+
documents: BundledDocuments
218+
): Map<string, DocumentKeySet> {
219+
const queryDocumentMap = new Map<string, DocumentKeySet>();
220+
const bundleConverter = new BundleConverter(this.serializer);
221+
for (const bundleDoc of documents) {
222+
if (bundleDoc.metadata.queries) {
223+
const documentKey = bundleConverter.toDocumentKey(
224+
bundleDoc.metadata.name!
225+
);
226+
for (const queryName of bundleDoc.metadata.queries) {
227+
const documentKeys = (
228+
queryDocumentMap.get(queryName) || documentKeySet()
229+
).add(documentKey);
230+
queryDocumentMap.set(queryName, documentKeys);
231+
}
232+
}
233+
}
234+
235+
return queryDocumentMap;
236+
}
237+
211238
/**
212239
* Update the progress to 'Success' and return the updated progress.
213240
*/
@@ -218,16 +245,18 @@ export class BundleLoader {
218245
'Bundled documents ends with a document metadata and missing document.'
219246
);
220247

221-
for (const q of this.queries) {
222-
await saveNamedQuery(this.localStore, q);
223-
}
224-
225-
const changedDocs = await applyBundleDocuments(
248+
const changedDocuments = await applyBundleDocuments(
226249
this.localStore,
227250
this.documents
228251
);
229252

253+
const queryDocumentMap = this.getQueryDocumentMapping(this.documents);
254+
255+
for (const q of this.queries) {
256+
await saveNamedQuery(this.localStore, q, queryDocumentMap.get(q.name!));
257+
}
258+
230259
this.progress.taskState = 'Success';
231-
return new BundleLoadResult({ ...this.progress }, changedDocs);
260+
return new BundleLoadResult({ ...this.progress }, changedDocuments);
232261
}
233262
}

packages/firestore/src/core/firestore_client.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,10 @@ import { TransactionRunner } from './transaction_runner';
5555
import { Datastore } from '../remote/datastore';
5656
import { BundleReader } from '../util/bundle_reader';
5757
import { LoadBundleTask } from '../api/bundle';
58-
import { newTextEncoder } from '../platform/serializer';
58+
import { newSerializer, newTextEncoder } from '../platform/serializer';
5959
import { toByteStreamReader } from '../platform/byte_stream_reader';
6060
import { NamedQuery } from './bundle';
61+
import { JsonProtoSerializer } from '../remote/serializer';
6162

6263
const LOG_TAG = 'FirestoreClient';
6364
export const MAX_CONCURRENT_LIMBO_RESOLUTIONS = 100;
@@ -537,7 +538,10 @@ export class FirestoreClient {
537538
): void {
538539
this.verifyNotTerminated();
539540

540-
const reader = createBundleReader(data);
541+
const reader = createBundleReader(
542+
data,
543+
newSerializer(this.databaseInfo.databaseId)
544+
);
541545
this.asyncQueue.enqueueAndForget(async () => {
542546
loadBundle(this.syncEngine, reader, resultTask);
543547
return resultTask.catch(e => {
@@ -798,24 +802,26 @@ export function enqueueExecuteQueryViaSnapshotListener(
798802
}
799803

800804
function createBundleReader(
801-
data: ReadableStream<Uint8Array> | ArrayBuffer | string
805+
data: ReadableStream<Uint8Array> | ArrayBuffer | string,
806+
serializer: JsonProtoSerializer
802807
): BundleReader {
803808
let content: ReadableStream<Uint8Array> | ArrayBuffer;
804809
if (typeof data === 'string') {
805810
content = newTextEncoder().encode(data);
806811
} else {
807812
content = data;
808813
}
809-
return new BundleReader(toByteStreamReader(content));
814+
return new BundleReader(toByteStreamReader(content), serializer);
810815
}
811816

812817
export function enqueueLoadBundle(
818+
databaseId: DatabaseId,
813819
asyncQueue: AsyncQueue,
814820
syncEngine: SyncEngine,
815821
data: ReadableStream<Uint8Array> | ArrayBuffer | string,
816822
resultTask: LoadBundleTask
817823
): void {
818-
const reader = createBundleReader(data);
824+
const reader = createBundleReader(data, newSerializer(databaseId));
819825
asyncQueue.enqueueAndForget(async () => {
820826
loadBundle(syncEngine, reader, resultTask);
821827
return resultTask.catch(e => {

packages/firestore/src/core/sync_engine.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1358,7 +1358,11 @@ async function loadBundleImpl(
13581358

13591359
task._updateProgress(bundleInitialProgress(metadata));
13601360

1361-
const loader = new BundleLoader(metadata, syncEngine.localStore);
1361+
const loader = new BundleLoader(
1362+
metadata,
1363+
syncEngine.localStore,
1364+
reader.serializer
1365+
);
13621366
let element = await reader.nextElement();
13631367
while (element) {
13641368
debugAssert(

packages/firestore/src/local/local_store.ts

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,7 +1373,8 @@ export function getNamedQuery(
13731373
*/
13741374
export async function saveNamedQuery(
13751375
localStore: LocalStore,
1376-
query: bundleProto.NamedQuery
1376+
query: bundleProto.NamedQuery,
1377+
documents: DocumentKeySet = documentKeySet()
13771378
): Promise<void> {
13781379
// Allocate a target for the named query such that it can be resumed
13791380
// from associated read time if users use it to listen.
@@ -1383,27 +1384,46 @@ export async function saveNamedQuery(
13831384
const allocated = await localStore.allocateTarget(
13841385
queryToTarget(fromBundledQuery(query.bundledQuery!))
13851386
);
1387+
13861388
const localStoreImpl = debugCast(localStore, LocalStoreImpl);
13871389
return localStoreImpl.persistence.runTransaction(
13881390
'Save named query',
13891391
'readwrite',
13901392
transaction => {
1391-
// Update allocated target's read time, if the bundle's read time is newer.
1392-
let updateReadTime = PersistencePromise.resolve();
13931393
const readTime = fromVersion(query.readTime!);
1394-
if (allocated.snapshotVersion.compareTo(readTime) < 0) {
1395-
const newTargetData = allocated.withResumeToken(
1396-
ByteString.EMPTY_BYTE_STRING,
1397-
readTime
1398-
);
1399-
updateReadTime = localStoreImpl.targetCache.updateTargetData(
1400-
transaction,
1401-
newTargetData
1402-
);
1394+
// Simply save the query itself if it is older than what the SDK already
1395+
// has.
1396+
if (allocated.snapshotVersion.compareTo(readTime) >= 0) {
1397+
return localStoreImpl.bundleCache.saveNamedQuery(transaction, query);
14031398
}
1404-
return updateReadTime.next(() =>
1405-
localStoreImpl.bundleCache.saveNamedQuery(transaction, query)
1399+
1400+
// Update existing target data because the query from the bundle is newer.
1401+
const newTargetData = allocated.withResumeToken(
1402+
ByteString.EMPTY_BYTE_STRING,
1403+
readTime
14061404
);
1405+
localStoreImpl.targetDataByTarget = localStoreImpl.targetDataByTarget.insert(
1406+
newTargetData.targetId,
1407+
newTargetData
1408+
);
1409+
return localStoreImpl.targetCache
1410+
.updateTargetData(transaction, newTargetData)
1411+
.next(() =>
1412+
localStoreImpl.targetCache.removeMatchingKeysForTargetId(
1413+
transaction,
1414+
allocated.targetId
1415+
)
1416+
)
1417+
.next(() =>
1418+
localStoreImpl.targetCache.addMatchingKeys(
1419+
transaction,
1420+
documents,
1421+
allocated.targetId
1422+
)
1423+
)
1424+
.next(() =>
1425+
localStoreImpl.bundleCache.saveNamedQuery(transaction, query)
1426+
);
14071427
}
14081428
);
14091429
}

packages/firestore/src/protos/firestore/bundle.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ message BundledDocumentMetadata {
7979

8080
// Whether the document exists.
8181
bool exists = 3;
82+
83+
// The names of the queries in this bundle that this document matches to.
84+
repeated string queries = 4;
8285
}
8386

8487
// Metadata describing the bundle file/stream.

packages/firestore/src/protos/firestore_bundle_proto.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ export interface BundledDocumentMetadata {
5454

5555
/** BundledDocumentMetadata exists */
5656
exists?: boolean | null;
57+
58+
/** The names of the queries in this bundle that this document matches to. */
59+
queries?: string[];
5760
}
5861

5962
/** Properties of a BundleMetadata. */

packages/firestore/src/util/bundle_reader.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { Deferred } from './promise';
2323
import { debugAssert } from './assert';
2424
import { toByteStreamReader } from '../platform/byte_stream_reader';
2525
import { newTextDecoder } from '../platform/serializer';
26+
import { JsonProtoSerializer } from '../remote/serializer';
2627

2728
/**
2829
* A complete element in the bundle stream, together with the byte length it
@@ -70,13 +71,20 @@ export class BundleReader {
7071
/** The decoder used to parse binary data into strings. */
7172
private textDecoder: TextDecoder;
7273

73-
static fromBundleSource(source: BundleSource): BundleReader {
74-
return new BundleReader(toByteStreamReader(source, BYTES_PER_READ));
74+
static fromBundleSource(
75+
source: BundleSource,
76+
serializer: JsonProtoSerializer
77+
): BundleReader {
78+
return new BundleReader(
79+
toByteStreamReader(source, BYTES_PER_READ),
80+
serializer
81+
);
7582
}
7683

7784
constructor(
7885
/** The reader to read from underlying binary bundle data source. */
79-
private reader: ReadableStreamReader<Uint8Array>
86+
private reader: ReadableStreamReader<Uint8Array>,
87+
readonly serializer: JsonProtoSerializer
8088
) {
8189
this.textDecoder = newTextDecoder();
8290
// Read the metadata (which is the first element).

0 commit comments

Comments
 (0)