11import { fromCollectionRef } from '../observable/fromRef' ;
2- import { Observable } from 'rxjs' ;
3- import { map , filter , scan } from 'rxjs/operators' ;
2+ import { Observable , of } from 'rxjs' ;
3+ import { map , filter , scan , tap , switchMap } from 'rxjs/operators' ;
44import { firestore } from 'firebase/app' ;
55
6- import { Query , DocumentChangeType , DocumentChange , DocumentChangeAction , Action } from '../interfaces' ;
6+ import { Query , DocumentChangeType , DocumentChange , DocumentChangeAction , Action , QuerySnapshot , DocumentChangeOrMetadata } from '../interfaces' ;
77
88/**
99 * Return a stream of document changes on a query. These results are not in sort order but in
@@ -22,12 +22,27 @@ export function docChanges<T>(query: Query, options?: firestore.SnapshotListenOp
2222 * Return a stream of document changes on a query. These results are in sort order.
2323 * @param query
2424 */
25- export function sortedChanges < T > ( query : Query , events : DocumentChangeType [ ] , options ?: firestore . SnapshotListenOptions ) : Observable < DocumentChangeAction < T > [ ] > {
25+ export function sortedChanges < T > ( query : Query , events : DocumentChangeType [ ] ) : Observable < DocumentChangeAction < T > [ ] > {
26+ const options : firestore . SnapshotListenOptions = events . indexOf ( 'metadata' ) > 0 ? { includeMetadataChanges : true } : { } ;
27+ let firstEmission = true ;
2628 return fromCollectionRef ( query , options )
2729 . pipe (
28- map ( changes => changes . payload . docChanges ( options ) ) ,
29- scan ( ( current , changes ) => combineChanges ( current , changes , events ) , [ ] ) ,
30- map ( changes => changes . map ( c => ( { type : c . type , payload : c } as DocumentChangeAction < T > ) ) ) ) ;
30+ switchMap ( changes => {
31+ const docChanges = changes . payload . docChanges ( options ) ;
32+ if ( firstEmission ) {
33+ return of ( { type : 'value' , payload : combineChanges ( [ ] , docChanges , events ) } as DocumentChangeOrMetadata < T > ) ;
34+ } else if ( firstEmission && docChanges . length > 0 ) {
35+ return of ( ...docChanges ) ;
36+ } else {
37+ return of ( { type : 'metadata' , payload : changes . payload . metadata } as DocumentChangeOrMetadata < T > ) ;
38+ }
39+ } ) ,
40+ tap ( ( ) => firstEmission = false ) ,
41+ tap ( change => console . log ( "change" , change ) ) ,
42+ filter ( change => events . indexOf ( change . type ) > - 1 ) ,
43+ scan ( ( current , changes ) => combineChanges ( current , changes , events ) , new Array < DocumentChange < T > > ( ) ) ,
44+ map ( changes => changes . map ( c => ( { type : c . type , payload : c } as DocumentChangeAction < T > ) ) )
45+ ) ;
3146}
3247
3348/**
@@ -37,7 +52,7 @@ export function sortedChanges<T>(query: Query, events: DocumentChangeType[], opt
3752 * @param changes
3853 * @param events
3954 */
40- export function combineChanges < T > ( current : DocumentChange < T > [ ] , changes : DocumentChange < T > [ ] , events : DocumentChangeType [ ] ) {
55+ export function combineChanges < T > ( current : DocumentChange < T > [ ] , changes : DocumentChangeOrMetadata < T > [ ] , events : DocumentChangeType [ ] ) {
4156 changes . forEach ( change => {
4257 // skip unwanted change types
4358 if ( events . indexOf ( change . type ) > - 1 ) {
@@ -52,32 +67,39 @@ export function combineChanges<T>(current: DocumentChange<T>[], changes: Documen
5267 * @param combined
5368 * @param change
5469 */
55- export function combineChange < T > ( combined : DocumentChange < T > [ ] , change : DocumentChange < T > ) : DocumentChange < T > [ ] {
70+ export function combineChange < T > ( combined : DocumentChange < T > [ ] , change : DocumentChangeOrMetadata < T > ) : DocumentChange < T > [ ] {
71+ if ( change . type == 'value' ) { return change . payload }
72+ const next = [ ...combined ] ;
5673 switch ( change . type ) {
5774 case 'added' :
58- if ( combined [ change . newIndex ] && combined [ change . newIndex ] . doc . id == change . doc . id ) {
75+ if ( next [ change . newIndex ] && next [ change . newIndex ] . doc . id == change . doc . id ) {
5976 // Not sure why the duplicates are getting fired
6077 } else {
61- combined . splice ( change . newIndex , 0 , change ) ;
78+ next . splice ( change . newIndex , 0 , change ) ;
6279 }
6380 break ;
6481 case 'modified' :
65- if ( combined [ change . oldIndex ] == null || combined [ change . oldIndex ] . doc . id == change . doc . id ) {
82+ if ( next [ change . oldIndex ] == null || next [ change . oldIndex ] . doc . id == change . doc . id ) {
6683 // When an item changes position we first remove it
6784 // and then add it's new position
6885 if ( change . oldIndex !== change . newIndex ) {
69- combined . splice ( change . oldIndex , 1 ) ;
70- combined . splice ( change . newIndex , 0 , change ) ;
86+ next . splice ( change . oldIndex , 1 ) ;
87+ next . splice ( change . newIndex , 0 , change ) ;
7188 } else {
72- combined . splice ( change . newIndex , 1 , change ) ;
89+ next . splice ( change . newIndex , 1 , change ) ;
7390 }
7491 }
7592 break ;
7693 case 'removed' :
77- if ( combined [ change . oldIndex ] && combined [ change . oldIndex ] . doc . id == change . doc . id ) {
78- combined . splice ( change . oldIndex , 1 ) ;
94+ if ( next [ change . oldIndex ] && next [ change . oldIndex ] . doc . id == change . doc . id ) {
95+ next . splice ( change . oldIndex , 1 ) ;
7996 }
8097 break ;
98+ case 'metadata' :
99+ next . forEach ( c => {
100+ ( < any > c . doc . metadata ) = change . payload ;
101+ } ) ;
102+ break ;
81103 }
82- return combined ;
104+ return next ;
83105}
0 commit comments