@ember-data/store 4.8.0-alpha.2 → 4.8.0-alpha.5
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} +147 -73
- package/addon/-private/caches/instance-cache.ts +697 -0
- package/addon/-private/{record-data-for.ts → caches/record-data-for.ts} +2 -7
- package/addon/-private/index.ts +13 -17
- 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 +17 -11
- package/addon/-private/managers/record-array-manager.ts +298 -0
- package/addon/-private/managers/record-data-manager.ts +830 -0
- package/addon/-private/managers/record-data-store-wrapper.ts +415 -0
- package/addon/-private/managers/record-notification-manager.ts +108 -0
- package/addon/-private/network/fetch-manager.ts +552 -0
- package/addon/-private/{finders.js → network/finders.js} +14 -17
- package/addon/-private/{request-cache.ts → network/request-cache.ts} +20 -17
- package/addon/-private/{snapshot-record-array.ts → network/snapshot-record-array.ts} +12 -29
- 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 +20 -51
- package/addon/-private/record-arrays/record-array.ts +48 -77
- package/addon/-private/{core-store.ts → store-service.ts} +482 -186
- 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/utils/is-non-empty-string.ts +1 -1
- package/addon/-private/{normalize-model-name.ts → utils/normalize-model-name.ts} +0 -0
- 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/package.json +12 -8
- package/addon/-private/backburner.js +0 -25
- package/addon/-private/fetch-manager.ts +0 -573
- 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 -600
- package/addon/-private/record-array-manager.ts +0 -444
- package/addon/-private/record-data-store-wrapper.ts +0 -239
- package/addon/-private/record-notification-manager.ts +0 -73
- package/addon/-private/weak-cache.ts +0 -125
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,13 +21,12 @@ 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 './weak-cache';
|
|
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';
|
|
26
28
|
|
|
27
|
-
const IDENTIFIERS = new
|
|
29
|
+
const IDENTIFIERS = new Set();
|
|
28
30
|
|
|
29
31
|
export function isStableIdentifier(identifier: Object): identifier is StableRecordIdentifier {
|
|
30
32
|
return IDENTIFIERS.has(identifier);
|
|
@@ -33,6 +35,10 @@ export function isStableIdentifier(identifier: Object): identifier is StableReco
|
|
|
33
35
|
const isFastBoot = typeof FastBoot !== 'undefined';
|
|
34
36
|
const _crypto: Crypto = isFastBoot ? (FastBoot.require('crypto') as Crypto) : window.crypto;
|
|
35
37
|
|
|
38
|
+
if (macroCondition(getOwnConfig<{ polyfillUUID: boolean }>().polyfillUUID)) {
|
|
39
|
+
importSync('./utils/uuid-polyfill');
|
|
40
|
+
}
|
|
41
|
+
|
|
36
42
|
function uuidv4(): string {
|
|
37
43
|
return _crypto.randomUUID();
|
|
38
44
|
}
|
|
@@ -47,10 +53,9 @@ function freeze<T>(obj: T): T {
|
|
|
47
53
|
interface KeyOptions {
|
|
48
54
|
lid: IdentifierMap;
|
|
49
55
|
id: IdentifierMap;
|
|
50
|
-
_allIdentifiers: StableRecordIdentifier[];
|
|
51
56
|
}
|
|
52
57
|
|
|
53
|
-
type IdentifierMap =
|
|
58
|
+
type IdentifierMap = Map<string, StableRecordIdentifier>;
|
|
54
59
|
type TypeMap = ConfidentDict<KeyOptions>;
|
|
55
60
|
export type MergeMethod = (
|
|
56
61
|
targetIdentifier: StableRecordIdentifier,
|
|
@@ -79,12 +84,15 @@ export function setIdentifierResetMethod(method: ResetMethod | null): void {
|
|
|
79
84
|
configuredResetMethod = method;
|
|
80
85
|
}
|
|
81
86
|
|
|
87
|
+
type WithLid = { lid: string };
|
|
88
|
+
type WithId = { id: string | null; type: string };
|
|
89
|
+
|
|
82
90
|
function defaultGenerationMethod(data: ResourceData | { type: string }, bucket: IdentifierBucket): string {
|
|
83
|
-
if (
|
|
84
|
-
return data.lid;
|
|
91
|
+
if (isNonEmptyString((data as WithLid).lid)) {
|
|
92
|
+
return (data as WithLid).lid;
|
|
85
93
|
}
|
|
86
|
-
if (
|
|
87
|
-
let { type, id } = data;
|
|
94
|
+
if ((data as WithId).id !== undefined) {
|
|
95
|
+
let { type, id } = data as WithId;
|
|
88
96
|
// TODO: add test for id not a string
|
|
89
97
|
if (isNonEmptyString(coerceId(id))) {
|
|
90
98
|
return `@lid:${normalizeModelName(type)}-${id}`;
|
|
@@ -97,7 +105,7 @@ function defaultEmptyCallback(...args: any[]): any {}
|
|
|
97
105
|
|
|
98
106
|
let DEBUG_MAP;
|
|
99
107
|
if (DEBUG) {
|
|
100
|
-
DEBUG_MAP = new
|
|
108
|
+
DEBUG_MAP = new WeakMap<StableRecordIdentifier, StableRecordIdentifier>();
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
/**
|
|
@@ -114,19 +122,16 @@ if (DEBUG) {
|
|
|
114
122
|
@public
|
|
115
123
|
*/
|
|
116
124
|
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
125
|
_cache = {
|
|
122
|
-
lids:
|
|
126
|
+
lids: new Map<string, StableRecordIdentifier>(),
|
|
123
127
|
types: Object.create(null) as TypeMap,
|
|
124
128
|
};
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
129
|
+
declare _generate: GenerationMethod;
|
|
130
|
+
declare _update: UpdateMethod;
|
|
131
|
+
declare _forget: ForgetMethod;
|
|
132
|
+
declare _reset: ResetMethod;
|
|
133
|
+
declare _merge: MergeMethod;
|
|
134
|
+
declare _isDefaultConfig: boolean;
|
|
130
135
|
|
|
131
136
|
constructor() {
|
|
132
137
|
// we cache the user configuredGenerationMethod at init because it must
|
|
@@ -136,13 +141,14 @@ export class IdentifierCache {
|
|
|
136
141
|
this._forget = configuredForgetMethod || defaultEmptyCallback;
|
|
137
142
|
this._reset = configuredResetMethod || defaultEmptyCallback;
|
|
138
143
|
this._merge = defaultEmptyCallback;
|
|
144
|
+
this._isDefaultConfig = !configuredGenerationMethod;
|
|
139
145
|
}
|
|
140
146
|
|
|
141
147
|
/**
|
|
142
148
|
* Internal hook to allow management of merge conflicts with identifiers.
|
|
143
149
|
*
|
|
144
|
-
* we allow late binding of this private internal merge so that
|
|
145
|
-
* can insert itself here to handle elimination of duplicates
|
|
150
|
+
* we allow late binding of this private internal merge so that
|
|
151
|
+
* the cache can insert itself here to handle elimination of duplicates
|
|
146
152
|
*
|
|
147
153
|
* @method __configureMerge
|
|
148
154
|
* @private
|
|
@@ -155,12 +161,9 @@ export class IdentifierCache {
|
|
|
155
161
|
* @method _getRecordIdentifier
|
|
156
162
|
* @private
|
|
157
163
|
*/
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
shouldGenerate: false
|
|
162
|
-
): StableRecordIdentifier | undefined;
|
|
163
|
-
private _getRecordIdentifier(
|
|
164
|
+
_getRecordIdentifier(resource: ResourceIdentifierObject, shouldGenerate: true): StableRecordIdentifier;
|
|
165
|
+
_getRecordIdentifier(resource: ResourceIdentifierObject, shouldGenerate: false): StableRecordIdentifier | undefined;
|
|
166
|
+
_getRecordIdentifier(
|
|
164
167
|
resource: ResourceIdentifierObject,
|
|
165
168
|
shouldGenerate: boolean = false
|
|
166
169
|
): StableRecordIdentifier | undefined {
|
|
@@ -168,22 +171,35 @@ export class IdentifierCache {
|
|
|
168
171
|
if (isStableIdentifier(resource)) {
|
|
169
172
|
if (DEBUG) {
|
|
170
173
|
// TODO should we instead just treat this case as a new generation skipping the short circuit?
|
|
171
|
-
if (!
|
|
174
|
+
if (!this._cache.lids.has(resource.lid) || this._cache.lids.get(resource.lid) !== resource) {
|
|
172
175
|
throw new Error(`The supplied identifier ${resource} does not belong to this store instance`);
|
|
173
176
|
}
|
|
174
177
|
}
|
|
178
|
+
if (LOG_IDENTIFIERS) {
|
|
179
|
+
// eslint-disable-next-line no-console
|
|
180
|
+
console.log(`Identifiers: Peeked Identifier was already Stable ${String(resource)}`);
|
|
181
|
+
}
|
|
175
182
|
return resource;
|
|
176
183
|
}
|
|
177
184
|
|
|
178
185
|
let lid = coerceId(resource.lid);
|
|
179
|
-
let identifier: StableRecordIdentifier | undefined = lid !== null ? this._cache.lids
|
|
186
|
+
let identifier: StableRecordIdentifier | undefined = lid !== null ? this._cache.lids.get(lid) : undefined;
|
|
180
187
|
|
|
181
188
|
if (identifier !== undefined) {
|
|
189
|
+
if (LOG_IDENTIFIERS) {
|
|
190
|
+
// eslint-disable-next-line no-console
|
|
191
|
+
console.log(`Identifiers: cache HIT ${identifier}`, resource);
|
|
192
|
+
}
|
|
182
193
|
return identifier;
|
|
183
194
|
}
|
|
184
195
|
|
|
196
|
+
if (LOG_IDENTIFIERS) {
|
|
197
|
+
// eslint-disable-next-line no-console
|
|
198
|
+
console.groupCollapsed(`Identifiers: ${shouldGenerate ? 'Generating' : 'Peeking'} Identifier`, resource);
|
|
199
|
+
}
|
|
200
|
+
|
|
185
201
|
if (shouldGenerate === false) {
|
|
186
|
-
if (!(
|
|
202
|
+
if (!(resource as ExistingResourceObject).type || !(resource as ExistingResourceObject).id) {
|
|
187
203
|
return;
|
|
188
204
|
}
|
|
189
205
|
}
|
|
@@ -198,31 +214,35 @@ export class IdentifierCache {
|
|
|
198
214
|
|
|
199
215
|
// go straight for the stable RecordIdentifier key'd to `lid`
|
|
200
216
|
if (lid !== null) {
|
|
201
|
-
identifier = keyOptions.lid
|
|
217
|
+
identifier = keyOptions.lid.get(lid);
|
|
202
218
|
}
|
|
203
219
|
|
|
204
220
|
// we may have not seen this resource before
|
|
205
221
|
// but just in case we check our own secondary lookup (`id`)
|
|
206
222
|
if (identifier === undefined && id !== null) {
|
|
207
|
-
identifier = keyOptions.id
|
|
223
|
+
identifier = keyOptions.id.get(id);
|
|
208
224
|
}
|
|
209
225
|
|
|
210
226
|
if (identifier === undefined) {
|
|
211
227
|
// we have definitely not seen this resource before
|
|
212
228
|
// so we allow the user configured `GenerationMethod` to tell us
|
|
213
229
|
let newLid = this._generate(resource, 'record');
|
|
230
|
+
if (LOG_IDENTIFIERS) {
|
|
231
|
+
// eslint-disable-next-line no-console
|
|
232
|
+
console.log(`Identifiers: lid ${newLid} determined for resource`, resource);
|
|
233
|
+
}
|
|
214
234
|
|
|
215
235
|
// we do this _even_ when `lid` is present because secondary lookups
|
|
216
236
|
// may need to be populated, but we enforce not giving us something
|
|
217
237
|
// different than expected
|
|
218
238
|
if (lid !== null && newLid !== lid) {
|
|
219
239
|
throw new Error(`You should not change the <lid> of a RecordIdentifier`);
|
|
220
|
-
} else if (lid === null) {
|
|
240
|
+
} else if (lid === null && !this._isDefaultConfig) {
|
|
221
241
|
// allow configuration to tell us that we have
|
|
222
242
|
// seen this `lid` before. E.g. a secondary lookup
|
|
223
243
|
// connects this resource to a previously seen
|
|
224
244
|
// resource.
|
|
225
|
-
identifier = keyOptions.lid
|
|
245
|
+
identifier = keyOptions.lid.get(newLid);
|
|
226
246
|
}
|
|
227
247
|
|
|
228
248
|
if (shouldGenerate === true) {
|
|
@@ -234,19 +254,27 @@ export class IdentifierCache {
|
|
|
234
254
|
if (DEBUG) {
|
|
235
255
|
// realistically if you hit this it means you changed `type` :/
|
|
236
256
|
// TODO consider how to handle type change assertions more gracefully
|
|
237
|
-
if (
|
|
257
|
+
if (this._cache.lids.has(identifier.lid)) {
|
|
238
258
|
throw new Error(`You should not change the <type> of a RecordIdentifier`);
|
|
239
259
|
}
|
|
240
260
|
}
|
|
241
|
-
this._cache.lids
|
|
261
|
+
this._cache.lids.set(identifier.lid, identifier);
|
|
242
262
|
|
|
243
263
|
// populate our primary lookup table
|
|
244
264
|
// TODO consider having the `lid` cache be
|
|
245
265
|
// one level up
|
|
246
|
-
keyOptions.lid
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
266
|
+
keyOptions.lid.set(identifier.lid, identifier);
|
|
267
|
+
|
|
268
|
+
if (LOG_IDENTIFIERS && shouldGenerate) {
|
|
269
|
+
// eslint-disable-next-line no-console
|
|
270
|
+
console.log(`Identifiers: generated ${String(identifier)} for`, resource);
|
|
271
|
+
if (resource[DEBUG_IDENTIFIER_BUCKET]) {
|
|
272
|
+
// eslint-disable-next-line no-console
|
|
273
|
+
console.trace(
|
|
274
|
+
`[WARNING] Identifiers: generated a new identifier from a previously used identifier. This is likely a bug.`
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
250
278
|
}
|
|
251
279
|
|
|
252
280
|
// populate our own secondary lookup table
|
|
@@ -257,7 +285,7 @@ export class IdentifierCache {
|
|
|
257
285
|
// because they may not match and we prefer
|
|
258
286
|
// what we've set via resource data
|
|
259
287
|
if (identifier.id !== null) {
|
|
260
|
-
keyOptions.id
|
|
288
|
+
keyOptions.id.set(identifier.id, identifier);
|
|
261
289
|
|
|
262
290
|
// TODO allow filling out of `id` here
|
|
263
291
|
// for the `username` non-client created
|
|
@@ -266,6 +294,15 @@ export class IdentifierCache {
|
|
|
266
294
|
}
|
|
267
295
|
}
|
|
268
296
|
|
|
297
|
+
if (LOG_IDENTIFIERS) {
|
|
298
|
+
if (!identifier && !shouldGenerate) {
|
|
299
|
+
// eslint-disable-next-line no-console
|
|
300
|
+
console.log(`Identifiers: cache MISS`, resource);
|
|
301
|
+
}
|
|
302
|
+
// eslint-disable-next-line no-console
|
|
303
|
+
console.groupEnd();
|
|
304
|
+
}
|
|
305
|
+
|
|
269
306
|
return identifier;
|
|
270
307
|
}
|
|
271
308
|
|
|
@@ -322,17 +359,22 @@ export class IdentifierCache {
|
|
|
322
359
|
|
|
323
360
|
// populate our unique table
|
|
324
361
|
if (DEBUG) {
|
|
325
|
-
if (
|
|
362
|
+
if (this._cache.lids.has(identifier.lid)) {
|
|
326
363
|
throw new Error(`The lid generated for the new record is not unique as it matches an existing identifier`);
|
|
327
364
|
}
|
|
328
365
|
}
|
|
329
|
-
this._cache.lids
|
|
366
|
+
this._cache.lids.set(identifier.lid, identifier);
|
|
330
367
|
|
|
331
368
|
// populate the type+lid cache
|
|
332
|
-
keyOptions.lid
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
369
|
+
keyOptions.lid.set(newLid, identifier);
|
|
370
|
+
if (data.id) {
|
|
371
|
+
keyOptions.id.set(data.id, identifier);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (LOG_IDENTIFIERS) {
|
|
375
|
+
// eslint-disable-next-line no-console
|
|
376
|
+
console.log(`Identifiers: createded identifier ${String(identifier)} for newly generated resource`, data);
|
|
377
|
+
}
|
|
336
378
|
|
|
337
379
|
return identifier;
|
|
338
380
|
}
|
|
@@ -362,13 +404,17 @@ export class IdentifierCache {
|
|
|
362
404
|
updateRecordIdentifier(identifierObject: RecordIdentifier, data: ResourceData): StableRecordIdentifier {
|
|
363
405
|
let identifier = this.getOrCreateRecordIdentifier(identifierObject);
|
|
364
406
|
|
|
365
|
-
let newId =
|
|
407
|
+
let newId =
|
|
408
|
+
(data as ExistingResourceObject).id !== undefined ? coerceId((data as ExistingResourceObject).id) : null;
|
|
366
409
|
let existingIdentifier = detectMerge(this._cache.types, identifier, data, newId, this._cache.lids);
|
|
367
410
|
|
|
368
411
|
if (!existingIdentifier) {
|
|
369
412
|
// If the incoming type does not match the identifier type, we need to create an identifier for the incoming
|
|
370
413
|
// data so we can merge the incoming data with the existing identifier, see #7325 and #7363
|
|
371
|
-
if (
|
|
414
|
+
if (
|
|
415
|
+
(data as ExistingResourceObject).type &&
|
|
416
|
+
identifier.type !== normalizeModelName((data as ExistingResourceObject).type)
|
|
417
|
+
) {
|
|
372
418
|
let incomingDataResource = { ...data };
|
|
373
419
|
// Need to strip the lid from the incomingData in order force a new identifier creation
|
|
374
420
|
delete incomingDataResource.lid;
|
|
@@ -378,7 +424,21 @@ export class IdentifierCache {
|
|
|
378
424
|
|
|
379
425
|
if (existingIdentifier) {
|
|
380
426
|
let keyOptions = getTypeIndex(this._cache.types, identifier.type);
|
|
381
|
-
|
|
427
|
+
let generatedIdentifier = identifier;
|
|
428
|
+
identifier = this._mergeRecordIdentifiers(
|
|
429
|
+
keyOptions,
|
|
430
|
+
generatedIdentifier,
|
|
431
|
+
existingIdentifier,
|
|
432
|
+
data,
|
|
433
|
+
newId as string
|
|
434
|
+
);
|
|
435
|
+
if (LOG_IDENTIFIERS) {
|
|
436
|
+
// eslint-disable-next-line no-console
|
|
437
|
+
console.log(
|
|
438
|
+
`Identifiers: merged identifiers ${generatedIdentifier.lid} and ${existingIdentifier.lid} for resource into ${identifier.lid}`,
|
|
439
|
+
data
|
|
440
|
+
);
|
|
441
|
+
}
|
|
382
442
|
}
|
|
383
443
|
|
|
384
444
|
let id = identifier.id;
|
|
@@ -387,12 +447,22 @@ export class IdentifierCache {
|
|
|
387
447
|
|
|
388
448
|
// add to our own secondary lookup table
|
|
389
449
|
if (id !== newId && newId !== null) {
|
|
450
|
+
if (LOG_IDENTIFIERS) {
|
|
451
|
+
// eslint-disable-next-line no-console
|
|
452
|
+
console.log(
|
|
453
|
+
`Identifiers: updated id for identifier ${identifier.lid} from '${id}' to '${newId}' for resource`,
|
|
454
|
+
data
|
|
455
|
+
);
|
|
456
|
+
}
|
|
390
457
|
let keyOptions = getTypeIndex(this._cache.types, identifier.type);
|
|
391
|
-
keyOptions.id
|
|
458
|
+
keyOptions.id.set(newId, identifier);
|
|
392
459
|
|
|
393
460
|
if (id !== null) {
|
|
394
|
-
|
|
461
|
+
keyOptions.id.delete(id);
|
|
395
462
|
}
|
|
463
|
+
} else if (LOG_IDENTIFIERS) {
|
|
464
|
+
// eslint-disable-next-line no-console
|
|
465
|
+
console.log(`Identifiers: updated identifier ${identifier.lid} resource`, data);
|
|
396
466
|
}
|
|
397
467
|
|
|
398
468
|
return identifier;
|
|
@@ -417,10 +487,10 @@ export class IdentifierCache {
|
|
|
417
487
|
this.forgetRecordIdentifier(abandoned);
|
|
418
488
|
|
|
419
489
|
// ensure a secondary cache entry for this id for the identifier we do keep
|
|
420
|
-
keyOptions.id
|
|
490
|
+
keyOptions.id.set(newId, kept);
|
|
421
491
|
// ensure a secondary cache entry for this id for the abandoned identifier's type we do keep
|
|
422
492
|
let baseKeyOptions = getTypeIndex(this._cache.types, existingIdentifier.type);
|
|
423
|
-
baseKeyOptions.id
|
|
493
|
+
baseKeyOptions.id.set(newId, kept);
|
|
424
494
|
|
|
425
495
|
// make sure that the `lid` on the data we are processing matches the lid we kept
|
|
426
496
|
data.lid = kept.lid;
|
|
@@ -444,16 +514,17 @@ export class IdentifierCache {
|
|
|
444
514
|
let identifier = this.getOrCreateRecordIdentifier(identifierObject);
|
|
445
515
|
let keyOptions = getTypeIndex(this._cache.types, identifier.type);
|
|
446
516
|
if (identifier.id !== null) {
|
|
447
|
-
|
|
517
|
+
keyOptions.id.delete(identifier.id);
|
|
448
518
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
let index = keyOptions._allIdentifiers.indexOf(identifier);
|
|
453
|
-
keyOptions._allIdentifiers.splice(index, 1);
|
|
519
|
+
this._cache.lids.delete(identifier.lid);
|
|
520
|
+
keyOptions.lid.delete(identifier.lid);
|
|
454
521
|
|
|
455
522
|
IDENTIFIERS.delete(identifierObject);
|
|
456
523
|
this._forget(identifier, 'record');
|
|
524
|
+
if (LOG_IDENTIFIERS) {
|
|
525
|
+
// eslint-disable-next-line no-console
|
|
526
|
+
console.log(`Identifiers: released identifier ${identifierObject.lid}`);
|
|
527
|
+
}
|
|
457
528
|
}
|
|
458
529
|
|
|
459
530
|
destroy() {
|
|
@@ -466,9 +537,8 @@ function getTypeIndex(typeMap: TypeMap, type: string): KeyOptions {
|
|
|
466
537
|
|
|
467
538
|
if (typeIndex === undefined) {
|
|
468
539
|
typeIndex = {
|
|
469
|
-
lid:
|
|
470
|
-
id:
|
|
471
|
-
_allIdentifiers: [],
|
|
540
|
+
lid: new Map(),
|
|
541
|
+
id: new Map(),
|
|
472
542
|
};
|
|
473
543
|
typeMap[type] = typeIndex;
|
|
474
544
|
}
|
|
@@ -507,6 +577,10 @@ function makeStableRecordIdentifier(
|
|
|
507
577
|
let { type, id, lid } = recordIdentifier;
|
|
508
578
|
return `${clientOriginated ? '[CLIENT_ORIGINATED] ' : ''}${type}:${id} (${lid})`;
|
|
509
579
|
},
|
|
580
|
+
toJSON() {
|
|
581
|
+
let { type, id, lid } = recordIdentifier;
|
|
582
|
+
return { type, id, lid };
|
|
583
|
+
},
|
|
510
584
|
};
|
|
511
585
|
wrapper[DEBUG_CLIENT_ORIGINATED] = clientOriginated;
|
|
512
586
|
wrapper[DEBUG_IDENTIFIER_BUCKET] = bucket;
|
|
@@ -568,8 +642,8 @@ function performRecordIdentifierUpdate(identifier: StableRecordIdentifier, data:
|
|
|
568
642
|
// for the multiple-cache-key scenario we "could"
|
|
569
643
|
// use a heuristic to guess the best id for display
|
|
570
644
|
// (usually when `data.id` is available and `data.attributes` is not)
|
|
571
|
-
if (
|
|
572
|
-
identifier.id = coerceId(data.id);
|
|
645
|
+
if ((data as ExistingResourceObject).id !== undefined) {
|
|
646
|
+
identifier.id = coerceId((data as ExistingResourceObject).id);
|
|
573
647
|
}
|
|
574
648
|
}
|
|
575
649
|
|
|
@@ -583,20 +657,20 @@ function detectMerge(
|
|
|
583
657
|
const { id, type, lid } = identifier;
|
|
584
658
|
if (id !== null && id !== newId && newId !== null) {
|
|
585
659
|
let keyOptions = getTypeIndex(typesCache, identifier.type);
|
|
586
|
-
let existingIdentifier = keyOptions.id
|
|
660
|
+
let existingIdentifier = keyOptions.id.get(newId);
|
|
587
661
|
|
|
588
662
|
return existingIdentifier !== undefined ? existingIdentifier : false;
|
|
589
663
|
} else {
|
|
590
|
-
let newType =
|
|
664
|
+
let newType = (data as ExistingResourceObject).type && normalizeModelName((data as ExistingResourceObject).type);
|
|
591
665
|
|
|
592
666
|
// If the ids and type are the same but lid is not the same, we should trigger a merge of the identifiers
|
|
593
667
|
if (id !== null && id === newId && newType === type && data.lid && data.lid !== lid) {
|
|
594
|
-
let existingIdentifier = lids
|
|
668
|
+
let existingIdentifier = lids.get(data.lid);
|
|
595
669
|
return existingIdentifier !== undefined ? existingIdentifier : false;
|
|
596
670
|
// If the lids are the same, and ids are the same, but types are different we should trigger a merge of the identifiers
|
|
597
671
|
} else if (id !== null && id === newId && newType && newType !== type && data.lid && data.lid === lid) {
|
|
598
672
|
let keyOptions = getTypeIndex(typesCache, newType);
|
|
599
|
-
let existingIdentifier = keyOptions.id
|
|
673
|
+
let existingIdentifier = keyOptions.id.get(id);
|
|
600
674
|
return existingIdentifier !== undefined ? existingIdentifier : false;
|
|
601
675
|
}
|
|
602
676
|
}
|