@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.
Files changed (43) hide show
  1. package/addon/-debug/index.js +1 -1
  2. package/addon/-private/{identifier-cache.ts → caches/identifier-cache.ts} +147 -73
  3. package/addon/-private/caches/instance-cache.ts +697 -0
  4. package/addon/-private/{record-data-for.ts → caches/record-data-for.ts} +2 -7
  5. package/addon/-private/index.ts +13 -17
  6. package/addon/-private/{model → legacy-model-support}/record-reference.ts +15 -13
  7. package/addon/-private/{schema-definition-service.ts → legacy-model-support/schema-definition-service.ts} +13 -9
  8. package/addon/-private/{model → legacy-model-support}/shim-model-class.ts +17 -11
  9. package/addon/-private/managers/record-array-manager.ts +298 -0
  10. package/addon/-private/managers/record-data-manager.ts +830 -0
  11. package/addon/-private/managers/record-data-store-wrapper.ts +415 -0
  12. package/addon/-private/managers/record-notification-manager.ts +108 -0
  13. package/addon/-private/network/fetch-manager.ts +552 -0
  14. package/addon/-private/{finders.js → network/finders.js} +14 -17
  15. package/addon/-private/{request-cache.ts → network/request-cache.ts} +20 -17
  16. package/addon/-private/{snapshot-record-array.ts → network/snapshot-record-array.ts} +12 -29
  17. package/addon/-private/{snapshot.ts → network/snapshot.ts} +40 -49
  18. package/addon/-private/{promise-proxies.ts → proxies/promise-proxies.ts} +4 -4
  19. package/addon/-private/{promise-proxy-base.js → proxies/promise-proxy-base.js} +0 -0
  20. package/addon/-private/record-arrays/adapter-populated-record-array.ts +20 -51
  21. package/addon/-private/record-arrays/record-array.ts +48 -77
  22. package/addon/-private/{core-store.ts → store-service.ts} +482 -186
  23. package/addon/-private/{coerce-id.ts → utils/coerce-id.ts} +1 -1
  24. package/addon/-private/{common.js → utils/common.js} +1 -2
  25. package/addon/-private/utils/construct-resource.ts +2 -2
  26. package/addon/-private/{identifer-debug-consts.ts → utils/identifer-debug-consts.ts} +0 -0
  27. package/addon/-private/utils/is-non-empty-string.ts +1 -1
  28. package/addon/-private/{normalize-model-name.ts → utils/normalize-model-name.ts} +0 -0
  29. package/addon/-private/utils/promise-record.ts +3 -3
  30. package/addon/-private/{serializer-response.ts → utils/serializer-response.ts} +2 -2
  31. package/addon/-private/utils/uuid-polyfill.ts +71 -0
  32. package/package.json +12 -8
  33. package/addon/-private/backburner.js +0 -25
  34. package/addon/-private/fetch-manager.ts +0 -573
  35. package/addon/-private/identity-map.ts +0 -54
  36. package/addon/-private/instance-cache.ts +0 -387
  37. package/addon/-private/internal-model-factory.ts +0 -359
  38. package/addon/-private/internal-model-map.ts +0 -121
  39. package/addon/-private/model/internal-model.ts +0 -600
  40. package/addon/-private/record-array-manager.ts +0 -444
  41. package/addon/-private/record-data-store-wrapper.ts +0 -239
  42. package/addon/-private/record-notification-manager.ts +0 -73
  43. package/addon/-private/weak-cache.ts +0 -125
@@ -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 an InternalModel and the `relationshipMeta` needs to be the meta
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 './coerce-id';
22
- import { DEBUG_CLIENT_ORIGINATED, DEBUG_IDENTIFIER_BUCKET } from './identifer-debug-consts';
23
- import normalizeModelName from './normalize-model-name';
24
- import isNonEmptyString from './utils/is-non-empty-string';
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 WeakSet();
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 = ConfidentDict<StableRecordIdentifier>;
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 ('lid' in data && isNonEmptyString(data.lid)) {
84
- return data.lid;
91
+ if (isNonEmptyString((data as WithLid).lid)) {
92
+ return (data as WithLid).lid;
85
93
  }
86
- if ('id' in data) {
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 WeakCache<StableRecordIdentifier, StableRecordIdentifier>('identifier-proxy-target');
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: Object.create(null) as IdentifierMap,
126
+ lids: new Map<string, StableRecordIdentifier>(),
123
127
  types: Object.create(null) as TypeMap,
124
128
  };
125
- private _generate: GenerationMethod;
126
- private _update: UpdateMethod;
127
- private _forget: ForgetMethod;
128
- private _reset: ResetMethod;
129
- private _merge: MergeMethod;
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 `internalModelFactory`
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
- private _getRecordIdentifier(resource: ResourceIdentifierObject, shouldGenerate: true): StableRecordIdentifier;
159
- private _getRecordIdentifier(
160
- resource: ResourceIdentifierObject,
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 (!(resource.lid in this._cache.lids) || this._cache.lids[resource.lid] !== resource) {
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[lid] : undefined;
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 (!('type' in resource) || !('id' in resource) || !resource.type || !resource.id) {
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[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[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[newLid];
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 (identifier.lid in this._cache.lids) {
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[identifier.lid] = identifier;
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[identifier.lid] = identifier;
247
- // TODO exists temporarily to support `peekAll`
248
- // but likely to move
249
- keyOptions._allIdentifiers.push(identifier);
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[identifier.id] = identifier;
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 (identifier.lid in this._cache.lids) {
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[identifier.lid] = identifier;
366
+ this._cache.lids.set(identifier.lid, identifier);
330
367
 
331
368
  // populate the type+lid cache
332
- keyOptions.lid[newLid] = identifier;
333
- // ensure a peekAll sees our new identifier too
334
- // TODO move this outta here?
335
- keyOptions._allIdentifiers.push(identifier);
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 = 'id' in data ? coerceId(data.id) : null;
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 ('type' in data && data.type && identifier.type !== normalizeModelName(data.type)) {
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
- identifier = this._mergeRecordIdentifiers(keyOptions, identifier, existingIdentifier, data, newId as string);
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[newId] = identifier;
458
+ keyOptions.id.set(newId, identifier);
392
459
 
393
460
  if (id !== null) {
394
- delete keyOptions.id[id];
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[newId] = kept;
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[newId] = kept;
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
- delete keyOptions.id[identifier.id];
517
+ keyOptions.id.delete(identifier.id);
448
518
  }
449
- delete this._cache.lids[identifier.lid];
450
- delete keyOptions.lid[identifier.lid];
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: Object.create(null),
470
- id: Object.create(null),
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 ('id' in data && data.id !== undefined) {
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[newId];
660
+ let existingIdentifier = keyOptions.id.get(newId);
587
661
 
588
662
  return existingIdentifier !== undefined ? existingIdentifier : false;
589
663
  } else {
590
- let newType = 'type' in data && data.type && normalizeModelName(data.type);
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[data.lid];
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[id];
673
+ let existingIdentifier = keyOptions.id.get(id);
600
674
  return existingIdentifier !== undefined ? existingIdentifier : false;
601
675
  }
602
676
  }