1
1
import { fromCollectionRef } from '../observable/fromRef' ;
2
2
import { Observable , SchedulerLike } from 'rxjs' ;
3
3
import { distinctUntilChanged , map , pairwise , scan , startWith } from 'rxjs/operators' ;
4
-
5
4
import { DocumentChange , DocumentChangeAction , DocumentChangeType , Query } from '../interfaces' ;
6
5
7
6
/**
@@ -11,9 +10,37 @@ import { DocumentChange, DocumentChangeAction, DocumentChangeType, Query } from
11
10
export function docChanges < T > ( query : Query , scheduler ?: SchedulerLike ) : Observable < DocumentChangeAction < T > [ ] > {
12
11
return fromCollectionRef ( query , scheduler )
13
12
. 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
+ ) ;
17
44
}
18
45
19
46
/**
@@ -23,30 +50,9 @@ export function sortedChanges<T>(
23
50
query : Query ,
24
51
events : DocumentChangeType [ ] ,
25
52
scheduler ?: SchedulerLike ) : Observable < DocumentChangeAction < T > [ ] > {
26
- return fromCollectionRef ( query , scheduler )
53
+ return docChanges < T > ( query , scheduler )
27
54
. 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 ) , [ ] ) ,
50
56
distinctUntilChanged ( ) , // cut down on unneed change cycles
51
57
map ( changes => changes . map ( c => ( { type : c . type , payload : c } as DocumentChangeAction < T > ) ) ) ) ;
52
58
}
@@ -82,6 +88,8 @@ function sliceAndSplice<T>(
82
88
83
89
/**
84
90
* 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 ===)
85
93
*/
86
94
export function combineChange < T > ( combined : DocumentChange < T > [ ] , change : DocumentChange < T > ) : DocumentChange < T > [ ] {
87
95
switch ( change . type ) {
0 commit comments