Skip to content

Commit 29bac5e

Browse files
Make View processing logic optional (#3561)
1 parent 1a82549 commit 29bac5e

File tree

12 files changed

+1253
-1030
lines changed

12 files changed

+1253
-1030
lines changed

packages/firestore/exp/dependencies.json

+252-282
Large diffs are not rendered by default.

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

+17-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ import {
2626
import { handleUserChange, LocalStore } from '../../../src/local/local_store';
2727
import { Deferred } from '../../../src/util/promise';
2828
import { logDebug } from '../../../src/util/log';
29-
import { SyncEngine } from '../../../src/core/sync_engine';
29+
import {
30+
SyncEngine,
31+
syncEngineListen,
32+
syncEngineUnlisten
33+
} from '../../../src/core/sync_engine';
3034
import { RemoteStore } from '../../../src/remote/remote_store';
3135
import { Persistence } from '../../../src/local/persistence';
3236
import { EventManager } from '../../../src/core/event_manager';
@@ -140,6 +144,9 @@ function verifyNotTerminated(firestore: Firestore): void {
140144
}
141145
}
142146

147+
// Note: These functions cannot be `async` since we want to throw an exception
148+
// when Firestore is terminated (via `getOnlineComponentProvider()`).
149+
143150
export function getSyncEngine(firestore: Firestore): Promise<SyncEngine> {
144151
return getOnlineComponentProvider(firestore).then(
145152
components => components.syncEngine
@@ -153,9 +160,15 @@ export function getRemoteStore(firestore: Firestore): Promise<RemoteStore> {
153160
}
154161

155162
export function getEventManager(firestore: Firestore): Promise<EventManager> {
156-
return getOnlineComponentProvider(firestore).then(
157-
components => components.eventManager
158-
);
163+
return getOnlineComponentProvider(firestore).then(components => {
164+
const eventManager = components.eventManager;
165+
eventManager.onListen = syncEngineListen.bind(null, components.syncEngine);
166+
eventManager.onUnlisten = syncEngineUnlisten.bind(
167+
null,
168+
components.syncEngine
169+
);
170+
return eventManager;
171+
});
159172
}
160173

161174
export function getPersistence(firestore: Firestore): Promise<Persistence> {

packages/firestore/exp/test/shim.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,8 @@ export class DocumentChange<T = legacy.DocumentData>
628628
readonly newIndex = this._delegate.oldIndex;
629629
}
630630

631-
export class CollectionReference<T = legacy.DocumentData> extends Query<T>
631+
export class CollectionReference<T = legacy.DocumentData>
632+
extends Query<T>
632633
implements legacy.CollectionReference<T> {
633634
constructor(
634635
firestore: FirebaseFirestore,

packages/firestore/src/api/blob.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ function assertBase64Available(): void {
4747

4848
/**
4949
* Immutable class holding a blob (binary data).
50-
* This class is directly exposed in the public API.
50+
*
51+
* This class is directly exposed in the public API. It extends the Bytes class
52+
* of the firestore-exp API to support `instanceof Bytes` checks during user
53+
* data conversion.
5154
*
5255
* Note that while you can't hide the constructor in JavaScript code, we are
5356
* using the hack above to make sure no-one outside this module can call it.

packages/firestore/src/core/component_provider.ts

+13-5
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ import {
2929
import {
3030
applyActiveTargetsChange,
3131
applyBatchState,
32+
applyOnlineStateChange,
3233
applyPrimaryState,
3334
applyTargetState,
3435
getActiveClients,
36+
handleCredentialChange,
3537
newSyncEngine,
3638
SyncEngine
3739
} from './sync_engine';
@@ -332,20 +334,26 @@ export class OnlineComponentProvider {
332334
this.syncEngine = this.createSyncEngine(cfg);
333335
this.eventManager = this.createEventManager(cfg);
334336

337+
this.syncEngine.subscribe(this.eventManager);
338+
335339
this.sharedClientState.onlineStateHandler = onlineState =>
336-
this.syncEngine.applyOnlineStateChange(
340+
applyOnlineStateChange(
341+
this.syncEngine,
337342
onlineState,
338343
OnlineStateSource.SharedClientState
339344
);
340345

341-
this.remoteStore.syncEngine = this.syncEngine;
346+
this.remoteStore.remoteSyncer.handleCredentialChange = handleCredentialChange.bind(
347+
null,
348+
this.syncEngine
349+
);
342350

343351
await this.remoteStore.start();
344352
await this.remoteStore.applyPrimaryState(this.syncEngine.isPrimaryClient);
345353
}
346354

347355
createEventManager(cfg: ComponentConfiguration): EventManager {
348-
return new EventManager(this.syncEngine);
356+
return new EventManager();
349357
}
350358

351359
createDatastore(cfg: ComponentConfiguration): Datastore {
@@ -360,7 +368,8 @@ export class OnlineComponentProvider {
360368
this.datastore,
361369
cfg.asyncQueue,
362370
onlineState =>
363-
this.syncEngine.applyOnlineStateChange(
371+
applyOnlineStateChange(
372+
this.syncEngine,
364373
onlineState,
365374
OnlineStateSource.RemoteStore
366375
),
@@ -372,7 +381,6 @@ export class OnlineComponentProvider {
372381
return newSyncEngine(
373382
this.localStore,
374383
this.remoteStore,
375-
this.datastore,
376384
this.sharedClientState,
377385
cfg.initialUser,
378386
cfg.maxConcurrentLimboResolutions,

packages/firestore/src/core/event_manager.ts

+13-6
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { debugAssert } from '../util/assert';
1919
import { EventHandler } from '../util/misc';
2020
import { ObjectMap } from '../util/obj_map';
2121
import { canonifyQuery, Query, queryEquals, stringifyQuery } from './query';
22-
import { SyncEngine, SyncEngineListener } from './sync_engine';
22+
import { SyncEngineListener } from './sync_engine';
2323
import { OnlineState } from './types';
2424
import { ChangeType, DocumentViewChange, ViewSnapshot } from './view_snapshot';
2525
import { wrapInUserErrorIfRecoverable } from '../util/async_queue';
@@ -45,6 +45,10 @@ export interface Observer<T> {
4545
* EventManager is responsible for mapping queries to query event emitters.
4646
* It handles "fan-out". -- Identical queries will re-use the same watch on the
4747
* backend.
48+
*
49+
* PORTING NOTE: On Web, EventManager `onListen` and `onUnlisten` need to be
50+
* assigned to SyncEngine's `listen()` and `unlisten()` API before usage. This
51+
* allows users to tree-shake the Watch logic.
4852
*/
4953
export class EventManager implements SyncEngineListener {
5054
private queries = new ObjectMap<Query, QueryListenersInfo>(
@@ -56,11 +60,13 @@ export class EventManager implements SyncEngineListener {
5660

5761
private snapshotsInSyncListeners: Set<Observer<void>> = new Set();
5862

59-
constructor(private syncEngine: SyncEngine) {
60-
this.syncEngine.subscribe(this);
61-
}
63+
/** Callback invoked when a Query is first listen to. */
64+
onListen?: (query: Query) => Promise<ViewSnapshot>;
65+
/** Callback invoked once all listeners to a Query are removed. */
66+
onUnlisten?: (query: Query) => Promise<void>;
6267

6368
async listen(listener: QueryListener): Promise<void> {
69+
debugAssert(!!this.onListen, 'onListen not set');
6470
const query = listener.query;
6571
let firstListen = false;
6672

@@ -72,7 +78,7 @@ export class EventManager implements SyncEngineListener {
7278

7379
if (firstListen) {
7480
try {
75-
queryInfo.viewSnap = await this.syncEngine.listen(query);
81+
queryInfo.viewSnap = await this.onListen(query);
7682
} catch (e) {
7783
const firestoreError = wrapInUserErrorIfRecoverable(
7884
e,
@@ -102,6 +108,7 @@ export class EventManager implements SyncEngineListener {
102108
}
103109

104110
async unlisten(listener: QueryListener): Promise<void> {
111+
debugAssert(!!this.onUnlisten, 'onUnlisten not set');
105112
const query = listener.query;
106113
let lastListen = false;
107114

@@ -116,7 +123,7 @@ export class EventManager implements SyncEngineListener {
116123

117124
if (lastListen) {
118125
this.queries.delete(query);
119-
return this.syncEngine.unlisten(query);
126+
return this.onUnlisten(query);
120127
}
121128
}
122129

packages/firestore/src/core/firestore_client.ts

+20-9
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,13 @@ import {
3939
Observer,
4040
QueryListener
4141
} from './event_manager';
42-
import { SyncEngine } from './sync_engine';
42+
import {
43+
registerPendingWritesCallback,
44+
SyncEngine,
45+
syncEngineListen,
46+
syncEngineUnlisten,
47+
syncEngineWrite
48+
} from './sync_engine';
4349
import { View } from './view';
4450
import { SharedClientState } from '../local/shared_client_state';
4551
import { AutoId } from '../util/misc';
@@ -277,6 +283,9 @@ export class FirestoreClient {
277283
this.syncEngine = onlineComponentProvider.syncEngine;
278284
this.eventMgr = onlineComponentProvider.eventManager;
279285

286+
this.eventMgr.onListen = syncEngineListen.bind(null, this.syncEngine);
287+
this.eventMgr.onUnlisten = syncEngineUnlisten.bind(null, this.syncEngine);
288+
280289
// When a user calls clearPersistence() in one client, all other clients
281290
// need to be terminated to allow the delete to succeed.
282291
this.persistence.setDatabaseDeletedListener(async () => {
@@ -405,9 +414,9 @@ export class FirestoreClient {
405414
this.verifyNotTerminated();
406415

407416
const deferred = new Deferred<void>();
408-
this.asyncQueue.enqueueAndForget(() => {
409-
return this.syncEngine.registerPendingWritesCallback(deferred);
410-
});
417+
this.asyncQueue.enqueueAndForget(() =>
418+
registerPendingWritesCallback(this.syncEngine, deferred)
419+
);
411420
return deferred.promise;
412421
}
413422

@@ -480,7 +489,7 @@ export class FirestoreClient {
480489
this.verifyNotTerminated();
481490
const deferred = new Deferred<void>();
482491
this.asyncQueue.enqueueAndForget(() =>
483-
this.syncEngine.write(mutations, deferred)
492+
syncEngineWrite(this.syncEngine, mutations, deferred)
484493
);
485494
return deferred.promise;
486495
}
@@ -549,7 +558,9 @@ export function enqueueWrite(
549558
mutations: Mutation[]
550559
): Promise<void> {
551560
const deferred = new Deferred<void>();
552-
asyncQueue.enqueueAndForget(() => syncEngine.write(mutations, deferred));
561+
asyncQueue.enqueueAndForget(() =>
562+
syncEngineWrite(syncEngine, mutations, deferred)
563+
);
553564
return deferred.promise;
554565
}
555566

@@ -570,9 +581,9 @@ export function enqueueWaitForPendingWrites(
570581
syncEngine: SyncEngine
571582
): Promise<void> {
572583
const deferred = new Deferred<void>();
573-
asyncQueue.enqueueAndForget(() => {
574-
return syncEngine.registerPendingWritesCallback(deferred);
575-
});
584+
asyncQueue.enqueueAndForget(() =>
585+
registerPendingWritesCallback(syncEngine, deferred)
586+
);
576587
return deferred.promise;
577588
}
578589

0 commit comments

Comments
 (0)