@@ -877,7 +877,7 @@ export class DocumentReference implements firestore.DocumentReference {
877877 observer : PartialObserver < firestore . DocumentSnapshot >
878878 ) : Unsubscribe ;
879879 onSnapshot (
880- options : firestore . DocumentListenOptions ,
880+ options : firestore . SnapshotListenOptions ,
881881 observer : PartialObserver < firestore . DocumentSnapshot >
882882 ) : Unsubscribe ;
883883 onSnapshot (
@@ -886,7 +886,7 @@ export class DocumentReference implements firestore.DocumentReference {
886886 onCompletion ?: CompleteFn
887887 ) : Unsubscribe ;
888888 onSnapshot (
889- options : firestore . DocumentListenOptions ,
889+ options : firestore . SnapshotListenOptions ,
890890 onNext : NextFn < firestore . DocumentSnapshot > ,
891891 onError ?: ErrorFn ,
892892 onCompletion ?: CompleteFn
@@ -899,7 +899,7 @@ export class DocumentReference implements firestore.DocumentReference {
899899 1 ,
900900 4
901901 ) ;
902- let options : firestore . DocumentListenOptions = {
902+ let options : firestore . SnapshotListenOptions = {
903903 includeMetadataChanges : false
904904 } ;
905905 let observer : PartialObserver < firestore . DocumentSnapshot > ;
@@ -908,7 +908,7 @@ export class DocumentReference implements firestore.DocumentReference {
908908 typeof args [ currArg ] === 'object' &&
909909 ! isPartialObserver ( args [ currArg ] )
910910 ) {
911- options = args [ currArg ] as firestore . DocumentListenOptions ;
911+ options = args [ currArg ] as firestore . SnapshotListenOptions ;
912912 validateOptionNames ( 'DocumentReference.onSnapshot' , options , [
913913 'includeMetadataChanges'
914914 ] ) ;
@@ -922,8 +922,7 @@ export class DocumentReference implements firestore.DocumentReference {
922922 }
923923
924924 const internalOptions = {
925- includeDocumentMetadataChanges : options . includeMetadataChanges ,
926- includeQueryMetadataChanges : options . includeMetadataChanges
925+ includeMetadataChanges : options . includeMetadataChanges
927926 } ;
928927
929928 if ( isPartialObserver ( args [ currArg ] ) ) {
@@ -1041,8 +1040,7 @@ export class DocumentReference implements firestore.DocumentReference {
10411040 ) : void {
10421041 const unlisten = this . onSnapshotInternal (
10431042 {
1044- includeQueryMetadataChanges : true ,
1045- includeDocumentMetadataChanges : true ,
1043+ includeMetadataChanges : true ,
10461044 waitForSyncWhenOnline : true
10471045 } ,
10481046 {
@@ -1566,7 +1564,7 @@ export class Query implements firestore.Query {
15661564
15671565 onSnapshot ( observer : PartialObserver < firestore . QuerySnapshot > ) : Unsubscribe ;
15681566 onSnapshot (
1569- options : firestore . QueryListenOptions ,
1567+ options : firestore . SnapshotListenOptions ,
15701568 observer : PartialObserver < firestore . QuerySnapshot >
15711569 ) : Unsubscribe ;
15721570 onSnapshot (
@@ -1575,37 +1573,30 @@ export class Query implements firestore.Query {
15751573 onCompletion ?: CompleteFn
15761574 ) : Unsubscribe ;
15771575 onSnapshot (
1578- options : firestore . QueryListenOptions ,
1576+ options : firestore . SnapshotListenOptions ,
15791577 onNext : NextFn < firestore . QuerySnapshot > ,
15801578 onError ?: ErrorFn ,
15811579 onCompletion ?: CompleteFn
15821580 ) : Unsubscribe ;
15831581
15841582 onSnapshot ( ...args : AnyJs [ ] ) : Unsubscribe {
15851583 validateBetweenNumberOfArgs ( 'Query.onSnapshot' , arguments , 1 , 4 ) ;
1586- let options : firestore . QueryListenOptions = { } ;
1584+ let options : firestore . SnapshotListenOptions = { } ;
15871585 let observer : PartialObserver < firestore . QuerySnapshot > ;
15881586 let currArg = 0 ;
15891587 if (
15901588 typeof args [ currArg ] === 'object' &&
15911589 ! isPartialObserver ( args [ currArg ] )
15921590 ) {
1593- options = args [ currArg ] as firestore . QueryListenOptions ;
1591+ options = args [ currArg ] as firestore . SnapshotListenOptions ;
15941592 validateOptionNames ( 'Query.onSnapshot' , options , [
1595- 'includeQueryMetadataChanges' ,
1596- 'includeDocumentMetadataChanges'
1593+ 'includeMetadataChanges'
15971594 ] ) ;
15981595 validateNamedOptionalType (
15991596 'Query.onSnapshot' ,
16001597 'boolean' ,
1601- 'includeDocumentMetadataChanges' ,
1602- options . includeDocumentMetadataChanges
1603- ) ;
1604- validateNamedOptionalType (
1605- 'Query.onSnapshot' ,
1606- 'boolean' ,
1607- 'includeQueryMetadataChanges' ,
1608- options . includeQueryMetadataChanges
1598+ 'includeMetadataChanges' ,
1599+ options . includeMetadataChanges
16091600 ) ;
16101601 currArg ++ ;
16111602 }
@@ -1692,8 +1683,7 @@ export class Query implements firestore.Query {
16921683 ) : void {
16931684 const unlisten = this . onSnapshotInternal (
16941685 {
1695- includeDocumentMetadataChanges : false ,
1696- includeQueryMetadataChanges : true ,
1686+ includeMetadataChanges : true ,
16971687 waitForSyncWhenOnline : true
16981688 } ,
16991689 {
@@ -1774,6 +1764,7 @@ export class Query implements firestore.Query {
17741764
17751765export class QuerySnapshot implements firestore . QuerySnapshot {
17761766 private _cachedChanges : firestore . DocumentChange [ ] | null = null ;
1767+ private _cachedChangesIncludeMetadataChanges : boolean | null = null ;
17771768
17781769 readonly metadata : firestore . SnapshotMetadata ;
17791770
@@ -1817,13 +1808,44 @@ export class QuerySnapshot implements firestore.QuerySnapshot {
18171808 return new Query ( this . _originalQuery , this . _firestore ) ;
18181809 }
18191810
1820- get docChanges ( ) : firestore . DocumentChange [ ] {
1821- if ( ! this . _cachedChanges ) {
1811+ docChanges (
1812+ options ?: firestore . SnapshotListenOptions
1813+ ) : firestore . DocumentChange [ ] {
1814+ validateOptionNames ( 'QuerySnapshot.docChanges' , options , [
1815+ 'includeMetadataChanges'
1816+ ] ) ;
1817+
1818+ if ( options ) {
1819+ validateNamedOptionalType (
1820+ 'QuerySnapshot.docChanges' ,
1821+ 'boolean' ,
1822+ 'includeMetadataChanges' ,
1823+ options . includeMetadataChanges
1824+ ) ;
1825+ }
1826+
1827+ const includeMetadataChanges = options && options . includeMetadataChanges ;
1828+
1829+ if ( includeMetadataChanges && this . _snapshot . excludesMetadataChanges ) {
1830+ throw new FirestoreError (
1831+ Code . INVALID_ARGUMENT ,
1832+ 'To include metadata changes with your document changes, you must ' +
1833+ 'also pass { includeMetadataChanges:true } to onSnapshot().'
1834+ ) ;
1835+ }
1836+
1837+ if (
1838+ ! this . _cachedChanges ||
1839+ this . _cachedChangesIncludeMetadataChanges !== includeMetadataChanges
1840+ ) {
18221841 this . _cachedChanges = changesFromSnapshot (
18231842 this . _firestore ,
1843+ includeMetadataChanges ,
18241844 this . _snapshot
18251845 ) ;
1846+ this . _cachedChangesIncludeMetadataChanges = includeMetadataChanges ;
18261847 }
1848+
18271849 return this . _cachedChanges ;
18281850 }
18291851
@@ -1850,6 +1872,30 @@ export class QuerySnapshot implements firestore.QuerySnapshot {
18501872 }
18511873}
18521874
1875+ // TODO(2018/11/01): As of 2018/04/17 we're changing docChanges from an array
1876+ // into a method. Because this is a runtime breaking change and somewhat subtle
1877+ // (both Array and Function have a .length, etc.), we'll replace the .length and
1878+ // @@iterator properties to throw a custom error message. In ~6 months we can
1879+ // delete the custom error as most folks will have hopefully migrated.
1880+ function throwDocChangesMethodError ( ) : never {
1881+ throw new FirestoreError (
1882+ Code . INVALID_ARGUMENT ,
1883+ 'QuerySnapshot.docChanges has been changed from a property into a ' +
1884+ 'method, so usages like "querySnapshot.docChanges" should become ' +
1885+ '"querySnapshot.docChanges()"'
1886+ ) ;
1887+ }
1888+
1889+ Object . defineProperty ( QuerySnapshot . prototype . docChanges , 'length' , {
1890+ get : ( ) => throwDocChangesMethodError ( )
1891+ } ) ;
1892+
1893+ if ( typeof Symbol !== 'undefined' ) {
1894+ Object . defineProperty ( QuerySnapshot . prototype . docChanges , Symbol . iterator , {
1895+ get : ( ) => throwDocChangesMethodError ( )
1896+ } ) ;
1897+ }
1898+
18531899export class CollectionReference extends Query
18541900 implements firestore . CollectionReference {
18551901 constructor ( path : ResourcePath , firestore : Firestore ) {
@@ -1968,6 +2014,7 @@ function validateReference(
19682014 */
19692015export function changesFromSnapshot (
19702016 firestore : Firestore ,
2017+ includeMetadataChanges : boolean ,
19712018 snapshot : ViewSnapshot
19722019) : firestore . DocumentChange [ ] {
19732020 if ( snapshot . oldDocs . isEmpty ( ) ) {
@@ -2002,26 +2049,30 @@ export function changesFromSnapshot(
20022049 // A DocumentSet that is updated incrementally as changes are applied to use
20032050 // to lookup the index of a document.
20042051 let indexTracker = snapshot . oldDocs ;
2005- return snapshot . docChanges . map ( change => {
2006- const doc = new QueryDocumentSnapshot (
2007- firestore ,
2008- change . doc . key ,
2009- change . doc ,
2010- snapshot . fromCache
2011- ) ;
2012- let oldIndex = - 1 ;
2013- let newIndex = - 1 ;
2014- if ( change . type !== ChangeType . Added ) {
2015- oldIndex = indexTracker . indexOf ( change . doc . key ) ;
2016- assert ( oldIndex >= 0 , 'Index for document not found' ) ;
2017- indexTracker = indexTracker . delete ( change . doc . key ) ;
2018- }
2019- if ( change . type !== ChangeType . Removed ) {
2020- indexTracker = indexTracker . add ( change . doc ) ;
2021- newIndex = indexTracker . indexOf ( change . doc . key ) ;
2022- }
2023- return { type : resultChangeType ( change . type ) , doc, oldIndex, newIndex } ;
2024- } ) ;
2052+ return snapshot . docChanges
2053+ . filter (
2054+ change => includeMetadataChanges || change . type !== ChangeType . Metadata
2055+ )
2056+ . map ( change => {
2057+ const doc = new QueryDocumentSnapshot (
2058+ firestore ,
2059+ change . doc . key ,
2060+ change . doc ,
2061+ snapshot . fromCache
2062+ ) ;
2063+ let oldIndex = - 1 ;
2064+ let newIndex = - 1 ;
2065+ if ( change . type !== ChangeType . Added ) {
2066+ oldIndex = indexTracker . indexOf ( change . doc . key ) ;
2067+ assert ( oldIndex >= 0 , 'Index for document not found' ) ;
2068+ indexTracker = indexTracker . delete ( change . doc . key ) ;
2069+ }
2070+ if ( change . type !== ChangeType . Removed ) {
2071+ indexTracker = indexTracker . add ( change . doc ) ;
2072+ newIndex = indexTracker . indexOf ( change . doc . key ) ;
2073+ }
2074+ return { type : resultChangeType ( change . type ) , doc, oldIndex, newIndex } ;
2075+ } ) ;
20252076 }
20262077}
20272078
0 commit comments