Skip to content

Commit 60bcfa6

Browse files
author
Brian Chen
committed
michael's comments resolved, need spec tests
1 parent beb7267 commit 60bcfa6

File tree

4 files changed

+47
-44
lines changed

4 files changed

+47
-44
lines changed

packages/firestore/src/api/database.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ export class Firestore implements firestore.FirebaseFirestore, FirebaseService {
511511
next: onSync
512512
};
513513
const errHandler = (err: Error): void => {
514-
console.error('Uncaught Error in onSnapshotsInSync:', err);
514+
throw fail('Uncaught Error in onSnapshotsInSync');
515515
};
516516
const asyncObserver = new AsyncObserver<void>({
517517
next: () => {

packages/firestore/src/core/event_manager.ts

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import { Query } from './query';
2222
import { SyncEngine, SyncEngineListener } from './sync_engine';
2323
import { OnlineState, TargetId } from './types';
2424
import { DocumentViewChange, ChangeType, ViewSnapshot } from './view_snapshot';
25-
import { AsyncObserver } from '../util/async_observer';
2625

2726
/**
2827
* Holds the listeners and the last received ViewSnapshot for a query being
@@ -54,7 +53,7 @@ export class EventManager implements SyncEngineListener {
5453

5554
private onlineState: OnlineState = OnlineState.Unknown;
5655

57-
private snapshotsInSyncListeners: Set<AsyncObserver<void>> = new Set();
56+
private snapshotsInSyncListeners: Set<Observer<void>> = new Set();
5857

5958
constructor(private syncEngine: SyncEngine) {
6059
this.syncEngine.subscribe(this);
@@ -73,12 +72,17 @@ export class EventManager implements SyncEngineListener {
7372
queryInfo.listeners.push(listener);
7473

7574
// Run global snapshot listeners if a consistent snapshot has been emitted.
76-
if (listener.applyOnlineStateChange(this.onlineState)) {
77-
this.runSnapshotsInSyncListeners();
78-
}
75+
const raisedEvent = listener.applyOnlineStateChange(this.onlineState);
76+
assert(
77+
!raisedEvent,
78+
"applyOnlineStateChange() shouldn't raise an event for brand-new listeners."
79+
);
7980

80-
if (queryInfo.viewSnap && listener.onViewSnapshot(queryInfo.viewSnap)) {
81-
this.runSnapshotsInSyncListeners();
81+
if (queryInfo.viewSnap) {
82+
const raisedEvent = listener.onViewSnapshot(queryInfo.viewSnap);
83+
if (raisedEvent) {
84+
this.raiseSnapshotsInSyncEvent();
85+
}
8286
}
8387

8488
if (firstListen) {
@@ -111,22 +115,21 @@ export class EventManager implements SyncEngineListener {
111115
}
112116

113117
onWatchChange(viewSnaps: ViewSnapshot[]): void {
114-
let shouldRunInSyncListeners = false;
118+
let raisedEvent = false;
115119
for (const viewSnap of viewSnaps) {
116120
const query = viewSnap.query;
117121
const queryInfo = this.queries.get(query);
118122
if (queryInfo) {
119123
for (const listener of queryInfo.listeners) {
120124
if (listener.onViewSnapshot(viewSnap)) {
121-
shouldRunInSyncListeners = true;
125+
raisedEvent = true;
122126
}
123127
}
124128
queryInfo.viewSnap = viewSnap;
125129
}
126130
}
127-
if (shouldRunInSyncListeners) {
128-
// Run global snapshot listeners if a consistent snapshot has been emitted.
129-
this.runSnapshotsInSyncListeners();
131+
if (raisedEvent) {
132+
this.raiseSnapshotsInSyncEvent();
130133
}
131134
}
132135

@@ -145,34 +148,34 @@ export class EventManager implements SyncEngineListener {
145148

146149
onOnlineStateChange(onlineState: OnlineState): void {
147150
this.onlineState = onlineState;
148-
let shouldRunInSyncListeners = false;
151+
let raisedEvent = false;
149152
this.queries.forEach((_, queryInfo) => {
150153
for (const listener of queryInfo.listeners) {
151154
// Run global snapshot listeners if a consistent snapshot has been emitted.
152155
if (listener.applyOnlineStateChange(onlineState)) {
153-
shouldRunInSyncListeners = true;
156+
raisedEvent = true;
154157
}
155158
}
156159
});
157-
if (shouldRunInSyncListeners) {
158-
this.runSnapshotsInSyncListeners();
160+
if (raisedEvent) {
161+
this.raiseSnapshotsInSyncEvent();
159162
}
160163
}
161164

162-
hasQueries(): boolean {
163-
return !this.queries.isEmpty();
164-
}
165-
166-
addSnapshotsInSyncListener(asyncObserver: AsyncObserver<void>): void {
167-
this.snapshotsInSyncListeners.add(asyncObserver);
165+
addSnapshotsInSyncListener(observer: Observer<void>): void {
166+
// If there are no active query listeners, run the callback immediately.
167+
if (this.queries.isEmpty()) {
168+
observer.next();
169+
}
170+
this.snapshotsInSyncListeners.add(observer);
168171
}
169172

170-
removeSnapshotsInSyncListener(asyncObserver: AsyncObserver<void>): void {
171-
this.snapshotsInSyncListeners.delete(asyncObserver);
173+
removeSnapshotsInSyncListener(observer: Observer<void>): void {
174+
this.snapshotsInSyncListeners.delete(observer);
172175
}
173176

174177
// Call all global snapshot listeners that have been set.
175-
private runSnapshotsInSyncListeners(): void {
178+
private raiseSnapshotsInSyncEvent(): void {
176179
this.snapshotsInSyncListeners.forEach(observer => {
177180
observer.next();
178181
});
@@ -217,7 +220,12 @@ export class QueryListener {
217220
this.options = options || {};
218221
}
219222

220-
/** Processes the ViewSnapshots and returns whether a snapshot was raised. */
223+
/**
224+
* Applies the new ViewSnapshot to this listener, raising a user-facing event
225+
* if applicable (depending on what changed, whether the user has opted into
226+
* metadata-only changes, etc.). Returns true if a user-facing event was
227+
* indeed raised.
228+
*/
221229
onViewSnapshot(snap: ViewSnapshot): boolean {
222230
assert(
223231
snap.docChanges.length > 0 || snap.syncStateChanged,
@@ -243,19 +251,19 @@ export class QueryListener {
243251
/* excludesMetadataChanges= */ true
244252
);
245253
}
246-
let didRaiseSnapshot = false;
254+
let raisedEvent = false;
247255
if (!this.raisedInitialEvent) {
248256
if (this.shouldRaiseInitialEvent(snap, this.onlineState)) {
249257
this.raiseInitialEvent(snap);
250-
didRaiseSnapshot = true;
258+
raisedEvent = true;
251259
}
252260
} else if (this.shouldRaiseEvent(snap)) {
253261
this.queryObserver.next(snap);
254-
didRaiseSnapshot = true;
262+
raisedEvent = true;
255263
}
256264

257265
this.snap = snap;
258-
return didRaiseSnapshot;
266+
return raisedEvent;
259267
}
260268

261269
onError(error: Error): void {
@@ -265,16 +273,16 @@ export class QueryListener {
265273
/** Returns whether a snapshot was raised. */
266274
applyOnlineStateChange(onlineState: OnlineState): boolean {
267275
this.onlineState = onlineState;
268-
let didRaiseSnapshot = false;
276+
let raisedEvent = false;
269277
if (
270278
this.snap &&
271279
!this.raisedInitialEvent &&
272280
this.shouldRaiseInitialEvent(this.snap, onlineState)
273281
) {
274282
this.raiseInitialEvent(this.snap);
275-
didRaiseSnapshot = true;
283+
raisedEvent = true;
276284
}
277-
return didRaiseSnapshot;
285+
return raisedEvent;
278286
}
279287

280288
private shouldRaiseInitialEvent(

packages/firestore/src/core/firestore_client.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ import { Query } from './query';
6262
import { Transaction } from './transaction';
6363
import { OnlineState, OnlineStateSource } from './types';
6464
import { ViewSnapshot } from './view_snapshot';
65-
import { AsyncObserver } from '../util/async_observer';
6665

6766
const LOG_TAG = 'FirestoreClient';
6867

@@ -618,26 +617,21 @@ export class FirestoreClient {
618617
return this.databaseInfo.databaseId;
619618
}
620619

621-
addSnapshotsInSyncListener(asyncObserver: AsyncObserver<void>): void {
620+
addSnapshotsInSyncListener(observer: Observer<void>): void {
622621
this.verifyNotShutdown();
623622
this.asyncQueue.enqueueAndForget(() => {
624-
// If there are no active query listeners, run the callback immediately.
625-
if (!this.eventMgr.hasQueries()) {
626-
asyncObserver.next();
627-
}
628-
this.eventMgr.addSnapshotsInSyncListener(asyncObserver);
623+
this.eventMgr.addSnapshotsInSyncListener(observer);
629624
return Promise.resolve();
630625
});
631626
}
632627

633-
removeSnapshotsInSyncListener(asyncObserver: AsyncObserver<void>): void {
628+
removeSnapshotsInSyncListener(observer: Observer<void>): void {
634629
// Checks for shutdown but does not raise error, allowing remove after
635630
// shutdown to be a no-op.
636631
if (this.clientShutdown) {
637632
return;
638633
}
639-
this.eventMgr.removeSnapshotsInSyncListener(asyncObserver);
640-
return;
634+
this.eventMgr.removeSnapshotsInSyncListener(observer);
641635
}
642636

643637
get clientShutdown(): boolean {

packages/firestore/test/integration/util/helpers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ export function waitForPendingWrites(
370370
return (db as any)._waitForPendingWrites();
371371
}
372372

373+
// TODO(b/139890752): Remove helper and use public API once this is launched.
373374
export function onSnapshotsInSync(
374375
db: firestore.FirebaseFirestore,
375376
onSync: () => void

0 commit comments

Comments
 (0)