@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 +1 -1
- package/addon/-private.js +1 -1
- package/addon/{index-f7d3d5e5.js → index-0d52354f.js} +264 -209
- package/addon/index-0d52354f.js.map +1 -0
- package/addon/index.js +1 -1
- package/ember-data-logo-dark.svg +12 -0
- package/ember-data-logo-light.svg +12 -0
- package/package.json +14 -8
- package/addon/index-f7d3d5e5.js.map +0 -1
package/LICENSE.md
CHANGED
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-
|
|
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 (
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
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
|
|
4716
|
-
* for this
|
|
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
|
-
*
|
|
4770
|
-
*
|
|
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
|
-
|
|
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
|
-
[
|
|
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.
|
|
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.
|
|
5097
|
+
this._schema = new DSModelSchemaDefinitionService(this);
|
|
5001
5098
|
}
|
|
5002
5099
|
}
|
|
5003
|
-
assert(`You must registerSchemaDefinitionService with the store to use custom model classes`, this.
|
|
5004
|
-
return this.
|
|
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
|
-
*
|
|
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
|
|
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.
|
|
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 {
|
|
5154
|
+
* @param {SchemaService} schema
|
|
5155
|
+
* @deprecated
|
|
5056
5156
|
* @public
|
|
5057
5157
|
*/
|
|
5058
5158
|
registerSchemaDefinitionService(schema) {
|
|
5059
|
-
this.
|
|
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, {
|