@ember-data/store 4.1.0 → 4.2.0-alpha.10

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 (29) hide show
  1. package/addon/-private/identifiers/cache.ts +3 -16
  2. package/addon/-private/identifiers/is-stable-identifier.ts +2 -2
  3. package/addon/-private/index.ts +1 -3
  4. package/addon/-private/system/core-store.ts +186 -986
  5. package/addon/-private/system/ds-model-store.ts +20 -111
  6. package/addon/-private/system/fetch-manager.ts +2 -1
  7. package/addon/-private/system/model/internal-model.ts +92 -345
  8. package/addon/-private/system/model/shim-model-class.ts +15 -16
  9. package/addon/-private/system/model/states.js +2 -14
  10. package/addon/-private/system/record-array-manager.js +21 -70
  11. package/addon/-private/system/record-arrays/adapter-populated-record-array.js +1 -20
  12. package/addon/-private/system/record-arrays/record-array.js +1 -8
  13. package/addon/-private/system/record-data-for.ts +10 -8
  14. package/addon/-private/system/record-notification-manager.ts +11 -10
  15. package/addon/-private/system/references/belongs-to.ts +32 -67
  16. package/addon/-private/system/references/has-many.ts +21 -41
  17. package/addon/-private/system/references/record.ts +15 -27
  18. package/addon/-private/system/references/reference.ts +7 -36
  19. package/addon/-private/system/schema-definition-service.ts +2 -2
  20. package/addon/-private/system/snapshot.ts +28 -48
  21. package/addon/-private/system/store/finders.js +2 -96
  22. package/addon/-private/system/store/internal-model-factory.ts +34 -28
  23. package/addon/-private/system/store/record-data-store-wrapper.ts +28 -36
  24. package/addon/-private/system/weak-cache.ts +125 -0
  25. package/addon/-private/ts-interfaces/identifier.ts +2 -2
  26. package/addon/-private/ts-interfaces/minimum-adapter-interface.ts +0 -1
  27. package/addon/-private/ts-interfaces/schema-definition-service.ts +2 -2
  28. package/package.json +16 -16
  29. package/addon/-private/system/deprecated-evented.js +0 -92
@@ -3,8 +3,8 @@
3
3
  */
4
4
  import { getOwner } from '@ember/application';
5
5
  import { A } from '@ember/array';
6
- import { assert, deprecate, inspect, warn } from '@ember/debug';
7
- import { computed, defineProperty, get, set } from '@ember/object';
6
+ import { assert, inspect, warn } from '@ember/debug';
7
+ import { set } from '@ember/object';
8
8
  import { _backburner as emberBackburner } from '@ember/runloop';
9
9
  import type { Backburner } from '@ember/runloop/-private/backburner';
10
10
  import Service from '@ember/service';
@@ -14,25 +14,9 @@ import { DEBUG } from '@glimmer/env';
14
14
  import Ember from 'ember';
15
15
 
16
16
  import require from 'require';
17
- import { all, default as RSVP, defer, Promise, resolve } from 'rsvp';
17
+ import { all, default as RSVP, Promise, resolve } from 'rsvp';
18
18
 
19
- import {
20
- CUSTOM_MODEL_CLASS,
21
- RECORD_DATA_ERRORS,
22
- RECORD_DATA_STATE,
23
- REQUEST_SERVICE,
24
- } from '@ember-data/canary-features';
25
- import {
26
- HAS_ADAPTER_PACKAGE,
27
- HAS_EMBER_DATA_PACKAGE,
28
- HAS_RECORD_DATA_PACKAGE,
29
- HAS_SERIALIZER_PACKAGE,
30
- } from '@ember-data/private-build-infra';
31
- import {
32
- DEPRECATE_DEFAULT_ADAPTER,
33
- DEPRECATE_DEFAULT_SERIALIZER,
34
- DEPRECATE_LEGACY_TEST_REGISTRATIONS,
35
- } from '@ember-data/private-build-infra/deprecations';
19
+ import { HAS_RECORD_DATA_PACKAGE } from '@ember-data/private-build-infra';
36
20
  import type {
37
21
  BelongsToRelationship,
38
22
  ManyRelationship,
@@ -40,8 +24,7 @@ import type {
40
24
  } from '@ember-data/record-data/-private';
41
25
  import type { RelationshipState } from '@ember-data/record-data/-private/graph/-state';
42
26
 
43
- import type { IdentifierCache } from '../identifiers/cache';
44
- import { identifierCacheFor } from '../identifiers/cache';
27
+ import { IdentifierCache } from '../identifiers/cache';
45
28
  import type { DSModel } from '../ts-interfaces/ds-model';
46
29
  import type {
47
30
  CollectionResourceDocument,
@@ -69,7 +52,6 @@ import constructResource from '../utils/construct-resource';
69
52
  import promiseRecord from '../utils/promise-record';
70
53
  import edBackburner from './backburner';
71
54
  import coerceId, { ensureStringId } from './coerce-id';
72
- import { errorsArrayToHash } from './errors-utils';
73
55
  import FetchManager, { SaveOp } from './fetch-manager';
74
56
  import type InternalModel from './model/internal-model';
75
57
  import {
@@ -87,9 +69,7 @@ import NotificationManager from './record-notification-manager';
87
69
  import type { BelongsToReference, HasManyReference } from './references';
88
70
  import { RecordReference } from './references';
89
71
  import type RequestCache from './request-cache';
90
- import type { default as Snapshot, PrivateSnapshot } from './snapshot';
91
- import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './store/common';
92
- import { _find, _findAll, _findBelongsTo, _findHasMany, _findMany, _query, _queryRecord } from './store/finders';
72
+ import { _findAll, _findBelongsTo, _findHasMany, _query, _queryRecord } from './store/finders';
93
73
  import {
94
74
  internalModelFactoryFor,
95
75
  peekRecordIdentifier,
@@ -97,7 +77,7 @@ import {
97
77
  setRecordIdentifier,
98
78
  } from './store/internal-model-factory';
99
79
  import RecordDataStoreWrapper from './store/record-data-store-wrapper';
100
- import { normalizeResponseHelper } from './store/serializer-response';
80
+ import WeakCache from './weak-cache';
101
81
 
102
82
  type RecordDataConstruct = typeof RecordDataClass;
103
83
  let _RecordData: RecordDataConstruct | undefined;
@@ -105,18 +85,8 @@ let _RecordData: RecordDataConstruct | undefined;
105
85
  const { ENV } = Ember;
106
86
  type AsyncTrackingToken = Readonly<{ label: string; trace: Error | string }>;
107
87
  type PromiseArray<T> = Promise<T[]>;
108
- type PendingFetchItem = {
109
- internalModel: InternalModel;
110
- resolver: RSVP.Deferred<InternalModel>;
111
- options: any;
112
- trace?: Error;
113
- };
114
- type PendingSaveItem = {
115
- snapshot: Snapshot;
116
- resolver: RSVP.Deferred<void>;
117
- };
118
-
119
- const RECORD_REFERENCES = new WeakMap<StableRecordIdentifier, RecordReference>();
88
+
89
+ const RECORD_REFERENCES = new WeakCache<StableRecordIdentifier, RecordReference>(DEBUG ? 'reference' : '');
120
90
 
121
91
  function freeze<T>(obj: T): T {
122
92
  if (typeof Object.freeze === 'function') {
@@ -126,26 +96,6 @@ function freeze<T>(obj: T): T {
126
96
  return obj;
127
97
  }
128
98
 
129
- function deprecateTestRegistration(factoryType: 'adapter', factoryName: '-json-api'): void;
130
- function deprecateTestRegistration(factoryType: 'serializer', factoryName: '-json-api' | '-rest' | '-default'): void;
131
- function deprecateTestRegistration(
132
- factoryType: 'serializer' | 'adapter',
133
- factoryName: '-json-api' | '-rest' | '-default'
134
- ): void {
135
- deprecate(
136
- `You looked up the ${factoryType} "${factoryName}" but it was not found. Likely this means you are using a legacy ember-qunit moduleFor helper. Add "needs: ['${factoryType}:${factoryName}']", "integration: true", or refactor to modern syntax to resolve this deprecation.`,
137
- false,
138
- {
139
- id: 'ember-data:-legacy-test-registrations',
140
- until: '3.17',
141
- for: '@ember-data/store',
142
- since: {
143
- available: '3.15',
144
- enabled: '3.15',
145
- },
146
- }
147
- );
148
- }
149
99
  /**
150
100
  The store contains all of the data for records loaded from the server.
151
101
  It is also responsible for creating instances of `Model` that wrap
@@ -219,9 +169,6 @@ function deprecateTestRegistration(
219
169
  @public
220
170
  @extends Ember.Service
221
171
  */
222
- interface CoreStore {
223
- adapter: string;
224
- }
225
172
 
226
173
  abstract class CoreStore extends Service {
227
174
  /**
@@ -233,6 +180,7 @@ abstract class CoreStore extends Service {
233
180
  public recordArrayManager: RecordArrayManager = new RecordArrayManager({ store: this });
234
181
 
235
182
  declare _notificationManager: NotificationManager;
183
+ declare identifierCache: IdentifierCache;
236
184
  private _adapterCache = Object.create(null);
237
185
  private _serializerCache = Object.create(null);
238
186
  public _storeWrapper = new RecordDataStoreWrapper(this);
@@ -244,20 +192,14 @@ abstract class CoreStore extends Service {
244
192
  These queues are currently controlled by a flush scheduled into
245
193
  ember-data's custom backburner instance.
246
194
  */
247
- // used for coalescing record save requests
248
- private _pendingSave: PendingSaveItem[] = [];
249
195
  // used for coalescing internal model updates
250
196
  private _updatedInternalModels: InternalModel[] = [];
251
197
 
252
- // used to keep track of all the find requests that need to be coalesced
253
- private _pendingFetch = new Map<string, PendingFetchItem[]>();
254
-
255
198
  declare _fetchManager: FetchManager;
256
199
  declare _schemaDefinitionService: SchemaDefinitionService;
257
200
 
258
201
  // DEBUG-only properties
259
202
  declare _trackedAsyncRequests: AsyncTrackingToken[];
260
- shouldAssertMethodCallsOnDestroyedStore: boolean = true;
261
203
  shouldTrackAsyncRequests: boolean = false;
262
204
  generateStackTracesForTrackedRequests: boolean = false;
263
205
  declare _trackAsyncRequestStart: (str: string) => void;
@@ -311,64 +253,27 @@ abstract class CoreStore extends Service {
311
253
  constructor() {
312
254
  super(...arguments);
313
255
 
314
- if (REQUEST_SERVICE) {
315
- this._fetchManager = new FetchManager(this);
316
- }
317
- if (CUSTOM_MODEL_CLASS) {
318
- this._notificationManager = new NotificationManager(this);
319
- this.__recordDataFor = this.__recordDataFor.bind(this);
320
- }
256
+ RECORD_REFERENCES._generator = (identifier) => {
257
+ return new RecordReference(this, identifier);
258
+ };
259
+
260
+ this._fetchManager = new FetchManager(this);
261
+ this._notificationManager = new NotificationManager(this);
262
+ this.__recordDataFor = this.__recordDataFor.bind(this);
263
+
264
+ /**
265
+ * Provides access to the IdentifierCache instance
266
+ * for this store.
267
+ *
268
+ * The IdentifierCache can be used to generate or
269
+ * retrieve a stable unique identifier for any resource.
270
+ *
271
+ * @property {IdentifierCache} identifierCache
272
+ * @public
273
+ */
274
+ this.identifierCache = new IdentifierCache();
321
275
 
322
276
  if (DEBUG) {
323
- if (HAS_EMBER_DATA_PACKAGE && HAS_SERIALIZER_PACKAGE) {
324
- // support for legacy moduleFor style unit tests
325
- // that did not include transforms in "needs"
326
- // or which were not set to integration:true
327
- // that were relying on ember-test-helpers
328
- // doing an auto-registration of the transform
329
- // or us doing one
330
- const Mapping = {
331
- date: 'DateTransform',
332
- boolean: 'BooleanTransform',
333
- number: 'NumberTransform',
334
- string: 'StringTransform',
335
- };
336
- type MapKeys = keyof typeof Mapping;
337
- const keys = Object.keys(Mapping) as MapKeys[];
338
- let shouldWarn = false;
339
-
340
- let owner = getOwner(this);
341
- keys.forEach((attributeType) => {
342
- const transformFactory = owner.factoryFor(`transform:${attributeType}`);
343
-
344
- if (!transformFactory) {
345
- // we don't deprecate this because the moduleFor style tests with the closed
346
- // resolver will be deprecated on their own. When that deprecation completes
347
- // we can drop this.
348
- const Transform = require(`@ember-data/serializer/-private`)[Mapping[attributeType]];
349
- owner.register(`transform:${attributeType}`, Transform);
350
- shouldWarn = true;
351
- }
352
- });
353
-
354
- if (shouldWarn) {
355
- deprecate(
356
- `You are relying on the automatic registration of the transforms "date", "number", "boolean", and "string". Likely this means you are using a legacy ember-qunit moduleFor helper. Add "needs: ['transform:date', 'transform:boolean', 'transform:number', 'transform:string']", "integration: true", or refactor to modern syntax to resolve this deprecation.`,
357
- false,
358
- {
359
- id: 'ember-data:-legacy-test-registrations',
360
- until: '3.17',
361
- for: '@ember-data/store',
362
- since: {
363
- available: '3.15',
364
- enabled: '3.15',
365
- },
366
- }
367
- );
368
- }
369
- }
370
-
371
- this.shouldAssertMethodCallsOnDestroyedStore = this.shouldAssertMethodCallsOnDestroyedStore || false;
372
277
  if (this.shouldTrackAsyncRequests === undefined) {
373
278
  this.shouldTrackAsyncRequests = false;
374
279
  }
@@ -378,14 +283,14 @@ abstract class CoreStore extends Service {
378
283
 
379
284
  this._trackedAsyncRequests = [];
380
285
  this._trackAsyncRequestStart = (label) => {
381
- let trace =
286
+ let trace: string | Error =
382
287
  'set `store.generateStackTracesForTrackedRequests = true;` to get a detailed trace for where this request originated';
383
288
 
384
289
  if (this.generateStackTracesForTrackedRequests) {
385
290
  try {
386
291
  throw new Error(`EmberData TrackedRequest: ${label}`);
387
292
  } catch (e) {
388
- trace = e;
293
+ trace = e as Error;
389
294
  }
390
295
  }
391
296
 
@@ -422,24 +327,7 @@ abstract class CoreStore extends Service {
422
327
  }
423
328
 
424
329
  getRequestStateService(): RequestCache {
425
- if (REQUEST_SERVICE) {
426
- return this._fetchManager.requestCache;
427
- }
428
- assert('RequestService is not available unless the feature flag is on and running on a canary build', false);
429
- }
430
-
431
- /**
432
- * Provides access to the IdentifierCache instance
433
- * for this store.
434
- *
435
- * The IdentifierCache can be used to generate or
436
- * retrieve a stable unique identifier for any resource.
437
- *
438
- * @property {IdentifierCache} identifierCache
439
- * @public
440
- */
441
- get identifierCache(): IdentifierCache {
442
- return identifierCacheFor(this);
330
+ return this._fetchManager.requestCache;
443
331
  }
444
332
 
445
333
  _instantiateRecord(
@@ -449,55 +337,51 @@ abstract class CoreStore extends Service {
449
337
  identifier: StableRecordIdentifier,
450
338
  properties?: { [key: string]: any }
451
339
  ) {
452
- if (CUSTOM_MODEL_CLASS) {
453
- // assert here
454
- if (properties !== undefined) {
455
- assert(
456
- `You passed '${properties}' as properties for record creation instead of an object.`,
457
- typeof properties === 'object' && properties !== null
458
- );
459
-
460
- if ('id' in properties) {
461
- internalModel.setId(properties.id);
462
- }
340
+ // assert here
341
+ if (properties !== undefined) {
342
+ assert(
343
+ `You passed '${properties}' as properties for record creation instead of an object.`,
344
+ typeof properties === 'object' && properties !== null
345
+ );
463
346
 
464
- // convert relationship Records to RecordDatas before passing to RecordData
465
- let defs = this._relationshipsDefinitionFor(modelName);
466
-
467
- if (defs !== null) {
468
- let keys = Object.keys(properties);
469
- let relationshipValue;
470
-
471
- for (let i = 0; i < keys.length; i++) {
472
- let prop = keys[i];
473
- let def = defs[prop];
474
-
475
- if (def !== undefined) {
476
- if (def.kind === 'hasMany') {
477
- if (DEBUG) {
478
- assertRecordsPassedToHasMany(properties[prop]);
479
- }
480
- relationshipValue = extractRecordDatasFromRecords(properties[prop]);
481
- } else {
482
- relationshipValue = extractRecordDataFromRecord(properties[prop]);
483
- }
347
+ if ('id' in properties) {
348
+ internalModel.setId(properties.id);
349
+ }
350
+
351
+ // convert relationship Records to RecordDatas before passing to RecordData
352
+ let defs = this._relationshipsDefinitionFor({ type: modelName });
353
+
354
+ if (defs !== null) {
355
+ let keys = Object.keys(properties);
356
+ let relationshipValue;
484
357
 
485
- properties[prop] = relationshipValue;
358
+ for (let i = 0; i < keys.length; i++) {
359
+ let prop = keys[i];
360
+ let def = defs[prop];
361
+
362
+ if (def !== undefined) {
363
+ if (def.kind === 'hasMany') {
364
+ if (DEBUG) {
365
+ assertRecordsPassedToHasMany(properties[prop]);
366
+ }
367
+ relationshipValue = extractRecordDatasFromRecords(properties[prop]);
368
+ } else {
369
+ relationshipValue = extractRecordDataFromRecord(properties[prop]);
486
370
  }
371
+
372
+ properties[prop] = relationshipValue;
487
373
  }
488
374
  }
489
375
  }
490
-
491
- // TODO guard against initRecordOptions no being there
492
- let createOptions = recordData._initRecordCreateOptions(properties);
493
- //TODO Igor pass a wrapper instead of RD
494
- let record = this.instantiateRecord(identifier, createOptions, this.__recordDataFor, this._notificationManager);
495
- setRecordIdentifier(record, identifier);
496
- //recordToInternalModelMap.set(record, internalModel);
497
- return record;
498
376
  }
499
377
 
500
- assert('should not be here, custom model class ff error', false);
378
+ // TODO guard against initRecordOptions no being there
379
+ let createOptions = recordData._initRecordCreateOptions(properties);
380
+ //TODO Igor pass a wrapper instead of RD
381
+ let record = this.instantiateRecord(identifier, createOptions, this.__recordDataFor, this._notificationManager);
382
+ setRecordIdentifier(record, identifier);
383
+ //recordToInternalModelMap.set(record, internalModel);
384
+ return record;
501
385
  }
502
386
 
503
387
  abstract instantiateRecord(
@@ -514,20 +398,12 @@ abstract class CoreStore extends Service {
514
398
  }
515
399
 
516
400
  // FeatureFlagged in the DSModelStore claas
517
- _attributesDefinitionFor(modelName: string, identifier?: StableRecordIdentifier): AttributesSchema {
518
- if (identifier) {
519
- return this.getSchemaDefinitionService().attributesDefinitionFor(identifier);
520
- } else {
521
- return this.getSchemaDefinitionService().attributesDefinitionFor(modelName);
522
- }
401
+ _attributesDefinitionFor(identifier: RecordIdentifier | { type: string }): AttributesSchema {
402
+ return this.getSchemaDefinitionService().attributesDefinitionFor(identifier);
523
403
  }
524
404
 
525
- _relationshipsDefinitionFor(modelName: string, identifier?: StableRecordIdentifier) {
526
- if (identifier) {
527
- return this.getSchemaDefinitionService().relationshipsDefinitionFor(identifier);
528
- } else {
529
- return this.getSchemaDefinitionService().relationshipsDefinitionFor(modelName);
530
- }
405
+ _relationshipsDefinitionFor(identifier: RecordIdentifier | { type: string }) {
406
+ return this.getSchemaDefinitionService().relationshipsDefinitionFor(identifier);
531
407
  }
532
408
 
533
409
  registerSchemaDefinitionService(schema: SchemaDefinitionService) {
@@ -535,15 +411,12 @@ abstract class CoreStore extends Service {
535
411
  }
536
412
 
537
413
  getSchemaDefinitionService(): SchemaDefinitionService {
538
- if (CUSTOM_MODEL_CLASS) {
539
- return this._schemaDefinitionService;
540
- }
541
- assert('need to enable CUSTOM_MODEL_CLASS feature flag in order to access SchemaDefinitionService');
414
+ return this._schemaDefinitionService;
542
415
  }
543
416
 
544
417
  // TODO Double check this return value is correct
545
418
  _relationshipMetaFor(modelName: string, id: string | null, key: string) {
546
- return this._relationshipsDefinitionFor(modelName)[key];
419
+ return this._relationshipsDefinitionFor({ type: modelName })[key];
547
420
  }
548
421
 
549
422
  /**
@@ -716,31 +589,12 @@ abstract class CoreStore extends Service {
716
589
  assertDestroyingStore(this, 'deleteRecord');
717
590
  }
718
591
  this._backburner.join(() => {
719
- if (CUSTOM_MODEL_CLASS) {
720
- let identifier = peekRecordIdentifier(record);
721
- if (identifier) {
722
- let internalModel = internalModelFactoryFor(this).peek(identifier);
723
- if (internalModel) {
724
- internalModel.deleteRecord();
725
- }
726
- } else {
727
- deprecate(
728
- `You passed a non ember-data managed record ${record} to store.deleteRecord. Ember Data store is not meant to manage non store records. This is not supported and will be removed`,
729
- false,
730
- {
731
- id: 'ember-data:delete-record-non-store',
732
- until: '4.0',
733
- for: '@ember-data/store',
734
- since: {
735
- available: '3.28',
736
- enabled: '3.28',
737
- },
738
- }
739
- );
740
- record.deleteRecord();
592
+ let identifier = peekRecordIdentifier(record);
593
+ if (identifier) {
594
+ let internalModel = internalModelFactoryFor(this).peek(identifier);
595
+ if (internalModel) {
596
+ internalModel.deleteRecord();
741
597
  }
742
- } else {
743
- record.deleteRecord();
744
598
  }
745
599
  });
746
600
  }
@@ -765,31 +619,12 @@ abstract class CoreStore extends Service {
765
619
  if (DEBUG) {
766
620
  assertDestroyingStore(this, 'unloadRecord');
767
621
  }
768
- if (CUSTOM_MODEL_CLASS) {
769
- let identifier = peekRecordIdentifier(record);
770
- if (identifier) {
771
- let internalModel = internalModelFactoryFor(this).peek(identifier);
772
- if (internalModel) {
773
- internalModel.unloadRecord();
774
- }
775
- } else {
776
- deprecate(
777
- `You passed a non ember-data managed record ${record} to store.unloadRecord. Ember Data store is not meant to manage non store records. This is not supported and will be removed`,
778
- false,
779
- {
780
- id: 'ember-data:unload-record-non-store',
781
- until: '4.0',
782
- for: '@ember-data/store',
783
- since: {
784
- available: '3.28',
785
- enabled: '3.28',
786
- },
787
- }
788
- );
789
- record.unloadRecord();
622
+ let identifier = peekRecordIdentifier(record);
623
+ if (identifier) {
624
+ let internalModel = internalModelFactoryFor(this).peek(identifier);
625
+ if (internalModel) {
626
+ internalModel.unloadRecord();
790
627
  }
791
- } else {
792
- record.unloadRecord();
793
628
  }
794
629
  }
795
630
 
@@ -1298,19 +1133,12 @@ abstract class CoreStore extends Service {
1298
1133
  return this._scheduleFetch(internalModel, options);
1299
1134
  }
1300
1135
 
1301
- //TODO double check about reloading
1302
- if (!REQUEST_SERVICE) {
1303
- if (internalModel.currentState.isLoading) {
1304
- return internalModel._promiseProxy;
1305
- }
1306
- } else {
1307
- if (internalModel.currentState.isLoading) {
1308
- let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier, options);
1309
- if (pendingRequest) {
1310
- return pendingRequest.then(() => Promise.resolve(internalModel));
1311
- }
1312
- return this._scheduleFetch(internalModel, options);
1136
+ if (internalModel.currentState.isLoading) {
1137
+ let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier, options);
1138
+ if (pendingRequest) {
1139
+ return pendingRequest.then(() => Promise.resolve(internalModel));
1313
1140
  }
1141
+ return this._scheduleFetch(internalModel, options);
1314
1142
  }
1315
1143
 
1316
1144
  return Promise.resolve(internalModel);
@@ -1347,29 +1175,6 @@ abstract class CoreStore extends Service {
1347
1175
  return promiseArray(all(promises).then(A, null, `DS: Store#findByIds of ${normalizedModelName} complete`));
1348
1176
  }
1349
1177
 
1350
- /**
1351
- This method is called by `findRecord` if it discovers that a particular
1352
- type/id pair hasn't been loaded yet to kick off a request to the
1353
- adapter.
1354
-
1355
- @method _fetchRecord
1356
- @private
1357
- @param {InternalModel} internalModel model
1358
- @return {Promise} promise
1359
- */
1360
- _fetchRecord(internalModel: InternalModel, options): Promise<InternalModel> {
1361
- let modelName = internalModel.modelName;
1362
- let adapter = this.adapterFor(modelName);
1363
-
1364
- assert(`You tried to find a record but you have no adapter (for ${modelName})`, adapter);
1365
- assert(
1366
- `You tried to find a record but your adapter (for ${modelName}) does not implement 'findRecord'`,
1367
- typeof adapter.findRecord === 'function'
1368
- );
1369
-
1370
- return _find(adapter, this, internalModel.modelClass, internalModel.id, internalModel, options);
1371
- }
1372
-
1373
1178
  _scheduleFetchMany(internalModels, options) {
1374
1179
  let fetches = new Array(internalModels.length);
1375
1180
 
@@ -1380,7 +1185,7 @@ abstract class CoreStore extends Service {
1380
1185
  return Promise.all(fetches);
1381
1186
  }
1382
1187
 
1383
- _scheduleFetchThroughFetchManager(internalModel: InternalModel, options = {}): RSVP.Promise<InternalModel> {
1188
+ _scheduleFetch(internalModel: InternalModel, options = {}): RSVP.Promise<InternalModel> {
1384
1189
  let generateStackTrace = this.generateStackTracesForTrackedRequests;
1385
1190
  // TODO remove this once we don't rely on state machine
1386
1191
  internalModel.send('loadingData');
@@ -1415,227 +1220,6 @@ abstract class CoreStore extends Service {
1415
1220
  );
1416
1221
  }
1417
1222
 
1418
- _scheduleFetch(internalModel: InternalModel, options): RSVP.Promise<InternalModel> {
1419
- if (REQUEST_SERVICE) {
1420
- return this._scheduleFetchThroughFetchManager(internalModel, options);
1421
- } else {
1422
- if (internalModel._promiseProxy) {
1423
- return internalModel._promiseProxy;
1424
- }
1425
-
1426
- assertIdentifierHasId(internalModel.identifier);
1427
-
1428
- let { id, modelName } = internalModel;
1429
- let resolver = defer<InternalModel>(`Fetching ${modelName}' with id: ${id}`);
1430
- let pendingFetchItem: PendingFetchItem = {
1431
- internalModel,
1432
- resolver,
1433
- options,
1434
- };
1435
-
1436
- if (DEBUG) {
1437
- if (this.generateStackTracesForTrackedRequests === true) {
1438
- let trace;
1439
-
1440
- try {
1441
- throw new Error(`Trace Origin for scheduled fetch for ${modelName}:${id}.`);
1442
- } catch (e) {
1443
- trace = e;
1444
- }
1445
-
1446
- // enable folks to discover the origin of this findRecord call when
1447
- // debugging. Ideally we would have a tracked queue for requests with
1448
- // labels or local IDs that could be used to merge this trace with
1449
- // the trace made available when we detect an async leak
1450
- pendingFetchItem.trace = trace;
1451
- }
1452
- }
1453
-
1454
- let promise = resolver.promise;
1455
-
1456
- internalModel.send('loadingData', promise);
1457
- if (this._pendingFetch.size === 0) {
1458
- emberBackburner.schedule('actions', this, this.flushAllPendingFetches);
1459
- }
1460
-
1461
- let fetches = this._pendingFetch;
1462
- let pending = fetches.get(modelName);
1463
-
1464
- if (pending === undefined) {
1465
- pending = [];
1466
- fetches.set(modelName, pending);
1467
- }
1468
-
1469
- pending.push(pendingFetchItem);
1470
-
1471
- return promise;
1472
- }
1473
- }
1474
-
1475
- flushAllPendingFetches() {
1476
- if (REQUEST_SERVICE) {
1477
- return;
1478
- //assert here
1479
- } else {
1480
- if (this.isDestroyed || this.isDestroying) {
1481
- return;
1482
- }
1483
-
1484
- this._pendingFetch.forEach(this._flushPendingFetchForType, this);
1485
- this._pendingFetch.clear();
1486
- }
1487
- }
1488
-
1489
- _flushPendingFetchForType(pendingFetchItems: PendingFetchItem[], modelName: string) {
1490
- let store = this;
1491
- let adapter = store.adapterFor(modelName);
1492
- let shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests;
1493
- let totalItems = pendingFetchItems.length;
1494
- let internalModels = new Array(totalItems);
1495
- let seeking = Object.create(null);
1496
-
1497
- let optionsMap = new WeakMap();
1498
-
1499
- for (let i = 0; i < totalItems; i++) {
1500
- let pendingItem = pendingFetchItems[i];
1501
- let internalModel = pendingItem.internalModel;
1502
- internalModels[i] = internalModel;
1503
- optionsMap.set(internalModel, pendingItem.options);
1504
- // We can remove this "not null" cast once we have enough typing
1505
- // to know we are only dealing with ExistingResourceIdentifierObjects
1506
- seeking[internalModel.id!] = pendingItem;
1507
- }
1508
-
1509
- function _fetchRecord(recordResolverPair) {
1510
- let recordFetch = store._fetchRecord(recordResolverPair.internalModel, recordResolverPair.options);
1511
-
1512
- recordResolverPair.resolver.resolve(recordFetch);
1513
- }
1514
-
1515
- function handleFoundRecords(foundInternalModels: InternalModel[], expectedInternalModels: InternalModel[]) {
1516
- // resolve found records
1517
- let found = Object.create(null);
1518
- for (let i = 0, l = foundInternalModels.length; i < l; i++) {
1519
- let internalModel = foundInternalModels[i];
1520
-
1521
- // We can remove this "not null" cast once we have enough typing
1522
- // to know we are only dealing with ExistingResourceIdentifierObjects
1523
- let pair = seeking[internalModel.id!];
1524
- found[internalModel.id!] = internalModel;
1525
-
1526
- if (pair) {
1527
- let resolver = pair.resolver;
1528
- resolver.resolve(internalModel);
1529
- }
1530
- }
1531
-
1532
- // reject missing records
1533
- let missingInternalModels: InternalModel[] = [];
1534
-
1535
- for (let i = 0, l = expectedInternalModels.length; i < l; i++) {
1536
- let internalModel = expectedInternalModels[i];
1537
-
1538
- // We can remove this "not null" cast once we have enough typing
1539
- // to know we are only dealing with ExistingResourceIdentifierObjects
1540
- if (!found[internalModel.id!]) {
1541
- missingInternalModels.push(internalModel);
1542
- }
1543
- }
1544
-
1545
- if (missingInternalModels.length) {
1546
- warn(
1547
- 'Ember Data expected to find records with the following ids in the adapter response but they were missing: [ "' +
1548
- missingInternalModels.map((r) => r.id).join('", "') +
1549
- '" ]',
1550
- false,
1551
- {
1552
- id: 'ds.store.missing-records-from-adapter',
1553
- }
1554
- );
1555
- rejectInternalModels(missingInternalModels);
1556
- }
1557
- }
1558
-
1559
- function rejectInternalModels(internalModels: InternalModel[], error?: Error) {
1560
- for (let i = 0, l = internalModels.length; i < l; i++) {
1561
- let internalModel = internalModels[i];
1562
-
1563
- // We can remove this "not null" cast once we have enough typing
1564
- // to know we are only dealing with ExistingResourceIdentifierObjects
1565
- let pair = seeking[internalModel.id!];
1566
-
1567
- if (pair) {
1568
- pair.resolver.reject(
1569
- error ||
1570
- new Error(
1571
- `Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.`
1572
- )
1573
- );
1574
- }
1575
- }
1576
- }
1577
-
1578
- if (shouldCoalesce) {
1579
- // TODO: Improve records => snapshots => records => snapshots
1580
- //
1581
- // We want to provide records to all store methods and snapshots to all
1582
- // adapter methods. To make sure we're doing that we're providing an array
1583
- // of snapshots to adapter.groupRecordsForFindMany(), which in turn will
1584
- // return grouped snapshots instead of grouped records.
1585
- //
1586
- // But since the _findMany() finder is a store method we need to get the
1587
- // records from the grouped snapshots even though the _findMany() finder
1588
- // will once again convert the records to snapshots for adapter.findMany()
1589
- let snapshots = new Array(totalItems);
1590
- for (let i = 0; i < totalItems; i++) {
1591
- let internalModel = internalModels[i];
1592
- snapshots[i] = internalModel.createSnapshot(optionsMap.get(internalModel));
1593
- }
1594
-
1595
- let groups;
1596
- if (adapter.groupRecordsForFindMany) {
1597
- groups = adapter.groupRecordsForFindMany(this, snapshots);
1598
- } else {
1599
- groups = [snapshots];
1600
- }
1601
-
1602
- for (let i = 0, l = groups.length; i < l; i++) {
1603
- let group = groups[i];
1604
- let totalInGroup = groups[i].length;
1605
- let ids = new Array(totalInGroup);
1606
- let groupedInternalModels = new Array(totalInGroup);
1607
-
1608
- for (let j = 0; j < totalInGroup; j++) {
1609
- let internalModel = group[j]._internalModel;
1610
-
1611
- groupedInternalModels[j] = internalModel;
1612
- ids[j] = internalModel.id;
1613
- }
1614
-
1615
- if (totalInGroup > 1) {
1616
- (function (groupedInternalModels) {
1617
- _findMany(adapter, store, modelName, ids, groupedInternalModels, optionsMap)
1618
- .then(function (foundInternalModels) {
1619
- handleFoundRecords(foundInternalModels, groupedInternalModels);
1620
- })
1621
- .catch(function (error) {
1622
- rejectInternalModels(groupedInternalModels, error);
1623
- });
1624
- })(groupedInternalModels);
1625
- } else if (ids.length === 1) {
1626
- let pair = seeking[groupedInternalModels[0].id];
1627
- _fetchRecord(pair);
1628
- } else {
1629
- assert("You cannot return an empty array from adapter's method groupRecordsForFindMany");
1630
- }
1631
- }
1632
- } else {
1633
- for (let i = 0; i < totalItems; i++) {
1634
- _fetchRecord(pendingFetchItems[i]);
1635
- }
1636
- }
1637
- }
1638
-
1639
1223
  /**
1640
1224
  Get the reference for the specified record.
1641
1225
 
@@ -1693,15 +1277,9 @@ abstract class CoreStore extends Service {
1693
1277
  isMaybeIdentifier(resourceIdentifier)
1694
1278
  );
1695
1279
 
1696
- let identifier: StableRecordIdentifier = identifierCacheFor(this).getOrCreateRecordIdentifier(resourceIdentifier);
1280
+ let identifier: StableRecordIdentifier = this.identifierCache.getOrCreateRecordIdentifier(resourceIdentifier);
1697
1281
  if (identifier) {
1698
- if (RECORD_REFERENCES.has(identifier)) {
1699
- return RECORD_REFERENCES.get(identifier);
1700
- }
1701
-
1702
- let reference = new RecordReference(this, identifier);
1703
- RECORD_REFERENCES.set(identifier, reference);
1704
- return reference;
1282
+ return RECORD_REFERENCES.lookup(identifier);
1705
1283
  }
1706
1284
  }
1707
1285
 
@@ -1757,7 +1335,7 @@ abstract class CoreStore extends Service {
1757
1335
  peekRecord(identifier: ResourceIdentifierObject): RecordInstance | null;
1758
1336
  peekRecord(identifier: ResourceIdentifierObject | string, id?: string | number): RecordInstance | null {
1759
1337
  if (arguments.length === 1 && isMaybeIdentifier(identifier)) {
1760
- let stableIdentifier = identifierCacheFor(this).peekRecordIdentifier(identifier);
1338
+ let stableIdentifier = this.identifierCache.peekRecordIdentifier(identifier);
1761
1339
  if (stableIdentifier) {
1762
1340
  return internalModelFactoryFor(this).peek(stableIdentifier)?.getRecord() || null;
1763
1341
  }
@@ -1799,9 +1377,7 @@ abstract class CoreStore extends Service {
1799
1377
  @return {Promise} promise
1800
1378
  */
1801
1379
  _reloadRecord(internalModel, options): RSVP.Promise<InternalModel> {
1802
- if (REQUEST_SERVICE) {
1803
- options.isReloading = true;
1804
- }
1380
+ options.isReloading = true;
1805
1381
  let { id, modelName } = internalModel;
1806
1382
  let adapter = this.adapterFor(modelName);
1807
1383
 
@@ -1849,7 +1425,7 @@ abstract class CoreStore extends Service {
1849
1425
  const trueId = ensureStringId(id);
1850
1426
  const resource = { type, id: trueId };
1851
1427
 
1852
- const identifier = identifierCacheFor(this).peekRecordIdentifier(resource);
1428
+ const identifier = this.identifierCache.peekRecordIdentifier(resource);
1853
1429
  const internalModel = identifier && internalModelFactoryFor(this).peek(identifier);
1854
1430
 
1855
1431
  return !!internalModel && internalModel.currentState.isLoaded;
@@ -2048,17 +1624,9 @@ abstract class CoreStore extends Service {
2048
1624
 
2049
1625
  if (internalModel) {
2050
1626
  // short circuit if we are already loading
2051
- if (REQUEST_SERVICE) {
2052
- let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier, options);
2053
- if (pendingRequest) {
2054
- return pendingRequest.then(() => internalModel.getRecord());
2055
- }
2056
- } else {
2057
- if (internalModel.currentState.isLoading) {
2058
- return internalModel._promiseProxy.then(() => {
2059
- return internalModel.getRecord();
2060
- });
2061
- }
1627
+ let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier, options);
1628
+ if (pendingRequest) {
1629
+ return pendingRequest.then(() => internalModel.getRecord());
2062
1630
  }
2063
1631
  }
2064
1632
 
@@ -2691,33 +2259,32 @@ abstract class CoreStore extends Service {
2691
2259
  @param {Object} options
2692
2260
  */
2693
2261
  scheduleSave(internalModel: InternalModel, resolver: RSVP.Deferred<void>, options): void | RSVP.Promise<void> {
2694
- if (REQUEST_SERVICE) {
2695
- if (internalModel._isRecordFullyDeleted()) {
2696
- resolver.resolve();
2697
- return resolver.promise;
2698
- }
2262
+ if (internalModel._isRecordFullyDeleted()) {
2263
+ resolver.resolve();
2264
+ return resolver.promise;
2265
+ }
2699
2266
 
2700
- internalModel.adapterWillCommit();
2267
+ internalModel.adapterWillCommit();
2701
2268
 
2702
- if (!options) {
2703
- options = {};
2704
- }
2705
- let recordData = internalModel._recordData;
2706
- let operation: 'createRecord' | 'deleteRecord' | 'updateRecord' = 'updateRecord';
2707
-
2708
- // TODO handle missing isNew
2709
- if (recordData.isNew && recordData.isNew()) {
2710
- operation = 'createRecord';
2711
- } else if (recordData.isDeleted && recordData.isDeleted()) {
2712
- operation = 'deleteRecord';
2713
- }
2269
+ if (!options) {
2270
+ options = {};
2271
+ }
2272
+ let recordData = internalModel._recordData;
2273
+ let operation: 'createRecord' | 'deleteRecord' | 'updateRecord' = 'updateRecord';
2714
2274
 
2715
- options[SaveOp] = operation;
2275
+ // TODO handle missing isNew
2276
+ if (recordData.isNew && recordData.isNew()) {
2277
+ operation = 'createRecord';
2278
+ } else if (recordData.isDeleted && recordData.isDeleted()) {
2279
+ operation = 'deleteRecord';
2280
+ }
2716
2281
 
2717
- let fetchManagerPromise = this._fetchManager.scheduleSave(internalModel.identifier, options);
2718
- let promise = fetchManagerPromise.then(
2719
- (payload) => {
2720
- /*
2282
+ options[SaveOp] = operation;
2283
+
2284
+ let fetchManagerPromise = this._fetchManager.scheduleSave(internalModel.identifier, options);
2285
+ let promise = fetchManagerPromise.then(
2286
+ (payload) => {
2287
+ /*
2721
2288
  Note to future spelunkers hoping to optimize.
2722
2289
  We rely on this `run` to create a run loop if needed
2723
2290
  that `store._push` and `store.didSaveRecord` will both share.
@@ -2726,40 +2293,25 @@ abstract class CoreStore extends Service {
2726
2293
  have an outer run loop available still from the first
2727
2294
  call to `store._push`;
2728
2295
  */
2729
- this._backburner.join(() => {
2730
- let data = payload && payload.data;
2731
- this.didSaveRecord(internalModel, { data }, operation);
2732
- if (payload && payload.included) {
2733
- this._push({ data: null, included: payload.included });
2734
- }
2735
- });
2736
- },
2737
- (e) => {
2738
- if (typeof e === 'string') {
2739
- throw e;
2296
+ this._backburner.join(() => {
2297
+ let data = payload && payload.data;
2298
+ this.didSaveRecord(internalModel, { data }, operation);
2299
+ if (payload && payload.included) {
2300
+ this._push({ data: null, included: payload.included });
2740
2301
  }
2741
- const { error, parsedErrors } = e;
2742
- this.recordWasInvalid(internalModel, parsedErrors, error);
2743
- throw error;
2302
+ });
2303
+ },
2304
+ (e) => {
2305
+ if (typeof e === 'string') {
2306
+ throw e;
2744
2307
  }
2745
- );
2746
-
2747
- return promise;
2748
- } else {
2749
- if (internalModel._isRecordFullyDeleted()) {
2750
- resolver.resolve();
2751
- return;
2308
+ const { error, parsedErrors } = e;
2309
+ this.recordWasInvalid(internalModel, parsedErrors, error);
2310
+ throw error;
2752
2311
  }
2312
+ );
2753
2313
 
2754
- let snapshot = internalModel.createSnapshot(options);
2755
- internalModel.adapterWillCommit();
2756
- this._pendingSave.push({
2757
- snapshot: snapshot,
2758
- resolver: resolver,
2759
- });
2760
-
2761
- emberBackburner.scheduleOnce('actions', this, this.flushPendingSave);
2762
- }
2314
+ return promise;
2763
2315
  }
2764
2316
 
2765
2317
  /**
@@ -2770,47 +2322,8 @@ abstract class CoreStore extends Service {
2770
2322
  @private
2771
2323
  */
2772
2324
  flushPendingSave() {
2773
- if (REQUEST_SERVICE) {
2774
- // assert here
2775
- return;
2776
- }
2777
- let pending = this._pendingSave.slice();
2778
- this._pendingSave = [];
2779
-
2780
- for (let i = 0, j = pending.length; i < j; i++) {
2781
- let pendingItem = pending[i];
2782
- let snapshot = pendingItem.snapshot;
2783
- let resolver = pendingItem.resolver;
2784
- // TODO We have to cast due to our reliance on this private property
2785
- // this will be refactored away once we change our pending API to be identifier based
2786
- let internalModel = (snapshot as unknown as PrivateSnapshot)._internalModel;
2787
- let adapter = this.adapterFor(internalModel.modelName);
2788
- let operation;
2789
-
2790
- if (RECORD_DATA_STATE) {
2791
- // TODO move this out of internalModel
2792
- if (internalModel.isNew()) {
2793
- operation = 'createRecord';
2794
- } else if (internalModel.isDeleted()) {
2795
- operation = 'deleteRecord';
2796
- } else {
2797
- operation = 'updateRecord';
2798
- }
2799
- } else {
2800
- if (internalModel.currentState.stateName === 'root.deleted.saved') {
2801
- resolver.resolve();
2802
- continue;
2803
- } else if (internalModel.isNew()) {
2804
- operation = 'createRecord';
2805
- } else if (internalModel.isDeleted()) {
2806
- operation = 'deleteRecord';
2807
- } else {
2808
- operation = 'updateRecord';
2809
- }
2810
- }
2811
-
2812
- resolver.resolve(_commit(adapter, this, operation, snapshot));
2813
- }
2325
+ // assert here
2326
+ return;
2814
2327
  }
2815
2328
 
2816
2329
  /**
@@ -2842,7 +2355,7 @@ abstract class CoreStore extends Service {
2842
2355
  );
2843
2356
  }
2844
2357
 
2845
- const cache = identifierCacheFor(this);
2358
+ const cache = this.identifierCache;
2846
2359
  const identifier = internalModel.identifier;
2847
2360
 
2848
2361
  if (op !== 'deleteRecord' && data) {
@@ -2868,11 +2381,7 @@ abstract class CoreStore extends Service {
2868
2381
  if (DEBUG) {
2869
2382
  assertDestroyingStore(this, 'recordWasInvalid');
2870
2383
  }
2871
- if (RECORD_DATA_ERRORS) {
2872
- internalModel.adapterDidInvalidate(parsedErrors, error);
2873
- } else {
2874
- internalModel.adapterDidInvalidate(parsedErrors);
2875
- }
2384
+ internalModel.adapterDidInvalidate(parsedErrors, error);
2876
2385
  }
2877
2386
 
2878
2387
  /**
@@ -2934,7 +2443,7 @@ abstract class CoreStore extends Service {
2934
2443
  // exclude store.push (root.empty) case
2935
2444
  let identifier = internalModel.identifier;
2936
2445
  if (isUpdate || isLoading) {
2937
- let updatedIdentifier = identifierCacheFor(this).updateRecordIdentifier(identifier, data);
2446
+ let updatedIdentifier = this.identifierCache.updateRecordIdentifier(identifier, data);
2938
2447
 
2939
2448
  if (updatedIdentifier !== identifier) {
2940
2449
  // we encountered a merge of identifiers in which
@@ -3197,30 +2706,17 @@ abstract class CoreStore extends Service {
3197
2706
 
3198
2707
  if (ENV.DS_WARN_ON_UNKNOWN_KEYS) {
3199
2708
  let unknownAttributes, unknownRelationships;
3200
- if (CUSTOM_MODEL_CLASS) {
3201
- let relationships = this.getSchemaDefinitionService().relationshipsDefinitionFor(modelName);
3202
- let attributes = this.getSchemaDefinitionService().attributesDefinitionFor(modelName);
3203
- // Check unknown attributes
3204
- unknownAttributes = Object.keys(data.attributes || {}).filter((key) => {
3205
- return !attributes[key];
3206
- });
3207
-
3208
- // Check unknown relationships
3209
- unknownRelationships = Object.keys(data.relationships || {}).filter((key) => {
3210
- return !relationships[key];
3211
- });
3212
- } else {
3213
- let modelClass = this.modelFor(modelName);
3214
- // Check unknown attributes
3215
- unknownAttributes = Object.keys(data.attributes || {}).filter((key) => {
3216
- return !get(modelClass, 'fields').has(key);
3217
- });
3218
-
3219
- // Check unknown relationships
3220
- unknownRelationships = Object.keys(data.relationships || {}).filter((key) => {
3221
- return !get(modelClass, 'fields').has(key);
3222
- });
3223
- }
2709
+ let relationships = this.getSchemaDefinitionService().relationshipsDefinitionFor(modelName);
2710
+ let attributes = this.getSchemaDefinitionService().attributesDefinitionFor(modelName);
2711
+ // Check unknown attributes
2712
+ unknownAttributes = Object.keys(data.attributes || {}).filter((key) => {
2713
+ return !attributes[key];
2714
+ });
2715
+
2716
+ // Check unknown relationships
2717
+ unknownRelationships = Object.keys(data.relationships || {}).filter((key) => {
2718
+ return !relationships[key];
2719
+ });
3224
2720
  let unknownAttributesMessage = `The payload for '${modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`;
3225
2721
  warn(unknownAttributesMessage, unknownAttributes.length === 0, {
3226
2722
  id: 'ds.store.unknown-keys-in-payload',
@@ -3350,38 +2846,26 @@ abstract class CoreStore extends Service {
3350
2846
  }
3351
2847
 
3352
2848
  serializeRecord(record: RecordInstance, options?: Dict<unknown>): unknown {
3353
- if (CUSTOM_MODEL_CLASS) {
3354
- let identifier = recordIdentifierFor(record);
3355
- let internalModel = internalModelFactoryFor(this).peek(identifier);
3356
- // TODO we used to check if the record was destroyed here
3357
- return internalModel!.createSnapshot(options).serialize(options);
3358
- }
3359
-
3360
- assert('serializeRecord is only available when CUSTOM_MODEL_CLASS ff is on', false);
2849
+ let identifier = recordIdentifierFor(record);
2850
+ let internalModel = internalModelFactoryFor(this).peek(identifier);
2851
+ // TODO we used to check if the record was destroyed here
2852
+ return internalModel!.createSnapshot(options).serialize(options);
3361
2853
  }
3362
2854
 
3363
2855
  saveRecord(record: RecordInstance, options?: Dict<unknown>): RSVP.Promise<RecordInstance> {
3364
- if (CUSTOM_MODEL_CLASS) {
3365
- let identifier = recordIdentifierFor(record);
3366
- let internalModel = internalModelFactoryFor(this).peek(identifier);
3367
- // TODO we used to check if the record was destroyed here
3368
- // Casting can be removed once REQUEST_SERVICE ff is turned on
3369
- // because a `Record` is provided there will always be a matching internalModel
3370
- return (internalModel!.save(options) as RSVP.Promise<void>).then(() => record);
3371
- }
3372
-
3373
- assert('saveRecord is only available when CUSTOM_MODEL_CLASS ff is on');
2856
+ let identifier = recordIdentifierFor(record);
2857
+ let internalModel = internalModelFactoryFor(this).peek(identifier);
2858
+ // TODO we used to check if the record was destroyed here
2859
+ // Casting can be removed once REQUEST_SERVICE ff is turned on
2860
+ // because a `Record` is provided there will always be a matching internalModel
2861
+ return (internalModel!.save(options) as RSVP.Promise<void>).then(() => record);
3374
2862
  }
3375
2863
 
3376
2864
  relationshipReferenceFor(identifier: RecordIdentifier, key: string): BelongsToReference | HasManyReference {
3377
- if (CUSTOM_MODEL_CLASS) {
3378
- let stableIdentifier = identifierCacheFor(this).getOrCreateRecordIdentifier(identifier);
3379
- let internalModel = internalModelFactoryFor(this).peek(stableIdentifier);
3380
- // TODO we used to check if the record was destroyed here
3381
- return internalModel!.referenceFor(null, key);
3382
- }
3383
-
3384
- assert('relationshipReferenceFor is only available when CUSTOM_MODEL_CLASS ff is on', false);
2865
+ let stableIdentifier = this.identifierCache.getOrCreateRecordIdentifier(identifier);
2866
+ let internalModel = internalModelFactoryFor(this).peek(stableIdentifier);
2867
+ // TODO we used to check if the record was destroyed here
2868
+ return internalModel!.referenceFor(null, key);
3385
2869
  }
3386
2870
 
3387
2871
  /**
@@ -3427,7 +2911,7 @@ abstract class CoreStore extends Service {
3427
2911
  _RecordData = require('@ember-data/record-data/-private').RecordData as RecordDataConstruct;
3428
2912
  }
3429
2913
 
3430
- let identifier = identifierCacheFor(this).getOrCreateRecordIdentifier({
2914
+ let identifier = this.identifierCache.getOrCreateRecordIdentifier({
3431
2915
  type: modelName,
3432
2916
  id,
3433
2917
  lid: clientId,
@@ -3442,7 +2926,7 @@ abstract class CoreStore extends Service {
3442
2926
  * @internal
3443
2927
  */
3444
2928
  __recordDataFor(resource: RecordIdentifier) {
3445
- const identifier = identifierCacheFor(this).getOrCreateRecordIdentifier(resource);
2929
+ const identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
3446
2930
  return this.recordDataFor(identifier, false);
3447
2931
  }
3448
2932
 
@@ -3560,25 +3044,15 @@ abstract class CoreStore extends Service {
3560
3044
 
3561
3045
  let owner = getOwner(this);
3562
3046
 
3047
+ // name specific adapter
3563
3048
  adapter = owner.lookup(`adapter:${normalizedModelName}`);
3564
-
3565
- // in production this is handled by the re-export
3566
- if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_ADAPTER_PACKAGE && adapter === undefined) {
3567
- if (normalizedModelName === '-json-api') {
3568
- const Adapter = require('@ember-data/adapter/json-api').default;
3569
- owner.register(`adapter:-json-api`, Adapter);
3570
- adapter = owner.lookup(`adapter:-json-api`);
3571
- deprecateTestRegistration('adapter', '-json-api');
3572
- }
3573
- }
3574
-
3575
3049
  if (adapter !== undefined) {
3576
3050
  set(adapter, 'store', this);
3577
3051
  _adapterCache[normalizedModelName] = adapter;
3578
3052
  return adapter;
3579
3053
  }
3580
3054
 
3581
- // no adapter found for the specific model, fallback and check for application adapter
3055
+ // no adapter found for the specific name, fallback and check for application adapter
3582
3056
  adapter = _adapterCache.application || owner.lookup('adapter:application');
3583
3057
  if (adapter !== undefined) {
3584
3058
  set(adapter, 'store', this);
@@ -3587,30 +3061,9 @@ abstract class CoreStore extends Service {
3587
3061
  return adapter;
3588
3062
  }
3589
3063
 
3590
- // no model specific adapter or application adapter, check for an `adapter`
3591
- // property defined on the store
3592
- let adapterName = this.adapter || '-json-api';
3593
- adapter = adapterName ? _adapterCache[adapterName] || owner.lookup(`adapter:${adapterName}`) : undefined;
3594
-
3595
- // in production this is handled by the re-export
3596
- if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_ADAPTER_PACKAGE && adapter === undefined) {
3597
- if (adapterName === '-json-api') {
3598
- const Adapter = require('@ember-data/adapter/json-api').default;
3599
- owner.register(`adapter:-json-api`, Adapter);
3600
- adapter = owner.lookup(`adapter:-json-api`);
3601
- deprecateTestRegistration('adapter', '-json-api');
3602
- }
3603
- }
3604
-
3605
- if (adapter !== undefined) {
3606
- set(adapter, 'store', this);
3607
- _adapterCache[normalizedModelName] = adapter;
3608
- _adapterCache[adapterName] = adapter;
3609
- return adapter;
3610
- }
3611
-
3612
3064
  // final fallback, no model specific adapter, no application adapter, no
3613
3065
  // `adapter` property on store: use json-api adapter
3066
+ // TODO we should likely deprecate this?
3614
3067
  adapter = _adapterCache['-json-api'] || owner.lookup('adapter:-json-api');
3615
3068
  assert(
3616
3069
  `No adapter was found for '${modelName}' and no 'application' adapter was found as a fallback.`,
@@ -3635,10 +3088,6 @@ abstract class CoreStore extends Service {
3635
3088
  for an `App.ApplicationSerializer` (the default serializer for
3636
3089
  your entire application).
3637
3090
 
3638
- if no `App.ApplicationSerializer` is found, it will attempt
3639
- to get the `defaultSerializer` from the `PersonAdapter`
3640
- (`adapterFor('person')`).
3641
-
3642
3091
  If a serializer cannot be found on the adapter, it will fall back
3643
3092
  to an instance of `JSONSerializer`.
3644
3093
 
@@ -3666,30 +3115,8 @@ abstract class CoreStore extends Service {
3666
3115
 
3667
3116
  let owner = getOwner(this);
3668
3117
 
3118
+ // by name
3669
3119
  serializer = owner.lookup(`serializer:${normalizedModelName}`);
3670
-
3671
- if (DEPRECATE_LEGACY_TEST_REGISTRATIONS) {
3672
- // in production this is handled by the re-export
3673
- if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_SERIALIZER_PACKAGE && serializer === undefined) {
3674
- if (normalizedModelName === '-json-api') {
3675
- const Serializer = require('@ember-data/serializer/json-api').default;
3676
- owner.register(`serializer:-json-api`, Serializer);
3677
- serializer = owner.lookup(`serializer:-json-api`);
3678
- deprecateTestRegistration('serializer', '-json-api');
3679
- } else if (normalizedModelName === '-rest') {
3680
- const Serializer = require('@ember-data/serializer/rest').default;
3681
- owner.register(`serializer:-rest`, Serializer);
3682
- serializer = owner.lookup(`serializer:-rest`);
3683
- deprecateTestRegistration('serializer', '-rest');
3684
- } else if (normalizedModelName === '-default') {
3685
- const Serializer = require('@ember-data/serializer/json').default;
3686
- owner.register(`serializer:-default`, Serializer);
3687
- serializer = owner.lookup(`serializer:-default`);
3688
- serializer && deprecateTestRegistration('serializer', '-default');
3689
- }
3690
- }
3691
- }
3692
-
3693
3120
  if (serializer !== undefined) {
3694
3121
  set(serializer, 'store', this);
3695
3122
  _serializerCache[normalizedModelName] = serializer;
@@ -3705,105 +3132,10 @@ abstract class CoreStore extends Service {
3705
3132
  return serializer;
3706
3133
  }
3707
3134
 
3708
- let serializerName;
3709
- if (DEPRECATE_DEFAULT_SERIALIZER) {
3710
- // no model specific serializer or application serializer, check for the `defaultSerializer`
3711
- // property defined on the adapter
3712
- let adapter = this.adapterFor(modelName);
3713
- serializerName = get(adapter, 'defaultSerializer');
3714
-
3715
- deprecate(
3716
- `store.serializerFor("${modelName}") resolved the "${serializerName}" serializer via the deprecated \`adapter.defaultSerializer\` property.\n\n\tPreviously, if no application or type-specific serializer was specified, the store would attempt to lookup a serializer via the \`defaultSerializer\` property on the type's adapter. This behavior is deprecated in favor of explicitly defining a type-specific serializer or application serializer`,
3717
- !serializerName,
3718
- {
3719
- id: 'ember-data:default-serializer',
3720
- until: '4.0',
3721
- url: 'https://deprecations.emberjs.com/ember-data/v3.x/#toc_ember-data-default-serializers',
3722
- for: '@ember-data/store',
3723
- since: {
3724
- available: '3.15',
3725
- enabled: '3.15',
3726
- },
3727
- }
3728
- );
3729
-
3730
- serializer = serializerName
3731
- ? _serializerCache[serializerName] || owner.lookup(`serializer:${serializerName}`)
3732
- : undefined;
3733
- }
3734
-
3735
- if (DEPRECATE_LEGACY_TEST_REGISTRATIONS) {
3736
- // in production this is handled by the re-export
3737
- if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_SERIALIZER_PACKAGE && serializer === undefined) {
3738
- if (serializerName === '-json-api') {
3739
- const Serializer = require('@ember-data/serializer/json-api').default;
3740
- owner.register(`serializer:-json-api`, Serializer);
3741
- serializer = owner.lookup(`serializer:-json-api`);
3742
- deprecateTestRegistration('serializer', '-json-api');
3743
- } else if (serializerName === '-rest') {
3744
- const Serializer = require('@ember-data/serializer/rest').default;
3745
- owner.register(`serializer:-rest`, Serializer);
3746
- serializer = owner.lookup(`serializer:-rest`);
3747
- deprecateTestRegistration('serializer', '-rest');
3748
- } else if (serializerName === '-default') {
3749
- const Serializer = require('@ember-data/serializer/json').default;
3750
- owner.register(`serializer:-default`, Serializer);
3751
- serializer = owner.lookup(`serializer:-default`);
3752
- serializer && deprecateTestRegistration('serializer', '-default');
3753
- }
3754
- }
3755
-
3756
- if (serializer !== undefined) {
3757
- set(serializer, 'store', this);
3758
- _serializerCache[normalizedModelName] = serializer;
3759
- _serializerCache[serializerName] = serializer;
3760
- return serializer;
3761
- }
3762
- }
3763
-
3764
- if (DEPRECATE_DEFAULT_SERIALIZER) {
3765
- // final fallback, no model specific serializer, no application serializer, no
3766
- // `serializer` property on store: use the convenience JSONSerializer
3767
- serializer = _serializerCache['-default'] || owner.lookup('serializer:-default');
3768
- if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_SERIALIZER_PACKAGE && serializer === undefined) {
3769
- const JSONSerializer = require('@ember-data/serializer/json').default;
3770
- owner.register('serializer:-default', JSONSerializer);
3771
- serializer = owner.lookup('serializer:-default');
3772
-
3773
- serializer && deprecateTestRegistration('serializer', '-default');
3774
- }
3775
-
3776
- deprecate(
3777
- `store.serializerFor("${modelName}") resolved the "-default" serializer via the deprecated "-default" lookup fallback.\n\n\tPreviously, when no type-specific serializer, application serializer, or adapter.defaultSerializer had been defined by the app, the "-default" serializer would be used which defaulted to the \`JSONSerializer\`. This behavior is deprecated in favor of explicitly defining an application or type-specific serializer`,
3778
- !serializer,
3779
- {
3780
- id: 'ember-data:default-serializer',
3781
- until: '4.0',
3782
- url: 'https://deprecations.emberjs.com/ember-data/v3.x/#toc_ember-data-default-serializers',
3783
- for: '@ember-data/store',
3784
- since: {
3785
- available: '3.15',
3786
- enabled: '3.15',
3787
- },
3788
- }
3789
- );
3790
-
3791
- assert(
3792
- `No serializer was found for '${modelName}' and no 'application' serializer was found as a fallback`,
3793
- serializer !== undefined
3794
- );
3795
-
3796
- set(serializer, 'store', this);
3797
- _serializerCache[normalizedModelName] = serializer;
3798
- _serializerCache['-default'] = serializer;
3799
-
3800
- return serializer;
3801
- } else {
3802
- assert(
3803
- `No serializer was found for '${modelName}' and no 'application' serializer was found as a fallback`,
3804
- serializer !== undefined
3805
- );
3806
- }
3135
+ assert(
3136
+ `No serializer was found for '${modelName}' and no 'application' serializer was found as a fallback`,
3137
+ serializer !== undefined
3138
+ );
3807
3139
  }
3808
3140
 
3809
3141
  destroy() {
@@ -3837,7 +3169,7 @@ abstract class CoreStore extends Service {
3837
3169
  super.willDestroy();
3838
3170
  this.recordArrayManager.destroy();
3839
3171
 
3840
- identifierCacheFor(this).destroy();
3172
+ this.identifierCache.destroy();
3841
3173
 
3842
3174
  // destroy the graph before unloadAll
3843
3175
  // since then we avoid churning relationships
@@ -3897,155 +3229,23 @@ abstract class CoreStore extends Service {
3897
3229
  }
3898
3230
  }
3899
3231
 
3900
- if (DEPRECATE_DEFAULT_ADAPTER) {
3901
- defineProperty(
3902
- CoreStore.prototype,
3903
- 'defaultAdapter',
3904
- computed('adapter', function () {
3905
- deprecate(
3906
- `store.adapterFor(modelName) resolved the ("${
3907
- this.adapter || '-json-api'
3908
- }") adapter via the deprecated \`store.defaultAdapter\` property.\n\n\tPreviously, applications could define the store's \`adapter\` property which would be used by \`defaultAdapter\` and \`adapterFor\` as a fallback for when an adapter was not found by an exact name match. This behavior is deprecated in favor of explicitly defining an application or type-specific adapter.`,
3909
- false,
3910
- {
3911
- id: 'ember-data:default-adapter',
3912
- until: '4.0',
3913
- url: 'https://deprecations.emberjs.com/ember-data/v3.x/#toc_ember-data-default-adapter',
3914
- for: '@ember-data/store',
3915
- since: {
3916
- available: '3.15',
3917
- enabled: '3.15',
3918
- },
3919
- }
3920
- );
3921
- let adapter = this.adapter || '-json-api';
3922
-
3923
- assert(
3924
- 'You tried to set `adapter` property to an instance of `Adapter`, where it should be a name',
3925
- typeof adapter === 'string'
3926
- );
3927
-
3928
- return this.adapterFor(adapter);
3929
- })
3930
- );
3931
- }
3932
-
3933
3232
  export default CoreStore;
3934
3233
 
3935
- function _commit(adapter, store, operation, snapshot) {
3936
- let internalModel = snapshot._internalModel;
3937
- let modelName = snapshot.modelName;
3938
- let modelClass = store.modelFor(modelName);
3939
- assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter);
3940
- assert(
3941
- `You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`,
3942
- typeof adapter[operation] === 'function'
3943
- );
3944
-
3945
- let promise = Promise.resolve().then(() => adapter[operation](store, modelClass, snapshot));
3946
- let serializer = store.serializerFor(modelName);
3947
- let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`;
3948
-
3949
- promise = guardDestroyedStore(promise, store, label);
3950
- promise = _guard(promise, _bind(_objectIsAlive, internalModel));
3951
-
3952
- return promise.then(
3953
- (adapterPayload) => {
3954
- /*
3955
- Note to future spelunkers hoping to optimize.
3956
- We rely on this `run` to create a run loop if needed
3957
- that `store._push` and `store.didSaveRecord` will both share.
3958
-
3959
- We use `join` because it is often the case that we
3960
- have an outer run loop available still from the first
3961
- call to `store._push`;
3962
- */
3963
- store._backburner.join(() => {
3964
- let payload, data, sideloaded;
3965
- if (adapterPayload) {
3966
- payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, snapshot.id, operation);
3967
- if (payload.included) {
3968
- sideloaded = payload.included;
3969
- }
3970
- data = payload.data;
3971
- }
3972
- store.didSaveRecord(internalModel, { data }, operation);
3973
- // seems risky, but if the tests pass might be fine?
3974
- if (sideloaded) {
3975
- store._push({ data: null, included: sideloaded });
3976
- }
3977
- });
3978
-
3979
- return internalModel;
3980
- },
3981
- function (error) {
3982
- if (error && error.isAdapterError === true && error.code === 'InvalidError') {
3983
- let parsedErrors;
3984
-
3985
- if (typeof serializer.extractErrors === 'function') {
3986
- parsedErrors = serializer.extractErrors(store, modelClass, error, snapshot.id);
3987
- } else {
3988
- parsedErrors = errorsArrayToHash(error.errors);
3989
- }
3990
-
3991
- store.recordWasInvalid(internalModel, parsedErrors, error);
3992
- } else {
3993
- store.recordWasError(internalModel, error);
3994
- }
3995
-
3996
- throw error;
3997
- },
3998
- label
3999
- );
4000
- }
4001
-
4002
3234
  let assertDestroyingStore: Function;
4003
3235
  let assertDestroyedStoreOnly: Function;
4004
3236
 
4005
3237
  if (DEBUG) {
4006
3238
  assertDestroyingStore = function assertDestroyedStore(store, method) {
4007
- if (!store.shouldAssertMethodCallsOnDestroyedStore) {
4008
- deprecate(
4009
- `Attempted to call store.${method}(), but the store instance has already been destroyed.`,
4010
- !(store.isDestroying || store.isDestroyed),
4011
- {
4012
- id: 'ember-data:method-calls-on-destroyed-store',
4013
- until: '3.8',
4014
- for: '@ember-data/store',
4015
- since: {
4016
- available: '3.8',
4017
- enabled: '3.8',
4018
- },
4019
- }
4020
- );
4021
- } else {
4022
- assert(
4023
- `Attempted to call store.${method}(), but the store instance has already been destroyed.`,
4024
- !(store.isDestroying || store.isDestroyed)
4025
- );
4026
- }
3239
+ assert(
3240
+ `Attempted to call store.${method}(), but the store instance has already been destroyed.`,
3241
+ !(store.isDestroying || store.isDestroyed)
3242
+ );
4027
3243
  };
4028
3244
  assertDestroyedStoreOnly = function assertDestroyedStoreOnly(store, method) {
4029
- if (!store.shouldAssertMethodCallsOnDestroyedStore) {
4030
- deprecate(
4031
- `Attempted to call store.${method}(), but the store instance has already been destroyed.`,
4032
- !store.isDestroyed,
4033
- {
4034
- id: 'ember-data:method-calls-on-destroyed-store',
4035
- until: '3.8',
4036
- for: '@ember-data/store',
4037
- since: {
4038
- available: '3.8',
4039
- enabled: '3.8',
4040
- },
4041
- }
4042
- );
4043
- } else {
4044
- assert(
4045
- `Attempted to call store.${method}(), but the store instance has already been destroyed.`,
4046
- !store.isDestroyed
4047
- );
4048
- }
3245
+ assert(
3246
+ `Attempted to call store.${method}(), but the store instance has already been destroyed.`,
3247
+ !store.isDestroyed
3248
+ );
4049
3249
  };
4050
3250
  }
4051
3251
 
@@ -4060,7 +3260,7 @@ if (DEBUG) {
4060
3260
  * @return {boolean}
4061
3261
  */
4062
3262
  function areAllInverseRecordsLoaded(store: CoreStore, resource: JsonApiRelationship): boolean {
4063
- const cache = identifierCacheFor(store);
3263
+ const cache = store.identifierCache;
4064
3264
 
4065
3265
  if (Array.isArray(resource.data)) {
4066
3266
  // treat as collection