1
1
import { deprecate } from '@ember/debug' ;
2
2
3
+ import { DEBUG_RELATIONSHIP_NOTIFICATIONS } from '@warp-drive/build-config/debugging' ;
3
4
import {
4
5
DEPRECATE_NON_UNIQUE_PAYLOADS ,
5
6
DEPRECATE_RELATIONSHIP_REMOTE_UPDATE_CLEARING_LOCAL_STATE ,
@@ -53,7 +54,13 @@ function _deprecatedCompare<T>(
53
54
adv = true ;
54
55
55
56
if ( ! prevSet . has ( member ) ) {
56
- changed = true ;
57
+ // Avoid unnecessarily notifying a change that already exists locally
58
+ if ( i < priorLocalLength ) {
59
+ const priorLocalMember = priorLocalState ! [ i ] ;
60
+ if ( priorLocalMember !== member ) {
61
+ changed = true ;
62
+ }
63
+ }
57
64
added . add ( member ) ;
58
65
onAdd ( member ) ;
59
66
}
@@ -158,25 +165,59 @@ function _compare<T>(
158
165
const finalLength = finalState . length ;
159
166
const prevLength = prevState . length ;
160
167
const iterationLength = Math . max ( finalLength , prevLength ) ;
161
- const equalLength = finalLength === prevLength ;
162
- let changed : boolean = finalSet . size !== prevSet . size ;
163
- let remoteOrderChanged = false ;
168
+ const equalLength = priorLocalState ? finalLength === priorLocalState . length : finalLength === prevLength ;
169
+ let remoteOrderChanged = finalSet . size !== prevSet . size ;
170
+ let changed : boolean = priorLocalState ? finalSet . size !== priorLocalState . length : remoteOrderChanged ;
164
171
const added = new Set < T > ( ) ;
165
172
const removed = new Set < T > ( ) ;
166
173
const priorLocalLength = priorLocalState ?. length ?? 0 ;
167
174
175
+ if ( DEBUG_RELATIONSHIP_NOTIFICATIONS ) {
176
+ if ( changed ) {
177
+ // console.log({
178
+ // priorState: priorLocalState?.slice(),
179
+ // finalState: finalState.slice(),
180
+ // prevState: prevState.slice(),
181
+ // });
182
+ }
183
+
184
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
185
+ changed &&
186
+ // eslint-disable-next-line no-console
187
+ console . log (
188
+ `changed because ${ priorLocalState ? 'finalSet.size !== priorLocalState.length' : 'finalSet.size !== prevSet.size' } `
189
+ ) ;
190
+ }
191
+
168
192
for ( let i = 0 ; i < iterationLength ; i ++ ) {
169
193
let member : T | undefined ;
170
194
171
195
// accumulate anything added
172
196
if ( i < finalLength ) {
173
197
member = finalState [ i ] ;
174
198
if ( ! prevSet . has ( member ) ) {
175
- // TODO: in order to avoid unnecessarily notifying a change here
176
- // we would need to only notify "changed" if member is not in
177
- // relationship.additions OR if localState[i] !== member
178
-
179
- changed = true ;
199
+ // Avoid unnecessarily notifying a change that already exists locally
200
+ if ( i < priorLocalLength ) {
201
+ const priorLocalMember = priorLocalState ! [ i ] ;
202
+ if ( priorLocalMember !== member ) {
203
+ if ( DEBUG_RELATIONSHIP_NOTIFICATIONS ) {
204
+ if ( ! changed ) {
205
+ // console.log({
206
+ // priorLocalMember,
207
+ // member,
208
+ // i,
209
+ // priorState: priorLocalState?.slice(),
210
+ // finalState: finalState.slice(),
211
+ // prevState: prevState.slice(),
212
+ // });
213
+ }
214
+
215
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions, no-console
216
+ ! changed && console . log ( `changed because priorLocalMember !== member && !prevSet.has(member)` ) ;
217
+ }
218
+ changed = true ;
219
+ }
220
+ }
180
221
added . add ( member ) ;
181
222
onAdd ( member ) ;
182
223
}
@@ -207,9 +248,19 @@ function _compare<T>(
207
248
if ( i < priorLocalLength ) {
208
249
const priorLocalMember = priorLocalState ! [ i ] ;
209
250
if ( priorLocalMember !== member ) {
251
+ if ( DEBUG_RELATIONSHIP_NOTIFICATIONS ) {
252
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions, no-console
253
+ ! changed && console . log ( `changed because priorLocalMember !== member && member !== prevMember` ) ;
254
+ }
210
255
changed = true ;
211
256
}
212
- } else {
257
+ } else if ( i < finalLength ) {
258
+ // if we have exceeded the length of priorLocalState and we are within the range
259
+ // of the finalState then we must have changed
260
+ if ( DEBUG_RELATIONSHIP_NOTIFICATIONS ) {
261
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions, no-console
262
+ ! changed && console . log ( `changed because priorMember !== member && index >= priorLocalLength` ) ;
263
+ }
213
264
changed = true ;
214
265
}
215
266
}
@@ -229,7 +280,53 @@ function _compare<T>(
229
280
}
230
281
231
282
if ( ! finalSet . has ( prevMember ) ) {
232
- changed = true ;
283
+ // if we are within finalLength, we can only be "changed" if we've already exceeded
284
+ // the index range of priorLocalState, as otherwise the previous member may still
285
+ // be removed.
286
+ //
287
+ // prior local: [1, 2, 3, 4]
288
+ // final state: [1, 2, 3]
289
+ // prev remote state: [1, 2, 5, 3, 4]
290
+ // i === 2
291
+ // prevMember === 5
292
+ // !finalSet.has(prevMember) === true
293
+ //
294
+ // because we will become changed at i===3,
295
+ // we do not need to worry about becoming changed at i===2
296
+ // as the arrays until now are still the same
297
+ //
298
+ // prior local: [1, 2, 3]
299
+ // final state: [1, 2, 3, 4]
300
+ // prev remote state: [1, 2, 5, 3, 4]
301
+ // i === 2
302
+ // prevMember === 5
303
+ // !finalSet.has(prevMember) === true
304
+ //
305
+ // because we will become changed at i===3
306
+ // we do not need to worry about becoming changed at i===2
307
+ //
308
+ // prior local: [1, 2, 3]
309
+ // final state: [1, 2, 3]
310
+ // prev remote state: [1, 2, 5, 3, 4]
311
+ // i === 2
312
+ // prevMember === 5
313
+ // !finalSet.has(prevMember) === true
314
+ //
315
+ // because we have same length and same membership order
316
+ // we do not need to worry about becoming changed at i===2
317
+ //
318
+ // if you do not have a priorLocalState you can't be changed
319
+ // ergo, we never need to set changed in this branch.
320
+ // this log can still be useful for debugging.
321
+ if ( DEBUG_RELATIONSHIP_NOTIFICATIONS ) {
322
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
323
+ ! changed &&
324
+ // eslint-disable-next-line no-console
325
+ console . log ( `changed because i >= priorLocalLength && i < finalLength && !finalSet.has(prevMember)` ) ;
326
+ }
327
+ //
328
+ // we do still set remoteOrderChanged as it has
329
+ remoteOrderChanged = true ;
233
330
removed . add ( prevMember ) ;
234
331
onDel ( prevMember ) ;
235
332
}
0 commit comments