@ember-data/store 4.8.0-alpha.4 → 4.8.0-beta.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.
@@ -4,7 +4,6 @@
4
4
  import { getOwner, setOwner } from '@ember/application';
5
5
  import { assert, deprecate } from '@ember/debug';
6
6
  import { _backburner as emberBackburner, run } from '@ember/runloop';
7
- import type { Backburner } from '@ember/runloop/-private/backburner';
8
7
  import Service from '@ember/service';
9
8
  import { registerWaiter, unregisterWaiter } from '@ember/test';
10
9
  import { DEBUG } from '@glimmer/env';
@@ -12,12 +11,12 @@ import { DEBUG } from '@glimmer/env';
12
11
  import { importSync } from '@embroider/macros';
13
12
  import { reject, resolve } from 'rsvp';
14
13
 
15
- import { V2CACHE_SINGLETON_RECORD_DATA } from '@ember-data/canary-features';
16
14
  import type DSModelClass from '@ember-data/model';
17
15
  import { HAS_MODEL_PACKAGE, HAS_RECORD_DATA_PACKAGE } from '@ember-data/private-build-infra';
18
16
  import {
19
17
  DEPRECATE_HAS_RECORD,
20
18
  DEPRECATE_JSON_API_FALLBACK,
19
+ DEPRECATE_PROMISE_PROXIES,
21
20
  DEPRECATE_STORE_FIND,
22
21
  DEPRECATE_V1CACHE_STORE_APIS,
23
22
  } from '@ember-data/private-build-infra/deprecations';
@@ -41,7 +40,6 @@ import type { SchemaDefinitionService } from '@ember-data/types/q/schema-definit
41
40
  import type { FindOptions } from '@ember-data/types/q/store';
42
41
  import type { Dict } from '@ember-data/types/q/utils';
43
42
 
44
- import edBackburner from './backburner';
45
43
  import { IdentifierCache } from './caches/identifier-cache';
46
44
  import {
47
45
  InstanceCache,
@@ -63,9 +61,10 @@ import NotificationManager from './managers/record-notification-manager';
63
61
  import FetchManager, { SaveOp } from './network/fetch-manager';
64
62
  import { _findAll, _query, _queryRecord } from './network/finders';
65
63
  import type RequestCache from './network/request-cache';
64
+ import type Snapshot from './network/snapshot';
65
+ import SnapshotRecordArray from './network/snapshot-record-array';
66
66
  import { PromiseArray, promiseArray, PromiseObject, promiseObject } from './proxies/promise-proxies';
67
- import AdapterPopulatedRecordArray from './record-arrays/adapter-populated-record-array';
68
- import RecordArray from './record-arrays/record-array';
67
+ import IdentifierArray, { Collection } from './record-arrays/identifier-array';
69
68
  import coerceId, { ensureStringId } from './utils/coerce-id';
70
69
  import constructResource from './utils/construct-resource';
71
70
  import normalizeModelName from './utils/normalize-model-name';
@@ -167,18 +166,7 @@ export interface CreateRecordProperties {
167
166
 
168
167
  class Store extends Service {
169
168
  __private_singleton_recordData!: RecordData;
170
- /**
171
- * Ember Data uses several specialized micro-queues for organizing
172
- and coalescing similar async work.
173
169
 
174
- These queues are currently controlled by a flush scheduled into
175
- ember-data's custom backburner instance.
176
- *
177
- * EmberData specific backburner instance
178
- * @property _backburner
179
- * @private
180
- */
181
- declare _backburner: Backburner;
182
170
  declare recordArrayManager: RecordArrayManager;
183
171
 
184
172
  declare _notificationManager: NotificationManager;
@@ -230,10 +218,6 @@ class Store extends Service {
230
218
  this._serializerCache = Object.create(null);
231
219
  this._modelFactoryCache = Object.create(null);
232
220
 
233
- // private
234
- // TODO we should find a path to something simpler than backburner
235
- this._backburner = edBackburner;
236
-
237
221
  if (DEBUG) {
238
222
  if (this.generateStackTracesForTrackedRequests === undefined) {
239
223
  this.generateStackTracesForTrackedRequests = false;
@@ -281,6 +265,37 @@ class Store extends Service {
281
265
  }
282
266
  }
283
267
 
268
+ declare _cbs: { coalesce?: () => void; sync?: () => void; notify?: () => void } | null;
269
+ _run(cb: () => void) {
270
+ assert(`EmberData should never encounter a nested run`, !this._cbs);
271
+ const _cbs: { coalesce?: () => void; sync?: () => void; notify?: () => void } = (this._cbs = {});
272
+ cb();
273
+ if (_cbs.coalesce) {
274
+ _cbs.coalesce();
275
+ }
276
+ if (_cbs.sync) {
277
+ _cbs.sync();
278
+ }
279
+ if (_cbs.notify) {
280
+ _cbs.notify();
281
+ }
282
+ this._cbs = null;
283
+ }
284
+ _join(cb: () => void): void {
285
+ if (this._cbs) {
286
+ cb();
287
+ } else {
288
+ this._run(cb);
289
+ }
290
+ }
291
+
292
+ _schedule(name: 'coalesce' | 'sync' | 'notify', cb: () => void): void {
293
+ assert(`EmberData expects to schedule only when there is an active run`, !!this._cbs);
294
+ assert(`EmberData expects only one flush per queue name, cannot schedule ${name}`, !this._cbs[name]);
295
+
296
+ this._cbs[name] = cb;
297
+ }
298
+
284
299
  /**
285
300
  * Retrieve the RequestStateService instance
286
301
  * associated with this Store.
@@ -321,25 +336,23 @@ class Store extends Service {
321
336
  ): DSModel | RecordInstance {
322
337
  if (HAS_MODEL_PACKAGE) {
323
338
  let modelName = identifier.type;
324
- let store = this;
325
339
 
326
340
  let recordData = this._instanceCache.getRecordData(identifier);
341
+ // TODO deprecate allowing unknown args setting
327
342
  let createOptions: any = {
328
- // TODO deprecate allowing unknown args setting
329
343
  _createProps: createRecordArgs,
330
344
  // TODO @deprecate consider deprecating accessing record properties during init which the below is necessary for
331
- _secretInit: (record: RecordInstance): void => {
332
- setRecordIdentifier(record, identifier);
333
- StoreMap.set(record, store);
334
- setRecordDataFor(record, recordData);
345
+ _secretInit: {
346
+ identifier,
347
+ recordData,
348
+ store: this,
349
+ cb: secretInit,
335
350
  },
336
- container: null, // necessary hack for setOwner?
337
351
  };
338
352
 
339
353
  // ensure that `getOwner(this)` works inside a model instance
340
354
  setOwner(createOptions, getOwner(this));
341
- delete createOptions.container;
342
- return getModelFactory(this, this._modelFactoryCache, modelName).create(createOptions);
355
+ return getModelFactory(this, this._modelFactoryCache, modelName).class.create(createOptions);
343
356
  }
344
357
  assert(`You must implement the store's instantiateRecord hook for your custom model class.`);
345
358
  }
@@ -394,15 +407,53 @@ class Store extends Service {
394
407
  * for use when information about a resource's schema needs
395
408
  * to be queried.
396
409
  *
397
- * This method can only be called once and needs to be called before
398
- * `getSchemaDefinitionService` is called when using `@ember-data/model`.
410
+ * This method can only be called more than once, but only one schema
411
+ * definition service may exist. Therefore if you wish to chain services
412
+ * you must lookup the existing service and close over it with the new
413
+ * service by calling `getSchemaDefinitionService` prior to registration.
414
+ *
415
+ * For Example:
416
+ *
417
+ * ```ts
418
+ * import Store from '@ember-data/store';
419
+ *
420
+ * class SchemaDelegator {
421
+ * constructor(schema) {
422
+ * this._schema = schema;
423
+ * }
424
+ *
425
+ * doesTypeExist(type: string): boolean {
426
+ * if (AbstractSchemas.has(type)) {
427
+ * return true;
428
+ * }
429
+ * return this._schema.doesTypeExist(type);
430
+ * }
431
+ *
432
+ * attributesDefinitionFor(identifier: RecordIdentifier | { type: string }): AttributesSchema {
433
+ * return this._schema.attributesDefinitionFor(identifier);
434
+ * }
435
+ *
436
+ * relationshipsDefinitionFor(identifier: RecordIdentifier | { type: string }): RelationshipsSchema {
437
+ * const schema = AbstractSchemas.get(identifier.type);
438
+ * return schema || this._schema.relationshipsDefinitionFor(identifier);
439
+ * }
440
+ * }
441
+ *
442
+ * export default class extends Store {
443
+ * constructor(...args) {
444
+ * super(...args);
445
+ *
446
+ * const schema = this.getSchemaDefinitionService();
447
+ * this.registerSchemaDefinitionService(new SchemaDelegator(schema));
448
+ * }
449
+ * }
450
+ * ```
399
451
  *
400
452
  * @method registerSchemaDefinitionService
401
453
  * @param {SchemaDefinitionService} schema
402
454
  * @public
403
455
  */
404
456
  registerSchemaDefinitionService(schema: SchemaDefinitionService) {
405
- assert(`Cannot register a schema definition service when one already exists`, !this._schemaDefinitionService);
406
457
  this._schemaDefinitionService = schema;
407
458
  }
408
459
 
@@ -508,8 +559,9 @@ class Store extends Service {
508
559
  // of record-arrays via ember's run loop, not our own.
509
560
  //
510
561
  // to remove this, we would need to move to a new `async` API.
511
- return emberBackburner.join(() => {
512
- return this._backburner.join(() => {
562
+ let record!: RecordInstance;
563
+ emberBackburner.join(() => {
564
+ this._join(() => {
513
565
  let normalizedModelName = normalizeModelName(modelName);
514
566
  let properties = { ...inputProperties };
515
567
 
@@ -551,11 +603,12 @@ class Store extends Service {
551
603
  (recordData as NonSingletonRecordDataManager).managedVersion === '1'
552
604
  );
553
605
  const resultProps = recordData.clientDidCreate(identifier, createOptions);
554
- this.recordArrayManager.recordDidChange(identifier);
606
+ this.recordArrayManager.identifierAdded(identifier);
555
607
 
556
- return this._instanceCache.getRecord(identifier, resultProps);
608
+ record = this._instanceCache.getRecord(identifier, resultProps);
557
609
  });
558
610
  });
611
+ return record;
559
612
  }
560
613
 
561
614
  /**
@@ -583,13 +636,15 @@ class Store extends Service {
583
636
  const identifier = peekRecordIdentifier(record);
584
637
  const recordData = identifier && this._instanceCache.peek({ identifier, bucket: 'recordData' });
585
638
  assert(`expected a recordData instance to exist for the record`, recordData);
586
- recordData.setIsDeleted(identifier, true);
639
+ this._join(() => {
640
+ recordData.setIsDeleted(identifier, true);
587
641
 
588
- if (recordData.isNew(identifier)) {
589
- run(() => {
590
- this._instanceCache.unloadRecord(identifier);
591
- });
592
- }
642
+ if (recordData.isNew(identifier)) {
643
+ run(() => {
644
+ this._instanceCache.unloadRecord(identifier);
645
+ });
646
+ }
647
+ });
593
648
  }
594
649
 
595
650
  /**
@@ -612,7 +667,7 @@ class Store extends Service {
612
667
  if (DEBUG) {
613
668
  assertDestroyingStore(this, 'unloadRecord');
614
669
  }
615
- let identifier = peekRecordIdentifier(record);
670
+ const identifier = peekRecordIdentifier(record);
616
671
  if (identifier) {
617
672
  this._instanceCache.unloadRecord(identifier);
618
673
  }
@@ -1079,14 +1134,14 @@ class Store extends Service {
1079
1134
  assertIdentifierHasId(identifier);
1080
1135
  promise = this._fetchManager.scheduleFetch(identifier, options);
1081
1136
  } else {
1082
- let snapshot = this._instanceCache.createSnapshot(identifier, options);
1137
+ let snapshot: Snapshot | null = null;
1083
1138
  let adapter = this.adapterFor(identifier.type);
1084
1139
 
1085
1140
  // Refetch the record if the adapter thinks the record is stale
1086
1141
  if (
1087
1142
  typeof options.reload === 'undefined' &&
1088
1143
  adapter.shouldReloadRecord &&
1089
- adapter.shouldReloadRecord(this, snapshot)
1144
+ adapter.shouldReloadRecord(this, (snapshot = this._instanceCache.createSnapshot(identifier, options)))
1090
1145
  ) {
1091
1146
  assertIdentifierHasId(identifier);
1092
1147
  promise = this._fetchManager.scheduleFetch(identifier, options);
@@ -1096,7 +1151,10 @@ class Store extends Service {
1096
1151
  options.backgroundReload !== false &&
1097
1152
  (options.backgroundReload ||
1098
1153
  !adapter.shouldBackgroundReloadRecord ||
1099
- adapter.shouldBackgroundReloadRecord(this, snapshot))
1154
+ adapter.shouldBackgroundReloadRecord(
1155
+ this,
1156
+ (snapshot = snapshot || this._instanceCache.createSnapshot(identifier, options))
1157
+ ))
1100
1158
  ) {
1101
1159
  assertIdentifierHasId(identifier);
1102
1160
  this._fetchManager.scheduleFetch(identifier, options);
@@ -1107,7 +1165,11 @@ class Store extends Service {
1107
1165
  }
1108
1166
  }
1109
1167
 
1110
- return promiseRecord(this, promise, `DS: Store#findRecord ${identifier}`);
1168
+ if (DEPRECATE_PROMISE_PROXIES) {
1169
+ return promiseRecord(this, promise);
1170
+ }
1171
+
1172
+ return promise.then((identifier: StableRecordIdentifier) => this.peekRecord(identifier));
1111
1173
  }
1112
1174
 
1113
1175
  /**
@@ -1338,8 +1400,8 @@ class Store extends Service {
1338
1400
  decoded: "/api/v1/person?ids[]=1&ids[]=2&ids[]=3"
1339
1401
  ```
1340
1402
 
1341
- This method returns a promise, which is resolved with an
1342
- [`AdapterPopulatedRecordArray`](/ember-data/release/classes/AdapterPopulatedRecordArray)
1403
+ This method returns a promise, which is resolved with a
1404
+ [`Collection`](/ember-data/release/classes/Collection)
1343
1405
  once the server returns.
1344
1406
 
1345
1407
  @since 1.13.0
@@ -1350,7 +1412,7 @@ class Store extends Service {
1350
1412
  @param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.query
1351
1413
  @return {Promise} promise
1352
1414
  */
1353
- query(modelName: string, query, options): PromiseArray<RecordInstance, AdapterPopulatedRecordArray> {
1415
+ query(modelName: string, query, options): PromiseArray<RecordInstance, Collection> | Promise<Collection> {
1354
1416
  if (DEBUG) {
1355
1417
  assertDestroyingStore(this, 'query');
1356
1418
  }
@@ -1384,9 +1446,12 @@ class Store extends Service {
1384
1446
  query,
1385
1447
  recordArray,
1386
1448
  adapterOptionsWrapper
1387
- ) as unknown as Promise<AdapterPopulatedRecordArray>;
1449
+ ) as unknown as Promise<Collection>;
1388
1450
 
1389
- return promiseArray(queryPromise);
1451
+ if (DEPRECATE_PROMISE_PROXIES) {
1452
+ return promiseArray(queryPromise);
1453
+ }
1454
+ return queryPromise;
1390
1455
  }
1391
1456
 
1392
1457
  /**
@@ -1487,7 +1552,11 @@ class Store extends Service {
1487
1552
  @param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.queryRecord
1488
1553
  @return {Promise} promise which resolves with the found record or `null`
1489
1554
  */
1490
- queryRecord(modelName: string, query, options?): PromiseObject<RecordInstance | null> {
1555
+ queryRecord(
1556
+ modelName: string,
1557
+ query,
1558
+ options?
1559
+ ): PromiseObject<RecordInstance | null> | Promise<RecordInstance | null> {
1491
1560
  if (DEBUG) {
1492
1561
  assertDestroyingStore(this, 'queryRecord');
1493
1562
  }
@@ -1520,7 +1589,10 @@ class Store extends Service {
1520
1589
  adapterOptionsWrapper
1521
1590
  ) as Promise<StableRecordIdentifier | null>;
1522
1591
 
1523
- return promiseObject(promise.then((identifier) => identifier && this.peekRecord(identifier)));
1592
+ if (DEPRECATE_PROMISE_PROXIES) {
1593
+ return promiseObject(promise.then((identifier) => identifier && this.peekRecord(identifier)));
1594
+ }
1595
+ return promise.then((identifier) => identifier && this.peekRecord(identifier));
1524
1596
  }
1525
1597
 
1526
1598
  /**
@@ -1714,7 +1786,7 @@ class Store extends Service {
1714
1786
  findAll(
1715
1787
  modelName: string,
1716
1788
  options: { reload?: boolean; backgroundReload?: boolean } = {}
1717
- ): PromiseArray<RecordInstance, RecordArray> {
1789
+ ): PromiseArray<RecordInstance, IdentifierArray> {
1718
1790
  if (DEBUG) {
1719
1791
  assertDestroyingStore(this, 'findAll');
1720
1792
  }
@@ -1740,7 +1812,7 @@ class Store extends Service {
1740
1812
  array.isUpdating = true;
1741
1813
  fetch = _findAll(adapter, this, normalizedModelName, options);
1742
1814
  } else {
1743
- let snapshotArray = array._createSnapshot(options);
1815
+ let snapshotArray = new SnapshotRecordArray(this, array, options);
1744
1816
 
1745
1817
  if (options.reload !== false) {
1746
1818
  if (
@@ -1748,7 +1820,7 @@ class Store extends Service {
1748
1820
  (!adapter.shouldReloadAll && snapshotArray.length === 0)
1749
1821
  ) {
1750
1822
  array.isUpdating = true;
1751
- fetch = _findAll(adapter, this, modelName, options);
1823
+ fetch = _findAll(adapter, this, modelName, options, snapshotArray);
1752
1824
  }
1753
1825
  }
1754
1826
 
@@ -1761,14 +1833,17 @@ class Store extends Service {
1761
1833
  adapter.shouldBackgroundReloadAll(this, snapshotArray)
1762
1834
  ) {
1763
1835
  array.isUpdating = true;
1764
- _findAll(adapter, this, modelName, options);
1836
+ _findAll(adapter, this, modelName, options, snapshotArray);
1765
1837
  }
1766
1838
 
1767
1839
  fetch = resolve(array);
1768
1840
  }
1769
1841
  }
1770
1842
 
1771
- return promiseArray(fetch);
1843
+ if (DEPRECATE_PROMISE_PROXIES) {
1844
+ return promiseArray(fetch);
1845
+ }
1846
+ return fetch;
1772
1847
  }
1773
1848
 
1774
1849
  /**
@@ -1796,7 +1871,7 @@ class Store extends Service {
1796
1871
  @param {String} modelName
1797
1872
  @return {RecordArray}
1798
1873
  */
1799
- peekAll(modelName) {
1874
+ peekAll(modelName: string): IdentifierArray {
1800
1875
  if (DEBUG) {
1801
1876
  assertDestroyingStore(this, 'peekAll');
1802
1877
  }
@@ -1805,8 +1880,9 @@ class Store extends Service {
1805
1880
  `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`,
1806
1881
  typeof modelName === 'string'
1807
1882
  );
1808
- let normalizedModelName = normalizeModelName(modelName);
1809
- return this.recordArrayManager.liveRecordArrayFor(normalizedModelName);
1883
+
1884
+ let type = normalizeModelName(modelName);
1885
+ return this.recordArrayManager.liveArrayFor(type);
1810
1886
  }
1811
1887
 
1812
1888
  /**
@@ -1833,24 +1909,29 @@ class Store extends Service {
1833
1909
  !modelName || typeof modelName === 'string'
1834
1910
  );
1835
1911
 
1836
- if (modelName === undefined) {
1837
- // destroy the graph before unloadAll
1838
- // since then we avoid churning relationships
1839
- // during unload
1840
- if (HAS_RECORD_DATA_PACKAGE) {
1841
- const peekGraph = (
1842
- importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
1843
- ).peekGraph;
1844
- let graph = peekGraph(this);
1845
- if (graph) {
1846
- graph.identifiers.clear();
1912
+ this._join(() => {
1913
+ if (modelName === undefined) {
1914
+ // destroy the graph before unloadAll
1915
+ // since then we avoid churning relationships
1916
+ // during unload
1917
+ if (HAS_RECORD_DATA_PACKAGE) {
1918
+ const peekGraph = (
1919
+ importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
1920
+ ).peekGraph;
1921
+ let graph = peekGraph(this);
1922
+ if (graph) {
1923
+ graph.identifiers.clear();
1924
+ }
1847
1925
  }
1926
+ this._notificationManager.destroy();
1927
+
1928
+ this.recordArrayManager.clear();
1929
+ this._instanceCache.clear();
1930
+ } else {
1931
+ let normalizedModelName = normalizeModelName(modelName);
1932
+ this._instanceCache.clear(normalizedModelName);
1848
1933
  }
1849
- this._instanceCache.clear();
1850
- } else {
1851
- let normalizedModelName = normalizeModelName(modelName);
1852
- this._instanceCache.clear(normalizedModelName);
1853
- }
1934
+ });
1854
1935
  }
1855
1936
 
1856
1937
  /**
@@ -2038,7 +2119,8 @@ class Store extends Service {
2038
2119
  if (DEBUG) {
2039
2120
  assertDestroyingStore(this, '_push');
2040
2121
  }
2041
- let identifiers = this._backburner.join(() => {
2122
+ let ret;
2123
+ this._join(() => {
2042
2124
  let included = jsonApiDoc.included;
2043
2125
  let i, length;
2044
2126
 
@@ -2055,11 +2137,13 @@ class Store extends Service {
2055
2137
  for (i = 0; i < length; i++) {
2056
2138
  identifiers[i] = this._instanceCache.loadData(jsonApiDoc.data[i]);
2057
2139
  }
2058
- return identifiers;
2140
+ ret = identifiers;
2141
+ return;
2059
2142
  }
2060
2143
 
2061
2144
  if (jsonApiDoc.data === null) {
2062
- return null;
2145
+ ret = null;
2146
+ return;
2063
2147
  }
2064
2148
 
2065
2149
  assert(
@@ -2069,11 +2153,11 @@ class Store extends Service {
2069
2153
  typeof jsonApiDoc.data === 'object'
2070
2154
  );
2071
2155
 
2072
- return this._instanceCache.loadData(jsonApiDoc.data);
2156
+ ret = this._instanceCache.loadData(jsonApiDoc.data);
2157
+ return;
2073
2158
  });
2074
2159
 
2075
- // this typecast is necessary because `backburner.join` is mistyped to return void
2076
- return identifiers;
2160
+ return ret;
2077
2161
  }
2078
2162
 
2079
2163
  /**
@@ -2228,7 +2312,7 @@ class Store extends Service {
2228
2312
  have an outer run loop available still from the first
2229
2313
  call to `store._push`;
2230
2314
  */
2231
- this._backburner.join(() => {
2315
+ this._join(() => {
2232
2316
  if (DEBUG) {
2233
2317
  assertDestroyingStore(this, 'saveRecord');
2234
2318
  }
@@ -2250,7 +2334,10 @@ class Store extends Service {
2250
2334
  //We first make sure the primary data has been updated
2251
2335
  const recordData = this._instanceCache.getRecordData(actualIdentifier);
2252
2336
  recordData.didCommit(identifier, data);
2253
- this.recordArrayManager.recordDidChange(actualIdentifier);
2337
+
2338
+ if (operation === 'deleteRecord') {
2339
+ this.recordArrayManager.identifierRemoved(actualIdentifier);
2340
+ }
2254
2341
 
2255
2342
  if (payload && payload.included) {
2256
2343
  this._push({ data: null, included: payload.included });
@@ -2315,17 +2402,11 @@ class Store extends Service {
2315
2402
  storeWrapper = arguments[3];
2316
2403
  }
2317
2404
 
2318
- if (V2CACHE_SINGLETON_RECORD_DATA) {
2319
- // @ts-expect-error
2320
- this.__private_singleton_recordData = this.__private_singleton_recordData || new _RecordData(storeWrapper);
2321
- (
2322
- this.__private_singleton_recordData as RecordData & { createCache(identifier: StableRecordIdentifier): void }
2323
- ).createCache(identifier);
2324
- return this.__private_singleton_recordData;
2325
- }
2326
-
2327
- // @ts-expect-error
2328
- return new _RecordData(identifier, storeWrapper);
2405
+ this.__private_singleton_recordData = this.__private_singleton_recordData || new _RecordData(storeWrapper);
2406
+ (
2407
+ this.__private_singleton_recordData as RecordData & { createCache(identifier: StableRecordIdentifier): void }
2408
+ ).createCache(identifier);
2409
+ return this.__private_singleton_recordData;
2329
2410
  }
2330
2411
 
2331
2412
  assert(`Expected store.createRecordDataFor to be implemented but it wasn't`);
@@ -2532,16 +2613,6 @@ class Store extends Service {
2532
2613
  this.recordArrayManager.destroy();
2533
2614
  this.identifierCache.destroy();
2534
2615
 
2535
- if (HAS_RECORD_DATA_PACKAGE) {
2536
- const peekGraph = (
2537
- importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
2538
- ).peekGraph;
2539
- let graph = peekGraph(this);
2540
- if (graph) {
2541
- graph.willDestroy();
2542
- }
2543
- }
2544
-
2545
2616
  this.unloadAll();
2546
2617
 
2547
2618
  if (DEBUG) {
@@ -2758,12 +2829,25 @@ function extractIdentifierFromRecord(
2758
2829
  }
2759
2830
  const extract = isForV1 ? recordDataFor : recordIdentifierFor;
2760
2831
 
2761
- if (isPromiseRecord(recordOrPromiseRecord)) {
2832
+ if (DEPRECATE_PROMISE_PROXIES && isPromiseRecord(recordOrPromiseRecord)) {
2762
2833
  let content = recordOrPromiseRecord.content;
2763
2834
  assert(
2764
2835
  'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.',
2765
2836
  content !== undefined
2766
2837
  );
2838
+ deprecate(
2839
+ `You passed in a PromiseProxy to a Relationship API that now expects a resolved value. await the value before setting it.`,
2840
+ false,
2841
+ {
2842
+ id: 'ember-data:deprecate-promise-proxies',
2843
+ until: '5.0',
2844
+ since: {
2845
+ enabled: '4.8',
2846
+ available: '4.8',
2847
+ },
2848
+ for: 'ember-data',
2849
+ }
2850
+ );
2767
2851
  return content ? extract(content) : null;
2768
2852
  }
2769
2853
 
@@ -2773,3 +2857,14 @@ function extractIdentifierFromRecord(
2773
2857
  function isPromiseRecord(record: PromiseProxyRecord | RecordInstance): record is PromiseProxyRecord {
2774
2858
  return !!record.then;
2775
2859
  }
2860
+
2861
+ function secretInit(
2862
+ record: RecordInstance,
2863
+ recordData: RecordData,
2864
+ identifier: StableRecordIdentifier,
2865
+ store: Store
2866
+ ): void {
2867
+ setRecordIdentifier(record, identifier);
2868
+ StoreMap.set(record, store);
2869
+ setRecordDataFor(record, recordData);
2870
+ }
@@ -1,3 +1,3 @@
1
1
  export default function isNonEmptyString(str: any): str is string {
2
- return typeof str === 'string' && str.length > 0;
2
+ return str && typeof str === 'string';
3
3
  }
@@ -7,10 +7,9 @@ import type Store from '../store-service';
7
7
 
8
8
  export default function promiseRecord(
9
9
  store: Store,
10
- promise: Promise<StableRecordIdentifier>,
11
- label?: string
10
+ promise: Promise<StableRecordIdentifier>
12
11
  ): PromiseObject<RecordInstance> {
13
12
  let toReturn = promise.then((identifier: StableRecordIdentifier) => store.peekRecord(identifier)!);
14
13
 
15
- return promiseObject(toReturn, label);
14
+ return promiseObject(toReturn);
16
15
  }