1
1
import { fromCollectionRef } from '../observable/fromRef' ;
2
2
import { Observable , SchedulerLike } from 'rxjs' ;
3
- import { map , scan } from 'rxjs/operators' ;
3
+ import { distinctUntilChanged , map , pairwise , scan , startWith } from 'rxjs/operators' ;
4
4
5
5
import { DocumentChange , DocumentChangeAction , DocumentChangeType , Query } from '../interfaces' ;
6
6
@@ -25,8 +25,29 @@ export function sortedChanges<T>(
25
25
scheduler ?: SchedulerLike ) : Observable < DocumentChangeAction < T > [ ] > {
26
26
return fromCollectionRef ( query , scheduler )
27
27
. pipe (
28
- map ( changes => changes . payload . docChanges ( ) ) ,
29
- scan ( ( current , changes ) => combineChanges ( current , changes , events ) , [ ] ) ,
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
+ } , [ ] ) ,
50
+ distinctUntilChanged ( ) , // cut down on unneed change cycles
30
51
map ( changes => changes . map ( c => ( { type : c . type , payload : c } as DocumentChangeAction < T > ) ) ) ) ;
31
52
}
32
53
@@ -44,6 +65,21 @@ export function combineChanges<T>(current: DocumentChange<T>[], changes: Documen
44
65
return current ;
45
66
}
46
67
68
+ /**
69
+ * Splice arguments on top of a sliced array, to break top-level ===
70
+ * this is useful for change-detection
71
+ */
72
+ function sliceAndSplice < T > (
73
+ original : T [ ] ,
74
+ start : number ,
75
+ deleteCount : number ,
76
+ ...args : T [ ]
77
+ ) : T [ ] {
78
+ const returnArray = original . slice ( ) ;
79
+ returnArray . splice ( start , deleteCount , ...args ) ;
80
+ return returnArray ;
81
+ }
82
+
47
83
/**
48
84
* Creates a new sorted array from a new change.
49
85
*/
@@ -53,24 +89,26 @@ export function combineChange<T>(combined: DocumentChange<T>[], change: Document
53
89
if ( combined [ change . newIndex ] && combined [ change . newIndex ] . doc . ref . isEqual ( change . doc . ref ) ) {
54
90
// Not sure why the duplicates are getting fired
55
91
} else {
56
- combined . splice ( change . newIndex , 0 , change ) ;
92
+ return sliceAndSplice ( combined , change . newIndex , 0 , change ) ;
57
93
}
58
94
break ;
59
95
case 'modified' :
60
96
if ( combined [ change . oldIndex ] == null || combined [ change . oldIndex ] . doc . ref . isEqual ( change . doc . ref ) ) {
61
97
// When an item changes position we first remove it
62
98
// and then add it's new position
63
99
if ( change . oldIndex !== change . newIndex ) {
64
- combined . splice ( change . oldIndex , 1 ) ;
65
- combined . splice ( change . newIndex , 0 , change ) ;
100
+ const copiedArray = combined . slice ( ) ;
101
+ copiedArray . splice ( change . oldIndex , 1 ) ;
102
+ copiedArray . splice ( change . newIndex , 0 , change ) ;
103
+ return copiedArray ;
66
104
} else {
67
- combined . splice ( change . newIndex , 1 , change ) ;
105
+ return sliceAndSplice ( combined , change . newIndex , 1 , change ) ;
68
106
}
69
107
}
70
108
break ;
71
109
case 'removed' :
72
110
if ( combined [ change . oldIndex ] && combined [ change . oldIndex ] . doc . ref . isEqual ( change . doc . ref ) ) {
73
- combined . splice ( change . oldIndex , 1 ) ;
111
+ return sliceAndSplice ( combined , change . oldIndex , 1 ) ;
74
112
}
75
113
break ;
76
114
}
0 commit comments