11import { fromCollectionRef } from '../observable/fromRef' ;
22import { Observable , SchedulerLike } from 'rxjs' ;
33import { distinctUntilChanged , map , pairwise , scan , startWith } from 'rxjs/operators' ;
4-
54import { DocumentChange , DocumentChangeAction , DocumentChangeType , Query } from '../interfaces' ;
65
76/**
@@ -11,9 +10,37 @@ import { DocumentChange, DocumentChangeAction, DocumentChangeType, Query } from
1110export function docChanges < T > ( query : Query , scheduler ?: SchedulerLike ) : Observable < DocumentChangeAction < T > [ ] > {
1211 return fromCollectionRef ( query , scheduler )
1312 . pipe (
14- map ( action =>
15- action . payload . docChanges ( )
16- . map ( change => ( { type : change . type , payload : change } as DocumentChangeAction < T > ) ) ) ) ;
13+ startWith ( undefined ) ,
14+ pairwise ( ) ,
15+ map ( ( [ priorAction , action ] ) => {
16+ const docChanges = action . payload . docChanges ( ) ;
17+ const actions = docChanges . map ( change => ( { type : change . type , payload : change } ) ) ;
18+ // the metadata has changed from the prior emission
19+ if ( priorAction && JSON . stringify ( priorAction . payload . metadata ) !== JSON . stringify ( action . payload . metadata ) ) {
20+ // go through all the docs in payload and figure out which ones changed
21+ action . payload . docs . forEach ( ( currentDoc , currentIndex ) => {
22+ const docChange = docChanges . find ( d => d . doc . ref . isEqual ( currentDoc . ref ) ) ;
23+ const priorDoc = priorAction ?. payload . docs . find ( d => d . ref . isEqual ( currentDoc . ref ) ) ;
24+ if ( docChange && JSON . stringify ( docChange . doc . metadata ) === JSON . stringify ( currentDoc . metadata ) ||
25+ ! docChange && priorDoc && JSON . stringify ( priorDoc . metadata ) === JSON . stringify ( currentDoc . metadata ) ) {
26+ // document doesn't appear to have changed, don't log another action
27+ } else {
28+ // since the actions are processed in order just push onto the array
29+ actions . push ( {
30+ type : 'modified' ,
31+ payload : {
32+ oldIndex : currentIndex ,
33+ newIndex : currentIndex ,
34+ type : 'modified' ,
35+ doc : currentDoc
36+ }
37+ } ) ;
38+ }
39+ } ) ;
40+ }
41+ return actions as DocumentChangeAction < T > [ ] ;
42+ } ) ,
43+ ) ;
1744}
1845
1946/**
@@ -23,30 +50,9 @@ export function sortedChanges<T>(
2350 query : Query ,
2451 events : DocumentChangeType [ ] ,
2552 scheduler ?: SchedulerLike ) : Observable < DocumentChangeAction < T > [ ] > {
26- return fromCollectionRef ( query , scheduler )
53+ return docChanges < T > ( query , scheduler )
2754 . pipe (
28- startWith ( undefined ) ,
29- pairwise ( ) ,
30- scan ( ( current , [ priorChanges , changes ] ) => {
31- const docChanges = changes . payload . docChanges ( ) ;
32- const ret = combineChanges ( current , docChanges , events ) ;
33- // docChanges({ includeMetadataChanges: true }) does't include metadata changes... wat?
34- if ( events . indexOf ( 'modified' ) > - 1 && priorChanges &&
35- JSON . stringify ( priorChanges . payload . metadata ) !== JSON . stringify ( changes . payload . metadata ) ) {
36- return ret . map ( it => {
37- const partOfDocChanges = ! ! docChanges . find ( d => d . doc . ref . isEqual ( it . doc . ref ) ) ;
38- return {
39- // if it's not one of the changed docs that means we already saw it's order change
40- // so this is purely metadata, so don't move the doc
41- oldIndex : partOfDocChanges ? it . oldIndex : it . newIndex ,
42- newIndex : it . newIndex ,
43- type : 'modified' ,
44- doc : changes . payload . docs . find ( d => d . ref . isEqual ( it . doc . ref ) )
45- } ;
46- } ) ;
47- }
48- return ret ;
49- } , [ ] ) ,
55+ scan ( ( current , changes ) => combineChanges < T > ( current , changes . map ( it => it . payload ) , events ) , [ ] ) ,
5056 distinctUntilChanged ( ) , // cut down on unneed change cycles
5157 map ( changes => changes . map ( c => ( { type : c . type , payload : c } as DocumentChangeAction < T > ) ) ) ) ;
5258}
@@ -82,6 +88,8 @@ function sliceAndSplice<T>(
8288
8389/**
8490 * Creates a new sorted array from a new change.
91+ * Build our own because we allow filtering of action types ('added', 'removed', 'modified') before scanning
92+ * and so we have greater control over change detection (by breaking ===)
8593 */
8694export function combineChange < T > ( combined : DocumentChange < T > [ ] , change : DocumentChange < T > ) : DocumentChange < T > [ ] {
8795 switch ( change . type ) {
0 commit comments