@@ -28,10 +28,13 @@ import { debugAssert } from '../../../src/util/assert';
28
28
import { cast } from '../../../lite/src/api/util' ;
29
29
import { DocumentSnapshot , QuerySnapshot } from './snapshot' ;
30
30
import {
31
+ addDocSnapshotListener ,
32
+ addQuerySnapshotListener ,
31
33
applyFirestoreDataConverter ,
32
34
getDocsViaSnapshotListener ,
33
35
getDocViaSnapshotListener ,
34
- SnapshotMetadata
36
+ SnapshotMetadata ,
37
+ validateHasExplicitOrderByForLimitToLast
35
38
} from '../../../src/api/database' ;
36
39
import { ViewSnapshot } from '../../../src/core/view_snapshot' ;
37
40
import {
@@ -44,6 +47,14 @@ import {
44
47
import { Document } from '../../../src/model/document' ;
45
48
import { DeleteMutation , Precondition } from '../../../src/model/mutation' ;
46
49
import { FieldPath } from '../../../src/api/field_path' ;
50
+ import {
51
+ CompleteFn ,
52
+ ErrorFn ,
53
+ isPartialObserver ,
54
+ NextFn ,
55
+ PartialObserver ,
56
+ Unsubscribe
57
+ } from '../../../src/api/observer' ;
47
58
48
59
export function getDoc < T > (
49
60
reference : firestore . DocumentReference < T >
@@ -101,17 +112,14 @@ export function getQuery<T>(
101
112
) : Promise < QuerySnapshot < T > > {
102
113
const internalQuery = cast < Query < T > > ( query , Query ) ;
103
114
const firestore = cast < Firestore > ( query . firestore , Firestore ) ;
115
+
116
+ validateHasExplicitOrderByForLimitToLast ( internalQuery . _query ) ;
104
117
return firestore . _getFirestoreClient ( ) . then ( async firestoreClient => {
105
118
const snapshot = await getDocsViaSnapshotListener (
106
119
firestoreClient ,
107
120
internalQuery . _query
108
121
) ;
109
- return new QuerySnapshot (
110
- firestore ,
111
- internalQuery ,
112
- snapshot ,
113
- new SnapshotMetadata ( snapshot . hasPendingWrites , snapshot . fromCache )
114
- ) ;
122
+ return new QuerySnapshot ( firestore , internalQuery , snapshot ) ;
115
123
} ) ;
116
124
}
117
125
@@ -124,12 +132,7 @@ export function getQueryFromCache<T>(
124
132
const snapshot = await firestoreClient . getDocumentsFromLocalCache (
125
133
internalQuery . _query
126
134
) ;
127
- return new QuerySnapshot (
128
- firestore ,
129
- internalQuery ,
130
- snapshot ,
131
- new SnapshotMetadata ( snapshot . hasPendingWrites , /* fromCache= */ true )
132
- ) ;
135
+ return new QuerySnapshot ( firestore , internalQuery , snapshot ) ;
133
136
} ) ;
134
137
}
135
138
@@ -144,12 +147,7 @@ export function getQueryFromServer<T>(
144
147
internalQuery . _query ,
145
148
{ source : 'server' }
146
149
) ;
147
- return new QuerySnapshot (
148
- firestore ,
149
- internalQuery ,
150
- snapshot ,
151
- new SnapshotMetadata ( snapshot . hasPendingWrites , snapshot . fromCache )
152
- ) ;
150
+ return new QuerySnapshot ( firestore , internalQuery , snapshot ) ;
153
151
} ) ;
154
152
}
155
153
@@ -280,6 +278,159 @@ export function addDoc<T>(
280
278
. then ( ( ) => docRef ) ;
281
279
}
282
280
281
+ // TODO(firestorexp): Make sure these overloads are tested via the Firestore
282
+ // integration tests
283
+ export function onSnapshot < T > (
284
+ reference : firestore . DocumentReference < T > ,
285
+ observer : {
286
+ next ?: ( snapshot : firestore . DocumentSnapshot < T > ) => void ;
287
+ error ?: ( error : firestore . FirestoreError ) => void ;
288
+ complete ?: ( ) => void ;
289
+ }
290
+ ) : Unsubscribe ;
291
+ export function onSnapshot < T > (
292
+ reference : firestore . DocumentReference < T > ,
293
+ options : firestore . SnapshotListenOptions ,
294
+ observer : {
295
+ next ?: ( snapshot : firestore . DocumentSnapshot < T > ) => void ;
296
+ error ?: ( error : firestore . FirestoreError ) => void ;
297
+ complete ?: ( ) => void ;
298
+ }
299
+ ) : Unsubscribe ;
300
+ export function onSnapshot < T > (
301
+ reference : firestore . DocumentReference < T > ,
302
+ onNext : ( snapshot : firestore . DocumentSnapshot < T > ) => void ,
303
+ onError ?: ( error : firestore . FirestoreError ) => void ,
304
+ onCompletion ?: ( ) => void
305
+ ) : Unsubscribe ;
306
+ export function onSnapshot < T > (
307
+ reference : firestore . DocumentReference < T > ,
308
+ options : firestore . SnapshotListenOptions ,
309
+ onNext : ( snapshot : firestore . DocumentSnapshot < T > ) => void ,
310
+ onError ?: ( error : firestore . FirestoreError ) => void ,
311
+ onCompletion ?: ( ) => void
312
+ ) : Unsubscribe ;
313
+ export function onSnapshot < T > (
314
+ query : firestore . Query < T > ,
315
+ observer : {
316
+ next ?: ( snapshot : firestore . QuerySnapshot < T > ) => void ;
317
+ error ?: ( error : firestore . FirestoreError ) => void ;
318
+ complete ?: ( ) => void ;
319
+ }
320
+ ) : Unsubscribe ;
321
+ export function onSnapshot < T > (
322
+ query : firestore . Query < T > ,
323
+ options : firestore . SnapshotListenOptions ,
324
+ observer : {
325
+ next ?: ( snapshot : firestore . QuerySnapshot < T > ) => void ;
326
+ error ?: ( error : firestore . FirestoreError ) => void ;
327
+ complete ?: ( ) => void ;
328
+ }
329
+ ) : Unsubscribe ;
330
+ export function onSnapshot < T > (
331
+ query : firestore . Query < T > ,
332
+ onNext : ( snapshot : firestore . QuerySnapshot < T > ) => void ,
333
+ onError ?: ( error : firestore . FirestoreError ) => void ,
334
+ onCompletion ?: ( ) => void
335
+ ) : Unsubscribe ;
336
+ export function onSnapshot < T > (
337
+ query : firestore . Query < T > ,
338
+ options : firestore . SnapshotListenOptions ,
339
+ onNext : ( snapshot : firestore . QuerySnapshot < T > ) => void ,
340
+ onError ?: ( error : firestore . FirestoreError ) => void ,
341
+ onCompletion ?: ( ) => void
342
+ ) : Unsubscribe ;
343
+ export function onSnapshot < T > (
344
+ ref : firestore . Query < T > | firestore . DocumentReference < T > ,
345
+ ...args : unknown [ ]
346
+ ) : Unsubscribe {
347
+ let options : firestore . SnapshotListenOptions = {
348
+ includeMetadataChanges : false
349
+ } ;
350
+ let currArg = 0 ;
351
+ if ( typeof args [ currArg ] === 'object' && ! isPartialObserver ( args [ currArg ] ) ) {
352
+ options = args [ currArg ] as firestore . SnapshotListenOptions ;
353
+ currArg ++ ;
354
+ }
355
+
356
+ const internalOptions = {
357
+ includeMetadataChanges : options . includeMetadataChanges
358
+ } ;
359
+
360
+ if ( isPartialObserver ( args [ currArg ] ) ) {
361
+ const userObserver = args [ currArg ] as PartialObserver <
362
+ firestore . QuerySnapshot < T >
363
+ > ;
364
+ args [ currArg ] = userObserver . next ?. bind ( userObserver ) ;
365
+ args [ currArg + 1 ] = userObserver . error ?. bind ( userObserver ) ;
366
+ args [ currArg + 2 ] = userObserver . complete ?. bind ( userObserver ) ;
367
+ }
368
+
369
+ let asyncObserver : Promise < Unsubscribe > ;
370
+
371
+ if ( ref instanceof DocumentReference ) {
372
+ const firestore = cast ( ref . firestore , Firestore ) ;
373
+
374
+ const observer : PartialObserver < ViewSnapshot > = {
375
+ next : snapshot => {
376
+ if ( args [ currArg ] ) {
377
+ ( args [ currArg ] as NextFn < firestore . DocumentSnapshot < T > > ) (
378
+ convertToDocSnapshot ( firestore , ref , snapshot )
379
+ ) ;
380
+ }
381
+ } ,
382
+ error : args [ currArg + 1 ] as ErrorFn ,
383
+ complete : args [ currArg + 2 ] as CompleteFn
384
+ } ;
385
+
386
+ asyncObserver = firestore
387
+ . _getFirestoreClient ( )
388
+ . then ( firestoreClient =>
389
+ addDocSnapshotListener (
390
+ firestoreClient ,
391
+ ref . _key ,
392
+ internalOptions ,
393
+ observer
394
+ )
395
+ ) ;
396
+ } else {
397
+ const query = cast < Query < T > > ( ref , Query ) ;
398
+ const firestore = cast ( query , Firestore ) ;
399
+
400
+ const observer : PartialObserver < ViewSnapshot > = {
401
+ next : snapshot => {
402
+ if ( args [ currArg ] ) {
403
+ ( args [ currArg ] as NextFn < firestore . QuerySnapshot < T > > ) (
404
+ new QuerySnapshot ( firestore , query , snapshot )
405
+ ) ;
406
+ }
407
+ } ,
408
+ error : args [ currArg + 1 ] as ErrorFn ,
409
+ complete : args [ currArg + 2 ] as CompleteFn
410
+ } ;
411
+
412
+ validateHasExplicitOrderByForLimitToLast ( query . _query ) ;
413
+
414
+ asyncObserver = firestore
415
+ . _getFirestoreClient ( )
416
+ . then ( firestoreClient =>
417
+ addQuerySnapshotListener (
418
+ firestoreClient ,
419
+ query . _query ,
420
+ internalOptions ,
421
+ observer
422
+ )
423
+ ) ;
424
+ }
425
+
426
+ // TODO(firestorexp): Add test that verifies that we don't raise a snapshot if
427
+ // unsubscribe is called before `asyncObserver` resolves.
428
+ return ( ) => {
429
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
430
+ asyncObserver . then ( unsubscribe => unsubscribe ( ) ) ;
431
+ } ;
432
+ }
433
+
283
434
/**
284
435
* Converts a ViewSnapshot that contains the single document specified by `ref`
285
436
* to a DocumentSnapshot.
0 commit comments