@ember-data/store 4.12.0-beta.7 → 4.12.0-beta.8

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.
package/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (C) 2017-2022 Ember.js contributors
3
+ Copyright (C) 2017-2023 Ember.js contributors
4
4
  Portions Copyright (C) 2011-2017 Tilde, Inc. and contributors.
5
5
  Portions Copyright (C) 2011 LivingSocial Inc.
6
6
 
package/addon/-private.js CHANGED
@@ -1 +1 @@
1
- export { f as AdapterPopulatedRecordArray, C as CacheHandler, j as IDENTIFIER_ARRAY_TAG, I as IdentifierArray, M as MUTATE, I as RecordArray, R as RecordArrayManager, h as SOURCE, S as Store, _ as _clearCaches, e as coerceId, k as fastPush, i as isStableIdentifier, n as normalizeModelName, g as notifyArray, p as peekCache, r as recordIdentifierFor, l as removeRecordDataFor, c as setIdentifierForgetMethod, a as setIdentifierGenerationMethod, d as setIdentifierResetMethod, b as setIdentifierUpdateMethod, s as storeFor } from "./index-f7d3d5e5";
1
+ export { f as AdapterPopulatedRecordArray, C as CacheHandler, j as IDENTIFIER_ARRAY_TAG, I as IdentifierArray, M as MUTATE, I as RecordArray, R as RecordArrayManager, h as SOURCE, S as Store, _ as _clearCaches, e as coerceId, k as fastPush, i as isStableIdentifier, n as normalizeModelName, g as notifyArray, p as peekCache, r as recordIdentifierFor, l as removeRecordDataFor, c as setIdentifierForgetMethod, a as setIdentifierGenerationMethod, d as setIdentifierResetMethod, b as setIdentifierUpdateMethod, s as storeFor } from "./index-0d52354f";
@@ -35,6 +35,111 @@ import ObjectProxy from '@ember/object/proxy';
35
35
  function normalizeModelName$1(modelName) {
36
36
  return dasherize(modelName);
37
37
  }
38
+ function getHydratedContent(store, request, document) {
39
+ if (Array.isArray(document.data)) {
40
+ const {
41
+ lid
42
+ } = document;
43
+ const {
44
+ recordArrayManager
45
+ } = store;
46
+ if (!lid) {
47
+ return recordArrayManager.createArray({
48
+ identifiers: document.data,
49
+ doc: document,
50
+ query: request
51
+ });
52
+ }
53
+ let managed = recordArrayManager._keyedArrays.get(lid);
54
+ if (!managed) {
55
+ managed = recordArrayManager.createArray({
56
+ identifiers: document.data,
57
+ doc: document
58
+ });
59
+ recordArrayManager._keyedArrays.set(lid, managed);
60
+ } else {
61
+ recordArrayManager.populateManagedArray(managed, document.data, document);
62
+ }
63
+ return managed;
64
+ } else {
65
+ return Object.assign({}, document, {
66
+ data: document.data ? store.peekRecord(document.data) : null
67
+ });
68
+ }
69
+ }
70
+ function calcShouldFetch(store, request, hasCachedValue, identifier) {
71
+ const {
72
+ cacheOptions
73
+ } = request;
74
+ return cacheOptions?.reload || !hasCachedValue || (store.lifetimes && identifier ? store.lifetimes.isHardExpired(identifier) : false);
75
+ }
76
+ function calcShouldBackgroundFetch(store, request, willFetch, identifier) {
77
+ const {
78
+ cacheOptions
79
+ } = request;
80
+ return !willFetch && (cacheOptions?.backgroundReload || (store.lifetimes && identifier ? store.lifetimes.isSoftExpired(identifier) : false));
81
+ }
82
+ function fetchContentAndHydrate(next, context, shouldFetch, shouldBackgroundFetch) {
83
+ const {
84
+ store
85
+ } = context.request;
86
+ const shouldHydrate = context.request[Symbol.for('ember-data:enable-hydration')] || false;
87
+ return next(context.request).then(document => {
88
+ store._enableAsyncFlush = true;
89
+ let response;
90
+ store._join(() => {
91
+ response = store.cache.put(document);
92
+ if (shouldFetch && shouldHydrate) {
93
+ response = getHydratedContent(store, context.request, response);
94
+ }
95
+ });
96
+ store._enableAsyncFlush = null;
97
+ if (shouldFetch) {
98
+ return response;
99
+ }
100
+ }, error => {
101
+ store._enableAsyncFlush = true;
102
+ store._join(() => {
103
+ store.cache.put(error);
104
+ });
105
+ store._enableAsyncFlush = null;
106
+
107
+ // TODO @runspired this is probably not the right thing to throw so make sure we add a test
108
+ if (!shouldBackgroundFetch) {
109
+ throw error;
110
+ }
111
+ });
112
+ }
113
+ const SkipCache = Symbol.for('ember-data:skip-cache');
114
+ const EnableHydration = Symbol.for('ember-data:enable-hydration');
115
+ const CacheHandler = {
116
+ request(context, next) {
117
+ // if we have no cache or no cache-key skip cache handling
118
+ if (!context.request.store || context.request.cacheOptions?.[SkipCache]) {
119
+ return next(context.request);
120
+ }
121
+ const {
122
+ store
123
+ } = context.request;
124
+ const identifier = store.identifierCache.getOrCreateDocumentIdentifier(context.request);
125
+ const peeked = identifier ? store.cache.peekRequest(identifier) : null;
126
+
127
+ // determine if we should skip cache
128
+ if (calcShouldFetch(store, context.request, !!peeked, identifier)) {
129
+ return fetchContentAndHydrate(next, context, true, false);
130
+ }
131
+
132
+ // if we have not skipped cache, determine if we should update behind the scenes
133
+ if (calcShouldBackgroundFetch(store, context.request, false, identifier)) {
134
+ void fetchContentAndHydrate(next, context, false, true);
135
+ }
136
+ if ('error' in peeked) {
137
+ throw peeked.error;
138
+ }
139
+ const shouldHydrate = context.request[EnableHydration] || false;
140
+ return Promise.resolve(shouldHydrate ? getHydratedContent(store, context.request, peeked.content) : peeked.content);
141
+ }
142
+ };
38
143
 
39
144
  /*
40
145
  * Returns the Cache instance associated with a given
@@ -145,9 +250,13 @@ function installPolyfill() {
145
250
  @module @ember-data/store
146
251
  */
147
252
  const IDENTIFIERS = new Set();
253
+ const DOCUMENTS = new Set();
148
254
  function isStableIdentifier(identifier) {
149
255
  return IDENTIFIERS.has(identifier);
150
256
  }
257
+ function isDocumentIdentifier(identifier) {
258
+ return DOCUMENTS.has(identifier);
259
+ }
151
260
  const isFastBoot = typeof FastBoot !== 'undefined';
152
261
  const _crypto = isFastBoot ? FastBoot.require('crypto') : window.crypto;
153
262
  if (macroCondition(getOwnConfig().polyfillUUID)) {
@@ -180,20 +289,31 @@ function setIdentifierResetMethod(method) {
180
289
  configuredResetMethod = method;
181
290
  }
182
291
  function defaultGenerationMethod(data, bucket) {
183
- if (isNonEmptyString(data.lid)) {
184
- return data.lid;
185
- }
186
- if (data.id !== undefined) {
187
- let {
188
- type,
189
- id
190
- } = data;
191
- // TODO: add test for id not a string
192
- if (isNonEmptyString(coerceId(id))) {
193
- return `@lid:${normalizeModelName$1(type)}-${id}`;
292
+ if (bucket === 'record') {
293
+ if (isNonEmptyString(data.lid)) {
294
+ return data.lid;
295
+ }
296
+ if (data.id !== undefined) {
297
+ let {
298
+ type,
299
+ id
300
+ } = data;
301
+ // TODO: add test for id not a string
302
+ if (isNonEmptyString(coerceId(id))) {
303
+ return `@lid:${normalizeModelName$1(type)}-${id}`;
304
+ }
305
+ }
306
+ return uuidv4();
307
+ } else if (bucket === 'document') {
308
+ if (!data.url) {
309
+ return null;
194
310
  }
311
+ if (!data.method || data.method.toUpperCase() === 'GET') {
312
+ return data.url;
313
+ }
314
+ return null;
195
315
  }
196
- return uuidv4();
316
+ assert(`Unknown bucket ${bucket}`, false);
197
317
  }
198
318
  function defaultEmptyCallback(...args) {}
199
319
  let DEBUG_MAP;
@@ -218,7 +338,8 @@ class IdentifierCache {
218
338
  constructor() {
219
339
  this._cache = {
220
340
  lids: new Map(),
221
- types: Object.create(null)
341
+ types: Object.create(null),
342
+ documents: new Map()
222
343
  };
223
344
  // we cache the user configuredGenerationMethod at init because it must
224
345
  // be configured prior and is not allowed to be changed
@@ -392,6 +513,36 @@ class IdentifierCache {
392
513
  return this._getRecordIdentifier(resource, false);
393
514
  }
394
515
 
516
+ /**
517
+ Returns the DocumentIdentifier for the given Request, creates one if it does not yet exist.
518
+ Returns `null` if the request does not have a `cacheKey` or `url`.
519
+ @method getOrCreateDocumentIdentifier
520
+ @param request
521
+ @returns {StableDocumentIdentifier | null}
522
+ @public
523
+ */
524
+ getOrCreateDocumentIdentifier(request) {
525
+ let cacheKey = request.cacheOptions?.key;
526
+ if (!cacheKey) {
527
+ cacheKey = this._generate(request, 'document');
528
+ }
529
+ if (!cacheKey) {
530
+ return null;
531
+ }
532
+ let identifier = this._cache.documents.get(cacheKey);
533
+ if (identifier === undefined) {
534
+ identifier = {
535
+ lid: cacheKey
536
+ };
537
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
538
+ Object.freeze(identifier);
539
+ }
540
+ DOCUMENTS.add(identifier);
541
+ this._cache.documents.set(cacheKey, identifier);
542
+ }
543
+ return identifier;
544
+ }
545
+
395
546
  /**
396
547
  Returns the Identifier for the given Resource, creates one if it does not yet exist.
397
548
  Specifically this means that we:
@@ -559,6 +710,9 @@ class IdentifierCache {
559
710
  }
560
711
  }
561
712
  destroy() {
713
+ this._cache.documents.forEach(identifier => {
714
+ DOCUMENTS.delete(identifier);
715
+ });
562
716
  this._reset();
563
717
  }
564
718
  }
@@ -792,8 +946,9 @@ class NotificationManager {
792
946
  * @param {NotificationCallback} callback
793
947
  * @returns {UnsubscribeToken} an opaque token to be used with unsubscribe
794
948
  */
949
+
795
950
  subscribe(identifier, callback) {
796
- assert(`Expected to receive a stable Identifier to subscribe to`, identifier === 'resource' || identifier === 'document' || isStableIdentifier(identifier));
951
+ assert(`Expected to receive a stable Identifier to subscribe to`, identifier === 'resource' || identifier === 'document' || isStableIdentifier(identifier) || isDocumentIdentifier(identifier));
797
952
  let map = Cache.get(identifier);
798
953
  if (!map) {
799
954
  map = new Map();
@@ -833,7 +988,7 @@ class NotificationManager {
833
988
 
834
989
  notify(identifier, value, key) {
835
990
  assert(`Notify does not accept a key argument for the namespace '${value}'. Received key '${key || ''}'.`, !key || value === 'attributes' || value === 'relationships');
836
- if (!isStableIdentifier(identifier)) {
991
+ if (!isStableIdentifier(identifier) && !isDocumentIdentifier(identifier)) {
837
992
  if (macroCondition(getOwnConfig().debug.LOG_NOTIFICATIONS)) {
838
993
  // eslint-disable-next-line no-console
839
994
  console.log(`Notifying: Expected to receive a stable Identifier to notify '${value}' '${key || ''}' with, but ${String(identifier)} is not in the cache`, identifier);
@@ -842,7 +997,7 @@ class NotificationManager {
842
997
  }
843
998
  if (macroCondition(getOwnConfig().debug.LOG_NOTIFICATIONS)) {
844
999
  // eslint-disable-next-line no-console
845
- console.log(`Buffering Notify: ${String(identifier)}\t${value}\t${key || ''}`);
1000
+ console.log(`Buffering Notify: ${String(identifier.lid)}\t${value}\t${key || ''}`);
846
1001
  }
847
1002
  const hasSubscribers = Boolean(Cache.get(identifier)?.size);
848
1003
  if (isCacheOperationValue(value) || hasSubscribers) {
@@ -894,7 +1049,7 @@ class NotificationManager {
894
1049
 
895
1050
  // TODO for documents this will need to switch based on Identifier kind
896
1051
  if (isCacheOperationValue(value)) {
897
- let callbackMap = Cache.get('resource');
1052
+ let callbackMap = Cache.get(isDocumentIdentifier(identifier) ? 'document' : 'resource');
898
1053
  if (callbackMap) {
899
1054
  callbackMap.forEach(cb => {
900
1055
  cb(identifier, value);
@@ -2273,7 +2428,7 @@ class LegacyWrapper {
2273
2428
  });
2274
2429
  }
2275
2430
  notifyChange(identifier, namespace, key) {
2276
- assert(`Expected a stable identifier`, isStableIdentifier(identifier));
2431
+ assert(`Expected a stable identifier`, isStableIdentifier(identifier) || isDocumentIdentifier(identifier));
2277
2432
 
2278
2433
  // TODO do we still get value from this?
2279
2434
  if (namespace === 'relationships' && key) {
@@ -2540,7 +2695,7 @@ class V2CacheStoreWrapper {
2540
2695
  });
2541
2696
  }
2542
2697
  notifyChange(identifier, namespace, key) {
2543
- assert(`Expected a stable identifier`, isStableIdentifier(identifier));
2698
+ assert(`Expected a stable identifier`, isStableIdentifier(identifier) || isDocumentIdentifier(identifier));
2544
2699
 
2545
2700
  // TODO do we still get value from this?
2546
2701
  if (namespace === 'relationships' && key) {
@@ -4712,75 +4867,18 @@ class Store {
4712
4867
  */
4713
4868
 
4714
4869
  /**
4715
- * Provides access to the IdentifierCache instance
4716
- * for this store.
4717
- *
4718
- * The IdentifierCache can be used to generate or
4719
- * retrieve a stable unique identifier for any resource.
4720
- *
4721
- * @property {IdentifierCache} identifierCache
4722
- * @public
4723
- */
4724
-
4725
- /**
4726
- * Provides access to the requestManager instance associated
4727
- * with this Store instance.
4728
- *
4729
- * When using `ember-data` this property is automatically
4730
- * set to an instance of `RequestManager`. When not using `ember-data`
4731
- * you must configure this property yourself, either by declaring
4732
- * it as a service or by initializing it.
4733
- *
4734
- * ```ts
4735
- * import Store, { CacheHandler } from '@ember-data/store';
4736
- * import RequestManager from '@ember-data/request';
4737
- * import Fetch from '@ember/data/request/fetch';
4738
- *
4739
- * class extends Store {
4740
- * constructor() {
4741
- * super(...arguments);
4742
- * this.requestManager = new RequestManager();
4743
- * this.requestManager.use([Fetch]);
4744
- * this.requestManager.useCache(CacheHandler);
4745
- * }
4746
- * }
4747
- * ```
4748
- *
4749
- * @public
4750
- * @property {RequestManager} requestManager
4751
- */
4752
-
4753
- /**
4754
- * A Property which an App may set to provide a Lifetimes Service
4755
- * to control when a cached request becomes stale.
4756
- *
4757
- * Note, when defined, these methods will only be invoked if `key` `url` and `method`
4758
- * are all present.
4759
- *
4760
- * `isSoftExpired` will only be invoked if `isHardExpired` returns `false`.
4761
- *
4762
- * ```ts
4763
- * store.lifetimes = {
4764
- * // make the request and ignore the current cache state
4765
- * isHardExpired(key: string, url: string, method?: HTTPMethod): boolean {
4766
- * return false;
4767
- * }
4870
+ * Provides access to the SchemaService instance
4871
+ * for this Store instance.
4768
4872
  *
4769
- * // make the request in the background if true, return cache state
4770
- * isSoftExpired(key: string, url: string, method: HTTPMethod): boolean {
4771
- * return false;
4772
- * }
4773
- * }
4774
- * ```
4873
+ * The SchemaService can be used to query for
4874
+ * information about the schema of a resource.
4775
4875
  *
4876
+ * @property {SchemaService} schema
4776
4877
  * @public
4777
- * @property {LivetimesService|undefined} lifetimes
4778
4878
  */
4779
-
4780
- // Private
4781
-
4782
- // DEBUG-only properties
4783
-
4879
+ get schema() {
4880
+ return this.getSchemaDefinitionService();
4881
+ }
4784
4882
  /**
4785
4883
  @method init
4786
4884
  @private
@@ -4888,10 +4986,9 @@ class Store {
4888
4986
  // we lazily set the cache handler when we issue the first request
4889
4987
  // because constructor doesn't allow for this to run after
4890
4988
  // the user has had the chance to set the prop.
4891
- const storeSymbol = Symbol.for('ember-data:enable-hydration');
4892
4989
  let opts = {
4893
4990
  store: this,
4894
- [storeSymbol]: true
4991
+ [EnableHydration]: true
4895
4992
  };
4896
4993
  if (macroCondition(getOwnConfig().env.TESTING)) {
4897
4994
  if (this.DISABLE_WAITER) {
@@ -4994,25 +5091,27 @@ class Store {
4994
5091
  */
4995
5092
  getSchemaDefinitionService() {
4996
5093
  if (macroCondition(getOwnConfig().packages.HAS_MODEL_PACKAGE)) {
4997
- if (!this._schemaDefinitionService) {
5094
+ if (!this._schema) {
4998
5095
  // it is potentially a mistake for the RFC to have not enabled chaining these services, though highlander rule is nice.
4999
5096
  // what ember-m3 did via private API to allow both worlds to interop would be much much harder using this.
5000
- this._schemaDefinitionService = new DSModelSchemaDefinitionService(this);
5097
+ this._schema = new DSModelSchemaDefinitionService(this);
5001
5098
  }
5002
5099
  }
5003
- assert(`You must registerSchemaDefinitionService with the store to use custom model classes`, this._schemaDefinitionService);
5004
- return this._schemaDefinitionService;
5100
+ assert(`You must registerSchemaDefinitionService with the store to use custom model classes`, this._schema);
5101
+ return this._schema;
5005
5102
  }
5006
5103
 
5007
5104
  /**
5008
- * Allows an app to register a custom SchemaDefinitionService
5105
+ * DEPRECATED - Use `registerSchema` instead.
5106
+ *
5107
+ * Allows an app to register a custom SchemaService
5009
5108
  * for use when information about a resource's schema needs
5010
5109
  * to be queried.
5011
5110
  *
5012
5111
  * This method can only be called more than once, but only one schema
5013
5112
  * definition service may exist. Therefore if you wish to chain services
5014
5113
  * you must lookup the existing service and close over it with the new
5015
- * service by calling `getSchemaDefinitionService` prior to registration.
5114
+ * service by accessing `store.schema` prior to registration.
5016
5115
  *
5017
5116
  * For Example:
5018
5117
  *
@@ -5045,18 +5144,73 @@ class Store {
5045
5144
  * constructor(...args) {
5046
5145
  * super(...args);
5047
5146
  *
5048
- * const schema = this.getSchemaDefinitionService();
5147
+ * const schema = this.schema;
5049
5148
  * this.registerSchemaDefinitionService(new SchemaDelegator(schema));
5050
5149
  * }
5051
5150
  * }
5052
5151
  * ```
5053
5152
  *
5054
5153
  * @method registerSchemaDefinitionService
5055
- * @param {SchemaDefinitionService} schema
5154
+ * @param {SchemaService} schema
5155
+ * @deprecated
5056
5156
  * @public
5057
5157
  */
5058
5158
  registerSchemaDefinitionService(schema) {
5059
- this._schemaDefinitionService = schema;
5159
+ this._schema = schema;
5160
+ }
5161
+ /**
5162
+ * Allows an app to register a custom SchemaService
5163
+ * for use when information about a resource's schema needs
5164
+ * to be queried.
5165
+ *
5166
+ * This method can only be called more than once, but only one schema
5167
+ * definition service may exist. Therefore if you wish to chain services
5168
+ * you must lookup the existing service and close over it with the new
5169
+ * service by accessing `store.schema` prior to registration.
5170
+ *
5171
+ * For Example:
5172
+ *
5173
+ * ```ts
5174
+ * import Store from '@ember-data/store';
5175
+ *
5176
+ * class SchemaDelegator {
5177
+ * constructor(schema) {
5178
+ * this._schema = schema;
5179
+ * }
5180
+ *
5181
+ * doesTypeExist(type: string): boolean {
5182
+ * if (AbstractSchemas.has(type)) {
5183
+ * return true;
5184
+ * }
5185
+ * return this._schema.doesTypeExist(type);
5186
+ * }
5187
+ *
5188
+ * attributesDefinitionFor(identifier: RecordIdentifier | { type: string }): AttributesSchema {
5189
+ * return this._schema.attributesDefinitionFor(identifier);
5190
+ * }
5191
+ *
5192
+ * relationshipsDefinitionFor(identifier: RecordIdentifier | { type: string }): RelationshipsSchema {
5193
+ * const schema = AbstractSchemas.get(identifier.type);
5194
+ * return schema || this._schema.relationshipsDefinitionFor(identifier);
5195
+ * }
5196
+ * }
5197
+ *
5198
+ * export default class extends Store {
5199
+ * constructor(...args) {
5200
+ * super(...args);
5201
+ *
5202
+ * const schema = this.schema;
5203
+ * this.registerSchema(new SchemaDelegator(schema));
5204
+ * }
5205
+ * }
5206
+ * ```
5207
+ *
5208
+ * @method registerSchema
5209
+ * @param {SchemaService} schema
5210
+ * @public
5211
+ */
5212
+ registerSchema(schema) {
5213
+ this._schema = schema;
5060
5214
  }
5061
5215
 
5062
5216
  /**
@@ -5587,6 +5741,9 @@ class Store {
5587
5741
  data: {
5588
5742
  record: identifier,
5589
5743
  options
5744
+ },
5745
+ cacheOptions: {
5746
+ [SkipCache]: true
5590
5747
  }
5591
5748
  });
5592
5749
  if (macroCondition(getOwnConfig().deprecations.DEPRECATE_PROMISE_PROXIES)) {
@@ -5801,6 +5958,9 @@ class Store {
5801
5958
  type: normalizeModelName$1(modelName),
5802
5959
  query,
5803
5960
  options: options || {}
5961
+ },
5962
+ cacheOptions: {
5963
+ [SkipCache]: true
5804
5964
  }
5805
5965
  });
5806
5966
  if (macroCondition(getOwnConfig().deprecations.DEPRECATE_PROMISE_PROXIES)) {
@@ -5903,6 +6063,9 @@ class Store {
5903
6063
  type: normalizeModelName$1(modelName),
5904
6064
  query,
5905
6065
  options: options || {}
6066
+ },
6067
+ cacheOptions: {
6068
+ [SkipCache]: true
5906
6069
  }
5907
6070
  });
5908
6071
  if (macroCondition(getOwnConfig().deprecations.DEPRECATE_PROMISE_PROXIES)) {
@@ -6073,6 +6236,9 @@ class Store {
6073
6236
  data: {
6074
6237
  type: normalizeModelName$1(modelName),
6075
6238
  options: options || {}
6239
+ },
6240
+ cacheOptions: {
6241
+ [SkipCache]: true
6076
6242
  }
6077
6243
  });
6078
6244
  if (macroCondition(getOwnConfig().deprecations.DEPRECATE_PROMISE_PROXIES)) {
@@ -6461,6 +6627,9 @@ class Store {
6461
6627
  data: {
6462
6628
  options,
6463
6629
  record: identifier
6630
+ },
6631
+ cacheOptions: {
6632
+ [SkipCache]: true
6464
6633
  }
6465
6634
  }).then(document => document.content);
6466
6635
  }
@@ -6800,120 +6969,6 @@ function secretInit(record, cache, identifier, store) {
6800
6969
  StoreMap.set(record, store);
6801
6970
  setCacheFor(record, cache);
6802
6971
  }
6803
- function getHydratedContent(store, request, document) {
6804
- if (Array.isArray(document.data)) {
6805
- const {
6806
- lid
6807
- } = document;
6808
- const {
6809
- recordArrayManager
6810
- } = store;
6811
- if (!lid) {
6812
- return recordArrayManager.createArray({
6813
- identifiers: document.data,
6814
- doc: document,
6815
- query: request
6816
- });
6817
- }
6818
- let managed = recordArrayManager._keyedArrays.get(lid);
6819
- if (!managed) {
6820
- managed = recordArrayManager.createArray({
6821
- identifiers: document.data,
6822
- doc: document
6823
- });
6824
- recordArrayManager._keyedArrays.set(lid, managed);
6825
- } else {
6826
- recordArrayManager.populateManagedArray(managed, document.data, document);
6827
- }
6828
- return managed;
6829
- } else {
6830
- return Object.assign({}, document, {
6831
- data: document.data ? store.peekRecord(document.data) : null
6832
- });
6833
- }
6834
- }
6835
- function calcShouldFetch(store, request, hasCachedValue, lid) {
6836
- const {
6837
- cacheOptions,
6838
- url,
6839
- method
6840
- } = request;
6841
- return cacheOptions?.reload || !hasCachedValue || (store.lifetimes && lid && url && method ? store.lifetimes.isHardExpired(lid, url, method) : false);
6842
- }
6843
- function calcShouldBackgroundFetch(store, request, willFetch, lid) {
6844
- const {
6845
- cacheOptions,
6846
- url,
6847
- method
6848
- } = request;
6849
- return !willFetch && (cacheOptions?.backgroundReload || (store.lifetimes && lid && url && method ? store.lifetimes.isSoftExpired(lid, url, method) : false));
6850
- }
6851
- function fetchContentAndHydrate(next, context, shouldFetch, shouldBackgroundFetch) {
6852
- const {
6853
- store
6854
- } = context.request;
6855
- const shouldHydrate = context.request[Symbol.for('ember-data:enable-hydration')] || false;
6856
- return next(context.request).then(document => {
6857
- store._enableAsyncFlush = true;
6858
- let response;
6859
- store._join(() => {
6860
- response = store.cache.put(document);
6861
- if (shouldFetch && shouldHydrate) {
6862
- response = getHydratedContent(store, context.request, response);
6863
- }
6864
- });
6865
- store._enableAsyncFlush = null;
6866
- if (shouldFetch) {
6867
- return response;
6868
- }
6869
- }, error => {
6870
- store._enableAsyncFlush = true;
6871
- store._join(() => {
6872
- store.cache.put(error);
6873
- });
6874
- store._enableAsyncFlush = null;
6875
-
6876
- // TODO @runspired this is probably not the right thing to throw so make sure we add a test
6877
- if (!shouldBackgroundFetch) {
6878
- throw error;
6879
- }
6880
- });
6881
- }
6882
- const CacheHandler = {
6883
- request(context, next) {
6884
- // if we have no cache or no cache-key skip cache handling
6885
- if (!context.request.store || !(context.request.cacheOptions?.key || context.request.url)) {
6886
- return next(context.request);
6887
- }
6888
- const {
6889
- store
6890
- } = context.request;
6891
- const {
6892
- cacheOptions,
6893
- url,
6894
- method
6895
- } = context.request;
6896
- const lid = cacheOptions?.key || method === 'GET' && url ? url : null;
6897
- const peeked = lid ? store.cache.peekRequest({
6898
- lid
6899
- }) : null;
6900
-
6901
- // determine if we should skip cache
6902
- if (calcShouldFetch(store, context.request, !!peeked, lid)) {
6903
- return fetchContentAndHydrate(next, context, true, false);
6904
- }
6905
-
6906
- // if we have not skipped cache, determine if we should update behind the scenes
6907
- if (calcShouldBackgroundFetch(store, context.request, false, lid)) {
6908
- void fetchContentAndHydrate(next, context, false, true);
6909
- }
6910
- if ('error' in peeked) {
6911
- throw peeked.error;
6912
- }
6913
- const shouldHydrate = context.request[Symbol.for('ember-data:enable-hydration')] || false;
6914
- return Promise.resolve(shouldHydrate ? getHydratedContent(store, context.request, peeked.content) : peeked.content);
6915
- }
6916
- };
6917
6972
  function normalizeModelName(modelName) {
6918
6973
  if (macroCondition(getOwnConfig().deprecations.DEPRECATE_HELPERS)) {
6919
6974
  deprecate(`the helper function normalizeModelName is deprecated. You should use model names that are already normalized, or use string helpers of your own. This function is primarily an alias for dasherize from @ember/string.`, false, {