1
1
import type { IdMap } from './IdMap' ;
2
- import { clone , hasOwn , isEqual } from './common' ;
2
+ import { clone , entriesOf , hasOwn , isEqual } from './common' ;
3
+ import type { Observer , OrderedObserver , UnorderedObserver } from './observers' ;
3
4
4
5
function isObjEmpty ( obj : Record < string , unknown > ) : boolean {
5
6
for ( const key in Object ( obj ) ) {
@@ -10,79 +11,72 @@ function isObjEmpty(obj: Record<string, unknown>): boolean {
10
11
return true ;
11
12
}
12
13
13
- type Observer < T extends { _id : string } > = {
14
- added ?: < TFields > ( id : T [ '_id' ] , fields : TFields ) => void ;
15
- changed ?: < TFields > ( id : T [ '_id' ] , fields : TFields ) => void ;
16
- removed ?: ( id : T [ '_id' ] ) => void ;
17
- movedBefore ?: ( id : T [ '_id' ] , before : T [ '_id' ] | null ) => void ;
18
- addedBefore ?: < TFields > ( id : T [ '_id' ] , fields : TFields , before : T [ '_id' ] | null ) => void ;
19
- } ;
20
-
21
- /** @deprecated internal use only */
22
14
export class DiffSequence {
23
- static diffQueryChanges < T extends { _id : string } , TProjection extends T = T > (
15
+ static diffQueryChanges < T extends { _id : string } > (
24
16
ordered : true ,
25
17
oldResults : T [ ] ,
26
18
newResults : T [ ] ,
27
- observer : Observer < T > ,
28
- options ?: { projectionFn ?: ( doc : T | Omit < T , '_id' > ) => TProjection } ,
19
+ observer : OrderedObserver < T > ,
20
+ options ?: { projectionFn ?: ( doc : T | Omit < T , '_id' > ) => Partial < T > } ,
29
21
) : void ;
30
22
31
- static diffQueryChanges < T extends { _id : string } , TProjection extends T = T > (
23
+ static diffQueryChanges < T extends { _id : string } > (
32
24
ordered : false ,
33
25
oldResults : IdMap < T [ '_id' ] , T > ,
34
26
newResults : IdMap < T [ '_id' ] , T > ,
35
- observer : Observer < T > ,
36
- options ?: { projectionFn ?: ( doc : T | Omit < T , '_id' > ) => TProjection } ,
27
+ observer : UnorderedObserver < T > ,
28
+ options ?: { projectionFn ?: ( doc : T | Omit < T , '_id' > ) => Partial < T > } ,
37
29
) : void ;
38
30
39
- static diffQueryChanges < T extends { _id : string } , TProjection extends T = T > (
31
+ static diffQueryChanges < T extends { _id : string } > (
40
32
ordered : boolean ,
41
33
oldResults : T [ ] | IdMap < T [ '_id' ] , T > ,
42
34
newResults : T [ ] | IdMap < T [ '_id' ] , T > ,
43
35
observer : Observer < T > ,
44
- options ?: { projectionFn ?: ( doc : T | Omit < T , '_id' > ) => TProjection } ,
36
+ options ?: { projectionFn ?: ( doc : T | Omit < T , '_id' > ) => Partial < T > } ,
45
37
) : void ;
46
38
47
- static diffQueryChanges < T extends { _id : string } , TProjection extends T = T > (
39
+ static diffQueryChanges < T extends { _id : string } > (
48
40
ordered : boolean ,
49
41
oldResults : T [ ] | IdMap < T [ '_id' ] , T > ,
50
42
newResults : T [ ] | IdMap < T [ '_id' ] , T > ,
51
43
observer : Observer < T > ,
52
- options ?: { projectionFn ?: ( doc : T | Omit < T , '_id' > ) => TProjection } ,
44
+ options ?: { projectionFn ?: ( doc : T | Omit < T , '_id' > ) => Partial < T > } ,
53
45
) : void {
54
- if ( ordered ) DiffSequence . diffQueryOrderedChanges ( oldResults as T [ ] , newResults as T [ ] , observer , options ) ;
55
- else DiffSequence . diffQueryUnorderedChanges ( oldResults as IdMap < T [ '_id' ] , T > , newResults as IdMap < T [ '_id' ] , T > , observer , options ) ;
46
+ if ( ordered ) DiffSequence . diffQueryOrderedChanges ( oldResults as T [ ] , newResults as T [ ] , observer as OrderedObserver < T > , options ) ;
47
+ else
48
+ DiffSequence . diffQueryUnorderedChanges (
49
+ oldResults as IdMap < T [ '_id' ] , T > ,
50
+ newResults as IdMap < T [ '_id' ] , T > ,
51
+ observer as UnorderedObserver < T > ,
52
+ options ,
53
+ ) ;
56
54
}
57
55
58
- private static diffQueryUnorderedChanges < T extends { _id : string } , TProjection extends T = T > (
56
+ private static diffQueryUnorderedChanges < T extends { _id : string } > (
59
57
oldResults : IdMap < T [ '_id' ] , T > ,
60
58
newResults : IdMap < T [ '_id' ] , T > ,
61
- observer : Observer < T > ,
62
- options ?: { projectionFn ?: ( doc : T | Omit < T , '_id' > ) => TProjection } ,
59
+ observer : UnorderedObserver < T > ,
60
+ options ?: { projectionFn ?: ( doc : T | Omit < T , '_id' > ) => Partial < T > } ,
63
61
) : void {
64
62
options = options || { } ;
65
63
const projectionFn = options . projectionFn || clone ;
66
64
67
- if ( observer . movedBefore ) {
68
- throw new Error ( '_diffQueryUnordered called with a movedBefore observer!' ) ;
69
- }
70
-
71
65
newResults . forEach ( ( newDoc , id ) => {
72
66
const oldDoc = oldResults . get ( id ) ;
73
67
if ( oldDoc ) {
74
68
if ( observer . changed && ! isEqual ( oldDoc , newDoc as any ) ) {
75
69
const projectedNew = projectionFn ( newDoc ) ;
76
70
const projectedOld = projectionFn ( oldDoc ) ;
77
- const changedFields = DiffSequence . makeChangedFields < unknown , unknown > ( projectedNew , projectedOld ) ;
71
+ const changedFields = DiffSequence . makeChangedFields ( projectedNew , projectedOld ) ;
78
72
if ( ! isObjEmpty ( changedFields ) ) {
79
- observer . changed ( id , changedFields as TProjection ) ;
73
+ observer . changed ( id , changedFields as Partial < T > ) ;
80
74
}
81
75
}
82
76
} else if ( observer . added ) {
83
- const fields = projectionFn ( newDoc ) as Omit < TProjection , '_id' > & { _id ?: string } ;
77
+ const fields = projectionFn ( newDoc ) as Omit < Partial < T > , '_id' > & { _id ?: string } ;
84
78
delete fields . _id ;
85
- observer . added ( newDoc . _id , fields ) ;
79
+ observer . added ( newDoc . _id , fields as Partial < T > ) ;
86
80
}
87
81
} ) ;
88
82
@@ -93,11 +87,11 @@ export class DiffSequence {
93
87
}
94
88
}
95
89
96
- private static diffQueryOrderedChanges < T extends { _id : string } , TProjection extends T = T > (
90
+ private static diffQueryOrderedChanges < T extends { _id : string } > (
97
91
oldResults : T [ ] ,
98
92
newResults : T [ ] ,
99
- observer : Observer < T > ,
100
- options ?: { projectionFn ?: ( doc : T | Omit < T , '_id' > ) => TProjection } ,
93
+ observer : OrderedObserver < T > ,
94
+ options ?: { projectionFn ?: ( doc : T | Omit < T , '_id' > ) => Partial < T > } ,
101
95
) : void {
102
96
options = options || { } ;
103
97
const projectionFn = options . projectionFn || clone ;
@@ -164,10 +158,10 @@ export class DiffSequence {
164
158
for ( let i = startOfGroup ; i < endOfGroup ; i ++ ) {
165
159
newDoc = newResults [ i ] ;
166
160
if ( ! hasOwn . call ( oldIndexOfId , newDoc . _id ) ) {
167
- fields = projectionFn ( newDoc ) as Omit < TProjection , '_id' > & { _id ?: string } ;
161
+ fields = projectionFn ( newDoc ) as Omit < Partial < T > , '_id' > & { _id ?: string } ;
168
162
delete fields . _id ;
169
- observer . addedBefore ?.( newDoc . _id , fields , groupId ) ;
170
- observer . added ?.( newDoc . _id , fields ) ;
163
+ if ( 'addedBefore' in observer ) observer . addedBefore ?.( newDoc . _id , fields as Partial < T > , groupId ) ;
164
+ observer . added ?.( newDoc . _id , fields as Partial < T > ) ;
171
165
} else {
172
166
oldDoc = oldResults [ oldIndexOfId . get ( newDoc . _id ) ! ] ;
173
167
projectedNew = projectionFn ( newDoc ) ;
@@ -176,7 +170,7 @@ export class DiffSequence {
176
170
if ( ! isObjEmpty ( fields ) ) {
177
171
observer . changed ?.( newDoc . _id , fields ) ;
178
172
}
179
- observer . movedBefore ?.( newDoc . _id , groupId ) ;
173
+ if ( 'movedBefore' in observer ) observer . movedBefore ?.( newDoc . _id , groupId ) ;
180
174
}
181
175
}
182
176
if ( groupId ) {
@@ -193,56 +187,50 @@ export class DiffSequence {
193
187
} ) ;
194
188
}
195
189
196
- private static diffObjects < TLeft , TRight > (
197
- left : Record < string , TLeft > ,
198
- right : Record < string , TRight > ,
190
+ private static diffObjects < T extends object > (
191
+ left : T ,
192
+ right : T ,
199
193
callbacks : {
200
- leftOnly ?: ( key : string , leftValue : TLeft ) => void ;
201
- rightOnly ?: ( key : string , rightValue : TRight ) => void ;
202
- both ?: ( key : string , leftValue : TLeft , rightValue : TRight ) => void ;
194
+ leftOnly ?: ( key : keyof T , leftValue : T [ keyof T ] ) => void ;
195
+ rightOnly ?: ( key : keyof T , rightValue : T [ keyof T ] ) => void ;
196
+ both ?: ( key : keyof T , leftValue : T [ keyof T ] , rightValue : T [ keyof T ] ) => void ;
203
197
} ,
204
198
) : void {
205
- Object . keys ( left ) . forEach ( ( key ) => {
206
- const leftValue = left [ key ] ;
207
- if ( hasOwn . call ( right , key ) ) {
199
+ entriesOf ( left ) . forEach ( ( [ key , leftValue ] ) => {
200
+ if ( key in right ) {
208
201
callbacks . both ?.( key , leftValue , right [ key ] ) ;
209
202
} else {
210
203
callbacks . leftOnly ?.( key , leftValue ) ;
211
204
}
212
205
} ) ;
213
206
214
207
if ( callbacks . rightOnly ) {
215
- Object . keys ( right ) . forEach ( ( key ) => {
216
- const rightValue = right [ key ] ;
217
- if ( ! hasOwn . call ( left , key ) ) {
208
+ entriesOf ( right ) . forEach ( ( [ key , rightValue ] ) => {
209
+ if ( ! ( key in left ) ) {
218
210
callbacks . rightOnly ?.( key , rightValue ) ;
219
211
}
220
212
} ) ;
221
213
}
222
214
}
223
215
224
- static makeChangedFields < TLeft , TRight > (
225
- newDoc : Record < string , TRight > ,
226
- oldDoc : Record < string , TLeft > ,
227
- ) : Record < string , TRight | undefined > {
228
- const fields : Record < string , TRight | undefined > = { } ;
229
- DiffSequence . diffObjects < TLeft , TRight > ( oldDoc , newDoc , {
216
+ static makeChangedFields < T extends object > ( newDoc : T , oldDoc : T ) : Partial < T > {
217
+ const fields : Partial < T > = { } ;
218
+ DiffSequence . diffObjects ( oldDoc , newDoc , {
230
219
leftOnly ( key ) {
231
220
fields [ key ] = undefined ;
232
221
} ,
233
222
rightOnly ( key , value ) {
234
223
fields [ key ] = value ;
235
224
} ,
236
225
both ( key , leftValue , rightValue ) {
237
- if ( ! isEqual ( leftValue as any , rightValue as any ) ) fields [ key ] = rightValue ;
226
+ if ( ! isEqual ( leftValue , rightValue ) ) fields [ key ] = rightValue ;
238
227
} ,
239
228
} ) ;
240
229
return fields ;
241
230
}
242
231
243
- static applyChanges ( doc : Record < string , any > , changeFields : Record < string , any > ) : void {
244
- Object . keys ( changeFields ) . forEach ( ( key ) => {
245
- const value = changeFields [ key ] ;
232
+ static applyChanges < T extends object > ( doc : T , changeFields : T ) : void {
233
+ entriesOf ( changeFields ) . forEach ( ( [ key , value ] ) => {
246
234
if ( typeof value === 'undefined' ) {
247
235
delete doc [ key ] ;
248
236
} else {
0 commit comments