@ember-data/store 4.2.0-beta.0 → 4.3.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 (30) 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 +192 -958
  5. package/addon/-private/system/ds-model-store.ts +20 -111
  6. package/addon/-private/system/fetch-manager.ts +11 -5
  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 +4 -11
  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/fetch-manager.ts +4 -0
  26. package/addon/-private/ts-interfaces/identifier.ts +2 -2
  27. package/addon/-private/ts-interfaces/minimum-adapter-interface.ts +0 -1
  28. package/addon/-private/ts-interfaces/schema-definition-service.ts +2 -2
  29. package/package.json +16 -16
  30. 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 });
484
353
 
485
- properties[prop] = relationshipValue;
354
+ if (defs !== null) {
355
+ let keys = Object.keys(properties);
356
+ let relationshipValue;
357
+
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,16 +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
- }
592
+ let identifier = peekRecordIdentifier(record);
593
+ if (identifier) {
594
+ let internalModel = internalModelFactoryFor(this).peek(identifier);
595
+ if (internalModel) {
596
+ internalModel.deleteRecord();
726
597
  }
727
- } else {
728
- record.deleteRecord();
729
598
  }
730
599
  });
731
600
  }
@@ -750,16 +619,12 @@ abstract class CoreStore extends Service {
750
619
  if (DEBUG) {
751
620
  assertDestroyingStore(this, 'unloadRecord');
752
621
  }
753
- if (CUSTOM_MODEL_CLASS) {
754
- let identifier = peekRecordIdentifier(record);
755
- if (identifier) {
756
- let internalModel = internalModelFactoryFor(this).peek(identifier);
757
- if (internalModel) {
758
- internalModel.unloadRecord();
759
- }
622
+ let identifier = peekRecordIdentifier(record);
623
+ if (identifier) {
624
+ let internalModel = internalModelFactoryFor(this).peek(identifier);
625
+ if (internalModel) {
626
+ internalModel.unloadRecord();
760
627
  }
761
- } else {
762
- record.unloadRecord();
763
628
  }
764
629
  }
765
630
 
@@ -1248,7 +1113,7 @@ abstract class CoreStore extends Service {
1248
1113
  return Promise.resolve(internalModel);
1249
1114
  }
1250
1115
 
1251
- _findByInternalModel(internalModel, options: { preload?: any } = {}) {
1116
+ _findByInternalModel(internalModel: InternalModel, options: FindOptions = {}) {
1252
1117
  if (options.preload) {
1253
1118
  this._backburner.join(() => {
1254
1119
  internalModel.preloadData(options.preload);
@@ -1263,24 +1128,17 @@ abstract class CoreStore extends Service {
1263
1128
  );
1264
1129
  }
1265
1130
 
1266
- _findEmptyInternalModel(internalModel, options) {
1131
+ _findEmptyInternalModel(internalModel: InternalModel, options: FindOptions) {
1267
1132
  if (internalModel.currentState.isEmpty) {
1268
1133
  return this._scheduleFetch(internalModel, options);
1269
1134
  }
1270
1135
 
1271
- //TODO double check about reloading
1272
- if (!REQUEST_SERVICE) {
1273
- if (internalModel.currentState.isLoading) {
1274
- return internalModel._promiseProxy;
1275
- }
1276
- } else {
1277
- if (internalModel.currentState.isLoading) {
1278
- let pending = this._fetchManager.getPendingFetch(internalModel.identifier);
1279
- if (pending) {
1280
- return pending.then(() => Promise.resolve(internalModel));
1281
- }
1282
- 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));
1283
1140
  }
1141
+ return this._scheduleFetch(internalModel, options);
1284
1142
  }
1285
1143
 
1286
1144
  return Promise.resolve(internalModel);
@@ -1317,29 +1175,6 @@ abstract class CoreStore extends Service {
1317
1175
  return promiseArray(all(promises).then(A, null, `DS: Store#findByIds of ${normalizedModelName} complete`));
1318
1176
  }
1319
1177
 
1320
- /**
1321
- This method is called by `findRecord` if it discovers that a particular
1322
- type/id pair hasn't been loaded yet to kick off a request to the
1323
- adapter.
1324
-
1325
- @method _fetchRecord
1326
- @private
1327
- @param {InternalModel} internalModel model
1328
- @return {Promise} promise
1329
- */
1330
- _fetchRecord(internalModel: InternalModel, options): Promise<InternalModel> {
1331
- let modelName = internalModel.modelName;
1332
- let adapter = this.adapterFor(modelName);
1333
-
1334
- assert(`You tried to find a record but you have no adapter (for ${modelName})`, adapter);
1335
- assert(
1336
- `You tried to find a record but your adapter (for ${modelName}) does not implement 'findRecord'`,
1337
- typeof adapter.findRecord === 'function'
1338
- );
1339
-
1340
- return _find(adapter, this, internalModel.modelClass, internalModel.id, internalModel, options);
1341
- }
1342
-
1343
1178
  _scheduleFetchMany(internalModels, options) {
1344
1179
  let fetches = new Array(internalModels.length);
1345
1180
 
@@ -1350,7 +1185,7 @@ abstract class CoreStore extends Service {
1350
1185
  return Promise.all(fetches);
1351
1186
  }
1352
1187
 
1353
- _scheduleFetchThroughFetchManager(internalModel: InternalModel, options = {}): RSVP.Promise<InternalModel> {
1188
+ _scheduleFetch(internalModel: InternalModel, options = {}): RSVP.Promise<InternalModel> {
1354
1189
  let generateStackTrace = this.generateStackTracesForTrackedRequests;
1355
1190
  // TODO remove this once we don't rely on state machine
1356
1191
  internalModel.send('loadingData');
@@ -1385,227 +1220,6 @@ abstract class CoreStore extends Service {
1385
1220
  );
1386
1221
  }
1387
1222
 
1388
- _scheduleFetch(internalModel: InternalModel, options): RSVP.Promise<InternalModel> {
1389
- if (REQUEST_SERVICE) {
1390
- return this._scheduleFetchThroughFetchManager(internalModel, options);
1391
- } else {
1392
- if (internalModel._promiseProxy) {
1393
- return internalModel._promiseProxy;
1394
- }
1395
-
1396
- assertIdentifierHasId(internalModel.identifier);
1397
-
1398
- let { id, modelName } = internalModel;
1399
- let resolver = defer<InternalModel>(`Fetching ${modelName}' with id: ${id}`);
1400
- let pendingFetchItem: PendingFetchItem = {
1401
- internalModel,
1402
- resolver,
1403
- options,
1404
- };
1405
-
1406
- if (DEBUG) {
1407
- if (this.generateStackTracesForTrackedRequests === true) {
1408
- let trace;
1409
-
1410
- try {
1411
- throw new Error(`Trace Origin for scheduled fetch for ${modelName}:${id}.`);
1412
- } catch (e) {
1413
- trace = e;
1414
- }
1415
-
1416
- // enable folks to discover the origin of this findRecord call when
1417
- // debugging. Ideally we would have a tracked queue for requests with
1418
- // labels or local IDs that could be used to merge this trace with
1419
- // the trace made available when we detect an async leak
1420
- pendingFetchItem.trace = trace;
1421
- }
1422
- }
1423
-
1424
- let promise = resolver.promise;
1425
-
1426
- internalModel.send('loadingData', promise);
1427
- if (this._pendingFetch.size === 0) {
1428
- emberBackburner.schedule('actions', this, this.flushAllPendingFetches);
1429
- }
1430
-
1431
- let fetches = this._pendingFetch;
1432
- let pending = fetches.get(modelName);
1433
-
1434
- if (pending === undefined) {
1435
- pending = [];
1436
- fetches.set(modelName, pending);
1437
- }
1438
-
1439
- pending.push(pendingFetchItem);
1440
-
1441
- return promise;
1442
- }
1443
- }
1444
-
1445
- flushAllPendingFetches() {
1446
- if (REQUEST_SERVICE) {
1447
- return;
1448
- //assert here
1449
- } else {
1450
- if (this.isDestroyed || this.isDestroying) {
1451
- return;
1452
- }
1453
-
1454
- this._pendingFetch.forEach(this._flushPendingFetchForType, this);
1455
- this._pendingFetch.clear();
1456
- }
1457
- }
1458
-
1459
- _flushPendingFetchForType(pendingFetchItems: PendingFetchItem[], modelName: string) {
1460
- let store = this;
1461
- let adapter = store.adapterFor(modelName);
1462
- let shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests;
1463
- let totalItems = pendingFetchItems.length;
1464
- let internalModels = new Array(totalItems);
1465
- let seeking = Object.create(null);
1466
-
1467
- let optionsMap = new WeakMap();
1468
-
1469
- for (let i = 0; i < totalItems; i++) {
1470
- let pendingItem = pendingFetchItems[i];
1471
- let internalModel = pendingItem.internalModel;
1472
- internalModels[i] = internalModel;
1473
- optionsMap.set(internalModel, pendingItem.options);
1474
- // We can remove this "not null" cast once we have enough typing
1475
- // to know we are only dealing with ExistingResourceIdentifierObjects
1476
- seeking[internalModel.id!] = pendingItem;
1477
- }
1478
-
1479
- function _fetchRecord(recordResolverPair) {
1480
- let recordFetch = store._fetchRecord(recordResolverPair.internalModel, recordResolverPair.options);
1481
-
1482
- recordResolverPair.resolver.resolve(recordFetch);
1483
- }
1484
-
1485
- function handleFoundRecords(foundInternalModels: InternalModel[], expectedInternalModels: InternalModel[]) {
1486
- // resolve found records
1487
- let found = Object.create(null);
1488
- for (let i = 0, l = foundInternalModels.length; i < l; i++) {
1489
- let internalModel = foundInternalModels[i];
1490
-
1491
- // We can remove this "not null" cast once we have enough typing
1492
- // to know we are only dealing with ExistingResourceIdentifierObjects
1493
- let pair = seeking[internalModel.id!];
1494
- found[internalModel.id!] = internalModel;
1495
-
1496
- if (pair) {
1497
- let resolver = pair.resolver;
1498
- resolver.resolve(internalModel);
1499
- }
1500
- }
1501
-
1502
- // reject missing records
1503
- let missingInternalModels: InternalModel[] = [];
1504
-
1505
- for (let i = 0, l = expectedInternalModels.length; i < l; i++) {
1506
- let internalModel = expectedInternalModels[i];
1507
-
1508
- // We can remove this "not null" cast once we have enough typing
1509
- // to know we are only dealing with ExistingResourceIdentifierObjects
1510
- if (!found[internalModel.id!]) {
1511
- missingInternalModels.push(internalModel);
1512
- }
1513
- }
1514
-
1515
- if (missingInternalModels.length) {
1516
- warn(
1517
- 'Ember Data expected to find records with the following ids in the adapter response but they were missing: [ "' +
1518
- missingInternalModels.map((r) => r.id).join('", "') +
1519
- '" ]',
1520
- false,
1521
- {
1522
- id: 'ds.store.missing-records-from-adapter',
1523
- }
1524
- );
1525
- rejectInternalModels(missingInternalModels);
1526
- }
1527
- }
1528
-
1529
- function rejectInternalModels(internalModels: InternalModel[], error?: Error) {
1530
- for (let i = 0, l = internalModels.length; i < l; i++) {
1531
- let internalModel = internalModels[i];
1532
-
1533
- // We can remove this "not null" cast once we have enough typing
1534
- // to know we are only dealing with ExistingResourceIdentifierObjects
1535
- let pair = seeking[internalModel.id!];
1536
-
1537
- if (pair) {
1538
- pair.resolver.reject(
1539
- error ||
1540
- new Error(
1541
- `Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.`
1542
- )
1543
- );
1544
- }
1545
- }
1546
- }
1547
-
1548
- if (shouldCoalesce) {
1549
- // TODO: Improve records => snapshots => records => snapshots
1550
- //
1551
- // We want to provide records to all store methods and snapshots to all
1552
- // adapter methods. To make sure we're doing that we're providing an array
1553
- // of snapshots to adapter.groupRecordsForFindMany(), which in turn will
1554
- // return grouped snapshots instead of grouped records.
1555
- //
1556
- // But since the _findMany() finder is a store method we need to get the
1557
- // records from the grouped snapshots even though the _findMany() finder
1558
- // will once again convert the records to snapshots for adapter.findMany()
1559
- let snapshots = new Array(totalItems);
1560
- for (let i = 0; i < totalItems; i++) {
1561
- let internalModel = internalModels[i];
1562
- snapshots[i] = internalModel.createSnapshot(optionsMap.get(internalModel));
1563
- }
1564
-
1565
- let groups;
1566
- if (adapter.groupRecordsForFindMany) {
1567
- groups = adapter.groupRecordsForFindMany(this, snapshots);
1568
- } else {
1569
- groups = [snapshots];
1570
- }
1571
-
1572
- for (let i = 0, l = groups.length; i < l; i++) {
1573
- let group = groups[i];
1574
- let totalInGroup = groups[i].length;
1575
- let ids = new Array(totalInGroup);
1576
- let groupedInternalModels = new Array(totalInGroup);
1577
-
1578
- for (let j = 0; j < totalInGroup; j++) {
1579
- let internalModel = group[j]._internalModel;
1580
-
1581
- groupedInternalModels[j] = internalModel;
1582
- ids[j] = internalModel.id;
1583
- }
1584
-
1585
- if (totalInGroup > 1) {
1586
- (function (groupedInternalModels) {
1587
- _findMany(adapter, store, modelName, ids, groupedInternalModels, optionsMap)
1588
- .then(function (foundInternalModels) {
1589
- handleFoundRecords(foundInternalModels, groupedInternalModels);
1590
- })
1591
- .catch(function (error) {
1592
- rejectInternalModels(groupedInternalModels, error);
1593
- });
1594
- })(groupedInternalModels);
1595
- } else if (ids.length === 1) {
1596
- let pair = seeking[groupedInternalModels[0].id];
1597
- _fetchRecord(pair);
1598
- } else {
1599
- assert("You cannot return an empty array from adapter's method groupRecordsForFindMany");
1600
- }
1601
- }
1602
- } else {
1603
- for (let i = 0; i < totalItems; i++) {
1604
- _fetchRecord(pendingFetchItems[i]);
1605
- }
1606
- }
1607
- }
1608
-
1609
1223
  /**
1610
1224
  Get the reference for the specified record.
1611
1225
 
@@ -1663,15 +1277,9 @@ abstract class CoreStore extends Service {
1663
1277
  isMaybeIdentifier(resourceIdentifier)
1664
1278
  );
1665
1279
 
1666
- let identifier: StableRecordIdentifier = identifierCacheFor(this).getOrCreateRecordIdentifier(resourceIdentifier);
1280
+ let identifier: StableRecordIdentifier = this.identifierCache.getOrCreateRecordIdentifier(resourceIdentifier);
1667
1281
  if (identifier) {
1668
- if (RECORD_REFERENCES.has(identifier)) {
1669
- return RECORD_REFERENCES.get(identifier);
1670
- }
1671
-
1672
- let reference = new RecordReference(this, identifier);
1673
- RECORD_REFERENCES.set(identifier, reference);
1674
- return reference;
1282
+ return RECORD_REFERENCES.lookup(identifier);
1675
1283
  }
1676
1284
  }
1677
1285
 
@@ -1727,7 +1335,7 @@ abstract class CoreStore extends Service {
1727
1335
  peekRecord(identifier: ResourceIdentifierObject): RecordInstance | null;
1728
1336
  peekRecord(identifier: ResourceIdentifierObject | string, id?: string | number): RecordInstance | null {
1729
1337
  if (arguments.length === 1 && isMaybeIdentifier(identifier)) {
1730
- let stableIdentifier = identifierCacheFor(this).peekRecordIdentifier(identifier);
1338
+ let stableIdentifier = this.identifierCache.peekRecordIdentifier(identifier);
1731
1339
  if (stableIdentifier) {
1732
1340
  return internalModelFactoryFor(this).peek(stableIdentifier)?.getRecord() || null;
1733
1341
  }
@@ -1769,9 +1377,7 @@ abstract class CoreStore extends Service {
1769
1377
  @return {Promise} promise
1770
1378
  */
1771
1379
  _reloadRecord(internalModel, options): RSVP.Promise<InternalModel> {
1772
- if (REQUEST_SERVICE) {
1773
- options.isReloading = true;
1774
- }
1380
+ options.isReloading = true;
1775
1381
  let { id, modelName } = internalModel;
1776
1382
  let adapter = this.adapterFor(modelName);
1777
1383
 
@@ -1819,7 +1425,7 @@ abstract class CoreStore extends Service {
1819
1425
  const trueId = ensureStringId(id);
1820
1426
  const resource = { type, id: trueId };
1821
1427
 
1822
- const identifier = identifierCacheFor(this).peekRecordIdentifier(resource);
1428
+ const identifier = this.identifierCache.peekRecordIdentifier(resource);
1823
1429
  const internalModel = identifier && internalModelFactoryFor(this).peek(identifier);
1824
1430
 
1825
1431
  return !!internalModel && internalModel.currentState.isLoaded;
@@ -2018,17 +1624,9 @@ abstract class CoreStore extends Service {
2018
1624
 
2019
1625
  if (internalModel) {
2020
1626
  // short circuit if we are already loading
2021
- if (REQUEST_SERVICE) {
2022
- let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier);
2023
- if (pendingRequest) {
2024
- return pendingRequest.then(() => internalModel.getRecord());
2025
- }
2026
- } else {
2027
- if (internalModel.currentState.isLoading) {
2028
- return internalModel._promiseProxy.then(() => {
2029
- return internalModel.getRecord();
2030
- });
2031
- }
1627
+ let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier, options);
1628
+ if (pendingRequest) {
1629
+ return pendingRequest.then(() => internalModel.getRecord());
2032
1630
  }
2033
1631
  }
2034
1632
 
@@ -2051,6 +1649,10 @@ abstract class CoreStore extends Service {
2051
1649
  return resolve(null);
2052
1650
  }
2053
1651
 
1652
+ if (!internalModel) {
1653
+ assert(`No InternalModel found for ${resource.lid}`, internalModel);
1654
+ }
1655
+
2054
1656
  return this._findByInternalModel(internalModel, options);
2055
1657
  }
2056
1658
 
@@ -2657,33 +2259,32 @@ abstract class CoreStore extends Service {
2657
2259
  @param {Object} options
2658
2260
  */
2659
2261
  scheduleSave(internalModel: InternalModel, resolver: RSVP.Deferred<void>, options): void | RSVP.Promise<void> {
2660
- if (REQUEST_SERVICE) {
2661
- if (internalModel._isRecordFullyDeleted()) {
2662
- resolver.resolve();
2663
- return resolver.promise;
2664
- }
2262
+ if (internalModel._isRecordFullyDeleted()) {
2263
+ resolver.resolve();
2264
+ return resolver.promise;
2265
+ }
2665
2266
 
2666
- internalModel.adapterWillCommit();
2267
+ internalModel.adapterWillCommit();
2667
2268
 
2668
- if (!options) {
2669
- options = {};
2670
- }
2671
- let recordData = internalModel._recordData;
2672
- let operation: 'createRecord' | 'deleteRecord' | 'updateRecord' = 'updateRecord';
2673
-
2674
- // TODO handle missing isNew
2675
- if (recordData.isNew && recordData.isNew()) {
2676
- operation = 'createRecord';
2677
- } else if (recordData.isDeleted && recordData.isDeleted()) {
2678
- operation = 'deleteRecord';
2679
- }
2269
+ if (!options) {
2270
+ options = {};
2271
+ }
2272
+ let recordData = internalModel._recordData;
2273
+ let operation: 'createRecord' | 'deleteRecord' | 'updateRecord' = 'updateRecord';
2274
+
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
+ }
2680
2281
 
2681
- options[SaveOp] = operation;
2282
+ options[SaveOp] = operation;
2682
2283
 
2683
- let fetchManagerPromise = this._fetchManager.scheduleSave(internalModel.identifier, options);
2684
- let promise = fetchManagerPromise.then(
2685
- (payload) => {
2686
- /*
2284
+ let fetchManagerPromise = this._fetchManager.scheduleSave(internalModel.identifier, options);
2285
+ let promise = fetchManagerPromise.then(
2286
+ (payload) => {
2287
+ /*
2687
2288
  Note to future spelunkers hoping to optimize.
2688
2289
  We rely on this `run` to create a run loop if needed
2689
2290
  that `store._push` and `store.didSaveRecord` will both share.
@@ -2692,40 +2293,25 @@ abstract class CoreStore extends Service {
2692
2293
  have an outer run loop available still from the first
2693
2294
  call to `store._push`;
2694
2295
  */
2695
- this._backburner.join(() => {
2696
- let data = payload && payload.data;
2697
- this.didSaveRecord(internalModel, { data }, operation);
2698
- if (payload && payload.included) {
2699
- this._push({ data: null, included: payload.included });
2700
- }
2701
- });
2702
- },
2703
- (e) => {
2704
- if (typeof e === 'string') {
2705
- 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 });
2706
2301
  }
2707
- const { error, parsedErrors } = e;
2708
- this.recordWasInvalid(internalModel, parsedErrors, error);
2709
- throw error;
2302
+ });
2303
+ },
2304
+ (e) => {
2305
+ if (typeof e === 'string') {
2306
+ throw e;
2710
2307
  }
2711
- );
2712
-
2713
- return promise;
2714
- } else {
2715
- if (internalModel._isRecordFullyDeleted()) {
2716
- resolver.resolve();
2717
- return;
2308
+ const { error, parsedErrors } = e;
2309
+ this.recordWasInvalid(internalModel, parsedErrors, error);
2310
+ throw error;
2718
2311
  }
2312
+ );
2719
2313
 
2720
- let snapshot = internalModel.createSnapshot(options);
2721
- internalModel.adapterWillCommit();
2722
- this._pendingSave.push({
2723
- snapshot: snapshot,
2724
- resolver: resolver,
2725
- });
2726
-
2727
- emberBackburner.scheduleOnce('actions', this, this.flushPendingSave);
2728
- }
2314
+ return promise;
2729
2315
  }
2730
2316
 
2731
2317
  /**
@@ -2736,47 +2322,8 @@ abstract class CoreStore extends Service {
2736
2322
  @private
2737
2323
  */
2738
2324
  flushPendingSave() {
2739
- if (REQUEST_SERVICE) {
2740
- // assert here
2741
- return;
2742
- }
2743
- let pending = this._pendingSave.slice();
2744
- this._pendingSave = [];
2745
-
2746
- for (let i = 0, j = pending.length; i < j; i++) {
2747
- let pendingItem = pending[i];
2748
- let snapshot = pendingItem.snapshot;
2749
- let resolver = pendingItem.resolver;
2750
- // TODO We have to cast due to our reliance on this private property
2751
- // this will be refactored away once we change our pending API to be identifier based
2752
- let internalModel = (snapshot as unknown as PrivateSnapshot)._internalModel;
2753
- let adapter = this.adapterFor(internalModel.modelName);
2754
- let operation;
2755
-
2756
- if (RECORD_DATA_STATE) {
2757
- // TODO move this out of internalModel
2758
- if (internalModel.isNew()) {
2759
- operation = 'createRecord';
2760
- } else if (internalModel.isDeleted()) {
2761
- operation = 'deleteRecord';
2762
- } else {
2763
- operation = 'updateRecord';
2764
- }
2765
- } else {
2766
- if (internalModel.currentState.stateName === 'root.deleted.saved') {
2767
- resolver.resolve();
2768
- continue;
2769
- } else if (internalModel.isNew()) {
2770
- operation = 'createRecord';
2771
- } else if (internalModel.isDeleted()) {
2772
- operation = 'deleteRecord';
2773
- } else {
2774
- operation = 'updateRecord';
2775
- }
2776
- }
2777
-
2778
- resolver.resolve(_commit(adapter, this, operation, snapshot));
2779
- }
2325
+ // assert here
2326
+ return;
2780
2327
  }
2781
2328
 
2782
2329
  /**
@@ -2808,7 +2355,7 @@ abstract class CoreStore extends Service {
2808
2355
  );
2809
2356
  }
2810
2357
 
2811
- const cache = identifierCacheFor(this);
2358
+ const cache = this.identifierCache;
2812
2359
  const identifier = internalModel.identifier;
2813
2360
 
2814
2361
  if (op !== 'deleteRecord' && data) {
@@ -2834,11 +2381,7 @@ abstract class CoreStore extends Service {
2834
2381
  if (DEBUG) {
2835
2382
  assertDestroyingStore(this, 'recordWasInvalid');
2836
2383
  }
2837
- if (RECORD_DATA_ERRORS) {
2838
- internalModel.adapterDidInvalidate(parsedErrors, error);
2839
- } else {
2840
- internalModel.adapterDidInvalidate(parsedErrors);
2841
- }
2384
+ internalModel.adapterDidInvalidate(parsedErrors, error);
2842
2385
  }
2843
2386
 
2844
2387
  /**
@@ -2900,7 +2443,7 @@ abstract class CoreStore extends Service {
2900
2443
  // exclude store.push (root.empty) case
2901
2444
  let identifier = internalModel.identifier;
2902
2445
  if (isUpdate || isLoading) {
2903
- let updatedIdentifier = identifierCacheFor(this).updateRecordIdentifier(identifier, data);
2446
+ let updatedIdentifier = this.identifierCache.updateRecordIdentifier(identifier, data);
2904
2447
 
2905
2448
  if (updatedIdentifier !== identifier) {
2906
2449
  // we encountered a merge of identifiers in which
@@ -3163,30 +2706,17 @@ abstract class CoreStore extends Service {
3163
2706
 
3164
2707
  if (ENV.DS_WARN_ON_UNKNOWN_KEYS) {
3165
2708
  let unknownAttributes, unknownRelationships;
3166
- if (CUSTOM_MODEL_CLASS) {
3167
- let relationships = this.getSchemaDefinitionService().relationshipsDefinitionFor(modelName);
3168
- let attributes = this.getSchemaDefinitionService().attributesDefinitionFor(modelName);
3169
- // Check unknown attributes
3170
- unknownAttributes = Object.keys(data.attributes || {}).filter((key) => {
3171
- return !attributes[key];
3172
- });
3173
-
3174
- // Check unknown relationships
3175
- unknownRelationships = Object.keys(data.relationships || {}).filter((key) => {
3176
- return !relationships[key];
3177
- });
3178
- } else {
3179
- let modelClass = this.modelFor(modelName);
3180
- // Check unknown attributes
3181
- unknownAttributes = Object.keys(data.attributes || {}).filter((key) => {
3182
- return !get(modelClass, 'fields').has(key);
3183
- });
3184
-
3185
- // Check unknown relationships
3186
- unknownRelationships = Object.keys(data.relationships || {}).filter((key) => {
3187
- return !get(modelClass, 'fields').has(key);
3188
- });
3189
- }
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
+ });
3190
2720
  let unknownAttributesMessage = `The payload for '${modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`;
3191
2721
  warn(unknownAttributesMessage, unknownAttributes.length === 0, {
3192
2722
  id: 'ds.store.unknown-keys-in-payload',
@@ -3316,38 +2846,26 @@ abstract class CoreStore extends Service {
3316
2846
  }
3317
2847
 
3318
2848
  serializeRecord(record: RecordInstance, options?: Dict<unknown>): unknown {
3319
- if (CUSTOM_MODEL_CLASS) {
3320
- let identifier = recordIdentifierFor(record);
3321
- let internalModel = internalModelFactoryFor(this).peek(identifier);
3322
- // TODO we used to check if the record was destroyed here
3323
- return internalModel!.createSnapshot(options).serialize(options);
3324
- }
3325
-
3326
- 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);
3327
2853
  }
3328
2854
 
3329
2855
  saveRecord(record: RecordInstance, options?: Dict<unknown>): RSVP.Promise<RecordInstance> {
3330
- if (CUSTOM_MODEL_CLASS) {
3331
- let identifier = recordIdentifierFor(record);
3332
- let internalModel = internalModelFactoryFor(this).peek(identifier);
3333
- // TODO we used to check if the record was destroyed here
3334
- // Casting can be removed once REQUEST_SERVICE ff is turned on
3335
- // because a `Record` is provided there will always be a matching internalModel
3336
- return (internalModel!.save(options) as RSVP.Promise<void>).then(() => record);
3337
- }
3338
-
3339
- 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);
3340
2862
  }
3341
2863
 
3342
2864
  relationshipReferenceFor(identifier: RecordIdentifier, key: string): BelongsToReference | HasManyReference {
3343
- if (CUSTOM_MODEL_CLASS) {
3344
- let stableIdentifier = identifierCacheFor(this).getOrCreateRecordIdentifier(identifier);
3345
- let internalModel = internalModelFactoryFor(this).peek(stableIdentifier);
3346
- // TODO we used to check if the record was destroyed here
3347
- return internalModel!.referenceFor(null, key);
3348
- }
3349
-
3350
- 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);
3351
2869
  }
3352
2870
 
3353
2871
  /**
@@ -3393,7 +2911,7 @@ abstract class CoreStore extends Service {
3393
2911
  _RecordData = require('@ember-data/record-data/-private').RecordData as RecordDataConstruct;
3394
2912
  }
3395
2913
 
3396
- let identifier = identifierCacheFor(this).getOrCreateRecordIdentifier({
2914
+ let identifier = this.identifierCache.getOrCreateRecordIdentifier({
3397
2915
  type: modelName,
3398
2916
  id,
3399
2917
  lid: clientId,
@@ -3408,7 +2926,7 @@ abstract class CoreStore extends Service {
3408
2926
  * @internal
3409
2927
  */
3410
2928
  __recordDataFor(resource: RecordIdentifier) {
3411
- const identifier = identifierCacheFor(this).getOrCreateRecordIdentifier(resource);
2929
+ const identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
3412
2930
  return this.recordDataFor(identifier, false);
3413
2931
  }
3414
2932
 
@@ -3526,25 +3044,15 @@ abstract class CoreStore extends Service {
3526
3044
 
3527
3045
  let owner = getOwner(this);
3528
3046
 
3047
+ // name specific adapter
3529
3048
  adapter = owner.lookup(`adapter:${normalizedModelName}`);
3530
-
3531
- // in production this is handled by the re-export
3532
- if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_ADAPTER_PACKAGE && adapter === undefined) {
3533
- if (normalizedModelName === '-json-api') {
3534
- const Adapter = require('@ember-data/adapter/json-api').default;
3535
- owner.register(`adapter:-json-api`, Adapter);
3536
- adapter = owner.lookup(`adapter:-json-api`);
3537
- deprecateTestRegistration('adapter', '-json-api');
3538
- }
3539
- }
3540
-
3541
3049
  if (adapter !== undefined) {
3542
3050
  set(adapter, 'store', this);
3543
3051
  _adapterCache[normalizedModelName] = adapter;
3544
3052
  return adapter;
3545
3053
  }
3546
3054
 
3547
- // 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
3548
3056
  adapter = _adapterCache.application || owner.lookup('adapter:application');
3549
3057
  if (adapter !== undefined) {
3550
3058
  set(adapter, 'store', this);
@@ -3553,30 +3061,9 @@ abstract class CoreStore extends Service {
3553
3061
  return adapter;
3554
3062
  }
3555
3063
 
3556
- // no model specific adapter or application adapter, check for an `adapter`
3557
- // property defined on the store
3558
- let adapterName = this.adapter || '-json-api';
3559
- adapter = adapterName ? _adapterCache[adapterName] || owner.lookup(`adapter:${adapterName}`) : undefined;
3560
-
3561
- // in production this is handled by the re-export
3562
- if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_ADAPTER_PACKAGE && adapter === undefined) {
3563
- if (adapterName === '-json-api') {
3564
- const Adapter = require('@ember-data/adapter/json-api').default;
3565
- owner.register(`adapter:-json-api`, Adapter);
3566
- adapter = owner.lookup(`adapter:-json-api`);
3567
- deprecateTestRegistration('adapter', '-json-api');
3568
- }
3569
- }
3570
-
3571
- if (adapter !== undefined) {
3572
- set(adapter, 'store', this);
3573
- _adapterCache[normalizedModelName] = adapter;
3574
- _adapterCache[adapterName] = adapter;
3575
- return adapter;
3576
- }
3577
-
3578
3064
  // final fallback, no model specific adapter, no application adapter, no
3579
3065
  // `adapter` property on store: use json-api adapter
3066
+ // TODO we should likely deprecate this?
3580
3067
  adapter = _adapterCache['-json-api'] || owner.lookup('adapter:-json-api');
3581
3068
  assert(
3582
3069
  `No adapter was found for '${modelName}' and no 'application' adapter was found as a fallback.`,
@@ -3601,10 +3088,6 @@ abstract class CoreStore extends Service {
3601
3088
  for an `App.ApplicationSerializer` (the default serializer for
3602
3089
  your entire application).
3603
3090
 
3604
- if no `App.ApplicationSerializer` is found, it will attempt
3605
- to get the `defaultSerializer` from the `PersonAdapter`
3606
- (`adapterFor('person')`).
3607
-
3608
3091
  If a serializer cannot be found on the adapter, it will fall back
3609
3092
  to an instance of `JSONSerializer`.
3610
3093
 
@@ -3632,30 +3115,8 @@ abstract class CoreStore extends Service {
3632
3115
 
3633
3116
  let owner = getOwner(this);
3634
3117
 
3118
+ // by name
3635
3119
  serializer = owner.lookup(`serializer:${normalizedModelName}`);
3636
-
3637
- if (DEPRECATE_LEGACY_TEST_REGISTRATIONS) {
3638
- // in production this is handled by the re-export
3639
- if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_SERIALIZER_PACKAGE && serializer === undefined) {
3640
- if (normalizedModelName === '-json-api') {
3641
- const Serializer = require('@ember-data/serializer/json-api').default;
3642
- owner.register(`serializer:-json-api`, Serializer);
3643
- serializer = owner.lookup(`serializer:-json-api`);
3644
- deprecateTestRegistration('serializer', '-json-api');
3645
- } else if (normalizedModelName === '-rest') {
3646
- const Serializer = require('@ember-data/serializer/rest').default;
3647
- owner.register(`serializer:-rest`, Serializer);
3648
- serializer = owner.lookup(`serializer:-rest`);
3649
- deprecateTestRegistration('serializer', '-rest');
3650
- } else if (normalizedModelName === '-default') {
3651
- const Serializer = require('@ember-data/serializer/json').default;
3652
- owner.register(`serializer:-default`, Serializer);
3653
- serializer = owner.lookup(`serializer:-default`);
3654
- serializer && deprecateTestRegistration('serializer', '-default');
3655
- }
3656
- }
3657
- }
3658
-
3659
3120
  if (serializer !== undefined) {
3660
3121
  set(serializer, 'store', this);
3661
3122
  _serializerCache[normalizedModelName] = serializer;
@@ -3671,105 +3132,10 @@ abstract class CoreStore extends Service {
3671
3132
  return serializer;
3672
3133
  }
3673
3134
 
3674
- let serializerName;
3675
- if (DEPRECATE_DEFAULT_SERIALIZER) {
3676
- // no model specific serializer or application serializer, check for the `defaultSerializer`
3677
- // property defined on the adapter
3678
- let adapter = this.adapterFor(modelName);
3679
- serializerName = get(adapter, 'defaultSerializer');
3680
-
3681
- deprecate(
3682
- `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`,
3683
- !serializerName,
3684
- {
3685
- id: 'ember-data:default-serializer',
3686
- until: '4.0',
3687
- url: 'https://deprecations.emberjs.com/ember-data/v3.x/#toc_ember-data-default-serializers',
3688
- for: '@ember-data/store',
3689
- since: {
3690
- available: '3.15',
3691
- enabled: '3.15',
3692
- },
3693
- }
3694
- );
3695
-
3696
- serializer = serializerName
3697
- ? _serializerCache[serializerName] || owner.lookup(`serializer:${serializerName}`)
3698
- : undefined;
3699
- }
3700
-
3701
- if (DEPRECATE_LEGACY_TEST_REGISTRATIONS) {
3702
- // in production this is handled by the re-export
3703
- if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_SERIALIZER_PACKAGE && serializer === undefined) {
3704
- if (serializerName === '-json-api') {
3705
- const Serializer = require('@ember-data/serializer/json-api').default;
3706
- owner.register(`serializer:-json-api`, Serializer);
3707
- serializer = owner.lookup(`serializer:-json-api`);
3708
- deprecateTestRegistration('serializer', '-json-api');
3709
- } else if (serializerName === '-rest') {
3710
- const Serializer = require('@ember-data/serializer/rest').default;
3711
- owner.register(`serializer:-rest`, Serializer);
3712
- serializer = owner.lookup(`serializer:-rest`);
3713
- deprecateTestRegistration('serializer', '-rest');
3714
- } else if (serializerName === '-default') {
3715
- const Serializer = require('@ember-data/serializer/json').default;
3716
- owner.register(`serializer:-default`, Serializer);
3717
- serializer = owner.lookup(`serializer:-default`);
3718
- serializer && deprecateTestRegistration('serializer', '-default');
3719
- }
3720
- }
3721
-
3722
- if (serializer !== undefined) {
3723
- set(serializer, 'store', this);
3724
- _serializerCache[normalizedModelName] = serializer;
3725
- _serializerCache[serializerName] = serializer;
3726
- return serializer;
3727
- }
3728
- }
3729
-
3730
- if (DEPRECATE_DEFAULT_SERIALIZER) {
3731
- // final fallback, no model specific serializer, no application serializer, no
3732
- // `serializer` property on store: use the convenience JSONSerializer
3733
- serializer = _serializerCache['-default'] || owner.lookup('serializer:-default');
3734
- if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_SERIALIZER_PACKAGE && serializer === undefined) {
3735
- const JSONSerializer = require('@ember-data/serializer/json').default;
3736
- owner.register('serializer:-default', JSONSerializer);
3737
- serializer = owner.lookup('serializer:-default');
3738
-
3739
- serializer && deprecateTestRegistration('serializer', '-default');
3740
- }
3741
-
3742
- deprecate(
3743
- `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`,
3744
- !serializer,
3745
- {
3746
- id: 'ember-data:default-serializer',
3747
- until: '4.0',
3748
- url: 'https://deprecations.emberjs.com/ember-data/v3.x/#toc_ember-data-default-serializers',
3749
- for: '@ember-data/store',
3750
- since: {
3751
- available: '3.15',
3752
- enabled: '3.15',
3753
- },
3754
- }
3755
- );
3756
-
3757
- assert(
3758
- `No serializer was found for '${modelName}' and no 'application' serializer was found as a fallback`,
3759
- serializer !== undefined
3760
- );
3761
-
3762
- set(serializer, 'store', this);
3763
- _serializerCache[normalizedModelName] = serializer;
3764
- _serializerCache['-default'] = serializer;
3765
-
3766
- return serializer;
3767
- } else {
3768
- assert(
3769
- `No serializer was found for '${modelName}' and no 'application' serializer was found as a fallback`,
3770
- serializer !== undefined
3771
- );
3772
- }
3135
+ assert(
3136
+ `No serializer was found for '${modelName}' and no 'application' serializer was found as a fallback`,
3137
+ serializer !== undefined
3138
+ );
3773
3139
  }
3774
3140
 
3775
3141
  destroy() {
@@ -3803,7 +3169,7 @@ abstract class CoreStore extends Service {
3803
3169
  super.willDestroy();
3804
3170
  this.recordArrayManager.destroy();
3805
3171
 
3806
- identifierCacheFor(this).destroy();
3172
+ this.identifierCache.destroy();
3807
3173
 
3808
3174
  // destroy the graph before unloadAll
3809
3175
  // since then we avoid churning relationships
@@ -3863,155 +3229,23 @@ abstract class CoreStore extends Service {
3863
3229
  }
3864
3230
  }
3865
3231
 
3866
- if (DEPRECATE_DEFAULT_ADAPTER) {
3867
- defineProperty(
3868
- CoreStore.prototype,
3869
- 'defaultAdapter',
3870
- computed('adapter', function () {
3871
- deprecate(
3872
- `store.adapterFor(modelName) resolved the ("${
3873
- this.adapter || '-json-api'
3874
- }") 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.`,
3875
- false,
3876
- {
3877
- id: 'ember-data:default-adapter',
3878
- until: '4.0',
3879
- url: 'https://deprecations.emberjs.com/ember-data/v3.x/#toc_ember-data-default-adapter',
3880
- for: '@ember-data/store',
3881
- since: {
3882
- available: '3.15',
3883
- enabled: '3.15',
3884
- },
3885
- }
3886
- );
3887
- let adapter = this.adapter || '-json-api';
3888
-
3889
- assert(
3890
- 'You tried to set `adapter` property to an instance of `Adapter`, where it should be a name',
3891
- typeof adapter === 'string'
3892
- );
3893
-
3894
- return this.adapterFor(adapter);
3895
- })
3896
- );
3897
- }
3898
-
3899
3232
  export default CoreStore;
3900
3233
 
3901
- function _commit(adapter, store, operation, snapshot) {
3902
- let internalModel = snapshot._internalModel;
3903
- let modelName = snapshot.modelName;
3904
- let modelClass = store.modelFor(modelName);
3905
- assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter);
3906
- assert(
3907
- `You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`,
3908
- typeof adapter[operation] === 'function'
3909
- );
3910
-
3911
- let promise = Promise.resolve().then(() => adapter[operation](store, modelClass, snapshot));
3912
- let serializer = store.serializerFor(modelName);
3913
- let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`;
3914
-
3915
- promise = guardDestroyedStore(promise, store, label);
3916
- promise = _guard(promise, _bind(_objectIsAlive, internalModel));
3917
-
3918
- return promise.then(
3919
- (adapterPayload) => {
3920
- /*
3921
- Note to future spelunkers hoping to optimize.
3922
- We rely on this `run` to create a run loop if needed
3923
- that `store._push` and `store.didSaveRecord` will both share.
3924
-
3925
- We use `join` because it is often the case that we
3926
- have an outer run loop available still from the first
3927
- call to `store._push`;
3928
- */
3929
- store._backburner.join(() => {
3930
- let payload, data, sideloaded;
3931
- if (adapterPayload) {
3932
- payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, snapshot.id, operation);
3933
- if (payload.included) {
3934
- sideloaded = payload.included;
3935
- }
3936
- data = payload.data;
3937
- }
3938
- store.didSaveRecord(internalModel, { data }, operation);
3939
- // seems risky, but if the tests pass might be fine?
3940
- if (sideloaded) {
3941
- store._push({ data: null, included: sideloaded });
3942
- }
3943
- });
3944
-
3945
- return internalModel;
3946
- },
3947
- function (error) {
3948
- if (error && error.isAdapterError === true && error.code === 'InvalidError') {
3949
- let parsedErrors;
3950
-
3951
- if (typeof serializer.extractErrors === 'function') {
3952
- parsedErrors = serializer.extractErrors(store, modelClass, error, snapshot.id);
3953
- } else {
3954
- parsedErrors = errorsArrayToHash(error.errors);
3955
- }
3956
-
3957
- store.recordWasInvalid(internalModel, parsedErrors, error);
3958
- } else {
3959
- store.recordWasError(internalModel, error);
3960
- }
3961
-
3962
- throw error;
3963
- },
3964
- label
3965
- );
3966
- }
3967
-
3968
3234
  let assertDestroyingStore: Function;
3969
3235
  let assertDestroyedStoreOnly: Function;
3970
3236
 
3971
3237
  if (DEBUG) {
3972
3238
  assertDestroyingStore = function assertDestroyedStore(store, method) {
3973
- if (!store.shouldAssertMethodCallsOnDestroyedStore) {
3974
- deprecate(
3975
- `Attempted to call store.${method}(), but the store instance has already been destroyed.`,
3976
- !(store.isDestroying || store.isDestroyed),
3977
- {
3978
- id: 'ember-data:method-calls-on-destroyed-store',
3979
- until: '3.8',
3980
- for: '@ember-data/store',
3981
- since: {
3982
- available: '3.8',
3983
- enabled: '3.8',
3984
- },
3985
- }
3986
- );
3987
- } else {
3988
- assert(
3989
- `Attempted to call store.${method}(), but the store instance has already been destroyed.`,
3990
- !(store.isDestroying || store.isDestroyed)
3991
- );
3992
- }
3239
+ assert(
3240
+ `Attempted to call store.${method}(), but the store instance has already been destroyed.`,
3241
+ !(store.isDestroying || store.isDestroyed)
3242
+ );
3993
3243
  };
3994
3244
  assertDestroyedStoreOnly = function assertDestroyedStoreOnly(store, method) {
3995
- if (!store.shouldAssertMethodCallsOnDestroyedStore) {
3996
- deprecate(
3997
- `Attempted to call store.${method}(), but the store instance has already been destroyed.`,
3998
- !store.isDestroyed,
3999
- {
4000
- id: 'ember-data:method-calls-on-destroyed-store',
4001
- until: '3.8',
4002
- for: '@ember-data/store',
4003
- since: {
4004
- available: '3.8',
4005
- enabled: '3.8',
4006
- },
4007
- }
4008
- );
4009
- } else {
4010
- assert(
4011
- `Attempted to call store.${method}(), but the store instance has already been destroyed.`,
4012
- !store.isDestroyed
4013
- );
4014
- }
3245
+ assert(
3246
+ `Attempted to call store.${method}(), but the store instance has already been destroyed.`,
3247
+ !store.isDestroyed
3248
+ );
4015
3249
  };
4016
3250
  }
4017
3251
 
@@ -4026,7 +3260,7 @@ if (DEBUG) {
4026
3260
  * @return {boolean}
4027
3261
  */
4028
3262
  function areAllInverseRecordsLoaded(store: CoreStore, resource: JsonApiRelationship): boolean {
4029
- const cache = identifierCacheFor(store);
3263
+ const cache = store.identifierCache;
4030
3264
 
4031
3265
  if (Array.isArray(resource.data)) {
4032
3266
  // treat as collection