@ember-data/store 4.8.0-alpha.4 → 4.8.0-beta.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/addon/-debug/index.js +34 -12
- package/addon/-private/caches/identifier-cache.ts +44 -36
- package/addon/-private/caches/instance-cache.ts +112 -124
- package/addon/-private/caches/record-data-for.ts +1 -6
- package/addon/-private/index.ts +10 -7
- package/addon/-private/legacy-model-support/shim-model-class.ts +11 -8
- package/addon/-private/managers/record-array-manager.ts +282 -326
- package/addon/-private/managers/record-data-manager.ts +143 -128
- package/addon/-private/managers/record-data-store-wrapper.ts +18 -10
- package/addon/-private/managers/record-notification-manager.ts +31 -12
- package/addon/-private/network/fetch-manager.ts +18 -3
- package/addon/-private/network/finders.js +11 -6
- package/addon/-private/network/request-cache.ts +20 -17
- package/addon/-private/network/snapshot-record-array.ts +12 -29
- package/addon/-private/proxies/promise-proxies.ts +72 -11
- package/addon/-private/record-arrays/identifier-array.ts +924 -0
- package/addon/-private/store-service.ts +203 -108
- package/addon/-private/utils/is-non-empty-string.ts +1 -1
- package/addon/-private/utils/promise-record.ts +2 -3
- package/addon/-private/utils/uuid-polyfill.ts +58 -56
- package/package.json +5 -5
- package/addon/-private/backburner.js +0 -25
- package/addon/-private/record-arrays/adapter-populated-record-array.ts +0 -128
- package/addon/-private/record-arrays/record-array.ts +0 -328
- package/addon/-private/utils/weak-cache.ts +0 -125
package/addon/-debug/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { assert } from '@ember/debug';
|
|
2
2
|
import { DEBUG } from '@glimmer/env';
|
|
3
3
|
|
|
4
|
+
import { DEPRECATE_NON_EXPLICIT_POLYMORPHISM } from '@ember-data/private-build-infra/deprecations';
|
|
5
|
+
|
|
4
6
|
/*
|
|
5
7
|
Assert that `addedRecord` has a valid type so it can be added to the
|
|
6
8
|
relationship of the `record`.
|
|
@@ -29,18 +31,38 @@ if (DEBUG) {
|
|
|
29
31
|
};
|
|
30
32
|
|
|
31
33
|
assertPolymorphicType = function assertPolymorphicType(parentIdentifier, parentDefinition, addedIdentifier, store) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
34
|
+
let asserted = false;
|
|
35
|
+
|
|
36
|
+
if (parentDefinition.inverseIsImplicit) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (parentDefinition.isPolymorphic) {
|
|
40
|
+
let meta = store.getSchemaDefinitionService().relationshipsDefinitionFor(addedIdentifier)[
|
|
41
|
+
parentDefinition.inverseKey
|
|
42
|
+
];
|
|
43
|
+
if (meta?.options?.as) {
|
|
44
|
+
asserted = true;
|
|
45
|
+
assert(
|
|
46
|
+
`The schema for the relationship '${parentDefinition.inverseKey}' on '${addedIdentifier.type}' type does not implement '${parentDefinition.type}' and thus cannot be assigned to the '${parentDefinition.key}' relationship in '${parentIdentifier.type}'. The definition should specify 'as: "${parentDefinition.type}"' in options.`,
|
|
47
|
+
meta.options.as === parentDefinition.type
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (DEPRECATE_NON_EXPLICIT_POLYMORPHISM && !asserted) {
|
|
53
|
+
store = store._store ? store._store : store; // allow usage with storeWrapper
|
|
54
|
+
let addedModelName = addedIdentifier.type;
|
|
55
|
+
let parentModelName = parentIdentifier.type;
|
|
56
|
+
let key = parentDefinition.key;
|
|
57
|
+
let relationshipModelName = parentDefinition.type;
|
|
58
|
+
let relationshipClass = store.modelFor(relationshipModelName);
|
|
59
|
+
let addedClass = store.modelFor(addedModelName);
|
|
60
|
+
|
|
61
|
+
let assertionMessage = `The '${addedModelName}' type does not implement '${relationshipModelName}' and thus cannot be assigned to the '${key}' relationship in '${parentModelName}'. Make it a descendant of '${relationshipModelName}' or use a mixin of the same name.`;
|
|
62
|
+
let isPolymorphic = checkPolymorphic(relationshipClass, addedClass);
|
|
63
|
+
|
|
64
|
+
assert(assertionMessage, isPolymorphic);
|
|
65
|
+
}
|
|
44
66
|
};
|
|
45
67
|
}
|
|
46
68
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { assert, warn } from '@ember/debug';
|
|
5
5
|
import { DEBUG } from '@glimmer/env';
|
|
6
6
|
|
|
7
|
-
import { getOwnConfig,
|
|
7
|
+
import { getOwnConfig, macroCondition } from '@embroider/macros';
|
|
8
8
|
|
|
9
9
|
import { LOG_IDENTIFIERS } from '@ember-data/private-build-infra/debugging';
|
|
10
10
|
import type { ExistingResourceObject, ResourceIdentifierObject } from '@ember-data/types/q/ember-data-json-api';
|
|
@@ -25,9 +25,9 @@ import coerceId from '../utils/coerce-id';
|
|
|
25
25
|
import { DEBUG_CLIENT_ORIGINATED, DEBUG_IDENTIFIER_BUCKET } from '../utils/identifer-debug-consts';
|
|
26
26
|
import isNonEmptyString from '../utils/is-non-empty-string';
|
|
27
27
|
import normalizeModelName from '../utils/normalize-model-name';
|
|
28
|
-
import
|
|
28
|
+
import installPolyfill from '../utils/uuid-polyfill';
|
|
29
29
|
|
|
30
|
-
const IDENTIFIERS = new
|
|
30
|
+
const IDENTIFIERS = new Set();
|
|
31
31
|
|
|
32
32
|
export function isStableIdentifier(identifier: Object): identifier is StableRecordIdentifier {
|
|
33
33
|
return IDENTIFIERS.has(identifier);
|
|
@@ -37,7 +37,7 @@ const isFastBoot = typeof FastBoot !== 'undefined';
|
|
|
37
37
|
const _crypto: Crypto = isFastBoot ? (FastBoot.require('crypto') as Crypto) : window.crypto;
|
|
38
38
|
|
|
39
39
|
if (macroCondition(getOwnConfig<{ polyfillUUID: boolean }>().polyfillUUID)) {
|
|
40
|
-
|
|
40
|
+
installPolyfill();
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
function uuidv4(): string {
|
|
@@ -56,7 +56,7 @@ interface KeyOptions {
|
|
|
56
56
|
id: IdentifierMap;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
type IdentifierMap =
|
|
59
|
+
type IdentifierMap = Map<string, StableRecordIdentifier>;
|
|
60
60
|
type TypeMap = ConfidentDict<KeyOptions>;
|
|
61
61
|
export type MergeMethod = (
|
|
62
62
|
targetIdentifier: StableRecordIdentifier,
|
|
@@ -85,12 +85,15 @@ export function setIdentifierResetMethod(method: ResetMethod | null): void {
|
|
|
85
85
|
configuredResetMethod = method;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
type WithLid = { lid: string };
|
|
89
|
+
type WithId = { id: string | null; type: string };
|
|
90
|
+
|
|
88
91
|
function defaultGenerationMethod(data: ResourceData | { type: string }, bucket: IdentifierBucket): string {
|
|
89
|
-
if (
|
|
90
|
-
return data.lid;
|
|
92
|
+
if (isNonEmptyString((data as WithLid).lid)) {
|
|
93
|
+
return (data as WithLid).lid;
|
|
91
94
|
}
|
|
92
|
-
if (
|
|
93
|
-
let { type, id } = data;
|
|
95
|
+
if ((data as WithId).id !== undefined) {
|
|
96
|
+
let { type, id } = data as WithId;
|
|
94
97
|
// TODO: add test for id not a string
|
|
95
98
|
if (isNonEmptyString(coerceId(id))) {
|
|
96
99
|
return `@lid:${normalizeModelName(type)}-${id}`;
|
|
@@ -103,7 +106,7 @@ function defaultEmptyCallback(...args: any[]): any {}
|
|
|
103
106
|
|
|
104
107
|
let DEBUG_MAP;
|
|
105
108
|
if (DEBUG) {
|
|
106
|
-
DEBUG_MAP = new
|
|
109
|
+
DEBUG_MAP = new WeakMap<StableRecordIdentifier, StableRecordIdentifier>();
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
/**
|
|
@@ -121,7 +124,7 @@ if (DEBUG) {
|
|
|
121
124
|
*/
|
|
122
125
|
export class IdentifierCache {
|
|
123
126
|
_cache = {
|
|
124
|
-
lids:
|
|
127
|
+
lids: new Map<string, StableRecordIdentifier>(),
|
|
125
128
|
types: Object.create(null) as TypeMap,
|
|
126
129
|
};
|
|
127
130
|
declare _generate: GenerationMethod;
|
|
@@ -129,6 +132,7 @@ export class IdentifierCache {
|
|
|
129
132
|
declare _forget: ForgetMethod;
|
|
130
133
|
declare _reset: ResetMethod;
|
|
131
134
|
declare _merge: MergeMethod;
|
|
135
|
+
declare _isDefaultConfig: boolean;
|
|
132
136
|
|
|
133
137
|
constructor() {
|
|
134
138
|
// we cache the user configuredGenerationMethod at init because it must
|
|
@@ -138,6 +142,7 @@ export class IdentifierCache {
|
|
|
138
142
|
this._forget = configuredForgetMethod || defaultEmptyCallback;
|
|
139
143
|
this._reset = configuredResetMethod || defaultEmptyCallback;
|
|
140
144
|
this._merge = defaultEmptyCallback;
|
|
145
|
+
this._isDefaultConfig = !configuredGenerationMethod;
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
/**
|
|
@@ -167,7 +172,7 @@ export class IdentifierCache {
|
|
|
167
172
|
if (isStableIdentifier(resource)) {
|
|
168
173
|
if (DEBUG) {
|
|
169
174
|
// TODO should we instead just treat this case as a new generation skipping the short circuit?
|
|
170
|
-
if (!
|
|
175
|
+
if (!this._cache.lids.has(resource.lid) || this._cache.lids.get(resource.lid) !== resource) {
|
|
171
176
|
throw new Error(`The supplied identifier ${resource} does not belong to this store instance`);
|
|
172
177
|
}
|
|
173
178
|
}
|
|
@@ -179,7 +184,7 @@ export class IdentifierCache {
|
|
|
179
184
|
}
|
|
180
185
|
|
|
181
186
|
let lid = coerceId(resource.lid);
|
|
182
|
-
let identifier: StableRecordIdentifier | undefined = lid !== null ? this._cache.lids
|
|
187
|
+
let identifier: StableRecordIdentifier | undefined = lid !== null ? this._cache.lids.get(lid) : undefined;
|
|
183
188
|
|
|
184
189
|
if (identifier !== undefined) {
|
|
185
190
|
if (LOG_IDENTIFIERS) {
|
|
@@ -210,13 +215,13 @@ export class IdentifierCache {
|
|
|
210
215
|
|
|
211
216
|
// go straight for the stable RecordIdentifier key'd to `lid`
|
|
212
217
|
if (lid !== null) {
|
|
213
|
-
identifier = keyOptions.lid
|
|
218
|
+
identifier = keyOptions.lid.get(lid);
|
|
214
219
|
}
|
|
215
220
|
|
|
216
221
|
// we may have not seen this resource before
|
|
217
222
|
// but just in case we check our own secondary lookup (`id`)
|
|
218
223
|
if (identifier === undefined && id !== null) {
|
|
219
|
-
identifier = keyOptions.id
|
|
224
|
+
identifier = keyOptions.id.get(id);
|
|
220
225
|
}
|
|
221
226
|
|
|
222
227
|
if (identifier === undefined) {
|
|
@@ -233,12 +238,12 @@ export class IdentifierCache {
|
|
|
233
238
|
// different than expected
|
|
234
239
|
if (lid !== null && newLid !== lid) {
|
|
235
240
|
throw new Error(`You should not change the <lid> of a RecordIdentifier`);
|
|
236
|
-
} else if (lid === null) {
|
|
241
|
+
} else if (lid === null && !this._isDefaultConfig) {
|
|
237
242
|
// allow configuration to tell us that we have
|
|
238
243
|
// seen this `lid` before. E.g. a secondary lookup
|
|
239
244
|
// connects this resource to a previously seen
|
|
240
245
|
// resource.
|
|
241
|
-
identifier = keyOptions.lid
|
|
246
|
+
identifier = keyOptions.lid.get(newLid);
|
|
242
247
|
}
|
|
243
248
|
|
|
244
249
|
if (shouldGenerate === true) {
|
|
@@ -250,16 +255,16 @@ export class IdentifierCache {
|
|
|
250
255
|
if (DEBUG) {
|
|
251
256
|
// realistically if you hit this it means you changed `type` :/
|
|
252
257
|
// TODO consider how to handle type change assertions more gracefully
|
|
253
|
-
if (this._cache.lids
|
|
258
|
+
if (this._cache.lids.has(identifier.lid)) {
|
|
254
259
|
throw new Error(`You should not change the <type> of a RecordIdentifier`);
|
|
255
260
|
}
|
|
256
261
|
}
|
|
257
|
-
this._cache.lids
|
|
262
|
+
this._cache.lids.set(identifier.lid, identifier);
|
|
258
263
|
|
|
259
264
|
// populate our primary lookup table
|
|
260
265
|
// TODO consider having the `lid` cache be
|
|
261
266
|
// one level up
|
|
262
|
-
keyOptions.lid
|
|
267
|
+
keyOptions.lid.set(identifier.lid, identifier);
|
|
263
268
|
|
|
264
269
|
if (LOG_IDENTIFIERS && shouldGenerate) {
|
|
265
270
|
// eslint-disable-next-line no-console
|
|
@@ -281,7 +286,7 @@ export class IdentifierCache {
|
|
|
281
286
|
// because they may not match and we prefer
|
|
282
287
|
// what we've set via resource data
|
|
283
288
|
if (identifier.id !== null) {
|
|
284
|
-
keyOptions.id
|
|
289
|
+
keyOptions.id.set(identifier.id, identifier);
|
|
285
290
|
|
|
286
291
|
// TODO allow filling out of `id` here
|
|
287
292
|
// for the `username` non-client created
|
|
@@ -355,14 +360,17 @@ export class IdentifierCache {
|
|
|
355
360
|
|
|
356
361
|
// populate our unique table
|
|
357
362
|
if (DEBUG) {
|
|
358
|
-
if (this._cache.lids
|
|
363
|
+
if (this._cache.lids.has(identifier.lid)) {
|
|
359
364
|
throw new Error(`The lid generated for the new record is not unique as it matches an existing identifier`);
|
|
360
365
|
}
|
|
361
366
|
}
|
|
362
|
-
this._cache.lids
|
|
367
|
+
this._cache.lids.set(identifier.lid, identifier);
|
|
363
368
|
|
|
364
369
|
// populate the type+lid cache
|
|
365
|
-
keyOptions.lid
|
|
370
|
+
keyOptions.lid.set(newLid, identifier);
|
|
371
|
+
if (data.id) {
|
|
372
|
+
keyOptions.id.set(data.id, identifier);
|
|
373
|
+
}
|
|
366
374
|
|
|
367
375
|
if (LOG_IDENTIFIERS) {
|
|
368
376
|
// eslint-disable-next-line no-console
|
|
@@ -448,10 +456,10 @@ export class IdentifierCache {
|
|
|
448
456
|
);
|
|
449
457
|
}
|
|
450
458
|
let keyOptions = getTypeIndex(this._cache.types, identifier.type);
|
|
451
|
-
keyOptions.id
|
|
459
|
+
keyOptions.id.set(newId, identifier);
|
|
452
460
|
|
|
453
461
|
if (id !== null) {
|
|
454
|
-
keyOptions.id
|
|
462
|
+
keyOptions.id.delete(id);
|
|
455
463
|
}
|
|
456
464
|
} else if (LOG_IDENTIFIERS) {
|
|
457
465
|
// eslint-disable-next-line no-console
|
|
@@ -480,10 +488,10 @@ export class IdentifierCache {
|
|
|
480
488
|
this.forgetRecordIdentifier(abandoned);
|
|
481
489
|
|
|
482
490
|
// ensure a secondary cache entry for this id for the identifier we do keep
|
|
483
|
-
keyOptions.id
|
|
491
|
+
keyOptions.id.set(newId, kept);
|
|
484
492
|
// ensure a secondary cache entry for this id for the abandoned identifier's type we do keep
|
|
485
493
|
let baseKeyOptions = getTypeIndex(this._cache.types, existingIdentifier.type);
|
|
486
|
-
baseKeyOptions.id
|
|
494
|
+
baseKeyOptions.id.set(newId, kept);
|
|
487
495
|
|
|
488
496
|
// make sure that the `lid` on the data we are processing matches the lid we kept
|
|
489
497
|
data.lid = kept.lid;
|
|
@@ -507,10 +515,10 @@ export class IdentifierCache {
|
|
|
507
515
|
let identifier = this.getOrCreateRecordIdentifier(identifierObject);
|
|
508
516
|
let keyOptions = getTypeIndex(this._cache.types, identifier.type);
|
|
509
517
|
if (identifier.id !== null) {
|
|
510
|
-
keyOptions.id
|
|
518
|
+
keyOptions.id.delete(identifier.id);
|
|
511
519
|
}
|
|
512
|
-
this._cache.lids
|
|
513
|
-
keyOptions.lid
|
|
520
|
+
this._cache.lids.delete(identifier.lid);
|
|
521
|
+
keyOptions.lid.delete(identifier.lid);
|
|
514
522
|
|
|
515
523
|
IDENTIFIERS.delete(identifierObject);
|
|
516
524
|
this._forget(identifier, 'record');
|
|
@@ -530,8 +538,8 @@ function getTypeIndex(typeMap: TypeMap, type: string): KeyOptions {
|
|
|
530
538
|
|
|
531
539
|
if (typeIndex === undefined) {
|
|
532
540
|
typeIndex = {
|
|
533
|
-
lid:
|
|
534
|
-
id:
|
|
541
|
+
lid: new Map(),
|
|
542
|
+
id: new Map(),
|
|
535
543
|
};
|
|
536
544
|
typeMap[type] = typeIndex;
|
|
537
545
|
}
|
|
@@ -650,7 +658,7 @@ function detectMerge(
|
|
|
650
658
|
const { id, type, lid } = identifier;
|
|
651
659
|
if (id !== null && id !== newId && newId !== null) {
|
|
652
660
|
let keyOptions = getTypeIndex(typesCache, identifier.type);
|
|
653
|
-
let existingIdentifier = keyOptions.id
|
|
661
|
+
let existingIdentifier = keyOptions.id.get(newId);
|
|
654
662
|
|
|
655
663
|
return existingIdentifier !== undefined ? existingIdentifier : false;
|
|
656
664
|
} else {
|
|
@@ -658,12 +666,12 @@ function detectMerge(
|
|
|
658
666
|
|
|
659
667
|
// If the ids and type are the same but lid is not the same, we should trigger a merge of the identifiers
|
|
660
668
|
if (id !== null && id === newId && newType === type && data.lid && data.lid !== lid) {
|
|
661
|
-
let existingIdentifier = lids
|
|
669
|
+
let existingIdentifier = lids.get(data.lid);
|
|
662
670
|
return existingIdentifier !== undefined ? existingIdentifier : false;
|
|
663
671
|
// If the lids are the same, and ids are the same, but types are different we should trigger a merge of the identifiers
|
|
664
672
|
} else if (id !== null && id === newId && newType && newType !== type && data.lid && data.lid === lid) {
|
|
665
673
|
let keyOptions = getTypeIndex(typesCache, newType);
|
|
666
|
-
let existingIdentifier = keyOptions.id
|
|
674
|
+
let existingIdentifier = keyOptions.id.get(id);
|
|
667
675
|
return existingIdentifier !== undefined ? existingIdentifier : false;
|
|
668
676
|
}
|
|
669
677
|
}
|