@ember-data/store 4.5.0-beta.0 → 4.5.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.
Files changed (64) hide show
  1. package/addon/-private/{system/backburner.js → backburner.js} +0 -0
  2. package/addon/-private/{system/coerce-id.ts → coerce-id.ts} +0 -0
  3. package/addon/-private/{system/store/common.js → common.js} +0 -0
  4. package/addon/-private/{system/core-store.ts → core-store.ts} +467 -1253
  5. package/addon/-private/{system/errors-utils.js → errors-utils.js} +7 -6
  6. package/addon/-private/{system/fetch-manager.ts → fetch-manager.ts} +72 -42
  7. package/addon/-private/finders.js +107 -0
  8. package/addon/-private/identifer-debug-consts.ts +3 -0
  9. package/addon/-private/{identifiers/cache.ts → identifier-cache.ts} +26 -14
  10. package/addon/-private/{system/identity-map.ts → identity-map.ts} +2 -1
  11. package/addon/-private/index.ts +17 -17
  12. package/addon/-private/instance-cache.ts +387 -0
  13. package/addon/-private/{system/store/internal-model-factory.ts → internal-model-factory.ts} +25 -19
  14. package/addon/-private/{system/internal-model-map.ts → internal-model-map.ts} +9 -5
  15. package/addon/-private/model/internal-model.ts +602 -0
  16. package/addon/-private/{system/references/record.ts → model/record-reference.ts} +23 -36
  17. package/addon/-private/{system/model → model}/shim-model-class.ts +19 -14
  18. package/addon/-private/{system/normalize-model-name.ts → normalize-model-name.ts} +0 -0
  19. package/addon/-private/{system/promise-proxies.ts → promise-proxies.ts} +12 -5
  20. package/addon/-private/{system/promise-proxy-base.js → promise-proxy-base.js} +0 -0
  21. package/addon/-private/{system/record-array-manager.ts → record-array-manager.ts} +19 -18
  22. package/addon/-private/{system/record-arrays → record-arrays}/adapter-populated-record-array.ts +11 -10
  23. package/addon/-private/{system/record-arrays → record-arrays}/record-array.ts +37 -19
  24. package/addon/-private/record-data-for.ts +39 -0
  25. package/addon/-private/{system/store/record-data-store-wrapper.ts → record-data-store-wrapper.ts} +21 -26
  26. package/addon/-private/{system/record-notification-manager.ts → record-notification-manager.ts} +8 -3
  27. package/addon/-private/{system/request-cache.ts → request-cache.ts} +5 -6
  28. package/addon/-private/{system/schema-definition-service.ts → schema-definition-service.ts} +30 -14
  29. package/addon/-private/{system/store/serializer-response.ts → serializer-response.ts} +7 -6
  30. package/addon/-private/{system/snapshot-record-array.ts → snapshot-record-array.ts} +27 -8
  31. package/addon/-private/{system/snapshot.ts → snapshot.ts} +54 -39
  32. package/addon/-private/utils/construct-resource.ts +7 -3
  33. package/addon/-private/utils/promise-record.ts +9 -18
  34. package/addon/-private/{system/weak-cache.ts → weak-cache.ts} +2 -2
  35. package/addon/index.ts +1 -0
  36. package/package.json +21 -20
  37. package/addon/-private/identifiers/is-stable-identifier.ts +0 -18
  38. package/addon/-private/identifiers/utils/uuid-v4.ts +0 -80
  39. package/addon/-private/system/ds-model-store.ts +0 -136
  40. package/addon/-private/system/model/internal-model.ts +0 -1303
  41. package/addon/-private/system/model/states.js +0 -736
  42. package/addon/-private/system/record-arrays.ts +0 -8
  43. package/addon/-private/system/record-data-for.ts +0 -54
  44. package/addon/-private/system/references/belongs-to.ts +0 -406
  45. package/addon/-private/system/references/has-many.ts +0 -487
  46. package/addon/-private/system/references/reference.ts +0 -205
  47. package/addon/-private/system/references.js +0 -9
  48. package/addon/-private/system/store/finders.js +0 -412
  49. package/addon/-private/ts-interfaces/ds-model.ts +0 -50
  50. package/addon/-private/ts-interfaces/ember-data-json-api.ts +0 -145
  51. package/addon/-private/ts-interfaces/fetch-manager.ts +0 -44
  52. package/addon/-private/ts-interfaces/identifier.ts +0 -246
  53. package/addon/-private/ts-interfaces/minimum-adapter-interface.ts +0 -584
  54. package/addon/-private/ts-interfaces/minimum-serializer-interface.ts +0 -257
  55. package/addon/-private/ts-interfaces/promise-proxies.ts +0 -3
  56. package/addon/-private/ts-interfaces/record-data-json-api.ts +0 -29
  57. package/addon/-private/ts-interfaces/record-data-record-wrapper.ts +0 -46
  58. package/addon/-private/ts-interfaces/record-data-schemas.ts +0 -45
  59. package/addon/-private/ts-interfaces/record-data-store-wrapper.ts +0 -56
  60. package/addon/-private/ts-interfaces/record-data.ts +0 -72
  61. package/addon/-private/ts-interfaces/record-instance.ts +0 -18
  62. package/addon/-private/ts-interfaces/schema-definition-service.ts +0 -12
  63. package/addon/-private/ts-interfaces/store.ts +0 -10
  64. package/addon/-private/ts-interfaces/utils.ts +0 -6
@@ -0,0 +1,387 @@
1
+ import { assert } from '@ember/debug';
2
+ import { DEBUG } from '@glimmer/env';
3
+
4
+ import { resolve } from 'rsvp';
5
+
6
+ import type { ExistingResourceObject, ResourceIdentifierObject } from '@ember-data/types/q/ember-data-json-api';
7
+ import type {
8
+ RecordIdentifier,
9
+ StableExistingRecordIdentifier,
10
+ StableRecordIdentifier,
11
+ } from '@ember-data/types/q/identifier';
12
+ import type { RecordData } from '@ember-data/types/q/record-data';
13
+ import type { RecordInstance } from '@ember-data/types/q/record-instance';
14
+ import type { FindOptions } from '@ember-data/types/q/store';
15
+
16
+ import coerceId, { ensureStringId } from './coerce-id';
17
+ import type { CreateRecordProperties } from './core-store';
18
+ import type Store from './core-store';
19
+ import { assertIdentifierHasId } from './core-store';
20
+ import { internalModelFactoryFor, setRecordIdentifier } from './internal-model-factory';
21
+ import InternalModel from './model/internal-model';
22
+ import RecordReference from './model/record-reference';
23
+ import normalizeModelName from './normalize-model-name';
24
+ import recordDataFor, { setRecordDataFor } from './record-data-for';
25
+ import RecordDataStoreWrapper from './record-data-store-wrapper';
26
+ import Snapshot from './snapshot';
27
+ import constructResource from './utils/construct-resource';
28
+ import WeakCache from './weak-cache';
29
+
30
+ const RECORD_REFERENCES = new WeakCache<StableRecordIdentifier, RecordReference>(DEBUG ? 'reference' : '');
31
+ export const StoreMap = new WeakCache<RecordInstance, Store>(DEBUG ? 'store' : '');
32
+
33
+ export function storeFor(record: RecordInstance): Store | undefined {
34
+ const store = StoreMap.get(record);
35
+
36
+ assert(
37
+ `A record in a disconnected state cannot utilize the store. This typically means the record has been destroyed, most commonly by unloading it.`,
38
+ store
39
+ );
40
+ return store;
41
+ }
42
+
43
+ type Caches = {
44
+ record: WeakMap<StableRecordIdentifier, RecordInstance>;
45
+ recordData: WeakMap<StableRecordIdentifier, RecordData>;
46
+ };
47
+ export class InstanceCache {
48
+ declare store: Store;
49
+ declare _storeWrapper: RecordDataStoreWrapper;
50
+
51
+ #instances: Caches = {
52
+ record: new WeakMap<StableRecordIdentifier, RecordInstance>(),
53
+ recordData: new WeakMap<StableRecordIdentifier, RecordData>(),
54
+ };
55
+
56
+ constructor(store: Store) {
57
+ this.store = store;
58
+
59
+ this._storeWrapper = new RecordDataStoreWrapper(this.store);
60
+ this.__recordDataFor = this.__recordDataFor.bind(this);
61
+
62
+ RECORD_REFERENCES._generator = (identifier) => {
63
+ return new RecordReference(this.store, identifier);
64
+ };
65
+ }
66
+ peek({ identifier, bucket }: { identifier: StableRecordIdentifier; bucket: 'record' }): RecordInstance | undefined;
67
+ peek({ identifier, bucket }: { identifier: StableRecordIdentifier; bucket: 'recordData' }): RecordData | undefined;
68
+ peek({
69
+ identifier,
70
+ bucket,
71
+ }: {
72
+ identifier: StableRecordIdentifier;
73
+ bucket: 'record' | 'recordData';
74
+ }): RecordData | RecordInstance | undefined {
75
+ return this.#instances[bucket]?.get(identifier);
76
+ }
77
+ set({
78
+ identifier,
79
+ bucket,
80
+ value,
81
+ }: {
82
+ identifier: StableRecordIdentifier;
83
+ bucket: 'record';
84
+ value: RecordInstance;
85
+ }): void {
86
+ this.#instances[bucket].set(identifier, value);
87
+ }
88
+
89
+ getRecord(identifier: StableRecordIdentifier, properties?: CreateRecordProperties): RecordInstance {
90
+ let record = this.peek({ identifier, bucket: 'record' });
91
+
92
+ if (!record) {
93
+ // TODO store this state somewhere better
94
+ const internalModel = this.getInternalModel(identifier);
95
+
96
+ if (internalModel._isDematerializing) {
97
+ // TODO this should be an assertion, this likely means
98
+ // we have a bug to find wherein our own store is calling this
99
+ // with an identifier that should have already been disconnected.
100
+ // the destroy + fetch again case is likely either preserving the
101
+ // identifier for re-use or failing to unload it.
102
+ return null as unknown as RecordInstance;
103
+ }
104
+
105
+ // TODO store this state somewhere better
106
+ internalModel.hasRecord = true;
107
+
108
+ if (properties && 'id' in properties) {
109
+ assert(`expected id to be a string or null`, properties.id !== undefined);
110
+ internalModel.setId(properties.id);
111
+ }
112
+
113
+ record = this._instantiateRecord(this.getRecordData(identifier), identifier, properties);
114
+ this.set({ identifier, bucket: 'record', value: record });
115
+ }
116
+
117
+ return record;
118
+ }
119
+
120
+ getReference(identifier: StableRecordIdentifier) {
121
+ return RECORD_REFERENCES.lookup(identifier);
122
+ }
123
+
124
+ _fetchDataIfNeededForIdentifier(
125
+ identifier: StableRecordIdentifier,
126
+ options: FindOptions = {}
127
+ ): Promise<StableRecordIdentifier> {
128
+ const internalModel = this.getInternalModel(identifier);
129
+
130
+ // pre-loading will change the isEmpty value
131
+ // TODO stpre this state somewhere other than InternalModel
132
+ const { isEmpty, isLoading } = internalModel;
133
+
134
+ if (options.preload) {
135
+ this.store._backburner.join(() => {
136
+ internalModel.preloadData(options.preload);
137
+ });
138
+ }
139
+
140
+ let promise: Promise<StableRecordIdentifier>;
141
+ if (isEmpty) {
142
+ assertIdentifierHasId(identifier);
143
+
144
+ promise = this.store._fetchManager.scheduleFetch(identifier, options);
145
+ } else if (isLoading) {
146
+ promise = this.store._fetchManager.getPendingFetch(identifier, options)!;
147
+ assert(`Expected to find a pending request for a record in the loading state, but found none`, promise);
148
+ } else {
149
+ promise = resolve(identifier);
150
+ }
151
+
152
+ return promise;
153
+ }
154
+
155
+ _instantiateRecord(
156
+ recordData: RecordData,
157
+ identifier: StableRecordIdentifier,
158
+ properties?: { [key: string]: unknown }
159
+ ) {
160
+ // assert here
161
+ if (properties !== undefined) {
162
+ assert(
163
+ `You passed '${typeof properties}' as properties for record creation instead of an object.`,
164
+ typeof properties === 'object' && properties !== null
165
+ );
166
+
167
+ const { type } = identifier;
168
+
169
+ // convert relationship Records to RecordDatas before passing to RecordData
170
+ let defs = this.store.getSchemaDefinitionService().relationshipsDefinitionFor({ type });
171
+
172
+ if (defs !== null) {
173
+ let keys = Object.keys(properties);
174
+ let relationshipValue;
175
+
176
+ for (let i = 0; i < keys.length; i++) {
177
+ let prop = keys[i];
178
+ let def = defs[prop];
179
+
180
+ if (def !== undefined) {
181
+ if (def.kind === 'hasMany') {
182
+ if (DEBUG) {
183
+ assertRecordsPassedToHasMany(properties[prop] as RecordInstance[]);
184
+ }
185
+ relationshipValue = extractRecordDatasFromRecords(properties[prop] as RecordInstance[]);
186
+ } else {
187
+ relationshipValue = extractRecordDataFromRecord(properties[prop] as RecordInstance);
188
+ }
189
+
190
+ properties[prop] = relationshipValue;
191
+ }
192
+ }
193
+ }
194
+ }
195
+
196
+ // TODO guard against initRecordOptions no being there
197
+ let createOptions = recordData._initRecordCreateOptions(properties);
198
+ //TODO Igor pass a wrapper instead of RD
199
+ let record = this.store.instantiateRecord(
200
+ identifier,
201
+ createOptions,
202
+ // eslint-disable-next-line @typescript-eslint/unbound-method
203
+ this.__recordDataFor,
204
+ this.store._notificationManager
205
+ );
206
+ setRecordIdentifier(record, identifier);
207
+ setRecordDataFor(record, recordData);
208
+ StoreMap.set(record, this.store);
209
+ return record;
210
+ }
211
+
212
+ _teardownRecord(record: RecordInstance) {
213
+ StoreMap.delete(record);
214
+ // TODO remove identifier:record cache link
215
+ this.store.teardownRecord(record);
216
+ }
217
+
218
+ removeRecord(identifier: StableRecordIdentifier): boolean {
219
+ let record = this.peek({ identifier, bucket: 'record' });
220
+
221
+ if (record) {
222
+ this.#instances.record.delete(identifier);
223
+ this._teardownRecord(record);
224
+ }
225
+
226
+ return !!record;
227
+ }
228
+
229
+ // TODO move RecordData Cache into InstanceCache
230
+ getRecordData(identifier: StableRecordIdentifier) {
231
+ let recordData = this.peek({ identifier, bucket: 'recordData' });
232
+
233
+ if (!recordData) {
234
+ recordData = this._createRecordData(identifier);
235
+ this.#instances.recordData.set(identifier, recordData);
236
+ this.getInternalModel(identifier).hasRecordData = true;
237
+ }
238
+
239
+ return recordData;
240
+ }
241
+
242
+ // TODO move InternalModel cache into InstanceCache
243
+ getInternalModel(identifier: StableRecordIdentifier) {
244
+ return this._internalModelForResource(identifier);
245
+ }
246
+
247
+ createSnapshot(identifier: StableRecordIdentifier, options: FindOptions = {}): Snapshot {
248
+ return new Snapshot(options, identifier, this.store);
249
+ }
250
+
251
+ __recordDataFor(resource: RecordIdentifier) {
252
+ const identifier = this.store.identifierCache.getOrCreateRecordIdentifier(resource);
253
+ return this.recordDataFor(identifier, false);
254
+ }
255
+
256
+ // TODO move this to InstanceCache
257
+ _createRecordData(identifier: StableRecordIdentifier): RecordData {
258
+ const recordData = this.store.createRecordDataFor(
259
+ identifier.type,
260
+ identifier.id,
261
+ identifier.lid,
262
+ this._storeWrapper
263
+ );
264
+ setRecordDataFor(identifier, recordData);
265
+ // TODO this is invalid for v2 recordData but required
266
+ // for v1 recordData. Remember to remove this once the
267
+ // RecordData manager handles converting recordData to identifier
268
+ setRecordIdentifier(recordData, identifier);
269
+ return recordData;
270
+ }
271
+
272
+ // TODO string candidate for early elimination
273
+ _internalModelForResource(resource: ResourceIdentifierObject): InternalModel {
274
+ return internalModelFactoryFor(this.store).getByResource(resource);
275
+ }
276
+
277
+ setRecordId(modelName: string, newId: string, clientId: string) {
278
+ internalModelFactoryFor(this.store).setRecordId(modelName, newId, clientId);
279
+ }
280
+
281
+ _load(data: ExistingResourceObject): StableExistingRecordIdentifier {
282
+ // TODO type should be pulled from the identifier for debug
283
+ let modelName = data.type;
284
+ assert(
285
+ `You must include an 'id' for ${modelName} in an object passed to 'push'`,
286
+ data.id !== null && data.id !== undefined && data.id !== ''
287
+ );
288
+ assert(
289
+ `You tried to push data with a type '${modelName}' but no model could be found with that name.`,
290
+ this.store.getSchemaDefinitionService().doesTypeExist(modelName)
291
+ );
292
+
293
+ // TODO this should determine identifier via the cache before making assumptions
294
+ const resource = constructResource(normalizeModelName(data.type), ensureStringId(data.id), coerceId(data.lid));
295
+ const maybeIdentifier = this.store.identifierCache.peekRecordIdentifier(resource);
296
+
297
+ let internalModel = internalModelFactoryFor(this.store).lookup(resource, data);
298
+
299
+ // store.push will be from empty
300
+ // findRecord will be from root.loading
301
+ // this cannot be loading state if we do not already have an identifier
302
+ // all else will be updates
303
+ const isLoading = internalModel.isLoading || (!internalModel.isLoaded && maybeIdentifier);
304
+ const isUpdate = internalModel.isEmpty === false && !isLoading;
305
+
306
+ // exclude store.push (root.empty) case
307
+ let identifier = internalModel.identifier;
308
+ if (isUpdate || isLoading) {
309
+ let updatedIdentifier = this.store.identifierCache.updateRecordIdentifier(identifier, data);
310
+
311
+ if (updatedIdentifier !== identifier) {
312
+ // we encountered a merge of identifiers in which
313
+ // two identifiers (and likely two internalModels)
314
+ // existed for the same resource. Now that we have
315
+ // determined the correct identifier to use, make sure
316
+ // that we also use the correct internalModel.
317
+ identifier = updatedIdentifier;
318
+ internalModel = internalModelFactoryFor(this.store).lookup(identifier);
319
+ }
320
+ }
321
+
322
+ internalModel.setupData(data);
323
+
324
+ if (!isUpdate) {
325
+ this.store.recordArrayManager.recordDidChange(identifier);
326
+ }
327
+
328
+ return identifier as StableExistingRecordIdentifier;
329
+ }
330
+
331
+ recordDataFor(identifier: StableRecordIdentifier | { type: string }, isCreate: boolean): RecordData {
332
+ let recordData: RecordData;
333
+ if (isCreate === true) {
334
+ // TODO remove once InternalModel is no longer essential to internal state
335
+ // and just build a new identifier directly
336
+ let internalModel = internalModelFactoryFor(this.store).build({ type: identifier.type, id: null });
337
+ let stableIdentifier = internalModel.identifier;
338
+ recordData = this.getRecordData(stableIdentifier);
339
+ recordData.clientDidCreate();
340
+ this.store.recordArrayManager.recordDidChange(stableIdentifier);
341
+ } else {
342
+ // TODO remove once InternalModel is no longer essential to internal state
343
+ internalModelFactoryFor(this.store).lookup(identifier as StableRecordIdentifier);
344
+ recordData = this.getRecordData(identifier as StableRecordIdentifier);
345
+ }
346
+
347
+ return recordData;
348
+ }
349
+ }
350
+
351
+ function assertRecordsPassedToHasMany(records: RecordInstance[]) {
352
+ assert(`You must pass an array of records to set a hasMany relationship`, Array.isArray(records));
353
+ assert(
354
+ `All elements of a hasMany relationship must be instances of Model, you passed ${records
355
+ .map((r) => `${typeof r}`)
356
+ .join(', ')}`,
357
+ (function () {
358
+ return records.every((record) => Object.prototype.hasOwnProperty.call(record, '_internalModel') === true);
359
+ })()
360
+ );
361
+ }
362
+
363
+ function extractRecordDatasFromRecords(records: RecordInstance[]): RecordData[] {
364
+ return records.map(extractRecordDataFromRecord) as RecordData[];
365
+ }
366
+ type PromiseProxyRecord = { then(): void; get(str: 'content'): RecordInstance | null | undefined };
367
+
368
+ function extractRecordDataFromRecord(recordOrPromiseRecord: PromiseProxyRecord | RecordInstance | null) {
369
+ if (!recordOrPromiseRecord) {
370
+ return null;
371
+ }
372
+
373
+ if (isPromiseRecord(recordOrPromiseRecord)) {
374
+ let content = recordOrPromiseRecord.get && recordOrPromiseRecord.get('content');
375
+ assert(
376
+ 'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.',
377
+ content !== undefined
378
+ );
379
+ return content ? recordDataFor(content) : null;
380
+ }
381
+
382
+ return recordDataFor(recordOrPromiseRecord);
383
+ }
384
+
385
+ function isPromiseRecord(record: PromiseProxyRecord | RecordInstance): record is PromiseProxyRecord {
386
+ return !!record.then;
387
+ }
@@ -1,28 +1,28 @@
1
1
  import { assert, warn } from '@ember/debug';
2
- import { isNone } from '@ember/utils';
3
2
  import { DEBUG } from '@glimmer/env';
4
3
 
5
- import type { IdentifierCache } from '../../identifiers/cache';
6
4
  import type {
7
5
  ExistingResourceObject,
8
6
  NewResourceIdentifierObject,
9
7
  ResourceIdentifierObject,
10
- } from '../../ts-interfaces/ember-data-json-api';
11
- import type { StableRecordIdentifier } from '../../ts-interfaces/identifier';
12
- import type { RecordData } from '../../ts-interfaces/record-data';
13
- import type { RecordInstance } from '../../ts-interfaces/record-instance';
14
- import constructResource from '../../utils/construct-resource';
15
- import type CoreStore from '../core-store';
16
- import IdentityMap from '../identity-map';
17
- import type InternalModelMap from '../internal-model-map';
18
- import InternalModel from '../model/internal-model';
19
- import WeakCache from '../weak-cache';
8
+ } from '@ember-data/types/q/ember-data-json-api';
9
+ import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
10
+ import type { RecordData } from '@ember-data/types/q/record-data';
11
+ import type { RecordInstance } from '@ember-data/types/q/record-instance';
12
+
13
+ import type Store from './core-store';
14
+ import type { IdentifierCache } from './identifier-cache';
15
+ import IdentityMap from './identity-map';
16
+ import type InternalModelMap from './internal-model-map';
17
+ import InternalModel from './model/internal-model';
18
+ import constructResource from './utils/construct-resource';
19
+ import WeakCache from './weak-cache';
20
20
 
21
21
  /**
22
22
  @module @ember-data/store
23
23
  */
24
- const FactoryCache = new WeakCache<CoreStore, InternalModelFactory>(DEBUG ? 'internal-model-factory' : '');
25
- FactoryCache._generator = (store: CoreStore) => {
24
+ const FactoryCache = new WeakCache<Store, InternalModelFactory>(DEBUG ? 'internal-model-factory' : '');
25
+ FactoryCache._generator = (store: Store) => {
26
26
  return new InternalModelFactory(store);
27
27
  };
28
28
  type NewResourceInfo = { type: string; id: string | null };
@@ -66,7 +66,7 @@ export function recordIdentifierFor(record: RecordInstance | RecordData): Stable
66
66
  }
67
67
 
68
68
  export function setRecordIdentifier(record: RecordInstance | RecordData, identifier: StableRecordIdentifier): void {
69
- if (DEBUG && RecordCache.has(record)) {
69
+ if (DEBUG && RecordCache.has(record) && RecordCache.get(record) !== identifier) {
70
70
  throw new Error(`${record} was already assigned an identifier`);
71
71
  }
72
72
 
@@ -81,7 +81,7 @@ export function setRecordIdentifier(record: RecordInstance | RecordData, identif
81
81
  RecordCache.set(record, identifier);
82
82
  }
83
83
 
84
- export function internalModelFactoryFor(store: CoreStore): InternalModelFactory {
84
+ export function internalModelFactoryFor(store: Store): InternalModelFactory {
85
85
  return FactoryCache.lookup(store);
86
86
  }
87
87
 
@@ -96,9 +96,9 @@ export function internalModelFactoryFor(store: CoreStore): InternalModelFactory
96
96
  export default class InternalModelFactory {
97
97
  declare _identityMap: IdentityMap;
98
98
  declare identifierCache: IdentifierCache;
99
- declare store: CoreStore;
99
+ declare store: Store;
100
100
 
101
- constructor(store: CoreStore) {
101
+ constructor(store: Store) {
102
102
  this.store = store;
103
103
  this.identifierCache = store.identifierCache;
104
104
  this.identifierCache.__configureMerge((identifier, matchedIdentifier, resourceData) => {
@@ -119,6 +119,10 @@ export default class InternalModelFactory {
119
119
  // we cannot merge internalModels when both have records
120
120
  // (this may not be strictly true, we could probably swap the internalModel the record points at)
121
121
  if (im && otherIm && im.hasRecord && otherIm.hasRecord) {
122
+ // TODO we probably don't need to throw these errors anymore
123
+ // once InternalModel is fully removed, as we can just "swap"
124
+ // what data source the abandoned record points at so long as
125
+ // it itself is not retained by the store in any way.
122
126
  if ('id' in resourceData) {
123
127
  throw new Error(
124
128
  `Failed to update the 'id' for the RecordIdentifier '${identifier.type}:${identifier.id} (${identifier.lid})' to '${resourceData.id}', because that id is already in use by '${matchedIdentifier.type}:${matchedIdentifier.id} (${matchedIdentifier.lid})'`
@@ -150,6 +154,7 @@ export default class InternalModelFactory {
150
154
  im = otherIm;
151
155
  // TODO do we need to notify the id change?
152
156
  im._id = intendedIdentifier.id;
157
+ im.identifier = intendedIdentifier;
153
158
  map.add(im, intendedIdentifier.lid);
154
159
 
155
160
  // just use im
@@ -268,10 +273,11 @@ export default class InternalModelFactory {
268
273
 
269
274
  assert(
270
275
  `'${modelName}' was saved to the server, but the response returned the new id '${id}', which has already been used with another record.'`,
271
- isNone(existingInternalModel) || existingInternalModel === internalModel
276
+ !existingInternalModel || existingInternalModel === internalModel
272
277
  );
273
278
 
274
279
  if (identifier.id === null) {
280
+ // TODO potentially this needs to handle merged result
275
281
  this.identifierCache.updateRecordIdentifier(identifier, { type, id });
276
282
  }
277
283
 
@@ -1,7 +1,8 @@
1
1
  import { assert } from '@ember/debug';
2
2
 
3
- import type { StableRecordIdentifier } from '../ts-interfaces/identifier';
4
- import type { ConfidentDict } from '../ts-interfaces/utils';
3
+ import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
4
+ import type { ConfidentDict } from '@ember-data/types/q/utils';
5
+
5
6
  import InternalModel from './model/internal-model';
6
7
 
7
8
  /**
@@ -19,10 +20,13 @@ import InternalModel from './model/internal-model';
19
20
  @internal
20
21
  */
21
22
  export default class InternalModelMap {
22
- private _idToModel: ConfidentDict<InternalModel> = Object.create(null);
23
- private _models: InternalModel[] = [];
23
+ _idToModel: ConfidentDict<InternalModel> = Object.create(null);
24
+ _models: InternalModel[] = [];
25
+ modelName: string;
24
26
 
25
- constructor(public modelName: string) {}
27
+ constructor(modelName: string) {
28
+ this.modelName = modelName;
29
+ }
26
30
 
27
31
  get(id: string): InternalModel | null {
28
32
  return this._idToModel[id] || null;