ember-data-model-fragments 7.0.2 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.release-plan.json +16 -4
- package/CHANGELOG.md +40 -0
- package/README.md +95 -31
- package/addon/array/fragment.js +19 -0
- package/addon/array/stateful.js +9 -45
- package/addon/attributes/array.js +55 -43
- package/addon/attributes/fragment-array.js +58 -46
- package/addon/attributes/fragment-owner.js +12 -2
- package/addon/attributes/fragment.js +61 -45
- package/addon/cache/fragment-cache.js +323 -24
- package/addon/cache/fragment-record-data-proxy.js +3 -1
- package/addon/cache/fragment-state-manager.js +283 -70
- package/addon/ext.js +52 -216
- package/addon/fragment.js +129 -48
- package/addon/index.js +15 -4
- package/addon/schema-service.js +190 -0
- package/addon/serializer.js +21 -0
- package/addon/serializers/fragment.js +85 -0
- package/addon/serializers/json-api.js +85 -0
- package/addon/serializers/rest.js +83 -0
- package/addon/serializers/utils.js +253 -0
- package/addon/store.js +301 -0
- package/addon/transforms/fragment.js +3 -7
- package/addon/util/fragment-cache.js +59 -0
- package/package.json +76 -65
- package/addon/record-data.js +0 -1131
- package/app/initializers/model-fragments.js +0 -11
- package/record-data.d.ts +0 -4
package/addon/record-data.js
DELETED
|
@@ -1,1131 +0,0 @@
|
|
|
1
|
-
// eslint-disable-next-line ember/use-ember-data-rfc-395-imports
|
|
2
|
-
import { RecordData } from 'ember-data/-private';
|
|
3
|
-
import { diffArray } from '@ember-data/model/-private';
|
|
4
|
-
import { recordDataFor } from '@ember-data/store/-private';
|
|
5
|
-
import { assert } from '@ember/debug';
|
|
6
|
-
import { typeOf } from '@ember/utils';
|
|
7
|
-
import { isArray } from '@ember/array';
|
|
8
|
-
import { getActualFragmentType, isFragment } from './fragment';
|
|
9
|
-
import isInstanceOfType from './util/instance-of-type';
|
|
10
|
-
import { gte } from 'ember-compatibility-helpers';
|
|
11
|
-
|
|
12
|
-
class FragmentBehavior {
|
|
13
|
-
constructor(recordData, definition) {
|
|
14
|
-
this.recordData = recordData;
|
|
15
|
-
this.definition = definition;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
getDefaultValue(key) {
|
|
19
|
-
const { options } = this.definition;
|
|
20
|
-
if (options.defaultValue === undefined) {
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
let defaultValue;
|
|
24
|
-
if (typeof options.defaultValue === 'function') {
|
|
25
|
-
const record = this.recordData._fragmentGetRecord();
|
|
26
|
-
defaultValue = options.defaultValue.call(null, record, options, key);
|
|
27
|
-
} else {
|
|
28
|
-
defaultValue = options.defaultValue;
|
|
29
|
-
}
|
|
30
|
-
assert(
|
|
31
|
-
"The fragment's default value must be an object or null",
|
|
32
|
-
defaultValue === null ||
|
|
33
|
-
typeOf(defaultValue) === 'object' ||
|
|
34
|
-
isFragment(defaultValue),
|
|
35
|
-
);
|
|
36
|
-
if (defaultValue === null) {
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
if (isFragment(defaultValue)) {
|
|
40
|
-
assert(
|
|
41
|
-
`The fragment's default value must be a '${this.definition.modelName}' fragment`,
|
|
42
|
-
isInstanceOfType(
|
|
43
|
-
defaultValue.store.modelFor(this.definition.modelName),
|
|
44
|
-
defaultValue,
|
|
45
|
-
),
|
|
46
|
-
);
|
|
47
|
-
const recordData = recordDataFor(defaultValue);
|
|
48
|
-
recordData.setFragmentOwner(this.recordData, key);
|
|
49
|
-
return recordData;
|
|
50
|
-
}
|
|
51
|
-
return this.recordData._newFragmentRecordData(
|
|
52
|
-
this.definition,
|
|
53
|
-
defaultValue,
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
pushData(fragment, canonical) {
|
|
58
|
-
assert(
|
|
59
|
-
'Fragment value must be a RecordData',
|
|
60
|
-
fragment === null || fragment instanceof RecordData,
|
|
61
|
-
);
|
|
62
|
-
assert(
|
|
63
|
-
'Fragment canonical value must be an object or null',
|
|
64
|
-
canonical === null || typeOf(canonical) === 'object',
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
if (canonical === null) {
|
|
68
|
-
// server replaced fragment with null
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (fragment) {
|
|
73
|
-
// merge the fragment with the new data from the server
|
|
74
|
-
fragment._fragmentPushData({ attributes: canonical });
|
|
75
|
-
return fragment;
|
|
76
|
-
}
|
|
77
|
-
return this.recordData._newFragmentRecordData(this.definition, canonical);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
willCommit(fragment) {
|
|
81
|
-
assert(
|
|
82
|
-
'Fragment value must be a RecordData',
|
|
83
|
-
fragment instanceof RecordData,
|
|
84
|
-
);
|
|
85
|
-
fragment._fragmentWillCommit();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
didCommit(fragment, canonical) {
|
|
89
|
-
assert(
|
|
90
|
-
'Fragment value must be a RecordData',
|
|
91
|
-
fragment === null || fragment instanceof RecordData,
|
|
92
|
-
);
|
|
93
|
-
assert(
|
|
94
|
-
'Fragment canonical value must be an object',
|
|
95
|
-
canonical == null || typeOf(canonical) === 'object',
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
if (canonical == null) {
|
|
99
|
-
fragment?._fragmentDidCommit(null);
|
|
100
|
-
|
|
101
|
-
if (canonical === null) {
|
|
102
|
-
// server replaced fragment with null
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// server confirmed in-flight fragment
|
|
107
|
-
return fragment;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (fragment) {
|
|
111
|
-
// merge the fragment with the new data from the server
|
|
112
|
-
fragment._fragmentDidCommit({ attributes: canonical });
|
|
113
|
-
return fragment;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return this.recordData._newFragmentRecordData(this.definition, canonical);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
commitWasRejected(fragment) {
|
|
120
|
-
assert(
|
|
121
|
-
'Fragment value must be a RecordData',
|
|
122
|
-
fragment instanceof RecordData,
|
|
123
|
-
);
|
|
124
|
-
fragment._fragmentCommitWasRejected();
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
rollback(fragment) {
|
|
128
|
-
assert(
|
|
129
|
-
'Fragment value must be a RecordData',
|
|
130
|
-
fragment instanceof RecordData,
|
|
131
|
-
);
|
|
132
|
-
fragment._fragmentRollbackAttributes();
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
unload(fragment) {
|
|
136
|
-
assert(
|
|
137
|
-
'Fragment value must be a RecordData',
|
|
138
|
-
fragment instanceof RecordData,
|
|
139
|
-
);
|
|
140
|
-
fragment._fragmentUnloadRecord();
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
isDirty(value, originalValue) {
|
|
144
|
-
assert(
|
|
145
|
-
'Fragment value must be a RecordData',
|
|
146
|
-
value === null || value instanceof RecordData,
|
|
147
|
-
);
|
|
148
|
-
assert(
|
|
149
|
-
'Fragment original value must be a RecordData',
|
|
150
|
-
originalValue === null || originalValue instanceof RecordData,
|
|
151
|
-
);
|
|
152
|
-
return (
|
|
153
|
-
value !== originalValue ||
|
|
154
|
-
(value !== null && value.hasChangedAttributes())
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
currentState(fragment) {
|
|
159
|
-
assert(
|
|
160
|
-
'Fragment value must be a RecordData',
|
|
161
|
-
fragment === null || fragment instanceof RecordData,
|
|
162
|
-
);
|
|
163
|
-
return fragment === null ? null : fragment.getCurrentState();
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
canonicalState(fragment) {
|
|
167
|
-
assert(
|
|
168
|
-
'Fragment value must be a RecordData',
|
|
169
|
-
fragment === null || fragment instanceof RecordData,
|
|
170
|
-
);
|
|
171
|
-
return fragment === null ? null : fragment.getCanonicalState();
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
class FragmentArrayBehavior {
|
|
176
|
-
constructor(recordData, definition) {
|
|
177
|
-
this.recordData = recordData;
|
|
178
|
-
this.definition = definition;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
getDefaultValue(key) {
|
|
182
|
-
const { options } = this.definition;
|
|
183
|
-
if (options.defaultValue === undefined) {
|
|
184
|
-
return [];
|
|
185
|
-
}
|
|
186
|
-
let defaultValue;
|
|
187
|
-
if (typeof options.defaultValue === 'function') {
|
|
188
|
-
const record = this.recordData._fragmentGetRecord();
|
|
189
|
-
defaultValue = options.defaultValue.call(null, record, options, key);
|
|
190
|
-
} else {
|
|
191
|
-
defaultValue = options.defaultValue;
|
|
192
|
-
}
|
|
193
|
-
assert(
|
|
194
|
-
"The fragment array's default value must be an array of fragments or null",
|
|
195
|
-
defaultValue === null ||
|
|
196
|
-
(isArray(defaultValue) &&
|
|
197
|
-
defaultValue.every((v) => typeOf(v) === 'object' || isFragment(v))),
|
|
198
|
-
);
|
|
199
|
-
if (defaultValue === null) {
|
|
200
|
-
return null;
|
|
201
|
-
}
|
|
202
|
-
return defaultValue.map((item) => {
|
|
203
|
-
if (isFragment(item)) {
|
|
204
|
-
assert(
|
|
205
|
-
`The fragment array's default value can only include '${this.definition.modelName}' fragments`,
|
|
206
|
-
isInstanceOfType(
|
|
207
|
-
item.store.modelFor(this.definition.modelName),
|
|
208
|
-
item,
|
|
209
|
-
),
|
|
210
|
-
);
|
|
211
|
-
const recordData = recordDataFor(defaultValue);
|
|
212
|
-
recordData.setFragmentOwner(this.recordData, key);
|
|
213
|
-
return recordData;
|
|
214
|
-
}
|
|
215
|
-
return this.recordData._newFragmentRecordData(this.definition, item);
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
pushData(fragmentArray, canonical) {
|
|
220
|
-
assert(
|
|
221
|
-
'Fragment array value must be an array of RecordData',
|
|
222
|
-
fragmentArray === null ||
|
|
223
|
-
(isArray(fragmentArray) &&
|
|
224
|
-
fragmentArray.every((rd) => rd instanceof RecordData)),
|
|
225
|
-
);
|
|
226
|
-
assert(
|
|
227
|
-
'Fragment array canonical value must be an array of objects',
|
|
228
|
-
canonical === null ||
|
|
229
|
-
(isArray(canonical) && canonical.every((v) => typeOf(v) === 'object')),
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
if (canonical === null) {
|
|
233
|
-
// push replaced fragment array with null
|
|
234
|
-
return null;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// merge the fragment array with the pushed data
|
|
238
|
-
return canonical.map((attributes, i) => {
|
|
239
|
-
const fragment = fragmentArray?.[i];
|
|
240
|
-
if (fragment) {
|
|
241
|
-
fragment._fragmentPushData({ attributes });
|
|
242
|
-
return fragment;
|
|
243
|
-
} else {
|
|
244
|
-
return this.recordData._newFragmentRecordData(
|
|
245
|
-
this.definition,
|
|
246
|
-
attributes,
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
willCommit(fragmentArray) {
|
|
253
|
-
assert(
|
|
254
|
-
'Fragment array value must be an array of RecordData',
|
|
255
|
-
isArray(fragmentArray) &&
|
|
256
|
-
fragmentArray.every((rd) => rd instanceof RecordData),
|
|
257
|
-
);
|
|
258
|
-
fragmentArray.forEach((fragment) => fragment._fragmentWillCommit());
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
didCommit(fragmentArray, canonical) {
|
|
262
|
-
assert(
|
|
263
|
-
'Fragment array value must be an array of RecordData',
|
|
264
|
-
fragmentArray === null ||
|
|
265
|
-
(isArray(fragmentArray) &&
|
|
266
|
-
fragmentArray.every((rd) => rd instanceof RecordData)),
|
|
267
|
-
);
|
|
268
|
-
assert(
|
|
269
|
-
'Fragment array canonical value must be an array of objects',
|
|
270
|
-
canonical == null ||
|
|
271
|
-
(isArray(canonical) && canonical.every((v) => typeOf(v) === 'object')),
|
|
272
|
-
);
|
|
273
|
-
|
|
274
|
-
if (canonical == null) {
|
|
275
|
-
fragmentArray?.forEach((fragment) => fragment._fragmentDidCommit(null));
|
|
276
|
-
if (canonical === null) {
|
|
277
|
-
// server replaced fragment array with null
|
|
278
|
-
return null;
|
|
279
|
-
}
|
|
280
|
-
// server confirmed in-flight fragments
|
|
281
|
-
return fragmentArray;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// merge the fragment array with the new data from the server
|
|
285
|
-
const result = canonical.map((attributes, i) => {
|
|
286
|
-
const fragment = fragmentArray?.[i];
|
|
287
|
-
if (fragment) {
|
|
288
|
-
fragment._fragmentDidCommit({ attributes });
|
|
289
|
-
return fragment;
|
|
290
|
-
} else {
|
|
291
|
-
return this.recordData._newFragmentRecordData(
|
|
292
|
-
this.definition,
|
|
293
|
-
attributes,
|
|
294
|
-
);
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
// cleanup the remaining fragments
|
|
299
|
-
for (let i = canonical.length; i < fragmentArray?.length; ++i) {
|
|
300
|
-
fragmentArray[i]._fragmentDidCommit(null);
|
|
301
|
-
}
|
|
302
|
-
return result;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
commitWasRejected(fragmentArray) {
|
|
306
|
-
assert(
|
|
307
|
-
'Fragment array value must be an array of RecordData',
|
|
308
|
-
isArray(fragmentArray) &&
|
|
309
|
-
fragmentArray.every((rd) => rd instanceof RecordData),
|
|
310
|
-
);
|
|
311
|
-
fragmentArray.forEach((fragment) => fragment._fragmentCommitWasRejected());
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
rollback(fragmentArray) {
|
|
315
|
-
assert(
|
|
316
|
-
'Fragment array value must be an array of RecordData',
|
|
317
|
-
isArray(fragmentArray) &&
|
|
318
|
-
fragmentArray.every((rd) => rd instanceof RecordData),
|
|
319
|
-
);
|
|
320
|
-
fragmentArray.forEach((fragment) => fragment._fragmentRollbackAttributes());
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
unload(fragmentArray) {
|
|
324
|
-
assert(
|
|
325
|
-
'Fragment array value must be an array of RecordData',
|
|
326
|
-
isArray(fragmentArray) &&
|
|
327
|
-
fragmentArray.every((rd) => rd instanceof RecordData),
|
|
328
|
-
);
|
|
329
|
-
fragmentArray.forEach((fragment) => fragment._fragmentUnloadRecord());
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
isDirty(value, originalValue) {
|
|
333
|
-
assert(
|
|
334
|
-
'Fragment array value must be an array of RecordData',
|
|
335
|
-
value === null ||
|
|
336
|
-
(isArray(value) && value.every((rd) => rd instanceof RecordData)),
|
|
337
|
-
);
|
|
338
|
-
assert(
|
|
339
|
-
'Fragment array original value must be an array of RecordData',
|
|
340
|
-
originalValue === null ||
|
|
341
|
-
(isArray(originalValue) &&
|
|
342
|
-
originalValue.every((rd) => rd instanceof RecordData)),
|
|
343
|
-
);
|
|
344
|
-
return (
|
|
345
|
-
!isArrayEqual(value, originalValue) ||
|
|
346
|
-
(value !== null && value.some((rd) => rd.hasChangedAttributes()))
|
|
347
|
-
);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
currentState(fragmentArray) {
|
|
351
|
-
assert(
|
|
352
|
-
'Fragment array value must be an array of RecordData',
|
|
353
|
-
fragmentArray === null ||
|
|
354
|
-
(isArray(fragmentArray) &&
|
|
355
|
-
fragmentArray.every((rd) => rd instanceof RecordData)),
|
|
356
|
-
);
|
|
357
|
-
return fragmentArray === null
|
|
358
|
-
? null
|
|
359
|
-
: fragmentArray.map((fragment) => fragment.getCurrentState());
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
canonicalState(fragmentArray) {
|
|
363
|
-
assert(
|
|
364
|
-
'Fragment array value must be an array of RecordData',
|
|
365
|
-
fragmentArray === null ||
|
|
366
|
-
(isArray(fragmentArray) &&
|
|
367
|
-
fragmentArray.every((rd) => rd instanceof RecordData)),
|
|
368
|
-
);
|
|
369
|
-
return fragmentArray === null
|
|
370
|
-
? null
|
|
371
|
-
: fragmentArray.map((fragment) => fragment.getCanonicalState());
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
class ArrayBehavior {
|
|
376
|
-
constructor(recordData, definition) {
|
|
377
|
-
this.recordData = recordData;
|
|
378
|
-
this.definition = definition;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
getDefaultValue(key) {
|
|
382
|
-
const { options } = this.definition;
|
|
383
|
-
if (options.defaultValue === undefined) {
|
|
384
|
-
return [];
|
|
385
|
-
}
|
|
386
|
-
let defaultValue;
|
|
387
|
-
if (typeof options.defaultValue === 'function') {
|
|
388
|
-
const record = this.recordData._fragmentGetRecord();
|
|
389
|
-
defaultValue = options.defaultValue.call(null, record, options, key);
|
|
390
|
-
} else {
|
|
391
|
-
defaultValue = options.defaultValue;
|
|
392
|
-
}
|
|
393
|
-
assert(
|
|
394
|
-
"The array's default value must be an array or null",
|
|
395
|
-
defaultValue === null || isArray(defaultValue),
|
|
396
|
-
);
|
|
397
|
-
if (defaultValue === null) {
|
|
398
|
-
return null;
|
|
399
|
-
}
|
|
400
|
-
return defaultValue.slice();
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
pushData(array, canonical) {
|
|
404
|
-
assert('Array value must be an array', array === null || isArray(array));
|
|
405
|
-
assert(
|
|
406
|
-
'Array canonical value must be an array',
|
|
407
|
-
canonical === null || isArray(canonical),
|
|
408
|
-
);
|
|
409
|
-
if (canonical === null) {
|
|
410
|
-
return null;
|
|
411
|
-
}
|
|
412
|
-
return canonical.slice();
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
willCommit(array) {
|
|
416
|
-
assert('Array value must be an array', isArray(array));
|
|
417
|
-
// nothing to do
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
didCommit(array, canonical) {
|
|
421
|
-
assert('Array value must be an array', array === null || isArray(array));
|
|
422
|
-
assert(
|
|
423
|
-
'Array canonical value must be an array',
|
|
424
|
-
canonical === null || canonical === undefined || isArray(canonical),
|
|
425
|
-
);
|
|
426
|
-
if (canonical === null) {
|
|
427
|
-
// server replaced array with null
|
|
428
|
-
return null;
|
|
429
|
-
}
|
|
430
|
-
if (canonical === undefined) {
|
|
431
|
-
// server confirmed in-flight array
|
|
432
|
-
return array;
|
|
433
|
-
}
|
|
434
|
-
// server returned new canonical data
|
|
435
|
-
return canonical.slice();
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
commitWasRejected(array) {
|
|
439
|
-
assert('Array value must be an array', isArray(array));
|
|
440
|
-
// nothing to do
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
rollback(array) {
|
|
444
|
-
assert('Array value must be an array', isArray(array));
|
|
445
|
-
// nothing to do
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
unload(array) {
|
|
449
|
-
assert('Array value must be an array', isArray(array));
|
|
450
|
-
// nothing to do
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
isDirty(value, originalValue) {
|
|
454
|
-
assert('Array value must be an array', value === null || isArray(value));
|
|
455
|
-
assert(
|
|
456
|
-
'Array original value must be an array',
|
|
457
|
-
originalValue === null || isArray(originalValue),
|
|
458
|
-
);
|
|
459
|
-
return !isArrayEqual(value, originalValue);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
currentState(array) {
|
|
463
|
-
assert('Array value must be an array', array === null || isArray(array));
|
|
464
|
-
return array === null ? null : array.slice();
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
canonicalState(array) {
|
|
468
|
-
assert('Array value must be an array', array === null || isArray(array));
|
|
469
|
-
return array === null ? null : array.slice();
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
export default class FragmentRecordData extends RecordData {
|
|
474
|
-
constructor(identifier, storeWrapper) {
|
|
475
|
-
super(identifier, storeWrapper);
|
|
476
|
-
|
|
477
|
-
const behavior = Object.create(null);
|
|
478
|
-
const definitions = this.storeWrapper.attributesDefinitionFor(
|
|
479
|
-
this.modelName,
|
|
480
|
-
);
|
|
481
|
-
for (const [key, definition] of Object.entries(definitions)) {
|
|
482
|
-
if (!definition.isFragment) {
|
|
483
|
-
continue;
|
|
484
|
-
}
|
|
485
|
-
switch (definition.kind) {
|
|
486
|
-
case 'fragment-array':
|
|
487
|
-
behavior[key] = new FragmentArrayBehavior(this, definition);
|
|
488
|
-
break;
|
|
489
|
-
case 'fragment':
|
|
490
|
-
behavior[key] = new FragmentBehavior(this, definition);
|
|
491
|
-
break;
|
|
492
|
-
case 'array':
|
|
493
|
-
behavior[key] = new ArrayBehavior(this, definition);
|
|
494
|
-
break;
|
|
495
|
-
default:
|
|
496
|
-
assert(`Unsupported fragment type: ${definition.kind}`);
|
|
497
|
-
break;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
this._fragmentBehavior = behavior;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
_getFragmentDefault(key) {
|
|
504
|
-
const behavior = this._fragmentBehavior[key];
|
|
505
|
-
assert(
|
|
506
|
-
`Attribute '${key}' for model '${this.modelName}' must be a fragment`,
|
|
507
|
-
behavior != null,
|
|
508
|
-
);
|
|
509
|
-
assert(
|
|
510
|
-
'Fragment default value was already initialized',
|
|
511
|
-
!this.hasFragment(key),
|
|
512
|
-
);
|
|
513
|
-
const defaultValue = behavior.getDefaultValue(key);
|
|
514
|
-
this._fragmentData[key] = defaultValue;
|
|
515
|
-
return defaultValue;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
getFragment(key) {
|
|
519
|
-
if (key in this._fragments) {
|
|
520
|
-
return this._fragments[key];
|
|
521
|
-
} else if (key in this._inFlightFragments) {
|
|
522
|
-
return this._inFlightFragments[key];
|
|
523
|
-
} else if (key in this._fragmentData) {
|
|
524
|
-
return this._fragmentData[key];
|
|
525
|
-
} else {
|
|
526
|
-
return this._getFragmentDefault(key);
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
hasFragment(key) {
|
|
531
|
-
return (
|
|
532
|
-
key in this._fragments ||
|
|
533
|
-
key in this._inFlightFragments ||
|
|
534
|
-
key in this._fragmentData
|
|
535
|
-
);
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
setDirtyFragment(key, value) {
|
|
539
|
-
const behavior = this._fragmentBehavior[key];
|
|
540
|
-
assert(
|
|
541
|
-
`Attribute '${key}' for model '${this.modelName}' must be a fragment`,
|
|
542
|
-
behavior != null,
|
|
543
|
-
);
|
|
544
|
-
let originalValue;
|
|
545
|
-
if (key in this._inFlightFragments) {
|
|
546
|
-
originalValue = this._inFlightFragments[key];
|
|
547
|
-
} else if (key in this._fragmentData) {
|
|
548
|
-
originalValue = this._fragmentData[key];
|
|
549
|
-
} else {
|
|
550
|
-
originalValue = this._getFragmentDefault(key);
|
|
551
|
-
}
|
|
552
|
-
const isDirty = behavior.isDirty(value, originalValue);
|
|
553
|
-
const oldDirty = this.isFragmentDirty(key);
|
|
554
|
-
if (isDirty !== oldDirty) {
|
|
555
|
-
this.notifyStateChange(key);
|
|
556
|
-
}
|
|
557
|
-
if (isDirty) {
|
|
558
|
-
this._fragments[key] = value;
|
|
559
|
-
this.fragmentDidDirty();
|
|
560
|
-
} else {
|
|
561
|
-
delete this._fragments[key];
|
|
562
|
-
this.fragmentDidReset();
|
|
563
|
-
}
|
|
564
|
-
// this._fragmentArrayCache[key]?.notify();
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
setDirtyAttribute(key, value) {
|
|
568
|
-
assert(
|
|
569
|
-
`Attribute '${key}' for model '${this.modelName}' must not be a fragment`,
|
|
570
|
-
this._fragmentBehavior[key] == null,
|
|
571
|
-
);
|
|
572
|
-
const oldDirty = this.isAttrDirty(key);
|
|
573
|
-
super.setDirtyAttribute(key, value);
|
|
574
|
-
|
|
575
|
-
const isDirty = this.isAttrDirty(key);
|
|
576
|
-
if (isDirty !== oldDirty) {
|
|
577
|
-
this.notifyStateChange(key);
|
|
578
|
-
}
|
|
579
|
-
if (isDirty) {
|
|
580
|
-
this.fragmentDidDirty();
|
|
581
|
-
} else {
|
|
582
|
-
this.fragmentDidReset();
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
getFragmentOwner() {
|
|
587
|
-
return this._fragmentOwner?.recordData;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
setFragmentOwner(recordData, key) {
|
|
591
|
-
assert(
|
|
592
|
-
'Fragment owner must be a RecordData',
|
|
593
|
-
recordData instanceof RecordData,
|
|
594
|
-
);
|
|
595
|
-
assert(
|
|
596
|
-
'Fragment owner key must be a fragment',
|
|
597
|
-
recordData._fragmentBehavior[key] != null,
|
|
598
|
-
);
|
|
599
|
-
assert(
|
|
600
|
-
'Fragments can only belong to one owner, try copying instead',
|
|
601
|
-
!this._fragmentOwner || this._fragmentOwner.recordData === recordData,
|
|
602
|
-
);
|
|
603
|
-
this._fragmentOwner = { recordData, key };
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
_newFragmentRecordDataForKey(key, attributes) {
|
|
607
|
-
const behavior = this._fragmentBehavior[key];
|
|
608
|
-
assert(
|
|
609
|
-
`Attribute '${key}' for model '${this.modelName}' must be a fragment`,
|
|
610
|
-
behavior != null,
|
|
611
|
-
);
|
|
612
|
-
return this._newFragmentRecordData(behavior.definition, attributes);
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
_newFragmentRecordData(definition, attributes) {
|
|
616
|
-
const type = getActualFragmentType(
|
|
617
|
-
definition.modelName,
|
|
618
|
-
definition.options,
|
|
619
|
-
attributes,
|
|
620
|
-
this._fragmentGetRecord(),
|
|
621
|
-
);
|
|
622
|
-
const recordData = this.storeWrapper.recordDataFor(type);
|
|
623
|
-
recordData.setFragmentOwner(this, definition.name);
|
|
624
|
-
recordData._fragmentPushData({ attributes });
|
|
625
|
-
return recordData;
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
hasChangedAttributes() {
|
|
629
|
-
return super.hasChangedAttributes() || this.hasChangedFragments();
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
hasChangedFragments() {
|
|
633
|
-
return Object.keys(this._fragmentsOrInFlight).length > 0;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
isFragmentDirty(key) {
|
|
637
|
-
return this.__fragments?.[key] !== undefined;
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
getCanonicalState() {
|
|
641
|
-
const result = Object.assign({}, this._data);
|
|
642
|
-
for (const [key, behavior] of Object.entries(this._fragmentBehavior)) {
|
|
643
|
-
const value =
|
|
644
|
-
key in this._fragmentData
|
|
645
|
-
? this._fragmentData[key]
|
|
646
|
-
: this._getFragmentDefault(key);
|
|
647
|
-
result[key] = behavior.canonicalState(value);
|
|
648
|
-
}
|
|
649
|
-
return result;
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
getCurrentState() {
|
|
653
|
-
const result = Object.assign(
|
|
654
|
-
{},
|
|
655
|
-
this._data,
|
|
656
|
-
this._inFlightAttributes,
|
|
657
|
-
this._attributes,
|
|
658
|
-
);
|
|
659
|
-
for (const [key, behavior] of Object.entries(this._fragmentBehavior)) {
|
|
660
|
-
result[key] = behavior.currentState(this.getFragment(key));
|
|
661
|
-
}
|
|
662
|
-
return result;
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
/*
|
|
666
|
-
Returns an object, whose keys are changed properties, and value is an
|
|
667
|
-
[oldProp, newProp] array.
|
|
668
|
-
|
|
669
|
-
@method changedAttributes
|
|
670
|
-
@private
|
|
671
|
-
*/
|
|
672
|
-
changedAttributes() {
|
|
673
|
-
const result = super.changedAttributes();
|
|
674
|
-
if (this.hasChangedFragments()) {
|
|
675
|
-
Object.assign(result, this.changedFragments());
|
|
676
|
-
}
|
|
677
|
-
return result;
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
changedFragments() {
|
|
681
|
-
const diffData = Object.create(null);
|
|
682
|
-
for (const [key, newFragment] of Object.entries(
|
|
683
|
-
this._fragmentsOrInFlight,
|
|
684
|
-
)) {
|
|
685
|
-
const behavior = this._fragmentBehavior[key];
|
|
686
|
-
const oldFragment = this._fragmentData[key];
|
|
687
|
-
diffData[key] = [
|
|
688
|
-
behavior.canonicalState(oldFragment),
|
|
689
|
-
behavior.currentState(newFragment),
|
|
690
|
-
];
|
|
691
|
-
}
|
|
692
|
-
return diffData;
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
_changedFragmentKeys(updates) {
|
|
696
|
-
const changedKeys = [];
|
|
697
|
-
const original = Object.assign(
|
|
698
|
-
{},
|
|
699
|
-
this._fragmentData,
|
|
700
|
-
this._inFlightFragments,
|
|
701
|
-
);
|
|
702
|
-
for (const key of Object.keys(updates)) {
|
|
703
|
-
if (this._fragments[key]) {
|
|
704
|
-
continue;
|
|
705
|
-
}
|
|
706
|
-
const eitherIsNull = original[key] === null || updates[key] === null;
|
|
707
|
-
if (
|
|
708
|
-
eitherIsNull ||
|
|
709
|
-
diffArray(original[key], updates[key]).firstChangeIndex !== null
|
|
710
|
-
) {
|
|
711
|
-
changedKeys.push(key);
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
return changedKeys;
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
pushData(data, calculateChange) {
|
|
718
|
-
let changedFragmentKeys;
|
|
719
|
-
|
|
720
|
-
const subFragmentsToProcess = [];
|
|
721
|
-
if (data.attributes) {
|
|
722
|
-
// copy so that we don't mutate the caller's data
|
|
723
|
-
const attributes = Object.assign({}, data.attributes);
|
|
724
|
-
data = Object.assign({}, data, { attributes });
|
|
725
|
-
|
|
726
|
-
for (const [key, behavior] of Object.entries(this._fragmentBehavior)) {
|
|
727
|
-
const canonical = data.attributes[key];
|
|
728
|
-
if (canonical === undefined) {
|
|
729
|
-
continue;
|
|
730
|
-
}
|
|
731
|
-
// strip fragments from the attributes so the super call does not process them
|
|
732
|
-
delete data.attributes[key];
|
|
733
|
-
|
|
734
|
-
subFragmentsToProcess.push({ key, behavior, canonical, attributes });
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
// Wee need first the attributes to be setup before the fragment, to be able to access them (for polymorphic fragments for example)
|
|
739
|
-
const changedAttributeKeys = super.pushData(data, calculateChange);
|
|
740
|
-
|
|
741
|
-
if (data.attributes) {
|
|
742
|
-
const newCanonicalFragments = {};
|
|
743
|
-
|
|
744
|
-
subFragmentsToProcess.forEach(({ key, behavior, canonical }) => {
|
|
745
|
-
const current =
|
|
746
|
-
key in this._fragmentData
|
|
747
|
-
? this._fragmentData[key]
|
|
748
|
-
: this._getFragmentDefault(key);
|
|
749
|
-
newCanonicalFragments[key] = behavior.pushData(current, canonical);
|
|
750
|
-
});
|
|
751
|
-
|
|
752
|
-
if (calculateChange) {
|
|
753
|
-
changedFragmentKeys = this._changedFragmentKeys(newCanonicalFragments);
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
Object.assign(this._fragmentData, newCanonicalFragments);
|
|
757
|
-
// update fragment arrays
|
|
758
|
-
changedFragmentKeys?.forEach((key) => {
|
|
759
|
-
this._fragmentArrayCache[key]?.notify();
|
|
760
|
-
});
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
const changedKeys = mergeArrays(changedAttributeKeys, changedFragmentKeys);
|
|
764
|
-
if (gte('ember-data', '4.5.0') && changedKeys?.length > 0) {
|
|
765
|
-
internalModelFor(this).notifyAttributes(changedKeys);
|
|
766
|
-
}
|
|
767
|
-
// on ember-data 2.8 - 4.4, InternalModel.setupData will notify
|
|
768
|
-
return changedKeys || [];
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
willCommit() {
|
|
772
|
-
for (const [key, behavior] of Object.entries(this._fragmentBehavior)) {
|
|
773
|
-
const data = this.getFragment(key);
|
|
774
|
-
if (data) {
|
|
775
|
-
behavior.willCommit(data);
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
this._inFlightFragments = this._fragments;
|
|
779
|
-
this._fragments = null;
|
|
780
|
-
// this.notifyStateChange();
|
|
781
|
-
super.willCommit();
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
/**
|
|
785
|
-
* Checks if the fragments which are considered as changed are still
|
|
786
|
-
* different to the state which is acknowledged by the server.
|
|
787
|
-
*
|
|
788
|
-
* This method is needed when data for the internal model is pushed and the
|
|
789
|
-
* pushed data might acknowledge dirty attributes as confirmed.
|
|
790
|
-
*/
|
|
791
|
-
_updateChangedFragments() {
|
|
792
|
-
for (const key of Object.keys(this._fragments)) {
|
|
793
|
-
const value = this._fragments[key];
|
|
794
|
-
const originalValue = this._fragmentData[key];
|
|
795
|
-
const behavior = this._fragmentBehavior[key];
|
|
796
|
-
const isDirty = behavior.isDirty(value, originalValue);
|
|
797
|
-
if (!isDirty) {
|
|
798
|
-
delete this._fragments[key];
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
didCommit(data) {
|
|
804
|
-
if (data?.attributes) {
|
|
805
|
-
// copy so that we don't mutate the caller's data
|
|
806
|
-
const attributes = Object.assign({}, data.attributes);
|
|
807
|
-
data = Object.assign({}, data, { attributes });
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
const newCanonicalFragments = {};
|
|
811
|
-
for (const [key, behavior] of Object.entries(this._fragmentBehavior)) {
|
|
812
|
-
let canonical;
|
|
813
|
-
if (data?.attributes) {
|
|
814
|
-
// strip fragments from the attributes so the super call does not process them
|
|
815
|
-
canonical = data.attributes[key];
|
|
816
|
-
delete data.attributes[key];
|
|
817
|
-
}
|
|
818
|
-
const fragment =
|
|
819
|
-
key in this._inFlightFragments
|
|
820
|
-
? this._inFlightFragments[key]
|
|
821
|
-
: this._fragmentData[key];
|
|
822
|
-
newCanonicalFragments[key] = behavior.didCommit(fragment, canonical);
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
const changedFragmentKeys = this._changedFragmentKeys(
|
|
826
|
-
newCanonicalFragments,
|
|
827
|
-
);
|
|
828
|
-
Object.assign(this._fragmentData, newCanonicalFragments);
|
|
829
|
-
this._inFlightFragments = null;
|
|
830
|
-
|
|
831
|
-
this._updateChangedFragments();
|
|
832
|
-
|
|
833
|
-
const changedAttributeKeys = super.didCommit(data);
|
|
834
|
-
|
|
835
|
-
// update fragment arrays
|
|
836
|
-
changedFragmentKeys.forEach((key) => {
|
|
837
|
-
this._fragmentArrayCache[key]?.notify();
|
|
838
|
-
});
|
|
839
|
-
|
|
840
|
-
const changedKeys = mergeArrays(changedAttributeKeys, changedFragmentKeys);
|
|
841
|
-
if (gte('ember-data', '4.5.0') && changedKeys?.length > 0) {
|
|
842
|
-
internalModelFor(this).notifyAttributes(changedKeys);
|
|
843
|
-
}
|
|
844
|
-
// on ember-data 2.8 - 4.4, InternalModel.adapterDidCommit will notify
|
|
845
|
-
return changedKeys;
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
commitWasRejected(identifier, errors) {
|
|
849
|
-
for (const [key, behavior] of Object.entries(this._fragmentBehavior)) {
|
|
850
|
-
const fragment =
|
|
851
|
-
key in this._inFlightFragments
|
|
852
|
-
? this._inFlightFragments[key]
|
|
853
|
-
: this._fragmentData[key];
|
|
854
|
-
if (fragment == null) {
|
|
855
|
-
continue;
|
|
856
|
-
}
|
|
857
|
-
behavior.commitWasRejected(fragment);
|
|
858
|
-
}
|
|
859
|
-
Object.assign(this._fragments, this._inFlightFragments);
|
|
860
|
-
this._inFlightFragments = null;
|
|
861
|
-
super.commitWasRejected(identifier, errors);
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
rollbackAttributes() {
|
|
865
|
-
let dirtyFragmentKeys;
|
|
866
|
-
if (this.hasChangedFragments()) {
|
|
867
|
-
dirtyFragmentKeys = Object.keys(this._fragments);
|
|
868
|
-
dirtyFragmentKeys.forEach((key) => {
|
|
869
|
-
this.rollbackFragment(key);
|
|
870
|
-
});
|
|
871
|
-
this._fragments = null;
|
|
872
|
-
}
|
|
873
|
-
const dirtyAttributeKeys = super.rollbackAttributes();
|
|
874
|
-
this.notifyStateChange();
|
|
875
|
-
this.fragmentDidReset();
|
|
876
|
-
return mergeArrays(dirtyAttributeKeys, dirtyFragmentKeys);
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
rollbackFragment(key) {
|
|
880
|
-
const behavior = this._fragmentBehavior[key];
|
|
881
|
-
assert(
|
|
882
|
-
`Attribute '${key}' for model '${this.modelName}' must be a fragment`,
|
|
883
|
-
behavior != null,
|
|
884
|
-
);
|
|
885
|
-
if (!this.isFragmentDirty(key)) {
|
|
886
|
-
return;
|
|
887
|
-
}
|
|
888
|
-
delete this._fragments[key];
|
|
889
|
-
const fragment = this._fragmentData[key];
|
|
890
|
-
if (fragment == null) {
|
|
891
|
-
return;
|
|
892
|
-
}
|
|
893
|
-
behavior.rollback(fragment);
|
|
894
|
-
this._fragmentArrayCache[key]?.notify();
|
|
895
|
-
|
|
896
|
-
if (!this.hasChangedAttributes()) {
|
|
897
|
-
this.notifyStateChange(key);
|
|
898
|
-
this.fragmentDidReset();
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
reset() {
|
|
903
|
-
super.reset();
|
|
904
|
-
this.__fragments = null;
|
|
905
|
-
this.__inFlightFragments = null;
|
|
906
|
-
this.__fragmentData = null;
|
|
907
|
-
this.__fragmentArrayCache = null;
|
|
908
|
-
this._fragmentOwner = null;
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
unloadRecord() {
|
|
912
|
-
for (const [key, behavior] of Object.entries(this._fragmentBehavior)) {
|
|
913
|
-
const fragment = this._fragments[key];
|
|
914
|
-
if (fragment != null) {
|
|
915
|
-
behavior.unload(fragment);
|
|
916
|
-
}
|
|
917
|
-
const inFlight = this._inFlightFragments[key];
|
|
918
|
-
if (inFlight != null) {
|
|
919
|
-
behavior.unload(inFlight);
|
|
920
|
-
}
|
|
921
|
-
const fragmentData = this._fragmentData[key];
|
|
922
|
-
if (fragmentData != null) {
|
|
923
|
-
behavior.unload(fragmentData);
|
|
924
|
-
}
|
|
925
|
-
this._fragmentArrayCache[key]?.destroy();
|
|
926
|
-
}
|
|
927
|
-
super.unloadRecord();
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
/**
|
|
931
|
-
* When a fragment becomes dirty, update the dirty state of the fragment's owner
|
|
932
|
-
*/
|
|
933
|
-
fragmentDidDirty() {
|
|
934
|
-
assert('Fragment is not dirty', this.hasChangedAttributes());
|
|
935
|
-
if (!this._fragmentOwner) {
|
|
936
|
-
return;
|
|
937
|
-
}
|
|
938
|
-
const { recordData: owner, key } = this._fragmentOwner;
|
|
939
|
-
if (owner.isFragmentDirty(key)) {
|
|
940
|
-
// fragment owner is already dirty
|
|
941
|
-
return;
|
|
942
|
-
}
|
|
943
|
-
assert(
|
|
944
|
-
`Fragment '${key}' in owner '${owner.modelName}' has not been initialized`,
|
|
945
|
-
key in owner._fragmentData,
|
|
946
|
-
);
|
|
947
|
-
|
|
948
|
-
owner._fragments[key] = owner._fragmentData[key];
|
|
949
|
-
owner.notifyStateChange(key);
|
|
950
|
-
owner.fragmentDidDirty();
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
/**
|
|
954
|
-
* When a fragment becomes clean, update the fragment owner
|
|
955
|
-
*/
|
|
956
|
-
fragmentDidReset() {
|
|
957
|
-
if (!this._fragmentOwner) {
|
|
958
|
-
return;
|
|
959
|
-
}
|
|
960
|
-
const { recordData: owner, key } = this._fragmentOwner;
|
|
961
|
-
if (!owner.isFragmentDirty(key)) {
|
|
962
|
-
// fragment owner is already clean
|
|
963
|
-
return;
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
const behavior = owner._fragmentBehavior[key];
|
|
967
|
-
const value = owner.getFragment(key);
|
|
968
|
-
const originalValue = owner._fragmentData[key];
|
|
969
|
-
const isDirty = behavior.isDirty(value, originalValue);
|
|
970
|
-
|
|
971
|
-
if (isDirty) {
|
|
972
|
-
// fragment is still dirty
|
|
973
|
-
return;
|
|
974
|
-
}
|
|
975
|
-
|
|
976
|
-
delete owner._fragments[key];
|
|
977
|
-
owner.notifyStateChange(key);
|
|
978
|
-
owner.fragmentDidReset();
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
notifyStateChange(key) {
|
|
982
|
-
if (key && gte('ember-data', '4.5.0')) {
|
|
983
|
-
this.storeWrapper.notifyPropertyChange(
|
|
984
|
-
this.modelName,
|
|
985
|
-
this.id,
|
|
986
|
-
this.clientId,
|
|
987
|
-
key,
|
|
988
|
-
);
|
|
989
|
-
} else {
|
|
990
|
-
this.storeWrapper.notifyStateChange(
|
|
991
|
-
this.modelName,
|
|
992
|
-
this.id,
|
|
993
|
-
this.clientId,
|
|
994
|
-
key,
|
|
995
|
-
);
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
/*
|
|
1000
|
-
* Ensure that any changes to the fragment record-data also update the InternalModel's
|
|
1001
|
-
* state machine and fire property change notifications on the Record
|
|
1002
|
-
*/
|
|
1003
|
-
|
|
1004
|
-
_fragmentGetRecord(properties) {
|
|
1005
|
-
if (gte('ember-data', '4.5.0')) {
|
|
1006
|
-
return this.storeWrapper._store._instanceCache.getRecord(
|
|
1007
|
-
this.identifier,
|
|
1008
|
-
properties,
|
|
1009
|
-
);
|
|
1010
|
-
}
|
|
1011
|
-
return internalModelFor(this).getRecord(properties);
|
|
1012
|
-
}
|
|
1013
|
-
_fragmentPushData(data) {
|
|
1014
|
-
internalModelFor(this).setupData(data);
|
|
1015
|
-
}
|
|
1016
|
-
_fragmentWillCommit() {
|
|
1017
|
-
internalModelFor(this).adapterWillCommit();
|
|
1018
|
-
}
|
|
1019
|
-
_fragmentDidCommit(data) {
|
|
1020
|
-
internalModelFor(this).adapterDidCommit(data);
|
|
1021
|
-
}
|
|
1022
|
-
_fragmentRollbackAttributes() {
|
|
1023
|
-
internalModelFor(this).rollbackAttributes();
|
|
1024
|
-
}
|
|
1025
|
-
_fragmentCommitWasRejected() {
|
|
1026
|
-
internalModelFor(this).adapterDidInvalidate();
|
|
1027
|
-
}
|
|
1028
|
-
_fragmentUnloadRecord() {
|
|
1029
|
-
internalModelFor(this).unloadRecord();
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
/**
|
|
1033
|
-
* The current dirty state
|
|
1034
|
-
*/
|
|
1035
|
-
get _fragments() {
|
|
1036
|
-
if (this.__fragments === null) {
|
|
1037
|
-
this.__fragments = Object.create(null);
|
|
1038
|
-
}
|
|
1039
|
-
return this.__fragments;
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
set _fragments(v) {
|
|
1043
|
-
this.__fragments = v;
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
/**
|
|
1047
|
-
* The current saved state
|
|
1048
|
-
*/
|
|
1049
|
-
get _fragmentData() {
|
|
1050
|
-
if (this.__fragmentData === null) {
|
|
1051
|
-
this.__fragmentData = Object.create(null);
|
|
1052
|
-
}
|
|
1053
|
-
return this.__fragmentData;
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
set _fragmentData(v) {
|
|
1057
|
-
this.__fragmentData = v;
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
/**
|
|
1061
|
-
* The fragments which are currently being saved to the backend
|
|
1062
|
-
*/
|
|
1063
|
-
get _inFlightFragments() {
|
|
1064
|
-
if (this.__inFlightFragments === null) {
|
|
1065
|
-
this.__inFlightFragments = Object.create(null);
|
|
1066
|
-
}
|
|
1067
|
-
return this.__inFlightFragments;
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
set _inFlightFragments(v) {
|
|
1071
|
-
this.__inFlightFragments = v;
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
get _fragmentsOrInFlight() {
|
|
1075
|
-
return this.__inFlightFragments &&
|
|
1076
|
-
Object.keys(this.__inFlightFragments).length > 0
|
|
1077
|
-
? this.__inFlightFragments
|
|
1078
|
-
: this.__fragments || {};
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
/**
|
|
1082
|
-
* Fragment array instances
|
|
1083
|
-
*
|
|
1084
|
-
* This likely belongs in InternalModel, since ember-data caches its has-many
|
|
1085
|
-
* arrays in `InternalModel#_manyArrayCache`. But we can't extend InternalModel.
|
|
1086
|
-
*/
|
|
1087
|
-
get _fragmentArrayCache() {
|
|
1088
|
-
if (this.__fragmentArrayCache === null) {
|
|
1089
|
-
this.__fragmentArrayCache = Object.create(null);
|
|
1090
|
-
}
|
|
1091
|
-
return this.__fragmentArrayCache;
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
function internalModelFor(recordData) {
|
|
1096
|
-
const store = recordData.storeWrapper._store;
|
|
1097
|
-
if (gte('ember-data', '4.5.0')) {
|
|
1098
|
-
return store._instanceCache._internalModelForResource(
|
|
1099
|
-
recordData.identifier,
|
|
1100
|
-
);
|
|
1101
|
-
}
|
|
1102
|
-
return store._internalModelForResource(recordData.identifier);
|
|
1103
|
-
}
|
|
1104
|
-
|
|
1105
|
-
function isArrayEqual(a, b) {
|
|
1106
|
-
if (a === b) {
|
|
1107
|
-
return true;
|
|
1108
|
-
}
|
|
1109
|
-
if (a === null || b === null) {
|
|
1110
|
-
return false;
|
|
1111
|
-
}
|
|
1112
|
-
if (a.length !== b.length) {
|
|
1113
|
-
return false;
|
|
1114
|
-
}
|
|
1115
|
-
for (let i = 0; i < a.length; ++i) {
|
|
1116
|
-
if (a[i] !== b[i]) {
|
|
1117
|
-
return false;
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
return true;
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
function mergeArrays(a, b) {
|
|
1124
|
-
if (b == null) {
|
|
1125
|
-
return a;
|
|
1126
|
-
}
|
|
1127
|
-
if (a == null) {
|
|
1128
|
-
return b;
|
|
1129
|
-
}
|
|
1130
|
-
return [...a, ...b];
|
|
1131
|
-
}
|