@ember-data/store 4.8.0-alpha.1 → 4.8.0-alpha.4
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/addon/-debug/index.js +1 -1
- package/addon/-private/{identifier-cache.ts → caches/identifier-cache.ts} +114 -47
- package/addon/-private/caches/instance-cache.ts +702 -0
- package/addon/-private/{record-data-for.ts → caches/record-data-for.ts} +2 -2
- package/addon/-private/index.ts +38 -21
- package/addon/-private/{model → legacy-model-support}/record-reference.ts +15 -13
- package/addon/-private/{schema-definition-service.ts → legacy-model-support/schema-definition-service.ts} +13 -9
- package/addon/-private/{model → legacy-model-support}/shim-model-class.ts +8 -4
- package/addon/-private/{record-array-manager.ts → managers/record-array-manager.ts} +21 -44
- package/addon/-private/managers/record-data-manager.ts +830 -0
- package/addon/-private/managers/record-data-store-wrapper.ts +413 -0
- package/addon/-private/managers/record-notification-manager.ts +90 -0
- package/addon/-private/network/fetch-manager.ts +552 -0
- package/addon/-private/{finders.js → network/finders.js} +4 -12
- package/addon/-private/{request-cache.ts → network/request-cache.ts} +1 -1
- package/addon/-private/{snapshot-record-array.ts → network/snapshot-record-array.ts} +3 -3
- package/addon/-private/{snapshot.ts → network/snapshot.ts} +40 -49
- package/addon/-private/{promise-proxies.ts → proxies/promise-proxies.ts} +4 -4
- package/addon/-private/{promise-proxy-base.js → proxies/promise-proxy-base.js} +0 -0
- package/addon/-private/record-arrays/adapter-populated-record-array.ts +9 -11
- package/addon/-private/record-arrays/record-array.ts +25 -15
- package/addon/-private/{core-store.ts → store-service.ts} +412 -148
- package/addon/-private/{coerce-id.ts → utils/coerce-id.ts} +1 -1
- package/addon/-private/{common.js → utils/common.js} +1 -2
- package/addon/-private/utils/construct-resource.ts +2 -2
- package/addon/-private/{identifer-debug-consts.ts → utils/identifer-debug-consts.ts} +0 -0
- package/addon/-private/{normalize-model-name.ts → utils/normalize-model-name.ts} +1 -3
- package/addon/-private/utils/promise-record.ts +3 -3
- package/addon/-private/{serializer-response.ts → utils/serializer-response.ts} +2 -2
- package/addon/-private/utils/uuid-polyfill.ts +71 -0
- package/addon/-private/{weak-cache.ts → utils/weak-cache.ts} +0 -0
- package/package.json +11 -7
- package/addon/-private/errors-utils.js +0 -146
- package/addon/-private/fetch-manager.ts +0 -597
- package/addon/-private/identity-map.ts +0 -54
- package/addon/-private/instance-cache.ts +0 -387
- package/addon/-private/internal-model-factory.ts +0 -359
- package/addon/-private/internal-model-map.ts +0 -121
- package/addon/-private/model/internal-model.ts +0 -602
- package/addon/-private/record-data-store-wrapper.ts +0 -243
- package/addon/-private/record-notification-manager.ts +0 -73
package/addon/-debug/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { DEBUG } from '@glimmer/env';
|
|
|
9
9
|
relationship (specified via `relationshipMeta`) of the `record`.
|
|
10
10
|
|
|
11
11
|
This utility should only be used internally, as both record parameters must
|
|
12
|
-
be
|
|
12
|
+
be stable record identifiers and the `relationshipMeta` needs to be the meta
|
|
13
13
|
information about the relationship, retrieved via
|
|
14
14
|
`record.relationshipFor(key)`.
|
|
15
15
|
*/
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
import { assert, warn } from '@ember/debug';
|
|
5
5
|
import { DEBUG } from '@glimmer/env';
|
|
6
6
|
|
|
7
|
+
import { getOwnConfig, importSync, macroCondition } from '@embroider/macros';
|
|
8
|
+
|
|
9
|
+
import { LOG_IDENTIFIERS } from '@ember-data/private-build-infra/debugging';
|
|
7
10
|
import type { ExistingResourceObject, ResourceIdentifierObject } from '@ember-data/types/q/ember-data-json-api';
|
|
8
11
|
import type {
|
|
9
12
|
ForgetMethod,
|
|
@@ -18,11 +21,11 @@ import type {
|
|
|
18
21
|
} from '@ember-data/types/q/identifier';
|
|
19
22
|
import type { ConfidentDict } from '@ember-data/types/q/utils';
|
|
20
23
|
|
|
21
|
-
import coerceId from '
|
|
22
|
-
import { DEBUG_CLIENT_ORIGINATED, DEBUG_IDENTIFIER_BUCKET } from '
|
|
23
|
-
import
|
|
24
|
-
import
|
|
25
|
-
import WeakCache from '
|
|
24
|
+
import coerceId from '../utils/coerce-id';
|
|
25
|
+
import { DEBUG_CLIENT_ORIGINATED, DEBUG_IDENTIFIER_BUCKET } from '../utils/identifer-debug-consts';
|
|
26
|
+
import isNonEmptyString from '../utils/is-non-empty-string';
|
|
27
|
+
import normalizeModelName from '../utils/normalize-model-name';
|
|
28
|
+
import WeakCache from '../utils/weak-cache';
|
|
26
29
|
|
|
27
30
|
const IDENTIFIERS = new WeakSet();
|
|
28
31
|
|
|
@@ -33,6 +36,10 @@ export function isStableIdentifier(identifier: Object): identifier is StableReco
|
|
|
33
36
|
const isFastBoot = typeof FastBoot !== 'undefined';
|
|
34
37
|
const _crypto: Crypto = isFastBoot ? (FastBoot.require('crypto') as Crypto) : window.crypto;
|
|
35
38
|
|
|
39
|
+
if (macroCondition(getOwnConfig<{ polyfillUUID: boolean }>().polyfillUUID)) {
|
|
40
|
+
importSync('./utils/uuid-polyfill');
|
|
41
|
+
}
|
|
42
|
+
|
|
36
43
|
function uuidv4(): string {
|
|
37
44
|
return _crypto.randomUUID();
|
|
38
45
|
}
|
|
@@ -47,7 +54,6 @@ function freeze<T>(obj: T): T {
|
|
|
47
54
|
interface KeyOptions {
|
|
48
55
|
lid: IdentifierMap;
|
|
49
56
|
id: IdentifierMap;
|
|
50
|
-
_allIdentifiers: StableRecordIdentifier[];
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
type IdentifierMap = ConfidentDict<StableRecordIdentifier>;
|
|
@@ -114,19 +120,15 @@ if (DEBUG) {
|
|
|
114
120
|
@public
|
|
115
121
|
*/
|
|
116
122
|
export class IdentifierCache {
|
|
117
|
-
// Typescript still leaks private properties in the final
|
|
118
|
-
// compiled class, so we may want to move these from _underscore
|
|
119
|
-
// to a WeakMap to avoid leaking
|
|
120
|
-
// currently we leak this for test purposes
|
|
121
123
|
_cache = {
|
|
122
124
|
lids: Object.create(null) as IdentifierMap,
|
|
123
125
|
types: Object.create(null) as TypeMap,
|
|
124
126
|
};
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
declare _generate: GenerationMethod;
|
|
128
|
+
declare _update: UpdateMethod;
|
|
129
|
+
declare _forget: ForgetMethod;
|
|
130
|
+
declare _reset: ResetMethod;
|
|
131
|
+
declare _merge: MergeMethod;
|
|
130
132
|
|
|
131
133
|
constructor() {
|
|
132
134
|
// we cache the user configuredGenerationMethod at init because it must
|
|
@@ -141,8 +143,8 @@ export class IdentifierCache {
|
|
|
141
143
|
/**
|
|
142
144
|
* Internal hook to allow management of merge conflicts with identifiers.
|
|
143
145
|
*
|
|
144
|
-
* we allow late binding of this private internal merge so that
|
|
145
|
-
* can insert itself here to handle elimination of duplicates
|
|
146
|
+
* we allow late binding of this private internal merge so that
|
|
147
|
+
* the cache can insert itself here to handle elimination of duplicates
|
|
146
148
|
*
|
|
147
149
|
* @method __configureMerge
|
|
148
150
|
* @private
|
|
@@ -155,12 +157,9 @@ export class IdentifierCache {
|
|
|
155
157
|
* @method _getRecordIdentifier
|
|
156
158
|
* @private
|
|
157
159
|
*/
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
shouldGenerate: false
|
|
162
|
-
): StableRecordIdentifier | undefined;
|
|
163
|
-
private _getRecordIdentifier(
|
|
160
|
+
_getRecordIdentifier(resource: ResourceIdentifierObject, shouldGenerate: true): StableRecordIdentifier;
|
|
161
|
+
_getRecordIdentifier(resource: ResourceIdentifierObject, shouldGenerate: false): StableRecordIdentifier | undefined;
|
|
162
|
+
_getRecordIdentifier(
|
|
164
163
|
resource: ResourceIdentifierObject,
|
|
165
164
|
shouldGenerate: boolean = false
|
|
166
165
|
): StableRecordIdentifier | undefined {
|
|
@@ -168,10 +167,14 @@ export class IdentifierCache {
|
|
|
168
167
|
if (isStableIdentifier(resource)) {
|
|
169
168
|
if (DEBUG) {
|
|
170
169
|
// TODO should we instead just treat this case as a new generation skipping the short circuit?
|
|
171
|
-
if (!(resource.lid
|
|
170
|
+
if (!(this._cache.lids[resource.lid] !== undefined) || this._cache.lids[resource.lid] !== resource) {
|
|
172
171
|
throw new Error(`The supplied identifier ${resource} does not belong to this store instance`);
|
|
173
172
|
}
|
|
174
173
|
}
|
|
174
|
+
if (LOG_IDENTIFIERS) {
|
|
175
|
+
// eslint-disable-next-line no-console
|
|
176
|
+
console.log(`Identifiers: Peeked Identifier was already Stable ${String(resource)}`);
|
|
177
|
+
}
|
|
175
178
|
return resource;
|
|
176
179
|
}
|
|
177
180
|
|
|
@@ -179,11 +182,20 @@ export class IdentifierCache {
|
|
|
179
182
|
let identifier: StableRecordIdentifier | undefined = lid !== null ? this._cache.lids[lid] : undefined;
|
|
180
183
|
|
|
181
184
|
if (identifier !== undefined) {
|
|
185
|
+
if (LOG_IDENTIFIERS) {
|
|
186
|
+
// eslint-disable-next-line no-console
|
|
187
|
+
console.log(`Identifiers: cache HIT ${identifier}`, resource);
|
|
188
|
+
}
|
|
182
189
|
return identifier;
|
|
183
190
|
}
|
|
184
191
|
|
|
192
|
+
if (LOG_IDENTIFIERS) {
|
|
193
|
+
// eslint-disable-next-line no-console
|
|
194
|
+
console.groupCollapsed(`Identifiers: ${shouldGenerate ? 'Generating' : 'Peeking'} Identifier`, resource);
|
|
195
|
+
}
|
|
196
|
+
|
|
185
197
|
if (shouldGenerate === false) {
|
|
186
|
-
if (!(
|
|
198
|
+
if (!(resource as ExistingResourceObject).type || !(resource as ExistingResourceObject).id) {
|
|
187
199
|
return;
|
|
188
200
|
}
|
|
189
201
|
}
|
|
@@ -211,6 +223,10 @@ export class IdentifierCache {
|
|
|
211
223
|
// we have definitely not seen this resource before
|
|
212
224
|
// so we allow the user configured `GenerationMethod` to tell us
|
|
213
225
|
let newLid = this._generate(resource, 'record');
|
|
226
|
+
if (LOG_IDENTIFIERS) {
|
|
227
|
+
// eslint-disable-next-line no-console
|
|
228
|
+
console.log(`Identifiers: lid ${newLid} determined for resource`, resource);
|
|
229
|
+
}
|
|
214
230
|
|
|
215
231
|
// we do this _even_ when `lid` is present because secondary lookups
|
|
216
232
|
// may need to be populated, but we enforce not giving us something
|
|
@@ -234,7 +250,7 @@ export class IdentifierCache {
|
|
|
234
250
|
if (DEBUG) {
|
|
235
251
|
// realistically if you hit this it means you changed `type` :/
|
|
236
252
|
// TODO consider how to handle type change assertions more gracefully
|
|
237
|
-
if (identifier.lid
|
|
253
|
+
if (this._cache.lids[identifier.lid] !== undefined) {
|
|
238
254
|
throw new Error(`You should not change the <type> of a RecordIdentifier`);
|
|
239
255
|
}
|
|
240
256
|
}
|
|
@@ -244,9 +260,17 @@ export class IdentifierCache {
|
|
|
244
260
|
// TODO consider having the `lid` cache be
|
|
245
261
|
// one level up
|
|
246
262
|
keyOptions.lid[identifier.lid] = identifier;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
263
|
+
|
|
264
|
+
if (LOG_IDENTIFIERS && shouldGenerate) {
|
|
265
|
+
// eslint-disable-next-line no-console
|
|
266
|
+
console.log(`Identifiers: generated ${String(identifier)} for`, resource);
|
|
267
|
+
if (resource[DEBUG_IDENTIFIER_BUCKET]) {
|
|
268
|
+
// eslint-disable-next-line no-console
|
|
269
|
+
console.trace(
|
|
270
|
+
`[WARNING] Identifiers: generated a new identifier from a previously used identifier. This is likely a bug.`
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
250
274
|
}
|
|
251
275
|
|
|
252
276
|
// populate our own secondary lookup table
|
|
@@ -266,6 +290,15 @@ export class IdentifierCache {
|
|
|
266
290
|
}
|
|
267
291
|
}
|
|
268
292
|
|
|
293
|
+
if (LOG_IDENTIFIERS) {
|
|
294
|
+
if (!identifier && !shouldGenerate) {
|
|
295
|
+
// eslint-disable-next-line no-console
|
|
296
|
+
console.log(`Identifiers: cache MISS`, resource);
|
|
297
|
+
}
|
|
298
|
+
// eslint-disable-next-line no-console
|
|
299
|
+
console.groupEnd();
|
|
300
|
+
}
|
|
301
|
+
|
|
269
302
|
return identifier;
|
|
270
303
|
}
|
|
271
304
|
|
|
@@ -322,7 +355,7 @@ export class IdentifierCache {
|
|
|
322
355
|
|
|
323
356
|
// populate our unique table
|
|
324
357
|
if (DEBUG) {
|
|
325
|
-
if (identifier.lid
|
|
358
|
+
if (this._cache.lids[identifier.lid] !== undefined) {
|
|
326
359
|
throw new Error(`The lid generated for the new record is not unique as it matches an existing identifier`);
|
|
327
360
|
}
|
|
328
361
|
}
|
|
@@ -330,9 +363,11 @@ export class IdentifierCache {
|
|
|
330
363
|
|
|
331
364
|
// populate the type+lid cache
|
|
332
365
|
keyOptions.lid[newLid] = identifier;
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
366
|
+
|
|
367
|
+
if (LOG_IDENTIFIERS) {
|
|
368
|
+
// eslint-disable-next-line no-console
|
|
369
|
+
console.log(`Identifiers: createded identifier ${String(identifier)} for newly generated resource`, data);
|
|
370
|
+
}
|
|
336
371
|
|
|
337
372
|
return identifier;
|
|
338
373
|
}
|
|
@@ -362,13 +397,17 @@ export class IdentifierCache {
|
|
|
362
397
|
updateRecordIdentifier(identifierObject: RecordIdentifier, data: ResourceData): StableRecordIdentifier {
|
|
363
398
|
let identifier = this.getOrCreateRecordIdentifier(identifierObject);
|
|
364
399
|
|
|
365
|
-
let newId =
|
|
400
|
+
let newId =
|
|
401
|
+
(data as ExistingResourceObject).id !== undefined ? coerceId((data as ExistingResourceObject).id) : null;
|
|
366
402
|
let existingIdentifier = detectMerge(this._cache.types, identifier, data, newId, this._cache.lids);
|
|
367
403
|
|
|
368
404
|
if (!existingIdentifier) {
|
|
369
405
|
// If the incoming type does not match the identifier type, we need to create an identifier for the incoming
|
|
370
406
|
// data so we can merge the incoming data with the existing identifier, see #7325 and #7363
|
|
371
|
-
if (
|
|
407
|
+
if (
|
|
408
|
+
(data as ExistingResourceObject).type &&
|
|
409
|
+
identifier.type !== normalizeModelName((data as ExistingResourceObject).type)
|
|
410
|
+
) {
|
|
372
411
|
let incomingDataResource = { ...data };
|
|
373
412
|
// Need to strip the lid from the incomingData in order force a new identifier creation
|
|
374
413
|
delete incomingDataResource.lid;
|
|
@@ -378,7 +417,21 @@ export class IdentifierCache {
|
|
|
378
417
|
|
|
379
418
|
if (existingIdentifier) {
|
|
380
419
|
let keyOptions = getTypeIndex(this._cache.types, identifier.type);
|
|
381
|
-
|
|
420
|
+
let generatedIdentifier = identifier;
|
|
421
|
+
identifier = this._mergeRecordIdentifiers(
|
|
422
|
+
keyOptions,
|
|
423
|
+
generatedIdentifier,
|
|
424
|
+
existingIdentifier,
|
|
425
|
+
data,
|
|
426
|
+
newId as string
|
|
427
|
+
);
|
|
428
|
+
if (LOG_IDENTIFIERS) {
|
|
429
|
+
// eslint-disable-next-line no-console
|
|
430
|
+
console.log(
|
|
431
|
+
`Identifiers: merged identifiers ${generatedIdentifier.lid} and ${existingIdentifier.lid} for resource into ${identifier.lid}`,
|
|
432
|
+
data
|
|
433
|
+
);
|
|
434
|
+
}
|
|
382
435
|
}
|
|
383
436
|
|
|
384
437
|
let id = identifier.id;
|
|
@@ -387,12 +440,22 @@ export class IdentifierCache {
|
|
|
387
440
|
|
|
388
441
|
// add to our own secondary lookup table
|
|
389
442
|
if (id !== newId && newId !== null) {
|
|
443
|
+
if (LOG_IDENTIFIERS) {
|
|
444
|
+
// eslint-disable-next-line no-console
|
|
445
|
+
console.log(
|
|
446
|
+
`Identifiers: updated id for identifier ${identifier.lid} from '${id}' to '${newId}' for resource`,
|
|
447
|
+
data
|
|
448
|
+
);
|
|
449
|
+
}
|
|
390
450
|
let keyOptions = getTypeIndex(this._cache.types, identifier.type);
|
|
391
451
|
keyOptions.id[newId] = identifier;
|
|
392
452
|
|
|
393
453
|
if (id !== null) {
|
|
394
|
-
|
|
454
|
+
keyOptions.id[id] = undefined as unknown as StableRecordIdentifier;
|
|
395
455
|
}
|
|
456
|
+
} else if (LOG_IDENTIFIERS) {
|
|
457
|
+
// eslint-disable-next-line no-console
|
|
458
|
+
console.log(`Identifiers: updated identifier ${identifier.lid} resource`, data);
|
|
396
459
|
}
|
|
397
460
|
|
|
398
461
|
return identifier;
|
|
@@ -444,16 +507,17 @@ export class IdentifierCache {
|
|
|
444
507
|
let identifier = this.getOrCreateRecordIdentifier(identifierObject);
|
|
445
508
|
let keyOptions = getTypeIndex(this._cache.types, identifier.type);
|
|
446
509
|
if (identifier.id !== null) {
|
|
447
|
-
|
|
510
|
+
keyOptions.id[identifier.id] = undefined as unknown as StableRecordIdentifier;
|
|
448
511
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
let index = keyOptions._allIdentifiers.indexOf(identifier);
|
|
453
|
-
keyOptions._allIdentifiers.splice(index, 1);
|
|
512
|
+
this._cache.lids[identifier.lid] = undefined as unknown as StableRecordIdentifier;
|
|
513
|
+
keyOptions.lid[identifier.lid] = undefined as unknown as StableRecordIdentifier;
|
|
454
514
|
|
|
455
515
|
IDENTIFIERS.delete(identifierObject);
|
|
456
516
|
this._forget(identifier, 'record');
|
|
517
|
+
if (LOG_IDENTIFIERS) {
|
|
518
|
+
// eslint-disable-next-line no-console
|
|
519
|
+
console.log(`Identifiers: released identifier ${identifierObject.lid}`);
|
|
520
|
+
}
|
|
457
521
|
}
|
|
458
522
|
|
|
459
523
|
destroy() {
|
|
@@ -468,7 +532,6 @@ function getTypeIndex(typeMap: TypeMap, type: string): KeyOptions {
|
|
|
468
532
|
typeIndex = {
|
|
469
533
|
lid: Object.create(null),
|
|
470
534
|
id: Object.create(null),
|
|
471
|
-
_allIdentifiers: [],
|
|
472
535
|
};
|
|
473
536
|
typeMap[type] = typeIndex;
|
|
474
537
|
}
|
|
@@ -507,6 +570,10 @@ function makeStableRecordIdentifier(
|
|
|
507
570
|
let { type, id, lid } = recordIdentifier;
|
|
508
571
|
return `${clientOriginated ? '[CLIENT_ORIGINATED] ' : ''}${type}:${id} (${lid})`;
|
|
509
572
|
},
|
|
573
|
+
toJSON() {
|
|
574
|
+
let { type, id, lid } = recordIdentifier;
|
|
575
|
+
return { type, id, lid };
|
|
576
|
+
},
|
|
510
577
|
};
|
|
511
578
|
wrapper[DEBUG_CLIENT_ORIGINATED] = clientOriginated;
|
|
512
579
|
wrapper[DEBUG_IDENTIFIER_BUCKET] = bucket;
|
|
@@ -568,8 +635,8 @@ function performRecordIdentifierUpdate(identifier: StableRecordIdentifier, data:
|
|
|
568
635
|
// for the multiple-cache-key scenario we "could"
|
|
569
636
|
// use a heuristic to guess the best id for display
|
|
570
637
|
// (usually when `data.id` is available and `data.attributes` is not)
|
|
571
|
-
if (
|
|
572
|
-
identifier.id = coerceId(data.id);
|
|
638
|
+
if ((data as ExistingResourceObject).id !== undefined) {
|
|
639
|
+
identifier.id = coerceId((data as ExistingResourceObject).id);
|
|
573
640
|
}
|
|
574
641
|
}
|
|
575
642
|
|
|
@@ -587,7 +654,7 @@ function detectMerge(
|
|
|
587
654
|
|
|
588
655
|
return existingIdentifier !== undefined ? existingIdentifier : false;
|
|
589
656
|
} else {
|
|
590
|
-
let newType =
|
|
657
|
+
let newType = (data as ExistingResourceObject).type && normalizeModelName((data as ExistingResourceObject).type);
|
|
591
658
|
|
|
592
659
|
// If the ids and type are the same but lid is not the same, we should trigger a merge of the identifiers
|
|
593
660
|
if (id !== null && id === newId && newType === type && data.lid && data.lid !== lid) {
|