@ember-data/store 5.4.0-beta.4 → 5.4.0-beta.6
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/README.md +8 -0
- package/addon-main.cjs +5 -0
- package/dist/-private.js +1 -0
- package/{addon/cache-handler-XLbbNJdo.js → dist/cache-handler-C5ilAUZ5.js} +1140 -657
- package/dist/cache-handler-C5ilAUZ5.js.map +1 -0
- package/{addon → dist}/index.js +4 -1
- package/{addon → dist}/index.js.map +1 -1
- package/dist/types.js +0 -0
- package/dist/types.js.map +1 -0
- package/package.json +48 -51
- package/unstable-preview-types/-private/cache-handler.d.ts +144 -0
- package/unstable-preview-types/-private/cache-handler.d.ts.map +1 -0
- package/unstable-preview-types/-private/caches/cache-utils.d.ts +11 -0
- package/unstable-preview-types/-private/caches/cache-utils.d.ts.map +1 -0
- package/unstable-preview-types/-private/caches/identifier-cache.d.ts +176 -0
- package/unstable-preview-types/-private/caches/identifier-cache.d.ts.map +1 -0
- package/unstable-preview-types/-private/caches/instance-cache.d.ts +61 -0
- package/unstable-preview-types/-private/caches/instance-cache.d.ts.map +1 -0
- package/unstable-preview-types/-private/caches/resource-utils.d.ts +12 -0
- package/unstable-preview-types/-private/caches/resource-utils.d.ts.map +1 -0
- package/unstable-preview-types/-private/document.d.ts +146 -0
- package/unstable-preview-types/-private/document.d.ts.map +1 -0
- package/unstable-preview-types/-private/legacy-model-support/record-reference.d.ts +179 -0
- package/unstable-preview-types/-private/legacy-model-support/record-reference.d.ts.map +1 -0
- package/unstable-preview-types/-private/legacy-model-support/shim-model-class.d.ts +19 -0
- package/unstable-preview-types/-private/legacy-model-support/shim-model-class.d.ts.map +1 -0
- package/unstable-preview-types/-private/managers/cache-capabilities-manager.d.ts +31 -0
- package/unstable-preview-types/-private/managers/cache-capabilities-manager.d.ts.map +1 -0
- package/unstable-preview-types/-private/managers/cache-manager.d.ts +441 -0
- package/unstable-preview-types/-private/managers/cache-manager.d.ts.map +1 -0
- package/unstable-preview-types/-private/managers/notification-manager.d.ts +96 -0
- package/unstable-preview-types/-private/managers/notification-manager.d.ts.map +1 -0
- package/unstable-preview-types/-private/managers/record-array-manager.d.ts +97 -0
- package/unstable-preview-types/-private/managers/record-array-manager.d.ts.map +1 -0
- package/unstable-preview-types/-private/network/request-cache.d.ts +109 -0
- package/unstable-preview-types/-private/network/request-cache.d.ts.map +1 -0
- package/unstable-preview-types/-private/record-arrays/identifier-array.d.ts +138 -0
- package/unstable-preview-types/-private/record-arrays/identifier-array.d.ts.map +1 -0
- package/unstable-preview-types/-private/record-arrays/native-proxy-type-fix.d.ts +118 -0
- package/unstable-preview-types/-private/record-arrays/native-proxy-type-fix.d.ts.map +1 -0
- package/unstable-preview-types/-private/store-service.d.ts +1522 -0
- package/unstable-preview-types/-private/store-service.d.ts.map +1 -0
- package/unstable-preview-types/-private/store-service.type-test.d.ts +4 -0
- package/unstable-preview-types/-private/store-service.type-test.d.ts.map +1 -0
- package/unstable-preview-types/-private/utils/coerce-id.d.ts +10 -0
- package/unstable-preview-types/-private/utils/coerce-id.d.ts.map +1 -0
- package/unstable-preview-types/-private/utils/construct-resource.d.ts +9 -0
- package/unstable-preview-types/-private/utils/construct-resource.d.ts.map +1 -0
- package/unstable-preview-types/-private/utils/is-non-empty-string.d.ts +4 -0
- package/unstable-preview-types/-private/utils/is-non-empty-string.d.ts.map +1 -0
- package/unstable-preview-types/-private/utils/normalize-model-name.d.ts +4 -0
- package/unstable-preview-types/-private/utils/normalize-model-name.d.ts.map +1 -0
- package/unstable-preview-types/-private/utils/uuid-polyfill.d.ts +4 -0
- package/unstable-preview-types/-private/utils/uuid-polyfill.d.ts.map +1 -0
- package/unstable-preview-types/-private.d.ts +25 -0
- package/unstable-preview-types/-private.d.ts.map +1 -0
- package/unstable-preview-types/-types/overview.d.ts +21 -0
- package/unstable-preview-types/-types/overview.d.ts.map +1 -0
- package/unstable-preview-types/-types/q/cache-capabilities-manager.d.ts +109 -0
- package/unstable-preview-types/-types/q/cache-capabilities-manager.d.ts.map +1 -0
- package/unstable-preview-types/-types/q/ds-model.d.ts +25 -0
- package/unstable-preview-types/-types/q/ds-model.d.ts.map +1 -0
- package/unstable-preview-types/-types/q/identifier.d.ts +193 -0
- package/unstable-preview-types/-types/q/identifier.d.ts.map +1 -0
- package/unstable-preview-types/-types/q/promise-proxies.d.ts +4 -0
- package/unstable-preview-types/-types/q/promise-proxies.d.ts.map +1 -0
- package/unstable-preview-types/-types/q/record-data-json-api.d.ts +36 -0
- package/unstable-preview-types/-types/q/record-data-json-api.d.ts.map +1 -0
- package/unstable-preview-types/-types/q/record-instance.d.ts +29 -0
- package/unstable-preview-types/-types/q/record-instance.d.ts.map +1 -0
- package/unstable-preview-types/-types/q/schema-service.d.ts +358 -0
- package/unstable-preview-types/-types/q/schema-service.d.ts.map +1 -0
- package/unstable-preview-types/-types/q/store.d.ts +38 -0
- package/unstable-preview-types/-types/q/store.d.ts.map +1 -0
- package/unstable-preview-types/index.d.ts +222 -0
- package/unstable-preview-types/index.d.ts.map +1 -0
- package/unstable-preview-types/types.d.ts +7 -0
- package/unstable-preview-types/types.d.ts.map +1 -0
- package/addon/-private.js +0 -1
- package/addon/cache-handler-XLbbNJdo.js.map +0 -1
- package/addon-main.js +0 -93
- /package/{addon → dist}/-private.js.map +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { deprecate,
|
|
2
|
-
import
|
|
1
|
+
import { deprecate, warn } from '@ember/debug';
|
|
2
|
+
import { macroCondition, getGlobalConfig, dependencySatisfies, importSync } from '@embroider/macros';
|
|
3
3
|
import { SkipCache, EnableHydration } from '@warp-drive/core-types/request';
|
|
4
|
-
import {
|
|
4
|
+
import { getOrSetGlobal, setTransient, peekTransient } from '@warp-drive/core-types/-private';
|
|
5
5
|
import { CACHE_OWNER, DEBUG_STALE_CACHE_OWNER, DEBUG_CLIENT_ORIGINATED, DEBUG_IDENTIFIER_BUCKET } from '@warp-drive/core-types/identifier';
|
|
6
|
-
import { dasherize } from '@ember/string';
|
|
7
|
-
import { defineSignal,
|
|
6
|
+
import { dasherize } from '@ember-data/request-utils/string';
|
|
7
|
+
import { defineSignal, createSignal, subscribe, createArrayTags, addToTransaction, addTransactionCB } from '@ember-data/tracking/-private';
|
|
8
8
|
import { _backburner } from '@ember/runloop';
|
|
9
9
|
import { compat } from '@ember-data/tracking';
|
|
10
10
|
|
|
@@ -13,7 +13,7 @@ import { compat } from '@ember-data/tracking';
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
function coerceId(id) {
|
|
16
|
-
if (macroCondition(
|
|
16
|
+
if (macroCondition(getGlobalConfig().WarpDrive.deprecations.DEPRECATE_NON_STRICT_ID)) {
|
|
17
17
|
let normalized;
|
|
18
18
|
if (id === null || id === undefined || id === '') {
|
|
19
19
|
normalized = null;
|
|
@@ -31,7 +31,11 @@ function coerceId(id) {
|
|
|
31
31
|
});
|
|
32
32
|
return normalized;
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
35
|
+
if (!test) {
|
|
36
|
+
throw new Error(`Resource IDs must be a non-empty string or null. Received '${String(id)}'.`);
|
|
37
|
+
}
|
|
38
|
+
})(id === null || typeof id === 'string' && id.length > 0) : {};
|
|
35
39
|
return id;
|
|
36
40
|
}
|
|
37
41
|
function ensureStringId(id) {
|
|
@@ -41,11 +45,15 @@ function ensureStringId(id) {
|
|
|
41
45
|
} else if (typeof id === 'number' && !isNaN(id)) {
|
|
42
46
|
normalized = String(id);
|
|
43
47
|
}
|
|
44
|
-
|
|
48
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
49
|
+
if (!test) {
|
|
50
|
+
throw new Error(`Expected id to be a string or number, received ${String(id)}`);
|
|
51
|
+
}
|
|
52
|
+
})(normalized !== null) : {};
|
|
45
53
|
return normalized;
|
|
46
54
|
}
|
|
47
55
|
function normalizeModelName(type) {
|
|
48
|
-
if (macroCondition(
|
|
56
|
+
if (macroCondition(getGlobalConfig().WarpDrive.deprecations.DEPRECATE_NON_STRICT_TYPES)) {
|
|
49
57
|
const result = dasherize(type);
|
|
50
58
|
deprecate(`The resource type '${type}' is not normalized. Update your application code to use '${result}' instead of '${type}'.`, result === type, {
|
|
51
59
|
id: 'ember-data:deprecate-non-strict-types',
|
|
@@ -121,8 +129,8 @@ function hasType(resource) {
|
|
|
121
129
|
/**
|
|
122
130
|
@module @ember-data/store
|
|
123
131
|
*/
|
|
124
|
-
const IDENTIFIERS = new Set();
|
|
125
|
-
const DOCUMENTS = new Set();
|
|
132
|
+
const IDENTIFIERS = getOrSetGlobal('IDENTIFIERS', new Set());
|
|
133
|
+
const DOCUMENTS = getOrSetGlobal('DOCUMENTS', new Set());
|
|
126
134
|
function isStableIdentifier(identifier) {
|
|
127
135
|
return identifier[CACHE_OWNER] !== undefined || IDENTIFIERS.has(identifier);
|
|
128
136
|
}
|
|
@@ -131,11 +139,15 @@ function isDocumentIdentifier(identifier) {
|
|
|
131
139
|
}
|
|
132
140
|
const isFastBoot = typeof FastBoot !== 'undefined';
|
|
133
141
|
const _crypto = isFastBoot ? FastBoot.require('crypto') : window.crypto;
|
|
134
|
-
if (macroCondition(
|
|
142
|
+
if (macroCondition(getGlobalConfig().WarpDrive.polyfillUUID)) {
|
|
135
143
|
installPolyfill();
|
|
136
144
|
}
|
|
137
145
|
function uuidv4() {
|
|
138
|
-
|
|
146
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
147
|
+
if (!test) {
|
|
148
|
+
throw new Error('crypto.randomUUID needs to be avaliable. Some browsers incorrectly disallow it in insecure contexts. You maybe want to enable the polyfill: https://github.com/emberjs/data#randomuuid-polyfill');
|
|
149
|
+
}
|
|
150
|
+
})(typeof _crypto.randomUUID === 'function') : {};
|
|
139
151
|
return _crypto.randomUUID();
|
|
140
152
|
}
|
|
141
153
|
function freeze(obj) {
|
|
@@ -148,26 +160,27 @@ function freeze(obj) {
|
|
|
148
160
|
// type IdentifierTypeLookup = { all: Set<StableRecordIdentifier>; id: Map<string, StableRecordIdentifier> };
|
|
149
161
|
// type IdentifiersByType = Map<string, IdentifierTypeLookup>;
|
|
150
162
|
|
|
151
|
-
let configuredForgetMethod;
|
|
152
|
-
let configuredGenerationMethod;
|
|
153
|
-
let configuredResetMethod;
|
|
154
|
-
let configuredUpdateMethod;
|
|
155
163
|
function setIdentifierGenerationMethod(method) {
|
|
156
|
-
configuredGenerationMethod
|
|
164
|
+
setTransient('configuredGenerationMethod', method);
|
|
157
165
|
}
|
|
158
166
|
function setIdentifierUpdateMethod(method) {
|
|
159
|
-
configuredUpdateMethod
|
|
167
|
+
setTransient('configuredUpdateMethod', method);
|
|
160
168
|
}
|
|
161
169
|
function setIdentifierForgetMethod(method) {
|
|
162
|
-
configuredForgetMethod
|
|
170
|
+
setTransient('configuredForgetMethod', method);
|
|
163
171
|
}
|
|
164
172
|
function setIdentifierResetMethod(method) {
|
|
165
|
-
configuredResetMethod
|
|
173
|
+
setTransient('configuredResetMethod', method);
|
|
174
|
+
}
|
|
175
|
+
function setKeyInfoForResource(method) {
|
|
176
|
+
setTransient('configuredKeyInfoMethod', method);
|
|
166
177
|
}
|
|
167
178
|
|
|
168
179
|
// Map<type, Map<id, lid>>
|
|
169
180
|
|
|
181
|
+
// TODO can we just delete this?
|
|
170
182
|
const NEW_IDENTIFIERS = new Map();
|
|
183
|
+
// TODO @runspired maybe needs peekTransient ?
|
|
171
184
|
let IDENTIFIER_CACHE_ID = 0;
|
|
172
185
|
function updateTypeIdMapping(typeMap, identifier, id) {
|
|
173
186
|
let idMap = typeMap.get(identifier.type);
|
|
@@ -179,7 +192,11 @@ function updateTypeIdMapping(typeMap, identifier, id) {
|
|
|
179
192
|
}
|
|
180
193
|
function defaultUpdateMethod(identifier, data, bucket) {
|
|
181
194
|
if (bucket === 'record') {
|
|
182
|
-
|
|
195
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
196
|
+
if (!test) {
|
|
197
|
+
throw new Error(`Expected identifier to be a StableRecordIdentifier`);
|
|
198
|
+
}
|
|
199
|
+
})(isStableIdentifier(identifier)) : {};
|
|
183
200
|
if (!identifier.id && hasId(data)) {
|
|
184
201
|
updateTypeIdMapping(NEW_IDENTIFIERS, identifier, data.id);
|
|
185
202
|
}
|
|
@@ -189,7 +206,11 @@ function defaultKeyInfoMethod(resource, known) {
|
|
|
189
206
|
// TODO RFC something to make this configurable
|
|
190
207
|
const id = hasId(resource) ? coerceId(resource.id) : null;
|
|
191
208
|
const type = hasType(resource) ? normalizeModelName(resource.type) : known ? known.type : null;
|
|
192
|
-
|
|
209
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
210
|
+
if (!test) {
|
|
211
|
+
throw new Error(`Expected keyInfoForResource to provide a type for the resource`);
|
|
212
|
+
}
|
|
213
|
+
})(type) : {};
|
|
193
214
|
return {
|
|
194
215
|
type,
|
|
195
216
|
id
|
|
@@ -200,7 +221,11 @@ function defaultGenerationMethod(data, bucket) {
|
|
|
200
221
|
if (hasLid(data)) {
|
|
201
222
|
return data.lid;
|
|
202
223
|
}
|
|
203
|
-
|
|
224
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
225
|
+
if (!test) {
|
|
226
|
+
throw new Error(`Cannot generate an identifier for a resource without a type`);
|
|
227
|
+
}
|
|
228
|
+
})(hasType(data)) : {};
|
|
204
229
|
if (hasId(data)) {
|
|
205
230
|
const type = normalizeModelName(data.type);
|
|
206
231
|
const lid = NEW_IDENTIFIERS.get(type)?.get(data.id);
|
|
@@ -216,15 +241,19 @@ function defaultGenerationMethod(data, bucket) {
|
|
|
216
241
|
}
|
|
217
242
|
return null;
|
|
218
243
|
}
|
|
219
|
-
|
|
244
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
245
|
+
{
|
|
246
|
+
throw new Error(`Unknown bucket ${bucket}`);
|
|
247
|
+
}
|
|
248
|
+
})() : {};
|
|
220
249
|
}
|
|
221
250
|
function defaultEmptyCallback(...args) {}
|
|
222
251
|
function defaultMergeMethod(a, _b, _c) {
|
|
223
252
|
return a;
|
|
224
253
|
}
|
|
225
254
|
let DEBUG_MAP;
|
|
226
|
-
if (macroCondition(
|
|
227
|
-
DEBUG_MAP = new WeakMap();
|
|
255
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
256
|
+
DEBUG_MAP = getOrSetGlobal('DEBUG_MAP', new WeakMap());
|
|
228
257
|
}
|
|
229
258
|
|
|
230
259
|
/**
|
|
@@ -244,13 +273,12 @@ class IdentifierCache {
|
|
|
244
273
|
constructor() {
|
|
245
274
|
// we cache the user configuredGenerationMethod at init because it must
|
|
246
275
|
// be configured prior and is not allowed to be changed
|
|
247
|
-
this._generate = configuredGenerationMethod || defaultGenerationMethod;
|
|
248
|
-
this._update = configuredUpdateMethod || defaultUpdateMethod;
|
|
249
|
-
this._forget = configuredForgetMethod || defaultEmptyCallback;
|
|
250
|
-
this._reset = configuredResetMethod || defaultEmptyCallback;
|
|
276
|
+
this._generate = peekTransient('configuredGenerationMethod') || defaultGenerationMethod;
|
|
277
|
+
this._update = peekTransient('configuredUpdateMethod') || defaultUpdateMethod;
|
|
278
|
+
this._forget = peekTransient('configuredForgetMethod') || defaultEmptyCallback;
|
|
279
|
+
this._reset = peekTransient('configuredResetMethod') || defaultEmptyCallback;
|
|
251
280
|
this._merge = defaultMergeMethod;
|
|
252
|
-
this._keyInfoForResource = defaultKeyInfoMethod;
|
|
253
|
-
this._isDefaultConfig = !configuredGenerationMethod;
|
|
281
|
+
this._keyInfoForResource = peekTransient('configuredKeyInfoMethod') || defaultKeyInfoMethod;
|
|
254
282
|
this._id = IDENTIFIER_CACHE_ID++;
|
|
255
283
|
this._cache = {
|
|
256
284
|
resources: new Map(),
|
|
@@ -282,19 +310,19 @@ class IdentifierCache {
|
|
|
282
310
|
*/
|
|
283
311
|
|
|
284
312
|
_getRecordIdentifier(resource, shouldGenerate) {
|
|
285
|
-
if (macroCondition(
|
|
313
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_IDENTIFIERS)) {
|
|
286
314
|
// eslint-disable-next-line no-console
|
|
287
315
|
console.groupCollapsed(`Identifiers: ${shouldGenerate ? 'Generating' : 'Peeking'} Identifier`, resource);
|
|
288
316
|
}
|
|
289
317
|
// short circuit if we're already the stable version
|
|
290
318
|
if (isStableIdentifier(resource)) {
|
|
291
|
-
if (macroCondition(
|
|
319
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
292
320
|
// TODO should we instead just treat this case as a new generation skipping the short circuit?
|
|
293
321
|
if (!this._cache.resources.has(resource.lid) || this._cache.resources.get(resource.lid) !== resource) {
|
|
294
322
|
throw new Error(`The supplied identifier ${JSON.stringify(resource)} does not belong to this store instance`);
|
|
295
323
|
}
|
|
296
324
|
}
|
|
297
|
-
if (macroCondition(
|
|
325
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_IDENTIFIERS)) {
|
|
298
326
|
// eslint-disable-next-line no-console
|
|
299
327
|
console.log(`Identifiers: cache HIT - Stable ${resource.lid}`);
|
|
300
328
|
// eslint-disable-next-line no-console
|
|
@@ -305,20 +333,20 @@ class IdentifierCache {
|
|
|
305
333
|
|
|
306
334
|
// the resource is unknown, ask the application to identify this data for us
|
|
307
335
|
const lid = this._generate(resource, 'record');
|
|
308
|
-
if (macroCondition(
|
|
336
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_IDENTIFIERS)) {
|
|
309
337
|
// eslint-disable-next-line no-console
|
|
310
338
|
console.log(`Identifiers: ${lid ? 'no ' : ''}lid ${lid ? lid + ' ' : ''}determined for resource`, resource);
|
|
311
339
|
}
|
|
312
340
|
let identifier = /*#__NOINLINE__*/getIdentifierFromLid(this._cache, lid, resource);
|
|
313
341
|
if (identifier !== null) {
|
|
314
|
-
if (macroCondition(
|
|
342
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_IDENTIFIERS)) {
|
|
315
343
|
// eslint-disable-next-line no-console
|
|
316
344
|
console.groupEnd();
|
|
317
345
|
}
|
|
318
346
|
return identifier;
|
|
319
347
|
}
|
|
320
348
|
if (shouldGenerate === 0) {
|
|
321
|
-
if (macroCondition(
|
|
349
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_IDENTIFIERS)) {
|
|
322
350
|
// eslint-disable-next-line no-console
|
|
323
351
|
console.groupEnd();
|
|
324
352
|
}
|
|
@@ -338,7 +366,7 @@ class IdentifierCache {
|
|
|
338
366
|
identifier = /*#__NOINLINE__*/makeStableRecordIdentifier(keyInfo, 'record', false);
|
|
339
367
|
}
|
|
340
368
|
addResourceToCache(this._cache, identifier);
|
|
341
|
-
if (macroCondition(
|
|
369
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_IDENTIFIERS)) {
|
|
342
370
|
// eslint-disable-next-line no-console
|
|
343
371
|
console.groupEnd();
|
|
344
372
|
}
|
|
@@ -380,7 +408,7 @@ class IdentifierCache {
|
|
|
380
408
|
identifier = {
|
|
381
409
|
lid: cacheKey
|
|
382
410
|
};
|
|
383
|
-
if (macroCondition(
|
|
411
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
384
412
|
Object.freeze(identifier);
|
|
385
413
|
}
|
|
386
414
|
DOCUMENTS.add(identifier);
|
|
@@ -426,7 +454,7 @@ class IdentifierCache {
|
|
|
426
454
|
}, 'record', true);
|
|
427
455
|
|
|
428
456
|
// populate our unique table
|
|
429
|
-
if (macroCondition(
|
|
457
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
430
458
|
if (this._cache.resources.has(identifier.lid)) {
|
|
431
459
|
throw new Error(`The lid generated for the new record is not unique as it matches an existing identifier`);
|
|
432
460
|
}
|
|
@@ -434,7 +462,7 @@ class IdentifierCache {
|
|
|
434
462
|
|
|
435
463
|
/*#__NOINLINE__*/
|
|
436
464
|
addResourceToCache(this._cache, identifier);
|
|
437
|
-
if (macroCondition(
|
|
465
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_IDENTIFIERS)) {
|
|
438
466
|
// eslint-disable-next-line no-console
|
|
439
467
|
console.log(`Identifiers: created identifier ${String(identifier)} for newly generated resource`, data);
|
|
440
468
|
}
|
|
@@ -483,7 +511,7 @@ class IdentifierCache {
|
|
|
483
511
|
if (hadLid) {
|
|
484
512
|
data.lid = identifier.lid;
|
|
485
513
|
}
|
|
486
|
-
if (macroCondition(
|
|
514
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_IDENTIFIERS)) {
|
|
487
515
|
// eslint-disable-next-line no-console
|
|
488
516
|
console.log(`Identifiers: merged identifiers ${generatedIdentifier.lid} and ${existingIdentifier.lid} for resource into ${identifier.lid}`, data);
|
|
489
517
|
}
|
|
@@ -495,17 +523,21 @@ class IdentifierCache {
|
|
|
495
523
|
|
|
496
524
|
// add to our own secondary lookup table
|
|
497
525
|
if (id !== newId && newId !== null) {
|
|
498
|
-
if (macroCondition(
|
|
526
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_IDENTIFIERS)) {
|
|
499
527
|
// eslint-disable-next-line no-console
|
|
500
528
|
console.log(`Identifiers: updated id for identifier ${identifier.lid} from '${String(id)}' to '${String(newId)}' for resource`, data);
|
|
501
529
|
}
|
|
502
530
|
const typeSet = this._cache.resourcesByType[identifier.type];
|
|
503
|
-
|
|
531
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
532
|
+
if (!test) {
|
|
533
|
+
throw new Error(`Expected to find a typeSet for ${identifier.type}`);
|
|
534
|
+
}
|
|
535
|
+
})(typeSet) : {};
|
|
504
536
|
typeSet.id.set(newId, identifier);
|
|
505
537
|
if (id !== null) {
|
|
506
538
|
typeSet.id.delete(id);
|
|
507
539
|
}
|
|
508
|
-
} else if (macroCondition(
|
|
540
|
+
} else if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_IDENTIFIERS)) {
|
|
509
541
|
// eslint-disable-next-line no-console
|
|
510
542
|
console.log(`Identifiers: updated identifier ${identifier.lid} resource`, data);
|
|
511
543
|
}
|
|
@@ -517,7 +549,11 @@ class IdentifierCache {
|
|
|
517
549
|
* @private
|
|
518
550
|
*/
|
|
519
551
|
_mergeRecordIdentifiers(keyInfo, identifier, existingIdentifier, data) {
|
|
520
|
-
|
|
552
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
553
|
+
if (!test) {
|
|
554
|
+
throw new Error(`Expected keyInfo to contain an id`);
|
|
555
|
+
}
|
|
556
|
+
})(hasId(keyInfo)) : {};
|
|
521
557
|
// delegate determining which identifier to keep to the configured MergeMethod
|
|
522
558
|
const kept = this._merge(identifier, existingIdentifier, data);
|
|
523
559
|
const abandoned = kept === identifier ? existingIdentifier : identifier;
|
|
@@ -564,7 +600,11 @@ class IdentifierCache {
|
|
|
564
600
|
forgetRecordIdentifier(identifierObject) {
|
|
565
601
|
const identifier = this.getOrCreateRecordIdentifier(identifierObject);
|
|
566
602
|
const typeSet = this._cache.resourcesByType[identifier.type];
|
|
567
|
-
|
|
603
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
604
|
+
if (!test) {
|
|
605
|
+
throw new Error(`Expected to find a typeSet for ${identifier.type}`);
|
|
606
|
+
}
|
|
607
|
+
})(typeSet) : {};
|
|
568
608
|
if (identifier.id !== null) {
|
|
569
609
|
typeSet.id.delete(identifier.id);
|
|
570
610
|
}
|
|
@@ -577,13 +617,13 @@ class IdentifierCache {
|
|
|
577
617
|
});
|
|
578
618
|
this._cache.polymorphicLidBackMap.delete(identifier.lid);
|
|
579
619
|
}
|
|
580
|
-
if (macroCondition(
|
|
620
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
581
621
|
identifier[DEBUG_STALE_CACHE_OWNER] = identifier[CACHE_OWNER];
|
|
582
622
|
}
|
|
583
623
|
identifier[CACHE_OWNER] = undefined;
|
|
584
624
|
IDENTIFIERS.delete(identifier);
|
|
585
625
|
this._forget(identifier, 'record');
|
|
586
|
-
if (macroCondition(
|
|
626
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_IDENTIFIERS)) {
|
|
587
627
|
// eslint-disable-next-line no-console
|
|
588
628
|
console.log(`Identifiers: released identifier ${identifierObject.lid}`);
|
|
589
629
|
}
|
|
@@ -598,7 +638,7 @@ class IdentifierCache {
|
|
|
598
638
|
}
|
|
599
639
|
function makeStableRecordIdentifier(recordIdentifier, bucket, clientOriginated) {
|
|
600
640
|
IDENTIFIERS.add(recordIdentifier);
|
|
601
|
-
if (macroCondition(
|
|
641
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
602
642
|
// we enforce immutability in dev
|
|
603
643
|
// but preserve our ability to do controlled updates to the reference
|
|
604
644
|
let wrapper = {
|
|
@@ -660,7 +700,7 @@ function makeStableRecordIdentifier(recordIdentifier, bucket, clientOriginated)
|
|
|
660
700
|
return recordIdentifier;
|
|
661
701
|
}
|
|
662
702
|
function performRecordIdentifierUpdate(identifier, keyInfo, data, updateFn) {
|
|
663
|
-
if (macroCondition(
|
|
703
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
664
704
|
const {
|
|
665
705
|
id,
|
|
666
706
|
type
|
|
@@ -735,7 +775,7 @@ function detectMerge(cache, keyInfo, identifier, data) {
|
|
|
735
775
|
}
|
|
736
776
|
function getIdentifierFromLid(cache, lid, resource) {
|
|
737
777
|
const identifier = cache.resources.get(lid);
|
|
738
|
-
if (macroCondition(
|
|
778
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_IDENTIFIERS)) {
|
|
739
779
|
// eslint-disable-next-line no-console
|
|
740
780
|
console.log(`Identifiers: cache ${identifier ? 'HIT' : 'MISS'} - Non-Stable ${lid}`, resource);
|
|
741
781
|
}
|
|
@@ -761,10 +801,6 @@ function addResourceToCache(cache, identifier) {
|
|
|
761
801
|
@module @ember-data/store
|
|
762
802
|
*/
|
|
763
803
|
|
|
764
|
-
/**
|
|
765
|
-
@module @ember-data/store
|
|
766
|
-
*/
|
|
767
|
-
|
|
768
804
|
/**
|
|
769
805
|
A `RecordReference` is a low-level API that allows users and
|
|
770
806
|
addon authors to perform meta-operations on a record.
|
|
@@ -773,10 +809,10 @@ function addResourceToCache(cache, identifier) {
|
|
|
773
809
|
@public
|
|
774
810
|
*/
|
|
775
811
|
class RecordReference {
|
|
812
|
+
// unsubscribe token given to us by the notification manager
|
|
813
|
+
___token;
|
|
814
|
+
___identifier;
|
|
776
815
|
constructor(store, identifier) {
|
|
777
|
-
// unsubscribe token given to us by the notification manager
|
|
778
|
-
this.___token = void 0;
|
|
779
|
-
this.___identifier = void 0;
|
|
780
816
|
this.store = store;
|
|
781
817
|
this.___identifier = identifier;
|
|
782
818
|
this.___token = store.notifications.subscribe(identifier, (_, bucket, notifiedKey) => {
|
|
@@ -919,7 +955,11 @@ class RecordReference {
|
|
|
919
955
|
if (id !== null) {
|
|
920
956
|
return this.store.findRecord(this.type, id);
|
|
921
957
|
}
|
|
922
|
-
|
|
958
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
959
|
+
{
|
|
960
|
+
throw new Error(`Unable to fetch record of type ${this.type} without an id`);
|
|
961
|
+
}
|
|
962
|
+
})() : {};
|
|
923
963
|
}
|
|
924
964
|
|
|
925
965
|
/**
|
|
@@ -942,7 +982,11 @@ class RecordReference {
|
|
|
942
982
|
reload: true
|
|
943
983
|
});
|
|
944
984
|
}
|
|
945
|
-
|
|
985
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
986
|
+
{
|
|
987
|
+
throw new Error(`Unable to fetch record of type ${this.type} without an id`);
|
|
988
|
+
}
|
|
989
|
+
})() : {};
|
|
946
990
|
}
|
|
947
991
|
}
|
|
948
992
|
defineSignal(RecordReference.prototype, '_ref');
|
|
@@ -950,7 +994,6 @@ defineSignal(RecordReference.prototype, '_ref');
|
|
|
950
994
|
/**
|
|
951
995
|
@module @ember-data/store
|
|
952
996
|
*/
|
|
953
|
-
|
|
954
997
|
class CacheCapabilitiesManager {
|
|
955
998
|
constructor(_store) {
|
|
956
999
|
this._store = _store;
|
|
@@ -995,7 +1038,11 @@ class CacheCapabilitiesManager {
|
|
|
995
1038
|
});
|
|
996
1039
|
}
|
|
997
1040
|
notifyChange(identifier, namespace, key) {
|
|
998
|
-
|
|
1041
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1042
|
+
if (!test) {
|
|
1043
|
+
throw new Error(`Expected a stable identifier`);
|
|
1044
|
+
}
|
|
1045
|
+
})(isStableIdentifier(identifier) || isDocumentIdentifier(identifier)) : {};
|
|
999
1046
|
|
|
1000
1047
|
// TODO do we still get value from this?
|
|
1001
1048
|
if (namespace === 'relationships' && key) {
|
|
@@ -1006,34 +1053,49 @@ class CacheCapabilitiesManager {
|
|
|
1006
1053
|
// @ts-expect-error
|
|
1007
1054
|
this._store.notifications.notify(identifier, namespace, key);
|
|
1008
1055
|
}
|
|
1009
|
-
getSchemaDefinitionService() {
|
|
1010
|
-
return this._store.getSchemaDefinitionService();
|
|
1011
|
-
}
|
|
1012
1056
|
get schema() {
|
|
1013
1057
|
return this._store.schema;
|
|
1014
1058
|
}
|
|
1015
1059
|
setRecordId(identifier, id) {
|
|
1016
|
-
|
|
1060
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1061
|
+
if (!test) {
|
|
1062
|
+
throw new Error(`Expected a stable identifier`);
|
|
1063
|
+
}
|
|
1064
|
+
})(isStableIdentifier(identifier)) : {};
|
|
1017
1065
|
this._store._instanceCache.setRecordId(identifier, id);
|
|
1018
1066
|
}
|
|
1019
1067
|
hasRecord(identifier) {
|
|
1020
1068
|
return Boolean(this._store._instanceCache.peek(identifier));
|
|
1021
1069
|
}
|
|
1022
1070
|
disconnectRecord(identifier) {
|
|
1023
|
-
|
|
1071
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1072
|
+
if (!test) {
|
|
1073
|
+
throw new Error(`Expected a stable identifier`);
|
|
1074
|
+
}
|
|
1075
|
+
})(isStableIdentifier(identifier)) : {};
|
|
1024
1076
|
this._store._instanceCache.disconnect(identifier);
|
|
1025
1077
|
this._pendingNotifies.delete(identifier);
|
|
1026
1078
|
}
|
|
1027
1079
|
}
|
|
1080
|
+
if (macroCondition(getGlobalConfig().WarpDrive.deprecations.ENABLE_LEGACY_SCHEMA_SERVICE)) {
|
|
1081
|
+
CacheCapabilitiesManager.prototype.getSchemaDefinitionService = function () {
|
|
1082
|
+
// FIXME add deprecation for this
|
|
1083
|
+
return this._store.schema;
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1028
1086
|
|
|
1029
1087
|
/*
|
|
1030
1088
|
* Returns the Cache instance associated with a given
|
|
1031
1089
|
* Model or Identifier
|
|
1032
1090
|
*/
|
|
1033
1091
|
|
|
1034
|
-
const CacheForIdentifierCache = new Map();
|
|
1092
|
+
const CacheForIdentifierCache = getOrSetGlobal('CacheForIdentifierCache', new Map());
|
|
1035
1093
|
function setCacheFor(identifier, cache) {
|
|
1036
|
-
|
|
1094
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1095
|
+
if (!test) {
|
|
1096
|
+
throw new Error(`Illegal set of identifier`);
|
|
1097
|
+
}
|
|
1098
|
+
})(!CacheForIdentifierCache.has(identifier) || CacheForIdentifierCache.get(identifier) === cache) : {};
|
|
1037
1099
|
CacheForIdentifierCache.set(identifier, cache);
|
|
1038
1100
|
}
|
|
1039
1101
|
function removeRecordDataFor(identifier) {
|
|
@@ -1053,7 +1115,7 @@ function isDestroyable(record) {
|
|
|
1053
1115
|
@module @ember-data/store
|
|
1054
1116
|
*/
|
|
1055
1117
|
|
|
1056
|
-
const RecordCache = new Map();
|
|
1118
|
+
const RecordCache = getOrSetGlobal('RecordCache', new Map());
|
|
1057
1119
|
function peekRecordIdentifier(record) {
|
|
1058
1120
|
return RecordCache.get(record);
|
|
1059
1121
|
}
|
|
@@ -1077,12 +1139,17 @@ function peekRecordIdentifier(record) {
|
|
|
1077
1139
|
@param {Object} record a record instance previously obstained from the store.
|
|
1078
1140
|
@return {StableRecordIdentifier}
|
|
1079
1141
|
*/
|
|
1142
|
+
|
|
1080
1143
|
function recordIdentifierFor(record) {
|
|
1081
|
-
|
|
1144
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1145
|
+
if (!test) {
|
|
1146
|
+
throw new Error(`${String(record)} is not a record instantiated by @ember-data/store`);
|
|
1147
|
+
}
|
|
1148
|
+
})(RecordCache.has(record)) : {};
|
|
1082
1149
|
return RecordCache.get(record);
|
|
1083
1150
|
}
|
|
1084
1151
|
function setRecordIdentifier(record, identifier) {
|
|
1085
|
-
if (macroCondition(
|
|
1152
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
1086
1153
|
if (RecordCache.has(record) && RecordCache.get(record) !== identifier) {
|
|
1087
1154
|
throw new Error(`${String(record)} was already assigned an identifier`);
|
|
1088
1155
|
}
|
|
@@ -1098,18 +1165,22 @@ function setRecordIdentifier(record, identifier) {
|
|
|
1098
1165
|
|
|
1099
1166
|
RecordCache.set(record, identifier);
|
|
1100
1167
|
}
|
|
1101
|
-
const StoreMap = new Map();
|
|
1168
|
+
const StoreMap = getOrSetGlobal('StoreMap', new Map());
|
|
1102
1169
|
function storeFor(record) {
|
|
1103
1170
|
const store = StoreMap.get(record);
|
|
1104
|
-
|
|
1171
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1172
|
+
if (!test) {
|
|
1173
|
+
throw new Error(`A record in a disconnected state cannot utilize the store. This typically means the record has been destroyed, most commonly by unloading it.`);
|
|
1174
|
+
}
|
|
1175
|
+
})(store) : {};
|
|
1105
1176
|
return store;
|
|
1106
1177
|
}
|
|
1107
1178
|
class InstanceCache {
|
|
1179
|
+
__instances = {
|
|
1180
|
+
record: new Map(),
|
|
1181
|
+
reference: new WeakMap()
|
|
1182
|
+
};
|
|
1108
1183
|
constructor(store) {
|
|
1109
|
-
this.__instances = {
|
|
1110
|
-
record: new Map(),
|
|
1111
|
-
reference: new WeakMap()
|
|
1112
|
-
};
|
|
1113
1184
|
this.store = store;
|
|
1114
1185
|
this._storeWrapper = new CacheCapabilitiesManager(this.store);
|
|
1115
1186
|
store.identifierCache.__configureMerge((identifier, matchedIdentifier, resourceData) => {
|
|
@@ -1139,7 +1210,11 @@ class InstanceCache {
|
|
|
1139
1210
|
if ('id' in resourceData) {
|
|
1140
1211
|
throw new Error(`Failed to update the 'id' for the RecordIdentifier '${identifier.type}:${String(identifier.id)} (${identifier.lid})' to '${String(resourceData.id)}', because that id is already in use by '${matchedIdentifier.type}:${String(matchedIdentifier.id)} (${matchedIdentifier.lid})'`);
|
|
1141
1212
|
}
|
|
1142
|
-
|
|
1213
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1214
|
+
{
|
|
1215
|
+
throw new Error(`Failed to update the RecordIdentifier '${identifier.type}:${String(identifier.id)} (${identifier.lid})' to merge with the detected duplicate identifier '${matchedIdentifier.type}:${String(matchedIdentifier.id)} (${String(matchedIdentifier.lid)})'`);
|
|
1216
|
+
}
|
|
1217
|
+
})() : {};
|
|
1143
1218
|
}
|
|
1144
1219
|
this.store.cache.patch({
|
|
1145
1220
|
op: 'mergeIdentifiers',
|
|
@@ -1164,7 +1239,11 @@ class InstanceCache {
|
|
|
1164
1239
|
getRecord(identifier, properties) {
|
|
1165
1240
|
let record = this.__instances.record.get(identifier);
|
|
1166
1241
|
if (!record) {
|
|
1167
|
-
|
|
1242
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1243
|
+
if (!test) {
|
|
1244
|
+
throw new Error(`Cannot create a new record instance while the store is being destroyed`);
|
|
1245
|
+
}
|
|
1246
|
+
})(!this.store.isDestroying && !this.store.isDestroyed) : {};
|
|
1168
1247
|
const cache = this.store.cache;
|
|
1169
1248
|
setCacheFor(identifier, cache);
|
|
1170
1249
|
record = this.store.instantiateRecord(identifier, properties || {});
|
|
@@ -1172,7 +1251,7 @@ class InstanceCache {
|
|
|
1172
1251
|
setCacheFor(record, cache);
|
|
1173
1252
|
StoreMap.set(record, this.store);
|
|
1174
1253
|
this.__instances.record.set(identifier, record);
|
|
1175
|
-
if (macroCondition(
|
|
1254
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_INSTANCE_CACHE)) {
|
|
1176
1255
|
// eslint-disable-next-line no-console
|
|
1177
1256
|
console.log(`InstanceCache: created Record for ${String(identifier)}`, properties);
|
|
1178
1257
|
}
|
|
@@ -1211,26 +1290,34 @@ class InstanceCache {
|
|
|
1211
1290
|
}
|
|
1212
1291
|
disconnect(identifier) {
|
|
1213
1292
|
const record = this.__instances.record.get(identifier);
|
|
1214
|
-
|
|
1293
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1294
|
+
if (!test) {
|
|
1295
|
+
throw new Error('Cannot destroy record while it is still materialized');
|
|
1296
|
+
}
|
|
1297
|
+
})(!isDestroyable(record) || record.isDestroyed || record.isDestroying) : {};
|
|
1215
1298
|
this.store._graph?.remove(identifier);
|
|
1216
1299
|
this.store.identifierCache.forgetRecordIdentifier(identifier);
|
|
1217
1300
|
removeRecordDataFor(identifier);
|
|
1218
1301
|
this.store._requestCache._clearEntries(identifier);
|
|
1219
|
-
if (macroCondition(
|
|
1302
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_INSTANCE_CACHE)) {
|
|
1220
1303
|
// eslint-disable-next-line no-console
|
|
1221
1304
|
console.log(`InstanceCache: disconnected ${String(identifier)}`);
|
|
1222
1305
|
}
|
|
1223
1306
|
}
|
|
1224
1307
|
unloadRecord(identifier) {
|
|
1225
|
-
if (macroCondition(
|
|
1308
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
1226
1309
|
const requests = this.store.getRequestStateService().getPendingRequestsForRecord(identifier);
|
|
1227
1310
|
if (requests.some(req => {
|
|
1228
1311
|
return req.type === 'mutation';
|
|
1229
1312
|
})) {
|
|
1230
|
-
|
|
1313
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1314
|
+
{
|
|
1315
|
+
throw new Error(`You can only unload a record which is not inFlight. '${String(identifier)}'`);
|
|
1316
|
+
}
|
|
1317
|
+
})() : {};
|
|
1231
1318
|
}
|
|
1232
1319
|
}
|
|
1233
|
-
if (macroCondition(
|
|
1320
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_INSTANCE_CACHE)) {
|
|
1234
1321
|
// eslint-disable-next-line no-console
|
|
1235
1322
|
console.groupCollapsed(`InstanceCache: unloading record for ${String(identifier)}`);
|
|
1236
1323
|
}
|
|
@@ -1245,7 +1332,7 @@ class InstanceCache {
|
|
|
1245
1332
|
StoreMap.delete(record);
|
|
1246
1333
|
RecordCache.delete(record);
|
|
1247
1334
|
removeRecordDataFor(record);
|
|
1248
|
-
if (macroCondition(
|
|
1335
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_INSTANCE_CACHE)) {
|
|
1249
1336
|
// eslint-disable-next-line no-console
|
|
1250
1337
|
console.log(`InstanceCache: destroyed record for ${String(identifier)}`);
|
|
1251
1338
|
}
|
|
@@ -1253,7 +1340,7 @@ class InstanceCache {
|
|
|
1253
1340
|
if (cache) {
|
|
1254
1341
|
cache.unloadRecord(identifier);
|
|
1255
1342
|
removeRecordDataFor(identifier);
|
|
1256
|
-
if (macroCondition(
|
|
1343
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_INSTANCE_CACHE)) {
|
|
1257
1344
|
// eslint-disable-next-line no-console
|
|
1258
1345
|
console.log(`InstanceCache: destroyed cache for ${String(identifier)}`);
|
|
1259
1346
|
}
|
|
@@ -1261,7 +1348,7 @@ class InstanceCache {
|
|
|
1261
1348
|
this.disconnect(identifier);
|
|
1262
1349
|
}
|
|
1263
1350
|
this.store._requestCache._clearEntries(identifier);
|
|
1264
|
-
if (macroCondition(
|
|
1351
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_INSTANCE_CACHE)) {
|
|
1265
1352
|
// eslint-disable-next-line no-console
|
|
1266
1353
|
console.log(`InstanceCache: unloaded RecordData for ${String(identifier)}`);
|
|
1267
1354
|
// eslint-disable-next-line no-console
|
|
@@ -1300,11 +1387,19 @@ class InstanceCache {
|
|
|
1300
1387
|
const oldId = identifier.id;
|
|
1301
1388
|
|
|
1302
1389
|
// ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record)
|
|
1303
|
-
|
|
1390
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1391
|
+
if (!test) {
|
|
1392
|
+
throw new Error(`'${type}' was saved to the server, but the response does not have an id and your record does not either.`);
|
|
1393
|
+
}
|
|
1394
|
+
})(!(id === null && oldId === null)) : {};
|
|
1304
1395
|
|
|
1305
1396
|
// ID absolutely can't be different than oldID if oldID is not null
|
|
1306
1397
|
// TODO this assertion and restriction may not strictly be needed in the identifiers world
|
|
1307
|
-
|
|
1398
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1399
|
+
if (!test) {
|
|
1400
|
+
throw new Error(`Cannot update the id for '${type}:${lid}' from '${String(oldId)}' to '${id}'.`);
|
|
1401
|
+
}
|
|
1402
|
+
})(!(oldId !== null && id !== oldId)) : {};
|
|
1308
1403
|
|
|
1309
1404
|
// ID can be null if oldID is not null (altered ID in response for a record)
|
|
1310
1405
|
// however, this is more than likely a developer error.
|
|
@@ -1312,7 +1407,7 @@ class InstanceCache {
|
|
|
1312
1407
|
warn(`Your ${type} record was saved to the server, but the response does not have an id.`, !(oldId !== null && id === null));
|
|
1313
1408
|
return;
|
|
1314
1409
|
}
|
|
1315
|
-
if (macroCondition(
|
|
1410
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_INSTANCE_CACHE)) {
|
|
1316
1411
|
// eslint-disable-next-line no-console
|
|
1317
1412
|
console.log(`InstanceCache: updating id to '${id}' for record ${String(identifier)}`);
|
|
1318
1413
|
}
|
|
@@ -1320,7 +1415,11 @@ class InstanceCache {
|
|
|
1320
1415
|
type,
|
|
1321
1416
|
id
|
|
1322
1417
|
});
|
|
1323
|
-
|
|
1418
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1419
|
+
if (!test) {
|
|
1420
|
+
throw new Error(`'${type}' was saved to the server, but the response returned the new id '${id}', which has already been used with another record.'`);
|
|
1421
|
+
}
|
|
1422
|
+
})(!existingIdentifier || existingIdentifier === identifier) : {};
|
|
1324
1423
|
if (identifier.id === null) {
|
|
1325
1424
|
// TODO potentially this needs to handle merged result
|
|
1326
1425
|
this.store.identifierCache.updateRecordIdentifier(identifier, {
|
|
@@ -1357,16 +1456,16 @@ function resourceIsFullyDeleted(instanceCache, identifier) {
|
|
|
1357
1456
|
function preloadData(store, identifier, preload) {
|
|
1358
1457
|
const jsonPayload = {};
|
|
1359
1458
|
//TODO(Igor) consider the polymorphic case
|
|
1360
|
-
const schemas = store.
|
|
1361
|
-
const
|
|
1459
|
+
const schemas = store.schema;
|
|
1460
|
+
const fields = schemas.fields(identifier);
|
|
1362
1461
|
Object.keys(preload).forEach(key => {
|
|
1363
1462
|
const preloadValue = preload[key];
|
|
1364
|
-
const
|
|
1365
|
-
if (
|
|
1463
|
+
const field = fields.get(key);
|
|
1464
|
+
if (field && (field.kind === 'hasMany' || field.kind === 'belongsTo')) {
|
|
1366
1465
|
if (!jsonPayload.relationships) {
|
|
1367
1466
|
jsonPayload.relationships = {};
|
|
1368
1467
|
}
|
|
1369
|
-
jsonPayload.relationships[key] = preloadRelationship(
|
|
1468
|
+
jsonPayload.relationships[key] = preloadRelationship(field, preloadValue);
|
|
1370
1469
|
} else {
|
|
1371
1470
|
if (!jsonPayload.attributes) {
|
|
1372
1471
|
jsonPayload.attributes = {};
|
|
@@ -1381,12 +1480,20 @@ function preloadData(store, identifier, preload) {
|
|
|
1381
1480
|
function preloadRelationship(schema, preloadValue) {
|
|
1382
1481
|
const relatedType = schema.type;
|
|
1383
1482
|
if (schema.kind === 'hasMany') {
|
|
1384
|
-
|
|
1483
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1484
|
+
if (!test) {
|
|
1485
|
+
throw new Error('You need to pass in an array to set a hasMany property on a record');
|
|
1486
|
+
}
|
|
1487
|
+
})(Array.isArray(preloadValue)) : {};
|
|
1385
1488
|
return {
|
|
1386
1489
|
data: preloadValue.map(value => _convertPreloadRelationshipToJSON(value, relatedType))
|
|
1387
1490
|
};
|
|
1388
1491
|
}
|
|
1389
|
-
|
|
1492
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1493
|
+
if (!test) {
|
|
1494
|
+
throw new Error('You should not pass in an array to set a belongsTo property on a record');
|
|
1495
|
+
}
|
|
1496
|
+
})(!Array.isArray(preloadValue)) : {};
|
|
1390
1497
|
return {
|
|
1391
1498
|
data: preloadValue ? _convertPreloadRelationshipToJSON(preloadValue, relatedType) : null
|
|
1392
1499
|
};
|
|
@@ -1415,7 +1522,7 @@ function _clearCaches() {
|
|
|
1415
1522
|
|
|
1416
1523
|
// if modelFor turns out to be a bottleneck we should replace with a Map
|
|
1417
1524
|
// and clear it during store teardown.
|
|
1418
|
-
const AvailableShims = new WeakMap();
|
|
1525
|
+
const AvailableShims = getOrSetGlobal('AvailableShims', new WeakMap());
|
|
1419
1526
|
function getShimClass(store, modelName) {
|
|
1420
1527
|
let shims = AvailableShims.get(store);
|
|
1421
1528
|
if (!shims) {
|
|
@@ -1428,15 +1535,6 @@ function getShimClass(store, modelName) {
|
|
|
1428
1535
|
}
|
|
1429
1536
|
return shim;
|
|
1430
1537
|
}
|
|
1431
|
-
function mapFromHash(hash) {
|
|
1432
|
-
const map = new Map();
|
|
1433
|
-
for (const i in hash) {
|
|
1434
|
-
if (Object.prototype.hasOwnProperty.call(hash, i)) {
|
|
1435
|
-
map.set(i, hash[i]);
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
return map;
|
|
1439
|
-
}
|
|
1440
1538
|
|
|
1441
1539
|
// Mimics the static apis of @ember-data/model
|
|
1442
1540
|
class ShimModelClass {
|
|
@@ -1445,67 +1543,71 @@ class ShimModelClass {
|
|
|
1445
1543
|
this.modelName = modelName;
|
|
1446
1544
|
}
|
|
1447
1545
|
get fields() {
|
|
1448
|
-
const
|
|
1546
|
+
const fields = new Map();
|
|
1547
|
+
const fieldSchemas = this.__store.schema.fields({
|
|
1449
1548
|
type: this.modelName
|
|
1450
1549
|
});
|
|
1451
|
-
|
|
1452
|
-
|
|
1550
|
+
fieldSchemas.forEach((schema, key) => {
|
|
1551
|
+
if (schema.kind === 'attribute' || schema.kind === 'belongsTo' || schema.kind === 'hasMany') {
|
|
1552
|
+
fields.set(key, schema.kind);
|
|
1553
|
+
}
|
|
1453
1554
|
});
|
|
1454
|
-
const fields = new Map();
|
|
1455
|
-
Object.keys(attrs).forEach(key => fields.set(key, 'attribute'));
|
|
1456
|
-
Object.keys(relationships).forEach(key => fields.set(key, relationships[key].kind));
|
|
1457
1555
|
return fields;
|
|
1458
1556
|
}
|
|
1459
1557
|
get attributes() {
|
|
1460
|
-
const attrs =
|
|
1558
|
+
const attrs = new Map();
|
|
1559
|
+
const fields = this.__store.schema.fields({
|
|
1461
1560
|
type: this.modelName
|
|
1462
1561
|
});
|
|
1463
|
-
|
|
1562
|
+
fields.forEach((schema, key) => {
|
|
1563
|
+
if (schema.kind === 'attribute') {
|
|
1564
|
+
attrs.set(key, schema);
|
|
1565
|
+
}
|
|
1566
|
+
});
|
|
1567
|
+
return attrs;
|
|
1464
1568
|
}
|
|
1465
1569
|
get relationshipsByName() {
|
|
1466
|
-
const
|
|
1570
|
+
const rels = new Map();
|
|
1571
|
+
const fields = this.__store.schema.fields({
|
|
1467
1572
|
type: this.modelName
|
|
1468
1573
|
});
|
|
1469
|
-
|
|
1574
|
+
fields.forEach((schema, key) => {
|
|
1575
|
+
if (schema.kind === 'belongsTo' || schema.kind === 'hasMany') {
|
|
1576
|
+
rels.set(key, schema);
|
|
1577
|
+
}
|
|
1578
|
+
});
|
|
1579
|
+
return rels;
|
|
1470
1580
|
}
|
|
1471
1581
|
eachAttribute(callback, binding) {
|
|
1472
|
-
|
|
1582
|
+
this.__store.schema.fields({
|
|
1473
1583
|
type: this.modelName
|
|
1474
|
-
})
|
|
1475
|
-
|
|
1476
|
-
|
|
1584
|
+
}).forEach((schema, key) => {
|
|
1585
|
+
if (schema.kind === 'attribute') {
|
|
1586
|
+
callback.call(binding, key, schema);
|
|
1587
|
+
}
|
|
1477
1588
|
});
|
|
1478
1589
|
}
|
|
1479
1590
|
eachRelationship(callback, binding) {
|
|
1480
|
-
|
|
1591
|
+
this.__store.schema.fields({
|
|
1481
1592
|
type: this.modelName
|
|
1482
|
-
})
|
|
1483
|
-
|
|
1484
|
-
|
|
1593
|
+
}).forEach((schema, key) => {
|
|
1594
|
+
if (schema.kind === 'belongsTo' || schema.kind === 'hasMany') {
|
|
1595
|
+
callback.call(binding, key, schema);
|
|
1596
|
+
}
|
|
1485
1597
|
});
|
|
1486
1598
|
}
|
|
1487
1599
|
eachTransformedAttribute(callback, binding) {
|
|
1488
|
-
|
|
1600
|
+
this.__store.schema.fields({
|
|
1489
1601
|
type: this.modelName
|
|
1490
|
-
})
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
callback.call(binding, key,
|
|
1602
|
+
}).forEach((schema, key) => {
|
|
1603
|
+
if (schema.kind === 'attribute') {
|
|
1604
|
+
const type = schema.type;
|
|
1605
|
+
if (type) callback.call(binding, key, type);
|
|
1494
1606
|
}
|
|
1495
1607
|
});
|
|
1496
1608
|
}
|
|
1497
1609
|
}
|
|
1498
|
-
|
|
1499
|
-
if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {
|
|
1500
|
-
throw new TypeError("attempted to use private field on non-instance");
|
|
1501
|
-
}
|
|
1502
|
-
return receiver;
|
|
1503
|
-
}
|
|
1504
|
-
var id = 0;
|
|
1505
|
-
function _classPrivateFieldKey(name) {
|
|
1506
|
-
return "__private_" + id++ + "_" + name;
|
|
1507
|
-
}
|
|
1508
|
-
var _cache = /*#__PURE__*/_classPrivateFieldKey("cache");
|
|
1610
|
+
|
|
1509
1611
|
/**
|
|
1510
1612
|
* The CacheManager wraps a Cache enforcing that only
|
|
1511
1613
|
* the public API surface area is exposed.
|
|
@@ -1525,13 +1627,10 @@ var _cache = /*#__PURE__*/_classPrivateFieldKey("cache");
|
|
|
1525
1627
|
* @public
|
|
1526
1628
|
*/
|
|
1527
1629
|
class CacheManager {
|
|
1630
|
+
version = '2';
|
|
1631
|
+
#cache;
|
|
1528
1632
|
constructor(cache) {
|
|
1529
|
-
this
|
|
1530
|
-
Object.defineProperty(this, _cache, {
|
|
1531
|
-
writable: true,
|
|
1532
|
-
value: void 0
|
|
1533
|
-
});
|
|
1534
|
-
_classPrivateFieldBase(this, _cache)[_cache] = cache;
|
|
1633
|
+
this.#cache = cache;
|
|
1535
1634
|
}
|
|
1536
1635
|
|
|
1537
1636
|
// Cache Management
|
|
@@ -1561,7 +1660,7 @@ class CacheManager {
|
|
|
1561
1660
|
* @public
|
|
1562
1661
|
*/
|
|
1563
1662
|
put(doc) {
|
|
1564
|
-
return
|
|
1663
|
+
return this.#cache.put(doc);
|
|
1565
1664
|
}
|
|
1566
1665
|
|
|
1567
1666
|
/**
|
|
@@ -1576,7 +1675,7 @@ class CacheManager {
|
|
|
1576
1675
|
* @return {void}
|
|
1577
1676
|
*/
|
|
1578
1677
|
patch(op) {
|
|
1579
|
-
|
|
1678
|
+
this.#cache.patch(op);
|
|
1580
1679
|
}
|
|
1581
1680
|
|
|
1582
1681
|
/**
|
|
@@ -1588,7 +1687,7 @@ class CacheManager {
|
|
|
1588
1687
|
* @param mutation
|
|
1589
1688
|
*/
|
|
1590
1689
|
mutate(mutation) {
|
|
1591
|
-
|
|
1690
|
+
this.#cache.mutate(mutation);
|
|
1592
1691
|
}
|
|
1593
1692
|
|
|
1594
1693
|
/**
|
|
@@ -1625,7 +1724,7 @@ class CacheManager {
|
|
|
1625
1724
|
*/
|
|
1626
1725
|
|
|
1627
1726
|
peek(identifier) {
|
|
1628
|
-
return
|
|
1727
|
+
return this.#cache.peek(identifier);
|
|
1629
1728
|
}
|
|
1630
1729
|
|
|
1631
1730
|
/**
|
|
@@ -1638,7 +1737,7 @@ class CacheManager {
|
|
|
1638
1737
|
* @public
|
|
1639
1738
|
*/
|
|
1640
1739
|
peekRequest(identifier) {
|
|
1641
|
-
return
|
|
1740
|
+
return this.#cache.peekRequest(identifier);
|
|
1642
1741
|
}
|
|
1643
1742
|
|
|
1644
1743
|
/**
|
|
@@ -1652,7 +1751,7 @@ class CacheManager {
|
|
|
1652
1751
|
* @return {void | string[]} if `hasRecord` is true then calculated key changes should be returned
|
|
1653
1752
|
*/
|
|
1654
1753
|
upsert(identifier, data, hasRecord) {
|
|
1655
|
-
return
|
|
1754
|
+
return this.#cache.upsert(identifier, data, hasRecord);
|
|
1656
1755
|
}
|
|
1657
1756
|
|
|
1658
1757
|
// Cache Forking Support
|
|
@@ -1670,7 +1769,7 @@ class CacheManager {
|
|
|
1670
1769
|
* @return Promise<Cache>
|
|
1671
1770
|
*/
|
|
1672
1771
|
fork() {
|
|
1673
|
-
return
|
|
1772
|
+
return this.#cache.fork();
|
|
1674
1773
|
}
|
|
1675
1774
|
|
|
1676
1775
|
/**
|
|
@@ -1686,7 +1785,7 @@ class CacheManager {
|
|
|
1686
1785
|
* @return Promise<void>
|
|
1687
1786
|
*/
|
|
1688
1787
|
merge(cache) {
|
|
1689
|
-
return
|
|
1788
|
+
return this.#cache.merge(cache);
|
|
1690
1789
|
}
|
|
1691
1790
|
|
|
1692
1791
|
/**
|
|
@@ -1723,7 +1822,7 @@ class CacheManager {
|
|
|
1723
1822
|
* @public
|
|
1724
1823
|
*/
|
|
1725
1824
|
diff() {
|
|
1726
|
-
return
|
|
1825
|
+
return this.#cache.diff();
|
|
1727
1826
|
}
|
|
1728
1827
|
|
|
1729
1828
|
// SSR Support
|
|
@@ -1739,7 +1838,7 @@ class CacheManager {
|
|
|
1739
1838
|
* @public
|
|
1740
1839
|
*/
|
|
1741
1840
|
dump() {
|
|
1742
|
-
return
|
|
1841
|
+
return this.#cache.dump();
|
|
1743
1842
|
}
|
|
1744
1843
|
|
|
1745
1844
|
/**
|
|
@@ -1760,7 +1859,7 @@ class CacheManager {
|
|
|
1760
1859
|
* @public
|
|
1761
1860
|
*/
|
|
1762
1861
|
hydrate(stream) {
|
|
1763
|
-
return
|
|
1862
|
+
return this.#cache.hydrate(stream);
|
|
1764
1863
|
}
|
|
1765
1864
|
|
|
1766
1865
|
// Cache
|
|
@@ -1781,7 +1880,7 @@ class CacheManager {
|
|
|
1781
1880
|
* @param options
|
|
1782
1881
|
*/
|
|
1783
1882
|
clientDidCreate(identifier, options) {
|
|
1784
|
-
return
|
|
1883
|
+
return this.#cache.clientDidCreate(identifier, options);
|
|
1785
1884
|
}
|
|
1786
1885
|
|
|
1787
1886
|
/**
|
|
@@ -1793,7 +1892,7 @@ class CacheManager {
|
|
|
1793
1892
|
* @param identifier
|
|
1794
1893
|
*/
|
|
1795
1894
|
willCommit(identifier, context) {
|
|
1796
|
-
|
|
1895
|
+
this.#cache.willCommit(identifier, context);
|
|
1797
1896
|
}
|
|
1798
1897
|
|
|
1799
1898
|
/**
|
|
@@ -1806,7 +1905,7 @@ class CacheManager {
|
|
|
1806
1905
|
* @param data
|
|
1807
1906
|
*/
|
|
1808
1907
|
didCommit(identifier, result) {
|
|
1809
|
-
return
|
|
1908
|
+
return this.#cache.didCommit(identifier, result);
|
|
1810
1909
|
}
|
|
1811
1910
|
|
|
1812
1911
|
/**
|
|
@@ -1819,7 +1918,7 @@ class CacheManager {
|
|
|
1819
1918
|
* @param errors
|
|
1820
1919
|
*/
|
|
1821
1920
|
commitWasRejected(identifier, errors) {
|
|
1822
|
-
|
|
1921
|
+
this.#cache.commitWasRejected(identifier, errors);
|
|
1823
1922
|
}
|
|
1824
1923
|
|
|
1825
1924
|
/**
|
|
@@ -1831,7 +1930,7 @@ class CacheManager {
|
|
|
1831
1930
|
* @param identifier
|
|
1832
1931
|
*/
|
|
1833
1932
|
unloadRecord(identifier) {
|
|
1834
|
-
|
|
1933
|
+
this.#cache.unloadRecord(identifier);
|
|
1835
1934
|
}
|
|
1836
1935
|
|
|
1837
1936
|
// Granular Resource Data APIs
|
|
@@ -1847,7 +1946,7 @@ class CacheManager {
|
|
|
1847
1946
|
* @return {unknown}
|
|
1848
1947
|
*/
|
|
1849
1948
|
getAttr(identifier, propertyName) {
|
|
1850
|
-
return
|
|
1949
|
+
return this.#cache.getAttr(identifier, propertyName);
|
|
1851
1950
|
}
|
|
1852
1951
|
|
|
1853
1952
|
/**
|
|
@@ -1860,7 +1959,7 @@ class CacheManager {
|
|
|
1860
1959
|
* @param value
|
|
1861
1960
|
*/
|
|
1862
1961
|
setAttr(identifier, propertyName, value) {
|
|
1863
|
-
|
|
1962
|
+
this.#cache.setAttr(identifier, propertyName, value);
|
|
1864
1963
|
}
|
|
1865
1964
|
|
|
1866
1965
|
/**
|
|
@@ -1872,7 +1971,7 @@ class CacheManager {
|
|
|
1872
1971
|
* @return
|
|
1873
1972
|
*/
|
|
1874
1973
|
changedAttrs(identifier) {
|
|
1875
|
-
return
|
|
1974
|
+
return this.#cache.changedAttrs(identifier);
|
|
1876
1975
|
}
|
|
1877
1976
|
|
|
1878
1977
|
/**
|
|
@@ -1884,7 +1983,7 @@ class CacheManager {
|
|
|
1884
1983
|
* @return {boolean}
|
|
1885
1984
|
*/
|
|
1886
1985
|
hasChangedAttrs(identifier) {
|
|
1887
|
-
return
|
|
1986
|
+
return this.#cache.hasChangedAttrs(identifier);
|
|
1888
1987
|
}
|
|
1889
1988
|
|
|
1890
1989
|
/**
|
|
@@ -1896,7 +1995,7 @@ class CacheManager {
|
|
|
1896
1995
|
* @return the names of attributes that were restored
|
|
1897
1996
|
*/
|
|
1898
1997
|
rollbackAttrs(identifier) {
|
|
1899
|
-
return
|
|
1998
|
+
return this.#cache.rollbackAttrs(identifier);
|
|
1900
1999
|
}
|
|
1901
2000
|
|
|
1902
2001
|
// Relationships
|
|
@@ -1930,7 +2029,7 @@ class CacheManager {
|
|
|
1930
2029
|
* @return {Map<string, RelationshipDiff>}
|
|
1931
2030
|
*/
|
|
1932
2031
|
changedRelationships(identifier) {
|
|
1933
|
-
return
|
|
2032
|
+
return this.#cache.changedRelationships(identifier);
|
|
1934
2033
|
}
|
|
1935
2034
|
|
|
1936
2035
|
/**
|
|
@@ -1942,7 +2041,7 @@ class CacheManager {
|
|
|
1942
2041
|
* @return {boolean}
|
|
1943
2042
|
*/
|
|
1944
2043
|
hasChangedRelationships(identifier) {
|
|
1945
|
-
return
|
|
2044
|
+
return this.#cache.hasChangedRelationships(identifier);
|
|
1946
2045
|
}
|
|
1947
2046
|
|
|
1948
2047
|
/**
|
|
@@ -1958,7 +2057,7 @@ class CacheManager {
|
|
|
1958
2057
|
* @return {string[]} the names of relationships that were restored
|
|
1959
2058
|
*/
|
|
1960
2059
|
rollbackRelationships(identifier) {
|
|
1961
|
-
return
|
|
2060
|
+
return this.#cache.rollbackRelationships(identifier);
|
|
1962
2061
|
}
|
|
1963
2062
|
|
|
1964
2063
|
/**
|
|
@@ -1971,7 +2070,7 @@ class CacheManager {
|
|
|
1971
2070
|
* @return resource relationship object
|
|
1972
2071
|
*/
|
|
1973
2072
|
getRelationship(identifier, propertyName) {
|
|
1974
|
-
return
|
|
2073
|
+
return this.#cache.getRelationship(identifier, propertyName);
|
|
1975
2074
|
}
|
|
1976
2075
|
|
|
1977
2076
|
// Resource State
|
|
@@ -1987,7 +2086,7 @@ class CacheManager {
|
|
|
1987
2086
|
* @param isDeleted
|
|
1988
2087
|
*/
|
|
1989
2088
|
setIsDeleted(identifier, isDeleted) {
|
|
1990
|
-
|
|
2089
|
+
this.#cache.setIsDeleted(identifier, isDeleted);
|
|
1991
2090
|
}
|
|
1992
2091
|
|
|
1993
2092
|
/**
|
|
@@ -1999,7 +2098,7 @@ class CacheManager {
|
|
|
1999
2098
|
* @return
|
|
2000
2099
|
*/
|
|
2001
2100
|
getErrors(identifier) {
|
|
2002
|
-
return
|
|
2101
|
+
return this.#cache.getErrors(identifier);
|
|
2003
2102
|
}
|
|
2004
2103
|
|
|
2005
2104
|
/**
|
|
@@ -2011,7 +2110,7 @@ class CacheManager {
|
|
|
2011
2110
|
* @return {boolean}
|
|
2012
2111
|
*/
|
|
2013
2112
|
isEmpty(identifier) {
|
|
2014
|
-
return
|
|
2113
|
+
return this.#cache.isEmpty(identifier);
|
|
2015
2114
|
}
|
|
2016
2115
|
|
|
2017
2116
|
/**
|
|
@@ -2024,7 +2123,7 @@ class CacheManager {
|
|
|
2024
2123
|
* @return {boolean}
|
|
2025
2124
|
*/
|
|
2026
2125
|
isNew(identifier) {
|
|
2027
|
-
return
|
|
2126
|
+
return this.#cache.isNew(identifier);
|
|
2028
2127
|
}
|
|
2029
2128
|
|
|
2030
2129
|
/**
|
|
@@ -2037,7 +2136,7 @@ class CacheManager {
|
|
|
2037
2136
|
* @return {boolean}
|
|
2038
2137
|
*/
|
|
2039
2138
|
isDeleted(identifier) {
|
|
2040
|
-
return
|
|
2139
|
+
return this.#cache.isDeleted(identifier);
|
|
2041
2140
|
}
|
|
2042
2141
|
|
|
2043
2142
|
/**
|
|
@@ -2050,13 +2149,14 @@ class CacheManager {
|
|
|
2050
2149
|
* @return {boolean}
|
|
2051
2150
|
*/
|
|
2052
2151
|
isDeletionCommitted(identifier) {
|
|
2053
|
-
return
|
|
2152
|
+
return this.#cache.isDeletionCommitted(identifier);
|
|
2054
2153
|
}
|
|
2055
2154
|
}
|
|
2056
2155
|
|
|
2057
2156
|
/**
|
|
2058
2157
|
* @module @ember-data/store
|
|
2059
2158
|
*/
|
|
2159
|
+
// eslint-disable-next-line no-restricted-imports
|
|
2060
2160
|
let tokenId = 0;
|
|
2061
2161
|
const CacheOperations = new Set(['added', 'removed', 'state', 'updated']);
|
|
2062
2162
|
function isCacheOperationValue(value) {
|
|
@@ -2068,7 +2168,7 @@ function runLoopIsFlushing() {
|
|
|
2068
2168
|
}
|
|
2069
2169
|
function _unsubscribe(tokens, token, cache) {
|
|
2070
2170
|
const identifier = tokens.get(token);
|
|
2071
|
-
if (macroCondition(
|
|
2171
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_NOTIFICATIONS)) {
|
|
2072
2172
|
if (!identifier) {
|
|
2073
2173
|
// eslint-disable-next-line no-console
|
|
2074
2174
|
console.log('Passed unknown unsubscribe token to unsubscribe', identifier);
|
|
@@ -2130,13 +2230,17 @@ class NotificationManager {
|
|
|
2130
2230
|
*/
|
|
2131
2231
|
|
|
2132
2232
|
subscribe(identifier, callback) {
|
|
2133
|
-
|
|
2233
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2234
|
+
if (!test) {
|
|
2235
|
+
throw new Error(`Expected to receive a stable Identifier to subscribe to`);
|
|
2236
|
+
}
|
|
2237
|
+
})(identifier === 'resource' || identifier === 'document' || isStableIdentifier(identifier) || isDocumentIdentifier(identifier)) : {};
|
|
2134
2238
|
let map = this._cache.get(identifier);
|
|
2135
2239
|
if (!map) {
|
|
2136
2240
|
map = new Map();
|
|
2137
2241
|
this._cache.set(identifier, map);
|
|
2138
2242
|
}
|
|
2139
|
-
const unsubToken = macroCondition(
|
|
2243
|
+
const unsubToken = macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? {
|
|
2140
2244
|
_tokenRef: tokenId++
|
|
2141
2245
|
} : {};
|
|
2142
2246
|
map.set(unsubToken, callback);
|
|
@@ -2169,15 +2273,19 @@ class NotificationManager {
|
|
|
2169
2273
|
*/
|
|
2170
2274
|
|
|
2171
2275
|
notify(identifier, value, key) {
|
|
2172
|
-
|
|
2276
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2277
|
+
if (!test) {
|
|
2278
|
+
throw new Error(`Notify does not accept a key argument for the namespace '${value}'. Received key '${key || ''}'.`);
|
|
2279
|
+
}
|
|
2280
|
+
})(!key || value === 'attributes' || value === 'relationships') : {};
|
|
2173
2281
|
if (!isStableIdentifier(identifier) && !isDocumentIdentifier(identifier)) {
|
|
2174
|
-
if (macroCondition(
|
|
2282
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_NOTIFICATIONS)) {
|
|
2175
2283
|
// eslint-disable-next-line no-console
|
|
2176
2284
|
console.log(`Notifying: Expected to receive a stable Identifier to notify '${value}' '${key || ''}' with, but ${String(identifier)} is not in the cache`, identifier);
|
|
2177
2285
|
}
|
|
2178
2286
|
return false;
|
|
2179
2287
|
}
|
|
2180
|
-
if (macroCondition(
|
|
2288
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_NOTIFICATIONS)) {
|
|
2181
2289
|
// eslint-disable-next-line no-console
|
|
2182
2290
|
console.log(`Buffering Notify: ${String(identifier.lid)}\t${value}\t${key || ''}`);
|
|
2183
2291
|
}
|
|
@@ -2224,7 +2332,7 @@ class NotificationManager {
|
|
|
2224
2332
|
this._onFlushCB = undefined;
|
|
2225
2333
|
}
|
|
2226
2334
|
_flushNotification(identifier, value, key) {
|
|
2227
|
-
if (macroCondition(
|
|
2335
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_NOTIFICATIONS)) {
|
|
2228
2336
|
// eslint-disable-next-line no-console
|
|
2229
2337
|
console.log(`Notifying: ${String(identifier)}\t${value}\t${key || ''}`);
|
|
2230
2338
|
}
|
|
@@ -2254,30 +2362,139 @@ class NotificationManager {
|
|
|
2254
2362
|
this._cache.clear();
|
|
2255
2363
|
}
|
|
2256
2364
|
}
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2365
|
+
|
|
2366
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2367
|
+
/*
|
|
2368
|
+
We redefine Proxy because the native Proxy type treats the `target` and
|
|
2369
|
+
`receiver` as the same type incorrectly.
|
|
2370
|
+
|
|
2371
|
+
We ported this from Typescript's own Proxy types on 3/10/2024.
|
|
2372
|
+
*/
|
|
2373
|
+
|
|
2374
|
+
const NativeProxy = Proxy;
|
|
2375
|
+
var __defProp = Object.defineProperty;
|
|
2376
|
+
var __export = (target, all) => {
|
|
2377
|
+
for (var name in all) __defProp(target, name, {
|
|
2378
|
+
get: all[name],
|
|
2379
|
+
enumerable: true
|
|
2261
2380
|
});
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2381
|
+
};
|
|
2382
|
+
|
|
2383
|
+
// src/runtime.ts
|
|
2384
|
+
var runtime_exports = {};
|
|
2385
|
+
__export(runtime_exports, {
|
|
2386
|
+
c: () => decorateClass,
|
|
2387
|
+
f: () => decorateFieldV1,
|
|
2388
|
+
g: () => decorateFieldV2,
|
|
2389
|
+
i: () => initializeDeferredDecorator,
|
|
2390
|
+
m: () => decorateMethodV1,
|
|
2391
|
+
n: () => decorateMethodV2,
|
|
2392
|
+
p: () => decoratePOJO
|
|
2393
|
+
});
|
|
2394
|
+
var deferred = /* @__PURE__ */new WeakMap();
|
|
2395
|
+
function deferDecorator(proto, prop, desc) {
|
|
2396
|
+
let map = deferred.get(proto);
|
|
2397
|
+
if (!map) {
|
|
2398
|
+
map = /* @__PURE__ */new Map();
|
|
2399
|
+
deferred.set(proto, map);
|
|
2400
|
+
}
|
|
2401
|
+
map.set(prop, desc);
|
|
2402
|
+
}
|
|
2403
|
+
function findDeferredDecorator(target, prop) {
|
|
2404
|
+
let cursor = target.prototype;
|
|
2405
|
+
while (cursor) {
|
|
2406
|
+
let desc = deferred.get(cursor)?.get(prop);
|
|
2407
|
+
if (desc) {
|
|
2408
|
+
return desc;
|
|
2409
|
+
}
|
|
2410
|
+
cursor = cursor.prototype;
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
function decorateFieldV1(target, prop, decorators, initializer) {
|
|
2414
|
+
return decorateFieldV2(target.prototype, prop, decorators, initializer);
|
|
2415
|
+
}
|
|
2416
|
+
function decorateFieldV2(prototype, prop, decorators, initializer) {
|
|
2417
|
+
let desc = {
|
|
2418
|
+
configurable: true,
|
|
2419
|
+
enumerable: true,
|
|
2420
|
+
writable: true,
|
|
2421
|
+
initializer: null
|
|
2422
|
+
};
|
|
2423
|
+
if (initializer) {
|
|
2424
|
+
desc.initializer = initializer;
|
|
2425
|
+
}
|
|
2426
|
+
for (let decorator of decorators) {
|
|
2427
|
+
desc = decorator(prototype, prop, desc) || desc;
|
|
2273
2428
|
}
|
|
2274
2429
|
if (desc.initializer === void 0) {
|
|
2275
|
-
Object.defineProperty(
|
|
2276
|
-
|
|
2430
|
+
Object.defineProperty(prototype, prop, desc);
|
|
2431
|
+
} else {
|
|
2432
|
+
deferDecorator(prototype, prop, desc);
|
|
2277
2433
|
}
|
|
2278
|
-
return desc;
|
|
2279
2434
|
}
|
|
2280
|
-
|
|
2435
|
+
function decorateMethodV1({
|
|
2436
|
+
prototype
|
|
2437
|
+
}, prop, decorators) {
|
|
2438
|
+
return decorateMethodV2(prototype, prop, decorators);
|
|
2439
|
+
}
|
|
2440
|
+
function decorateMethodV2(prototype, prop, decorators) {
|
|
2441
|
+
const origDesc = Object.getOwnPropertyDescriptor(prototype, prop);
|
|
2442
|
+
let desc = {
|
|
2443
|
+
...origDesc
|
|
2444
|
+
};
|
|
2445
|
+
for (let decorator of decorators) {
|
|
2446
|
+
desc = decorator(prototype, prop, desc) || desc;
|
|
2447
|
+
}
|
|
2448
|
+
if (desc.initializer !== void 0) {
|
|
2449
|
+
desc.value = desc.initializer ? desc.initializer.call(prototype) : void 0;
|
|
2450
|
+
desc.initializer = void 0;
|
|
2451
|
+
}
|
|
2452
|
+
Object.defineProperty(prototype, prop, desc);
|
|
2453
|
+
}
|
|
2454
|
+
function initializeDeferredDecorator(target, prop) {
|
|
2455
|
+
let desc = findDeferredDecorator(target.constructor, prop);
|
|
2456
|
+
if (desc) {
|
|
2457
|
+
Object.defineProperty(target, prop, {
|
|
2458
|
+
enumerable: desc.enumerable,
|
|
2459
|
+
configurable: desc.configurable,
|
|
2460
|
+
writable: desc.writable,
|
|
2461
|
+
value: desc.initializer ? desc.initializer.call(target) : void 0
|
|
2462
|
+
});
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
function decorateClass(target, decorators) {
|
|
2466
|
+
return decorators.reduce((accum, decorator) => decorator(accum) || accum, target);
|
|
2467
|
+
}
|
|
2468
|
+
function decoratePOJO(pojo, decorated) {
|
|
2469
|
+
for (let [type, prop, decorators] of decorated) {
|
|
2470
|
+
if (type === "field") {
|
|
2471
|
+
decoratePojoField(pojo, prop, decorators);
|
|
2472
|
+
} else {
|
|
2473
|
+
decorateMethodV2(pojo, prop, decorators);
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
return pojo;
|
|
2477
|
+
}
|
|
2478
|
+
function decoratePojoField(pojo, prop, decorators) {
|
|
2479
|
+
let desc = {
|
|
2480
|
+
configurable: true,
|
|
2481
|
+
enumerable: true,
|
|
2482
|
+
writable: true,
|
|
2483
|
+
initializer: () => Object.getOwnPropertyDescriptor(pojo, prop)?.value
|
|
2484
|
+
};
|
|
2485
|
+
for (let decorator of decorators) {
|
|
2486
|
+
desc = decorator(pojo, prop, desc) || desc;
|
|
2487
|
+
}
|
|
2488
|
+
if (desc.initializer) {
|
|
2489
|
+
desc.value = desc.initializer.call(pojo);
|
|
2490
|
+
delete desc.initializer;
|
|
2491
|
+
}
|
|
2492
|
+
Object.defineProperty(pojo, prop, desc);
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2495
|
+
/**
|
|
2496
|
+
@module @ember-data/store
|
|
2497
|
+
*/
|
|
2281
2498
|
const ARRAY_GETTER_METHODS = new Set([Symbol.iterator, 'concat', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'flat', 'flatMap', 'forEach', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'map', 'reduce', 'reduceRight', 'slice', 'some', 'values']);
|
|
2282
2499
|
const ARRAY_SETTER_METHODS = new Set(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
|
|
2283
2500
|
const SYNC_PROPS = new Set(['[]', 'length', 'links', 'meta']);
|
|
@@ -2290,11 +2507,11 @@ function isArraySetter(prop) {
|
|
|
2290
2507
|
function isSelfProp(self, prop) {
|
|
2291
2508
|
return prop in self;
|
|
2292
2509
|
}
|
|
2293
|
-
const ARRAY_SIGNAL = Symbol('#signal');
|
|
2294
|
-
const SOURCE = Symbol('#source');
|
|
2295
|
-
const MUTATE = Symbol('#update');
|
|
2296
|
-
const NOTIFY = Symbol('#notify');
|
|
2297
|
-
const IS_COLLECTION = Symbol.for('Collection');
|
|
2510
|
+
const ARRAY_SIGNAL = getOrSetGlobal('#signal', Symbol('#signal'));
|
|
2511
|
+
const SOURCE = getOrSetGlobal('#source', Symbol('#source'));
|
|
2512
|
+
const MUTATE = getOrSetGlobal('#update', Symbol('#update'));
|
|
2513
|
+
const NOTIFY = getOrSetGlobal('#notify', Symbol('#notify'));
|
|
2514
|
+
const IS_COLLECTION = getOrSetGlobal('IS_COLLECTION', Symbol.for('Collection'));
|
|
2298
2515
|
function notifyArray(arr) {
|
|
2299
2516
|
addToTransaction(arr[ARRAY_SIGNAL]);
|
|
2300
2517
|
}
|
|
@@ -2310,7 +2527,11 @@ function safeForEach(instance, arr, store, callback, target) {
|
|
|
2310
2527
|
}
|
|
2311
2528
|
// clone to prevent mutation
|
|
2312
2529
|
arr = arr.slice();
|
|
2313
|
-
|
|
2530
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2531
|
+
if (!test) {
|
|
2532
|
+
throw new Error('`forEach` expects a function as first argument.');
|
|
2533
|
+
}
|
|
2534
|
+
})(typeof callback === 'function') : {};
|
|
2314
2535
|
|
|
2315
2536
|
// because we retrieveLatest above we need not worry if array is mutated during iteration
|
|
2316
2537
|
// by unloadRecord/rollbackAttributes
|
|
@@ -2336,7 +2557,28 @@ function safeForEach(instance, arr, store, callback, target) {
|
|
|
2336
2557
|
@class RecordArray
|
|
2337
2558
|
@public
|
|
2338
2559
|
*/
|
|
2339
|
-
|
|
2560
|
+
|
|
2561
|
+
class IdentifierArray {
|
|
2562
|
+
/**
|
|
2563
|
+
The flag to signal a `RecordArray` is currently loading data.
|
|
2564
|
+
Example
|
|
2565
|
+
```javascript
|
|
2566
|
+
let people = store.peekAll('person');
|
|
2567
|
+
people.isUpdating; // false
|
|
2568
|
+
people.update();
|
|
2569
|
+
people.isUpdating; // true
|
|
2570
|
+
```
|
|
2571
|
+
@property isUpdating
|
|
2572
|
+
@public
|
|
2573
|
+
@type Boolean
|
|
2574
|
+
*/
|
|
2575
|
+
|
|
2576
|
+
isLoaded = true;
|
|
2577
|
+
isDestroying = false;
|
|
2578
|
+
isDestroyed = false;
|
|
2579
|
+
_updatingPromise = null;
|
|
2580
|
+
[IS_COLLECTION] = true;
|
|
2581
|
+
[SOURCE];
|
|
2340
2582
|
[NOTIFY]() {
|
|
2341
2583
|
notifyArray(this);
|
|
2342
2584
|
}
|
|
@@ -2361,29 +2603,13 @@ let IdentifierArray = (_class = class IdentifierArray {
|
|
|
2361
2603
|
get length() {
|
|
2362
2604
|
return this[SOURCE].length;
|
|
2363
2605
|
}
|
|
2606
|
+
static {
|
|
2607
|
+
decorateMethodV2(this.prototype, "length", [compat]);
|
|
2608
|
+
}
|
|
2364
2609
|
set length(value) {
|
|
2365
2610
|
this[SOURCE].length = value;
|
|
2366
2611
|
}
|
|
2367
2612
|
constructor(options) {
|
|
2368
|
-
/**
|
|
2369
|
-
The flag to signal a `RecordArray` is currently loading data.
|
|
2370
|
-
Example
|
|
2371
|
-
```javascript
|
|
2372
|
-
let people = store.peekAll('person');
|
|
2373
|
-
people.isUpdating; // false
|
|
2374
|
-
people.update();
|
|
2375
|
-
people.isUpdating; // true
|
|
2376
|
-
```
|
|
2377
|
-
@property isUpdating
|
|
2378
|
-
@public
|
|
2379
|
-
@type Boolean
|
|
2380
|
-
*/
|
|
2381
|
-
this.isLoaded = true;
|
|
2382
|
-
this.isDestroying = false;
|
|
2383
|
-
this.isDestroyed = false;
|
|
2384
|
-
this._updatingPromise = null;
|
|
2385
|
-
this[IS_COLLECTION] = true;
|
|
2386
|
-
this[SOURCE] = void 0;
|
|
2387
2613
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
2388
2614
|
const self = this;
|
|
2389
2615
|
this.modelName = options.type;
|
|
@@ -2404,7 +2630,7 @@ let IdentifierArray = (_class = class IdentifierArray {
|
|
|
2404
2630
|
// we track all mutations within the call
|
|
2405
2631
|
// and forward them as one
|
|
2406
2632
|
|
|
2407
|
-
const proxy = new
|
|
2633
|
+
const proxy = new NativeProxy(this[SOURCE], {
|
|
2408
2634
|
get(target, prop, receiver) {
|
|
2409
2635
|
const index = convertToInt(prop);
|
|
2410
2636
|
if (_SIGNAL.shouldReset && (index !== null || SYNC_PROPS.has(prop) || isArrayGetter(prop))) {
|
|
@@ -2455,11 +2681,19 @@ let IdentifierArray = (_class = class IdentifierArray {
|
|
|
2455
2681
|
// array functions must run through Reflect to work properly
|
|
2456
2682
|
// binding via other means will not work.
|
|
2457
2683
|
if (!options.allowMutation) {
|
|
2458
|
-
|
|
2684
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2685
|
+
if (!test) {
|
|
2686
|
+
throw new Error(`Mutating this array of records via ${String(prop)} is not allowed.`);
|
|
2687
|
+
}
|
|
2688
|
+
})(options.allowMutation) : {};
|
|
2459
2689
|
return;
|
|
2460
2690
|
}
|
|
2461
2691
|
const args = Array.prototype.slice.call(arguments);
|
|
2462
|
-
|
|
2692
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2693
|
+
if (!test) {
|
|
2694
|
+
throw new Error(`Cannot start a new array transaction while a previous transaction is underway`);
|
|
2695
|
+
}
|
|
2696
|
+
})(!transaction) : {};
|
|
2463
2697
|
transaction = true;
|
|
2464
2698
|
const result = self[MUTATE](target, receiver, prop, args, _SIGNAL);
|
|
2465
2699
|
transaction = false;
|
|
@@ -2501,7 +2735,11 @@ let IdentifierArray = (_class = class IdentifierArray {
|
|
|
2501
2735
|
} else if (transaction) {
|
|
2502
2736
|
return Reflect.set(target, prop, value);
|
|
2503
2737
|
} else {
|
|
2504
|
-
|
|
2738
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2739
|
+
{
|
|
2740
|
+
throw new Error(`unexpected length set`);
|
|
2741
|
+
}
|
|
2742
|
+
})() : {};
|
|
2505
2743
|
}
|
|
2506
2744
|
}
|
|
2507
2745
|
if (prop === 'links') {
|
|
@@ -2524,23 +2762,36 @@ let IdentifierArray = (_class = class IdentifierArray {
|
|
|
2524
2762
|
if (index === null || index > target.length) {
|
|
2525
2763
|
if (index !== null && transaction) {
|
|
2526
2764
|
const identifier = recordIdentifierFor(value);
|
|
2527
|
-
|
|
2765
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2766
|
+
if (!test) {
|
|
2767
|
+
throw new Error(`Cannot set index ${index} past the end of the array.`);
|
|
2768
|
+
}
|
|
2769
|
+
})(isStableIdentifier(identifier)) : {};
|
|
2528
2770
|
target[index] = identifier;
|
|
2529
2771
|
return true;
|
|
2530
2772
|
} else if (isSelfProp(self, prop)) {
|
|
2773
|
+
// @ts-expect-error not all properties are indeces and we can't safely cast
|
|
2531
2774
|
self[prop] = value;
|
|
2532
2775
|
return true;
|
|
2533
2776
|
}
|
|
2534
2777
|
return false;
|
|
2535
2778
|
}
|
|
2536
2779
|
if (!options.allowMutation) {
|
|
2537
|
-
|
|
2780
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2781
|
+
if (!test) {
|
|
2782
|
+
throw new Error(`Mutating ${String(prop)} on this Array is not allowed.`);
|
|
2783
|
+
}
|
|
2784
|
+
})(options.allowMutation) : {};
|
|
2538
2785
|
return false;
|
|
2539
2786
|
}
|
|
2540
2787
|
const original = target[index];
|
|
2541
2788
|
const newIdentifier = extractIdentifierFromRecord$1(value);
|
|
2542
2789
|
target[index] = newIdentifier;
|
|
2543
|
-
|
|
2790
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2791
|
+
if (!test) {
|
|
2792
|
+
throw new Error(`Expected a record`);
|
|
2793
|
+
}
|
|
2794
|
+
})(isStableIdentifier(newIdentifier)) : {};
|
|
2544
2795
|
// We generate "transactions" whenever a setter method on the array
|
|
2545
2796
|
// is called and might bulk update multiple array cells. Fundamentally,
|
|
2546
2797
|
// all array operations decompose into individual cell replacements.
|
|
@@ -2565,7 +2816,11 @@ let IdentifierArray = (_class = class IdentifierArray {
|
|
|
2565
2816
|
return true;
|
|
2566
2817
|
},
|
|
2567
2818
|
deleteProperty(target, prop) {
|
|
2568
|
-
|
|
2819
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2820
|
+
if (!test) {
|
|
2821
|
+
throw new Error(`Deleting keys on managed arrays is disallowed`);
|
|
2822
|
+
}
|
|
2823
|
+
})(transaction) : {};
|
|
2569
2824
|
if (!transaction) {
|
|
2570
2825
|
return false;
|
|
2571
2826
|
}
|
|
@@ -2613,11 +2868,19 @@ let IdentifierArray = (_class = class IdentifierArray {
|
|
|
2613
2868
|
}
|
|
2614
2869
|
|
|
2615
2870
|
/*
|
|
2616
|
-
Update this
|
|
2871
|
+
Update this Array and return a promise which resolves once the update
|
|
2617
2872
|
is finished.
|
|
2618
2873
|
*/
|
|
2619
2874
|
_update() {
|
|
2620
|
-
|
|
2875
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2876
|
+
if (!test) {
|
|
2877
|
+
throw new Error(`_update cannot be used with this array`);
|
|
2878
|
+
}
|
|
2879
|
+
})(this.modelName) : {};
|
|
2880
|
+
// @ts-expect-error typescript is unable to handle the complexity of
|
|
2881
|
+
// T = unknown, modelName = string
|
|
2882
|
+
// T extends TypedRecordInstance, modelName = TypeFromInstance<T>
|
|
2883
|
+
// both being valid options to pass through here.
|
|
2621
2884
|
return this.store.findAll(this.modelName, {
|
|
2622
2885
|
reload: true
|
|
2623
2886
|
});
|
|
@@ -2642,7 +2905,9 @@ let IdentifierArray = (_class = class IdentifierArray {
|
|
|
2642
2905
|
const promise = Promise.all(this.map(record => this.store.saveRecord(record))).then(() => this);
|
|
2643
2906
|
return promise;
|
|
2644
2907
|
}
|
|
2645
|
-
}
|
|
2908
|
+
}
|
|
2909
|
+
|
|
2910
|
+
// this will error if someone tries to call
|
|
2646
2911
|
// A(identifierArray) since it is not configurable
|
|
2647
2912
|
// which is preferable to the `meta` override we used
|
|
2648
2913
|
// before which required importing all of Ember
|
|
@@ -2657,9 +2922,9 @@ compat(desc);
|
|
|
2657
2922
|
Object.defineProperty(IdentifierArray.prototype, '[]', desc);
|
|
2658
2923
|
defineSignal(IdentifierArray.prototype, 'isUpdating', false);
|
|
2659
2924
|
class Collection extends IdentifierArray {
|
|
2925
|
+
query = null;
|
|
2660
2926
|
constructor(options) {
|
|
2661
2927
|
super(options);
|
|
2662
|
-
this.query = null;
|
|
2663
2928
|
this.query = options.query || null;
|
|
2664
2929
|
this.isLoaded = options.isLoaded || false;
|
|
2665
2930
|
}
|
|
@@ -2670,8 +2935,20 @@ class Collection extends IdentifierArray {
|
|
|
2670
2935
|
} = this;
|
|
2671
2936
|
|
|
2672
2937
|
// TODO save options from initial request?
|
|
2673
|
-
|
|
2674
|
-
|
|
2938
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2939
|
+
if (!test) {
|
|
2940
|
+
throw new Error(`update cannot be used with this array`);
|
|
2941
|
+
}
|
|
2942
|
+
})(this.modelName) : {};
|
|
2943
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2944
|
+
if (!test) {
|
|
2945
|
+
throw new Error(`update cannot be used with no query`);
|
|
2946
|
+
}
|
|
2947
|
+
})(query) : {};
|
|
2948
|
+
// @ts-expect-error typescript is unable to handle the complexity of
|
|
2949
|
+
// T = unknown, modelName = string
|
|
2950
|
+
// T extends TypedRecordInstance, modelName = TypeFromInstance<T>
|
|
2951
|
+
// both being valid options to pass through here.
|
|
2675
2952
|
const promise = store.query(this.modelName, query, {
|
|
2676
2953
|
_recordArray: this
|
|
2677
2954
|
});
|
|
@@ -2690,14 +2967,18 @@ Collection.prototype.query = null;
|
|
|
2690
2967
|
// Object.setPrototypeOf(IdentifierArray.prototype, Array.prototype);
|
|
2691
2968
|
|
|
2692
2969
|
function assertRecordPassedToHasMany(record) {
|
|
2693
|
-
|
|
2970
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2971
|
+
if (!test) {
|
|
2972
|
+
throw new Error(`All elements of a hasMany relationship must be instances of Model, you passed $${typeof record}`);
|
|
2973
|
+
}
|
|
2974
|
+
})(function () {
|
|
2694
2975
|
try {
|
|
2695
2976
|
recordIdentifierFor(record);
|
|
2696
2977
|
return true;
|
|
2697
2978
|
} catch {
|
|
2698
2979
|
return false;
|
|
2699
2980
|
}
|
|
2700
|
-
}());
|
|
2981
|
+
}()) : {};
|
|
2701
2982
|
}
|
|
2702
2983
|
function extractIdentifierFromRecord$1(record) {
|
|
2703
2984
|
if (!record) {
|
|
@@ -2710,7 +2991,7 @@ function extractIdentifierFromRecord$1(record) {
|
|
|
2710
2991
|
/**
|
|
2711
2992
|
@module @ember-data/store
|
|
2712
2993
|
*/
|
|
2713
|
-
const FAKE_ARR = {};
|
|
2994
|
+
const FAKE_ARR = getOrSetGlobal('FAKE_ARR', {});
|
|
2714
2995
|
const SLICE_BATCH_SIZE = 1200;
|
|
2715
2996
|
/**
|
|
2716
2997
|
* This is a clever optimization.
|
|
@@ -3058,9 +3339,10 @@ function sync(array, changes, arraySet) {
|
|
|
3058
3339
|
/**
|
|
3059
3340
|
* @module @ember-data/store
|
|
3060
3341
|
*/
|
|
3061
|
-
|
|
3062
|
-
const
|
|
3063
|
-
const
|
|
3342
|
+
|
|
3343
|
+
const Touching = getOrSetGlobal('Touching', Symbol('touching'));
|
|
3344
|
+
const RequestPromise = getOrSetGlobal('RequestPromise', Symbol('promise'));
|
|
3345
|
+
const EMPTY_ARR = macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? Object.freeze([]) : [];
|
|
3064
3346
|
function hasRecordIdentifier(op) {
|
|
3065
3347
|
return 'recordIdentifier' in op;
|
|
3066
3348
|
}
|
|
@@ -3073,12 +3355,12 @@ function hasRecordIdentifier(op) {
|
|
|
3073
3355
|
* @public
|
|
3074
3356
|
*/
|
|
3075
3357
|
class RequestStateService {
|
|
3358
|
+
_pending = new Map();
|
|
3359
|
+
_done = new Map();
|
|
3360
|
+
_subscriptions = new Map();
|
|
3361
|
+
_toFlush = [];
|
|
3362
|
+
_store;
|
|
3076
3363
|
constructor(store) {
|
|
3077
|
-
this._pending = new Map();
|
|
3078
|
-
this._done = new Map();
|
|
3079
|
-
this._subscriptions = new Map();
|
|
3080
|
-
this._toFlush = [];
|
|
3081
|
-
this._store = void 0;
|
|
3082
3364
|
this._store = store;
|
|
3083
3365
|
}
|
|
3084
3366
|
_clearEntries(identifier) {
|
|
@@ -3131,7 +3413,11 @@ class RequestStateService {
|
|
|
3131
3413
|
throw error;
|
|
3132
3414
|
});
|
|
3133
3415
|
}
|
|
3134
|
-
|
|
3416
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3417
|
+
{
|
|
3418
|
+
throw new Error(`Expected a well formed query`);
|
|
3419
|
+
}
|
|
3420
|
+
})() : {};
|
|
3135
3421
|
}
|
|
3136
3422
|
_triggerSubscriptions(req) {
|
|
3137
3423
|
if (req.state === 'pending') {
|
|
@@ -3264,8 +3550,16 @@ function constructResource(type, id, lid) {
|
|
|
3264
3550
|
if ('id' in resource) {
|
|
3265
3551
|
resource.id = coerceId(resource.id);
|
|
3266
3552
|
}
|
|
3267
|
-
|
|
3268
|
-
|
|
3553
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3554
|
+
if (!test) {
|
|
3555
|
+
throw new Error('Expected either id or lid to be a valid string');
|
|
3556
|
+
}
|
|
3557
|
+
})('id' in resource && isNonEmptyString(resource.id) || isNonEmptyString(resource.lid)) : {};
|
|
3558
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3559
|
+
if (!test) {
|
|
3560
|
+
throw new Error('if id is present, the type must be a string');
|
|
3561
|
+
}
|
|
3562
|
+
})(!('id' in resource) || typeof resource.type === 'string') : {};
|
|
3269
3563
|
return resource;
|
|
3270
3564
|
} else {
|
|
3271
3565
|
const trueId = coerceId(id);
|
|
@@ -3277,7 +3571,11 @@ function constructResource(type, id, lid) {
|
|
|
3277
3571
|
}
|
|
3278
3572
|
throw new Error('Expected either id or lid to be a valid string');
|
|
3279
3573
|
}
|
|
3280
|
-
|
|
3574
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3575
|
+
if (!test) {
|
|
3576
|
+
throw new Error('type must be a string');
|
|
3577
|
+
}
|
|
3578
|
+
})(typeof type === 'string') : {};
|
|
3281
3579
|
if (isNonEmptyString(lid)) {
|
|
3282
3580
|
return {
|
|
3283
3581
|
type,
|
|
@@ -3297,6 +3595,26 @@ function constructResource(type, id, lid) {
|
|
|
3297
3595
|
*/
|
|
3298
3596
|
// this import location is deprecated but breaks in 4.8 and older
|
|
3299
3597
|
|
|
3598
|
+
// `AwaitedKeys` is needed here to resolve any promise types like `PromiseBelongsTo`.
|
|
3599
|
+
|
|
3600
|
+
/**
|
|
3601
|
+
* Currently only records that extend object can be created via
|
|
3602
|
+
* store.createRecord. This is a limitation of the current API,
|
|
3603
|
+
* but can be worked around by creating a new identifier, running
|
|
3604
|
+
* the cache.clientDidCreate method, and then peeking the record
|
|
3605
|
+
* for the identifier.
|
|
3606
|
+
*
|
|
3607
|
+
* To assign primary key to a record during creation, only `id` will
|
|
3608
|
+
* work correctly for `store.createRecord`, other primary key may be
|
|
3609
|
+
* handled by updating the record after creation or using the flow
|
|
3610
|
+
* described above.
|
|
3611
|
+
*
|
|
3612
|
+
* TODO: These are limitations we want to (and can) address. If you
|
|
3613
|
+
* have need of lifting these limitations, please open an issue.
|
|
3614
|
+
*
|
|
3615
|
+
* @typedoc
|
|
3616
|
+
*/
|
|
3617
|
+
|
|
3300
3618
|
/**
|
|
3301
3619
|
* A Store coordinates interaction between your application, a [Cache](https://api.emberjs.com/ember-data/release/classes/%3CInterface%3E%20Cache),
|
|
3302
3620
|
* and sources of data (such as your API or a local persistence layer)
|
|
@@ -3308,18 +3626,47 @@ function constructResource(type, id, lid) {
|
|
|
3308
3626
|
* export default class extends Store {}
|
|
3309
3627
|
* ```
|
|
3310
3628
|
*
|
|
3311
|
-
* Most
|
|
3629
|
+
* Most Applications will only have a single `Store` configured as a Service
|
|
3312
3630
|
* in this manner. However, setting up multiple stores is possible, including using
|
|
3313
|
-
* each as a unique service.
|
|
3631
|
+
* each as a unique service or within a specific context.
|
|
3314
3632
|
*
|
|
3315
3633
|
|
|
3316
3634
|
@class Store
|
|
3317
3635
|
@public
|
|
3318
3636
|
*/
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3637
|
+
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
|
3638
|
+
const EmptyClass = class {
|
|
3639
|
+
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
|
3640
|
+
constructor(args) {}
|
|
3641
|
+
};
|
|
3642
|
+
const BaseClass = macroCondition(dependencySatisfies('ember-source', '*')) ? macroCondition(getGlobalConfig().WarpDrive.deprecations.DEPRECATE_STORE_EXTENDS_EMBER_OBJECT) ? importSync('@ember/object') : EmptyClass : EmptyClass;
|
|
3643
|
+
if (BaseClass !== EmptyClass) {
|
|
3644
|
+
deprecate(`The Store class extending from EmberObject is deprecated.
|
|
3645
|
+
Please remove usage of EmberObject APIs and mark your class as not requiring it.
|
|
3646
|
+
|
|
3647
|
+
To mark the class as no longer extending from EmberObject, in ember-cli-build.js
|
|
3648
|
+
set the following config:
|
|
3649
|
+
|
|
3650
|
+
\`\`\`js
|
|
3651
|
+
const app = new EmberApp(defaults, {
|
|
3652
|
+
emberData: {
|
|
3653
|
+
deprecations: {
|
|
3654
|
+
DEPRECATE_STORE_EXTENDS_EMBER_OBJECT: false
|
|
3655
|
+
}
|
|
3656
|
+
}
|
|
3657
|
+
});
|
|
3658
|
+
\`\`\`
|
|
3659
|
+
`, false, {
|
|
3660
|
+
id: 'ember-data:deprecate-store-extends-ember-object',
|
|
3661
|
+
until: '6.0',
|
|
3662
|
+
for: 'ember-data',
|
|
3663
|
+
since: {
|
|
3664
|
+
available: '5.4',
|
|
3665
|
+
enabled: '5.4'
|
|
3666
|
+
}
|
|
3667
|
+
});
|
|
3668
|
+
}
|
|
3669
|
+
class Store extends BaseClass {
|
|
3323
3670
|
/**
|
|
3324
3671
|
* Provides access to the NotificationManager associated
|
|
3325
3672
|
* with this Store instance.
|
|
@@ -3342,7 +3689,10 @@ class Store extends EmberObject {
|
|
|
3342
3689
|
* @public
|
|
3343
3690
|
*/
|
|
3344
3691
|
get schema() {
|
|
3345
|
-
|
|
3692
|
+
if (!this._schema) {
|
|
3693
|
+
this._schema = this.createSchemaService();
|
|
3694
|
+
}
|
|
3695
|
+
return this._schema;
|
|
3346
3696
|
}
|
|
3347
3697
|
|
|
3348
3698
|
/**
|
|
@@ -3368,7 +3718,7 @@ class Store extends EmberObject {
|
|
|
3368
3718
|
* ```ts
|
|
3369
3719
|
* import Store, { CacheHandler } from '@ember-data/store';
|
|
3370
3720
|
* import RequestManager from '@ember-data/request';
|
|
3371
|
-
* import Fetch from '@ember
|
|
3721
|
+
* import Fetch from '@ember-data/request/fetch';
|
|
3372
3722
|
*
|
|
3373
3723
|
* class extends Store {
|
|
3374
3724
|
* constructor() {
|
|
@@ -3385,7 +3735,7 @@ class Store extends EmberObject {
|
|
|
3385
3735
|
*/
|
|
3386
3736
|
|
|
3387
3737
|
/**
|
|
3388
|
-
* A Property which an App may set to provide a
|
|
3738
|
+
* A Property which an App may set to provide a CachePolicy
|
|
3389
3739
|
* to control when a cached request becomes stale.
|
|
3390
3740
|
*
|
|
3391
3741
|
* Note, when defined, these methods will only be invoked if a
|
|
@@ -3411,7 +3761,7 @@ class Store extends EmberObject {
|
|
|
3411
3761
|
* ```
|
|
3412
3762
|
*
|
|
3413
3763
|
* @public
|
|
3414
|
-
* @property {
|
|
3764
|
+
* @property {CachePolicy|undefined} lifetimes
|
|
3415
3765
|
*/
|
|
3416
3766
|
|
|
3417
3767
|
// Private
|
|
@@ -3436,7 +3786,6 @@ class Store extends EmberObject {
|
|
|
3436
3786
|
@private
|
|
3437
3787
|
*/
|
|
3438
3788
|
constructor(createArgs) {
|
|
3439
|
-
// @ts-expect-error ember-source types improperly expect createArgs to be `Owner`
|
|
3440
3789
|
super(createArgs);
|
|
3441
3790
|
Object.assign(this, createArgs);
|
|
3442
3791
|
this.identifierCache = new IdentifierCache();
|
|
@@ -3455,9 +3804,13 @@ class Store extends EmberObject {
|
|
|
3455
3804
|
this.isDestroyed = false;
|
|
3456
3805
|
}
|
|
3457
3806
|
_run(cb) {
|
|
3458
|
-
|
|
3807
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3808
|
+
if (!test) {
|
|
3809
|
+
throw new Error(`EmberData should never encounter a nested run`);
|
|
3810
|
+
}
|
|
3811
|
+
})(!this._cbs) : {};
|
|
3459
3812
|
const _cbs = this._cbs = {};
|
|
3460
|
-
if (macroCondition(
|
|
3813
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
3461
3814
|
try {
|
|
3462
3815
|
cb();
|
|
3463
3816
|
if (_cbs.coalesce) {
|
|
@@ -3494,8 +3847,16 @@ class Store extends EmberObject {
|
|
|
3494
3847
|
}
|
|
3495
3848
|
}
|
|
3496
3849
|
_schedule(name, cb) {
|
|
3497
|
-
|
|
3498
|
-
|
|
3850
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3851
|
+
if (!test) {
|
|
3852
|
+
throw new Error(`EmberData expects to schedule only when there is an active run`);
|
|
3853
|
+
}
|
|
3854
|
+
})(!!this._cbs) : {};
|
|
3855
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3856
|
+
if (!test) {
|
|
3857
|
+
throw new Error(`EmberData expects only one flush per queue name, cannot schedule ${name}`);
|
|
3858
|
+
}
|
|
3859
|
+
})(!this._cbs[name]) : {};
|
|
3499
3860
|
this._cbs[name] = cb;
|
|
3500
3861
|
}
|
|
3501
3862
|
|
|
@@ -3514,7 +3875,7 @@ class Store extends EmberObject {
|
|
|
3514
3875
|
return this._requestCache;
|
|
3515
3876
|
}
|
|
3516
3877
|
_getAllPending() {
|
|
3517
|
-
if (macroCondition(
|
|
3878
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.TESTING)) {
|
|
3518
3879
|
const all = [];
|
|
3519
3880
|
const pending = this._requestCache._pending;
|
|
3520
3881
|
pending.forEach(requests => {
|
|
@@ -3539,7 +3900,7 @@ class Store extends EmberObject {
|
|
|
3539
3900
|
* and document cached.
|
|
3540
3901
|
*
|
|
3541
3902
|
* The cache key used is `requestConfig.cacheOptions.key`
|
|
3542
|
-
* if present, falling back to `
|
|
3903
|
+
* if present, falling back to `requestConfig.url`.
|
|
3543
3904
|
*
|
|
3544
3905
|
* Params are not serialized as part of the cache-key, so
|
|
3545
3906
|
* either ensure they are already in the url or utilize
|
|
@@ -3557,7 +3918,7 @@ class Store extends EmberObject {
|
|
|
3557
3918
|
* When a cache-key is determined, the request may fulfill
|
|
3558
3919
|
* from cache provided the cache is not stale.
|
|
3559
3920
|
*
|
|
3560
|
-
* Cache staleness is determined by the configured
|
|
3921
|
+
* Cache staleness is determined by the configured CachePolicy
|
|
3561
3922
|
* with priority given to the `cacheOptions.reload` and
|
|
3562
3923
|
* `cacheOptions.backgroundReload` on the request if present.
|
|
3563
3924
|
*
|
|
@@ -3592,12 +3953,12 @@ class Store extends EmberObject {
|
|
|
3592
3953
|
const identifierCache = this.identifierCache;
|
|
3593
3954
|
opts.records = requestConfig.records.map(r => identifierCache.getOrCreateRecordIdentifier(r));
|
|
3594
3955
|
}
|
|
3595
|
-
if (macroCondition(
|
|
3956
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.TESTING)) {
|
|
3596
3957
|
if (this.DISABLE_WAITER) {
|
|
3597
3958
|
opts.disableTestWaiter = typeof requestConfig.disableTestWaiter === 'boolean' ? requestConfig.disableTestWaiter : true;
|
|
3598
3959
|
}
|
|
3599
3960
|
}
|
|
3600
|
-
if (macroCondition(
|
|
3961
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_REQUESTS)) {
|
|
3601
3962
|
let options;
|
|
3602
3963
|
try {
|
|
3603
3964
|
options = JSON.parse(JSON.stringify(requestConfig));
|
|
@@ -3607,9 +3968,10 @@ class Store extends EmberObject {
|
|
|
3607
3968
|
// eslint-disable-next-line no-console
|
|
3608
3969
|
console.log(`request: [[START]] ${requestConfig.op && !requestConfig.url ? '(LEGACY) ' : ''}${requestConfig.op || '<unknown operation>'} ${requestConfig.url || '<empty url>'} ${requestConfig.method || '<empty method>'}`, options);
|
|
3609
3970
|
}
|
|
3610
|
-
const
|
|
3971
|
+
const request = Object.assign({}, requestConfig, opts);
|
|
3972
|
+
const future = this.requestManager.request(request);
|
|
3611
3973
|
future.onFinalize(() => {
|
|
3612
|
-
if (macroCondition(
|
|
3974
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_REQUESTS)) {
|
|
3613
3975
|
// eslint-disable-next-line no-console
|
|
3614
3976
|
console.log(`request: [[FINALIZE]] ${requestConfig.op && !requestConfig.url ? '(LEGACY) ' : ''}${requestConfig.op || '<unknown operation>'} ${requestConfig.url || '<empty url>'} ${requestConfig.method || '<empty method>'}`);
|
|
3615
3977
|
}
|
|
@@ -3628,7 +3990,7 @@ class Store extends EmberObject {
|
|
|
3628
3990
|
* a resource.
|
|
3629
3991
|
*
|
|
3630
3992
|
* This hook can be used to select or instantiate any desired
|
|
3631
|
-
* mechanism of
|
|
3993
|
+
* mechanism of presenting cache data to the ui for access
|
|
3632
3994
|
* mutation, and interaction.
|
|
3633
3995
|
*
|
|
3634
3996
|
* @method instantiateRecord (hook)
|
|
@@ -3652,134 +4014,7 @@ class Store extends EmberObject {
|
|
|
3652
4014
|
*/
|
|
3653
4015
|
|
|
3654
4016
|
/**
|
|
3655
|
-
|
|
3656
|
-
* for this Store instance.
|
|
3657
|
-
*
|
|
3658
|
-
* The SchemaDefinitionService can be used to query for
|
|
3659
|
-
* information about the schema of a resource.
|
|
3660
|
-
*
|
|
3661
|
-
* @method getSchemaDefinitionService
|
|
3662
|
-
* @public
|
|
3663
|
-
*/
|
|
3664
|
-
getSchemaDefinitionService() {
|
|
3665
|
-
assert(`You must registerSchemaDefinitionService with the store to use custom model classes`, this._schema);
|
|
3666
|
-
return this._schema;
|
|
3667
|
-
}
|
|
3668
|
-
|
|
3669
|
-
/**
|
|
3670
|
-
* DEPRECATED - Use `registerSchema` instead.
|
|
3671
|
-
*
|
|
3672
|
-
* Allows an app to register a custom SchemaService
|
|
3673
|
-
* for use when information about a resource's schema needs
|
|
3674
|
-
* to be queried.
|
|
3675
|
-
*
|
|
3676
|
-
* This method can only be called more than once, but only one schema
|
|
3677
|
-
* definition service may exist. Therefore if you wish to chain services
|
|
3678
|
-
* you must lookup the existing service and close over it with the new
|
|
3679
|
-
* service by accessing `store.schema` prior to registration.
|
|
3680
|
-
*
|
|
3681
|
-
* For Example:
|
|
3682
|
-
*
|
|
3683
|
-
* ```ts
|
|
3684
|
-
* import Store from '@ember-data/store';
|
|
3685
|
-
*
|
|
3686
|
-
* class SchemaDelegator {
|
|
3687
|
-
* constructor(schema) {
|
|
3688
|
-
* this._schema = schema;
|
|
3689
|
-
* }
|
|
3690
|
-
*
|
|
3691
|
-
* doesTypeExist(type: string): boolean {
|
|
3692
|
-
* if (AbstractSchemas.has(type)) {
|
|
3693
|
-
* return true;
|
|
3694
|
-
* }
|
|
3695
|
-
* return this._schema.doesTypeExist(type);
|
|
3696
|
-
* }
|
|
3697
|
-
*
|
|
3698
|
-
* attributesDefinitionFor(identifier: RecordIdentifier | { type: string }): AttributesSchema {
|
|
3699
|
-
* return this._schema.attributesDefinitionFor(identifier);
|
|
3700
|
-
* }
|
|
3701
|
-
*
|
|
3702
|
-
* relationshipsDefinitionFor(identifier: RecordIdentifier | { type: string }): RelationshipsSchema {
|
|
3703
|
-
* const schema = AbstractSchemas.get(identifier.type);
|
|
3704
|
-
* return schema || this._schema.relationshipsDefinitionFor(identifier);
|
|
3705
|
-
* }
|
|
3706
|
-
* }
|
|
3707
|
-
*
|
|
3708
|
-
* export default class extends Store {
|
|
3709
|
-
* constructor(...args) {
|
|
3710
|
-
* super(...args);
|
|
3711
|
-
*
|
|
3712
|
-
* const schema = this.schema;
|
|
3713
|
-
* this.registerSchemaDefinitionService(new SchemaDelegator(schema));
|
|
3714
|
-
* }
|
|
3715
|
-
* }
|
|
3716
|
-
* ```
|
|
3717
|
-
*
|
|
3718
|
-
* @method registerSchemaDefinitionService
|
|
3719
|
-
* @param {SchemaService} schema
|
|
3720
|
-
* @deprecated
|
|
3721
|
-
* @public
|
|
3722
|
-
*/
|
|
3723
|
-
registerSchemaDefinitionService(schema) {
|
|
3724
|
-
this._schema = schema;
|
|
3725
|
-
}
|
|
3726
|
-
/**
|
|
3727
|
-
* Allows an app to register a custom SchemaService
|
|
3728
|
-
* for use when information about a resource's schema needs
|
|
3729
|
-
* to be queried.
|
|
3730
|
-
*
|
|
3731
|
-
* This method can only be called more than once, but only one schema
|
|
3732
|
-
* definition service may exist. Therefore if you wish to chain services
|
|
3733
|
-
* you must lookup the existing service and close over it with the new
|
|
3734
|
-
* service by accessing `store.schema` prior to registration.
|
|
3735
|
-
*
|
|
3736
|
-
* For Example:
|
|
3737
|
-
*
|
|
3738
|
-
* ```ts
|
|
3739
|
-
* import Store from '@ember-data/store';
|
|
3740
|
-
*
|
|
3741
|
-
* class SchemaDelegator {
|
|
3742
|
-
* constructor(schema) {
|
|
3743
|
-
* this._schema = schema;
|
|
3744
|
-
* }
|
|
3745
|
-
*
|
|
3746
|
-
* doesTypeExist(type: string): boolean {
|
|
3747
|
-
* if (AbstractSchemas.has(type)) {
|
|
3748
|
-
* return true;
|
|
3749
|
-
* }
|
|
3750
|
-
* return this._schema.doesTypeExist(type);
|
|
3751
|
-
* }
|
|
3752
|
-
*
|
|
3753
|
-
* attributesDefinitionFor(identifier: RecordIdentifier | { type: string }): AttributesSchema {
|
|
3754
|
-
* return this._schema.attributesDefinitionFor(identifier);
|
|
3755
|
-
* }
|
|
3756
|
-
*
|
|
3757
|
-
* relationshipsDefinitionFor(identifier: RecordIdentifier | { type: string }): RelationshipsSchema {
|
|
3758
|
-
* const schema = AbstractSchemas.get(identifier.type);
|
|
3759
|
-
* return schema || this._schema.relationshipsDefinitionFor(identifier);
|
|
3760
|
-
* }
|
|
3761
|
-
* }
|
|
3762
|
-
*
|
|
3763
|
-
* export default class extends Store {
|
|
3764
|
-
* constructor(...args) {
|
|
3765
|
-
* super(...args);
|
|
3766
|
-
*
|
|
3767
|
-
* const schema = this.schema;
|
|
3768
|
-
* this.registerSchema(new SchemaDelegator(schema));
|
|
3769
|
-
* }
|
|
3770
|
-
* }
|
|
3771
|
-
* ```
|
|
3772
|
-
*
|
|
3773
|
-
* @method registerSchema
|
|
3774
|
-
* @param {SchemaService} schema
|
|
3775
|
-
* @public
|
|
3776
|
-
*/
|
|
3777
|
-
registerSchema(schema) {
|
|
3778
|
-
this._schema = schema;
|
|
3779
|
-
}
|
|
3780
|
-
|
|
3781
|
-
/**
|
|
3782
|
-
Returns the schema for a particular `modelName`.
|
|
4017
|
+
Returns the schema for a particular resource type (modelName).
|
|
3783
4018
|
When used with Model from @ember-data/model the return is the model class,
|
|
3784
4019
|
but this is not guaranteed.
|
|
3785
4020
|
If looking to query attribute or relationship information it is
|
|
@@ -3793,17 +4028,29 @@ class Store extends EmberObject {
|
|
|
3793
4028
|
for example.
|
|
3794
4029
|
@method modelFor
|
|
3795
4030
|
@public
|
|
3796
|
-
@
|
|
4031
|
+
@deprecated
|
|
4032
|
+
@param {string} type
|
|
3797
4033
|
@return {ModelSchema}
|
|
3798
4034
|
*/
|
|
3799
|
-
// TODO @deprecate in favor of schema APIs, requires adapter/serializer overhaul or replacement
|
|
3800
4035
|
|
|
3801
4036
|
modelFor(type) {
|
|
3802
|
-
|
|
4037
|
+
// FIXME add deprecation and deprecation stripping
|
|
4038
|
+
// FIXME/TODO update RFC to remove this method
|
|
4039
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
3803
4040
|
assertDestroyedStoreOnly(this, 'modelFor');
|
|
3804
4041
|
}
|
|
3805
|
-
|
|
3806
|
-
|
|
4042
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4043
|
+
if (!test) {
|
|
4044
|
+
throw new Error(`You need to pass <type> to the store's modelFor method`);
|
|
4045
|
+
}
|
|
4046
|
+
})(typeof type === 'string' && type.length) : {};
|
|
4047
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4048
|
+
if (!test) {
|
|
4049
|
+
throw new Error(`No model was found for '${type}' and no schema handles the type`);
|
|
4050
|
+
}
|
|
4051
|
+
})(this.schema.hasResource({
|
|
4052
|
+
type
|
|
4053
|
+
})) : {};
|
|
3807
4054
|
return getShimClass(this, type);
|
|
3808
4055
|
}
|
|
3809
4056
|
|
|
@@ -3818,7 +4065,7 @@ class Store extends EmberObject {
|
|
|
3818
4065
|
```
|
|
3819
4066
|
To create a new instance of a `Post` that has a relationship with a `User` record:
|
|
3820
4067
|
```js
|
|
3821
|
-
let user = this.store.peekRecord('user', 1);
|
|
4068
|
+
let user = this.store.peekRecord('user', '1');
|
|
3822
4069
|
store.createRecord('post', {
|
|
3823
4070
|
title: 'Ember is awesome!',
|
|
3824
4071
|
user: user
|
|
@@ -3826,17 +4073,26 @@ class Store extends EmberObject {
|
|
|
3826
4073
|
```
|
|
3827
4074
|
@method createRecord
|
|
3828
4075
|
@public
|
|
3829
|
-
@param {String}
|
|
4076
|
+
@param {String} type the name of the resource
|
|
3830
4077
|
@param {Object} inputProperties a hash of properties to set on the
|
|
3831
4078
|
newly created record.
|
|
3832
4079
|
@return {Model} record
|
|
3833
4080
|
*/
|
|
3834
|
-
|
|
3835
|
-
|
|
4081
|
+
|
|
4082
|
+
createRecord(type, inputProperties) {
|
|
4083
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
3836
4084
|
assertDestroyingStore(this, 'createRecord');
|
|
3837
4085
|
}
|
|
3838
|
-
|
|
3839
|
-
|
|
4086
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4087
|
+
if (!test) {
|
|
4088
|
+
throw new Error(`You need to pass a model name to the store's createRecord method`);
|
|
4089
|
+
}
|
|
4090
|
+
})(type) : {};
|
|
4091
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4092
|
+
if (!test) {
|
|
4093
|
+
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${type}`);
|
|
4094
|
+
}
|
|
4095
|
+
})(typeof type === 'string') : {};
|
|
3840
4096
|
|
|
3841
4097
|
// This is wrapped in a `run.join` so that in test environments users do not need to manually wrap
|
|
3842
4098
|
// calls to `createRecord`. The run loop usage here is because we batch the joining and updating
|
|
@@ -3845,7 +4101,7 @@ class Store extends EmberObject {
|
|
|
3845
4101
|
// to remove this, we would need to move to a new `async` API.
|
|
3846
4102
|
let record;
|
|
3847
4103
|
this._join(() => {
|
|
3848
|
-
const normalizedModelName = normalizeModelName(
|
|
4104
|
+
const normalizedModelName = normalizeModelName(type);
|
|
3849
4105
|
const properties = {
|
|
3850
4106
|
...inputProperties
|
|
3851
4107
|
};
|
|
@@ -3854,25 +4110,28 @@ class Store extends EmberObject {
|
|
|
3854
4110
|
// give the adapter an opportunity to generate one. Typically,
|
|
3855
4111
|
// client-side ID generators will use something like uuid.js
|
|
3856
4112
|
// to avoid conflicts.
|
|
3857
|
-
|
|
4113
|
+
let id = null;
|
|
3858
4114
|
if (properties.id === null || properties.id === undefined) {
|
|
3859
|
-
const adapter = this.adapterFor?.(
|
|
4115
|
+
const adapter = this.adapterFor?.(normalizedModelName, true);
|
|
3860
4116
|
if (adapter && adapter.generateIdForRecord) {
|
|
3861
|
-
properties.id = adapter.generateIdForRecord(this,
|
|
4117
|
+
id = properties.id = coerceId(adapter.generateIdForRecord(this, normalizedModelName, properties));
|
|
3862
4118
|
} else {
|
|
3863
|
-
properties.id = null;
|
|
4119
|
+
id = properties.id = null;
|
|
3864
4120
|
}
|
|
4121
|
+
} else {
|
|
4122
|
+
id = properties.id = coerceId(properties.id);
|
|
3865
4123
|
}
|
|
3866
|
-
|
|
3867
|
-
// Coerce ID to a string
|
|
3868
|
-
properties.id = coerceId(properties.id);
|
|
3869
4124
|
const resource = {
|
|
3870
4125
|
type: normalizedModelName,
|
|
3871
|
-
id
|
|
4126
|
+
id
|
|
3872
4127
|
};
|
|
3873
4128
|
if (resource.id) {
|
|
3874
4129
|
const identifier = this.identifierCache.peekRecordIdentifier(resource);
|
|
3875
|
-
|
|
4130
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4131
|
+
if (!test) {
|
|
4132
|
+
throw new Error(`The id ${String(properties.id)} has already been used with another '${normalizedModelName}' record.`);
|
|
4133
|
+
}
|
|
4134
|
+
})(!identifier) : {};
|
|
3876
4135
|
}
|
|
3877
4136
|
const identifier = this.identifierCache.createIdentifierForNewRecord(resource);
|
|
3878
4137
|
const cache = this.cache;
|
|
@@ -3894,15 +4153,19 @@ class Store extends EmberObject {
|
|
|
3894
4153
|
```
|
|
3895
4154
|
@method deleteRecord
|
|
3896
4155
|
@public
|
|
3897
|
-
@param {
|
|
4156
|
+
@param {unknown} record
|
|
3898
4157
|
*/
|
|
3899
4158
|
deleteRecord(record) {
|
|
3900
|
-
if (macroCondition(
|
|
4159
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
3901
4160
|
assertDestroyingStore(this, 'deleteRecord');
|
|
3902
4161
|
}
|
|
3903
4162
|
const identifier = peekRecordIdentifier(record);
|
|
3904
4163
|
const cache = this.cache;
|
|
3905
|
-
|
|
4164
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4165
|
+
if (!test) {
|
|
4166
|
+
throw new Error(`expected the record to be connected to a cache`);
|
|
4167
|
+
}
|
|
4168
|
+
})(identifier) : {};
|
|
3906
4169
|
this._join(() => {
|
|
3907
4170
|
cache.setIsDeleted(identifier, true);
|
|
3908
4171
|
if (cache.isNew(identifier)) {
|
|
@@ -3916,7 +4179,7 @@ class Store extends EmberObject {
|
|
|
3916
4179
|
This will cause the record to be destroyed and freed up for garbage collection.
|
|
3917
4180
|
Example
|
|
3918
4181
|
```javascript
|
|
3919
|
-
store.findRecord('post', 1).then(function(post) {
|
|
4182
|
+
store.findRecord('post', '1').then(function(post) {
|
|
3920
4183
|
store.unloadRecord(post);
|
|
3921
4184
|
});
|
|
3922
4185
|
```
|
|
@@ -3925,7 +4188,7 @@ class Store extends EmberObject {
|
|
|
3925
4188
|
@param {Model} record
|
|
3926
4189
|
*/
|
|
3927
4190
|
unloadRecord(record) {
|
|
3928
|
-
if (macroCondition(
|
|
4191
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
3929
4192
|
assertDestroyingStore(this, 'unloadRecord');
|
|
3930
4193
|
}
|
|
3931
4194
|
const identifier = peekRecordIdentifier(record);
|
|
@@ -3942,8 +4205,7 @@ class Store extends EmberObject {
|
|
|
3942
4205
|
resolved with the record.
|
|
3943
4206
|
**Example 1**
|
|
3944
4207
|
```app/routes/post.js
|
|
3945
|
-
|
|
3946
|
-
export default class PostRoute extends Route {
|
|
4208
|
+
export default class PostRoute extends Route {
|
|
3947
4209
|
model({ post_id }) {
|
|
3948
4210
|
return this.store.findRecord('post', post_id);
|
|
3949
4211
|
}
|
|
@@ -3954,8 +4216,7 @@ class Store extends EmberObject {
|
|
|
3954
4216
|
of `type` (modelName) and `id` as separate arguments. You may recognize this combo as
|
|
3955
4217
|
the typical pairing from [JSON:API](https://jsonapi.org/format/#document-resource-object-identification)
|
|
3956
4218
|
```app/routes/post.js
|
|
3957
|
-
|
|
3958
|
-
export default class PostRoute extends Route {
|
|
4219
|
+
export default class PostRoute extends Route {
|
|
3959
4220
|
model({ post_id: id }) {
|
|
3960
4221
|
return this.store.findRecord({ type: 'post', id });
|
|
3961
4222
|
}
|
|
@@ -3978,8 +4239,7 @@ class Store extends EmberObject {
|
|
|
3978
4239
|
for the comment also looks like `/posts/1/comments/2` if you want to fetch the comment
|
|
3979
4240
|
without also fetching the post you can pass in the post to the `findRecord` call:
|
|
3980
4241
|
```app/routes/post-comments.js
|
|
3981
|
-
|
|
3982
|
-
export default class PostRoute extends Route {
|
|
4242
|
+
export default class PostRoute extends Route {
|
|
3983
4243
|
model({ post_id, comment_id: id }) {
|
|
3984
4244
|
return this.store.findRecord({ type: 'comment', id, { preload: { post: post_id }} });
|
|
3985
4245
|
}
|
|
@@ -4005,8 +4265,7 @@ class Store extends EmberObject {
|
|
|
4005
4265
|
This could also be achieved by supplying the post id to the adapter via the adapterOptions
|
|
4006
4266
|
property on the options hash.
|
|
4007
4267
|
```app/routes/post-comments.js
|
|
4008
|
-
|
|
4009
|
-
export default class PostRoute extends Route {
|
|
4268
|
+
export default class PostRoute extends Route {
|
|
4010
4269
|
model({ post_id, comment_id: id }) {
|
|
4011
4270
|
return this.store.findRecord({ type: 'comment', id, { adapterOptions: { post: post_id }} });
|
|
4012
4271
|
}
|
|
@@ -4029,8 +4288,8 @@ class Store extends EmberObject {
|
|
|
4029
4288
|
```
|
|
4030
4289
|
If you have access to the post model you can also pass the model itself to preload:
|
|
4031
4290
|
```javascript
|
|
4032
|
-
let post = await store.findRecord('post', 1);
|
|
4033
|
-
let comment = await store.findRecord('comment', 2, { post: myPostModel });
|
|
4291
|
+
let post = await store.findRecord('post', '1');
|
|
4292
|
+
let comment = await store.findRecord('comment', '2', { post: myPostModel });
|
|
4034
4293
|
```
|
|
4035
4294
|
### Reloading
|
|
4036
4295
|
The reload behavior is configured either via the passed `options` hash or
|
|
@@ -4054,7 +4313,7 @@ class Store extends EmberObject {
|
|
|
4054
4313
|
// revision: 2
|
|
4055
4314
|
// }
|
|
4056
4315
|
// ]
|
|
4057
|
-
store.findRecord('post', 1, { reload: true }).then(function(post) {
|
|
4316
|
+
store.findRecord('post', '1', { reload: true }).then(function(post) {
|
|
4058
4317
|
post.revision; // 2
|
|
4059
4318
|
});
|
|
4060
4319
|
```
|
|
@@ -4083,7 +4342,7 @@ class Store extends EmberObject {
|
|
|
4083
4342
|
revision: 1
|
|
4084
4343
|
}
|
|
4085
4344
|
});
|
|
4086
|
-
let blogPost = store.findRecord('post', 1).then(function(post) {
|
|
4345
|
+
let blogPost = store.findRecord('post', '1').then(function(post) {
|
|
4087
4346
|
post.revision; // 1
|
|
4088
4347
|
});
|
|
4089
4348
|
// later, once adapter#findRecord resolved with
|
|
@@ -4100,8 +4359,7 @@ class Store extends EmberObject {
|
|
|
4100
4359
|
boolean value for `backgroundReload` in the options object for
|
|
4101
4360
|
`findRecord`.
|
|
4102
4361
|
```app/routes/post/edit.js
|
|
4103
|
-
|
|
4104
|
-
export default class PostEditRoute extends Route {
|
|
4362
|
+
export default class PostEditRoute extends Route {
|
|
4105
4363
|
model(params) {
|
|
4106
4364
|
return this.store.findRecord('post', params.post_id, { backgroundReload: false });
|
|
4107
4365
|
}
|
|
@@ -4110,8 +4368,7 @@ class Store extends EmberObject {
|
|
|
4110
4368
|
If you pass an object on the `adapterOptions` property of the options
|
|
4111
4369
|
argument it will be passed to your adapter via the snapshot
|
|
4112
4370
|
```app/routes/post/edit.js
|
|
4113
|
-
|
|
4114
|
-
export default class PostEditRoute extends Route {
|
|
4371
|
+
export default class PostEditRoute extends Route {
|
|
4115
4372
|
model(params) {
|
|
4116
4373
|
return this.store.findRecord('post', params.post_id, {
|
|
4117
4374
|
adapterOptions: { subscribe: false }
|
|
@@ -4143,8 +4400,7 @@ class Store extends EmberObject {
|
|
|
4143
4400
|
model, when we retrieve a specific post we can have the server also return that post's
|
|
4144
4401
|
comments in the same request:
|
|
4145
4402
|
```app/routes/post.js
|
|
4146
|
-
|
|
4147
|
-
export default class PostRoute extends Route {
|
|
4403
|
+
export default class PostRoute extends Route {
|
|
4148
4404
|
model(params) {
|
|
4149
4405
|
return this.store.findRecord('post', params.post_id, { include: 'comments' });
|
|
4150
4406
|
}
|
|
@@ -4172,8 +4428,7 @@ class Store extends EmberObject {
|
|
|
4172
4428
|
using a dot-separated sequence of relationship names. So to request both the post's
|
|
4173
4429
|
comments and the authors of those comments the request would look like this:
|
|
4174
4430
|
```app/routes/post.js
|
|
4175
|
-
|
|
4176
|
-
export default class PostRoute extends Route {
|
|
4431
|
+
export default class PostRoute extends Route {
|
|
4177
4432
|
model(params) {
|
|
4178
4433
|
return this.store.findRecord('post', params.post_id, { include: 'comments,comments.author' });
|
|
4179
4434
|
}
|
|
@@ -4196,41 +4451,47 @@ class Store extends EmberObject {
|
|
|
4196
4451
|
2. Then pass through the applicable fields to your `findRecord` request.
|
|
4197
4452
|
Given a `post` model with attributes body, title, publishDate and meta, you can retrieve a filtered list of attributes.
|
|
4198
4453
|
```app/routes/post.js
|
|
4199
|
-
|
|
4200
|
-
export default Route.extend({
|
|
4454
|
+
export default class extends Route {
|
|
4201
4455
|
model(params) {
|
|
4202
4456
|
return this.store.findRecord('post', params.post_id, { adapterOptions: { fields: { post: 'body,title' } });
|
|
4203
4457
|
}
|
|
4204
|
-
}
|
|
4458
|
+
}
|
|
4205
4459
|
```
|
|
4206
4460
|
Moreover, you can filter attributes on related models as well. If a `post` has a `belongsTo` relationship to a user,
|
|
4207
4461
|
just include the relationship key and attributes.
|
|
4208
4462
|
```app/routes/post.js
|
|
4209
|
-
|
|
4210
|
-
export default Route.extend({
|
|
4463
|
+
export default class extends Route {
|
|
4211
4464
|
model(params) {
|
|
4212
4465
|
return this.store.findRecord('post', params.post_id, { adapterOptions: { fields: { post: 'body,title', user: 'name,email' } });
|
|
4213
4466
|
}
|
|
4214
|
-
}
|
|
4467
|
+
}
|
|
4215
4468
|
```
|
|
4216
4469
|
@since 1.13.0
|
|
4217
4470
|
@method findRecord
|
|
4218
4471
|
@public
|
|
4219
|
-
@param {String|object}
|
|
4472
|
+
@param {String|object} type - either a string representing the name of the resource or a ResourceIdentifier object containing both the type (a string) and the id (a string) for the record or an lid (a string) of an existing record
|
|
4220
4473
|
@param {(String|Integer|Object)} id - optional object with options for the request only if the first param is a ResourceIdentifier, else the string id of the record to be retrieved
|
|
4221
4474
|
@param {Object} [options] - if the first param is a string this will be the optional options for the request. See examples for available options.
|
|
4222
4475
|
@return {Promise} promise
|
|
4223
4476
|
*/
|
|
4224
4477
|
|
|
4225
4478
|
findRecord(resource, id, options) {
|
|
4226
|
-
if (macroCondition(
|
|
4479
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
4227
4480
|
assertDestroyingStore(this, 'findRecord');
|
|
4228
4481
|
}
|
|
4229
|
-
|
|
4482
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4483
|
+
if (!test) {
|
|
4484
|
+
throw new Error(`You need to pass a modelName or resource identifier as the first argument to the store's findRecord method`);
|
|
4485
|
+
}
|
|
4486
|
+
})(resource) : {};
|
|
4230
4487
|
if (isMaybeIdentifier(resource)) {
|
|
4231
4488
|
options = id;
|
|
4232
4489
|
} else {
|
|
4233
|
-
|
|
4490
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4491
|
+
if (!test) {
|
|
4492
|
+
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${resource}`);
|
|
4493
|
+
}
|
|
4494
|
+
})(typeof resource === 'string') : {};
|
|
4234
4495
|
const type = normalizeModelName(resource);
|
|
4235
4496
|
const normalizedId = ensureStringId(id);
|
|
4236
4497
|
resource = constructResource(type, normalizedId);
|
|
@@ -4267,7 +4528,7 @@ class Store extends EmberObject {
|
|
|
4267
4528
|
Get the reference for the specified record.
|
|
4268
4529
|
Example
|
|
4269
4530
|
```javascript
|
|
4270
|
-
let userRef = store.getReference('user', 1);
|
|
4531
|
+
let userRef = store.getReference('user', '1');
|
|
4271
4532
|
// check if the user is loaded
|
|
4272
4533
|
let isLoaded = userRef.value() !== null;
|
|
4273
4534
|
// get the record of the reference (null if not yet available)
|
|
@@ -4294,7 +4555,7 @@ class Store extends EmberObject {
|
|
|
4294
4555
|
*/
|
|
4295
4556
|
// TODO @deprecate getReference (and references generally)
|
|
4296
4557
|
getReference(resource, id) {
|
|
4297
|
-
if (macroCondition(
|
|
4558
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
4298
4559
|
assertDestroyingStore(this, 'getReference');
|
|
4299
4560
|
}
|
|
4300
4561
|
let resourceIdentifier;
|
|
@@ -4305,7 +4566,11 @@ class Store extends EmberObject {
|
|
|
4305
4566
|
const normalizedId = ensureStringId(id);
|
|
4306
4567
|
resourceIdentifier = constructResource(type, normalizedId);
|
|
4307
4568
|
}
|
|
4308
|
-
|
|
4569
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4570
|
+
if (!test) {
|
|
4571
|
+
throw new Error('getReference expected to receive either a resource identifier or type and id as arguments');
|
|
4572
|
+
}
|
|
4573
|
+
})(isMaybeIdentifier(resourceIdentifier)) : {};
|
|
4309
4574
|
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resourceIdentifier);
|
|
4310
4575
|
return this._instanceCache.getReference(identifier);
|
|
4311
4576
|
}
|
|
@@ -4319,8 +4584,8 @@ class Store extends EmberObject {
|
|
|
4319
4584
|
_Note: This is a synchronous method and does not return a promise._
|
|
4320
4585
|
**Example 1**
|
|
4321
4586
|
```js
|
|
4322
|
-
let post = store.peekRecord('post', 1);
|
|
4323
|
-
post.id; // 1
|
|
4587
|
+
let post = store.peekRecord('post', '1');
|
|
4588
|
+
post.id; // '1'
|
|
4324
4589
|
```
|
|
4325
4590
|
`peekRecord` can be called with a single identifier argument instead of the combination
|
|
4326
4591
|
of `type` (modelName) and `id` as separate arguments. You may recognize this combo as
|
|
@@ -4328,14 +4593,14 @@ class Store extends EmberObject {
|
|
|
4328
4593
|
**Example 2**
|
|
4329
4594
|
```js
|
|
4330
4595
|
let post = store.peekRecord({ type: 'post', id });
|
|
4331
|
-
post.id; // 1
|
|
4596
|
+
post.id; // '1'
|
|
4332
4597
|
```
|
|
4333
4598
|
If you have previously received an lid from an Identifier for this record, you can lookup the record again using
|
|
4334
4599
|
just the lid.
|
|
4335
4600
|
**Example 3**
|
|
4336
4601
|
```js
|
|
4337
4602
|
let post = store.peekRecord({ lid });
|
|
4338
|
-
post.id; // 1
|
|
4603
|
+
post.id; // '1'
|
|
4339
4604
|
```
|
|
4340
4605
|
@since 1.13.0
|
|
4341
4606
|
@method peekRecord
|
|
@@ -4353,11 +4618,19 @@ class Store extends EmberObject {
|
|
|
4353
4618
|
// this is basically an "are we not empty" query.
|
|
4354
4619
|
return isLoaded ? this._instanceCache.getRecord(stableIdentifier) : null;
|
|
4355
4620
|
}
|
|
4356
|
-
if (macroCondition(
|
|
4621
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
4357
4622
|
assertDestroyingStore(this, 'peekRecord');
|
|
4358
4623
|
}
|
|
4359
|
-
|
|
4360
|
-
|
|
4624
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4625
|
+
if (!test) {
|
|
4626
|
+
throw new Error(`You need to pass a model name to the store's peekRecord method`);
|
|
4627
|
+
}
|
|
4628
|
+
})(identifier) : {};
|
|
4629
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4630
|
+
if (!test) {
|
|
4631
|
+
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${String(identifier)}`);
|
|
4632
|
+
}
|
|
4633
|
+
})(typeof identifier === 'string') : {};
|
|
4361
4634
|
const type = normalizeModelName(identifier);
|
|
4362
4635
|
const normalizedId = ensureStringId(id);
|
|
4363
4636
|
const resource = {
|
|
@@ -4388,7 +4661,7 @@ class Store extends EmberObject {
|
|
|
4388
4661
|
---
|
|
4389
4662
|
If you do something like this:
|
|
4390
4663
|
```javascript
|
|
4391
|
-
store.query('person', { ids: [1, 2, 3] });
|
|
4664
|
+
store.query('person', { ids: ['1', '2', '3'] });
|
|
4392
4665
|
```
|
|
4393
4666
|
The request made to the server will look something like this:
|
|
4394
4667
|
```
|
|
@@ -4401,24 +4674,37 @@ class Store extends EmberObject {
|
|
|
4401
4674
|
@since 1.13.0
|
|
4402
4675
|
@method query
|
|
4403
4676
|
@public
|
|
4404
|
-
@param {String}
|
|
4405
|
-
@param {
|
|
4677
|
+
@param {String} type the name of the resource
|
|
4678
|
+
@param {object} query a query to be used by the adapter
|
|
4406
4679
|
@param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.query
|
|
4407
4680
|
@return {Promise} promise
|
|
4408
4681
|
*/
|
|
4409
|
-
|
|
4410
|
-
|
|
4682
|
+
|
|
4683
|
+
query(type, query, options = {}) {
|
|
4684
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
4411
4685
|
assertDestroyingStore(this, 'query');
|
|
4412
4686
|
}
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4687
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4688
|
+
if (!test) {
|
|
4689
|
+
throw new Error(`You need to pass a model name to the store's query method`);
|
|
4690
|
+
}
|
|
4691
|
+
})(type) : {};
|
|
4692
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4693
|
+
if (!test) {
|
|
4694
|
+
throw new Error(`You need to pass a query hash to the store's query method`);
|
|
4695
|
+
}
|
|
4696
|
+
})(query) : {};
|
|
4697
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4698
|
+
if (!test) {
|
|
4699
|
+
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${type}`);
|
|
4700
|
+
}
|
|
4701
|
+
})(typeof type === 'string') : {};
|
|
4416
4702
|
const promise = this.request({
|
|
4417
4703
|
op: 'query',
|
|
4418
4704
|
data: {
|
|
4419
|
-
type: normalizeModelName(
|
|
4705
|
+
type: normalizeModelName(type),
|
|
4420
4706
|
query,
|
|
4421
|
-
options: options
|
|
4707
|
+
options: options
|
|
4422
4708
|
},
|
|
4423
4709
|
cacheOptions: {
|
|
4424
4710
|
[SkipCache]: true
|
|
@@ -4503,22 +4789,35 @@ class Store extends EmberObject {
|
|
|
4503
4789
|
@since 1.13.0
|
|
4504
4790
|
@method queryRecord
|
|
4505
4791
|
@public
|
|
4506
|
-
@param {
|
|
4507
|
-
@param {
|
|
4508
|
-
@param {
|
|
4792
|
+
@param {string} type
|
|
4793
|
+
@param {object} query an opaque query to be used by the adapter
|
|
4794
|
+
@param {object} options optional, may include `adapterOptions` hash which will be passed to adapter.queryRecord
|
|
4509
4795
|
@return {Promise} promise which resolves with the found record or `null`
|
|
4510
4796
|
*/
|
|
4511
|
-
|
|
4512
|
-
|
|
4797
|
+
|
|
4798
|
+
queryRecord(type, query, options) {
|
|
4799
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
4513
4800
|
assertDestroyingStore(this, 'queryRecord');
|
|
4514
4801
|
}
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4802
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4803
|
+
if (!test) {
|
|
4804
|
+
throw new Error(`You need to pass a model name to the store's queryRecord method`);
|
|
4805
|
+
}
|
|
4806
|
+
})(type) : {};
|
|
4807
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4808
|
+
if (!test) {
|
|
4809
|
+
throw new Error(`You need to pass a query hash to the store's queryRecord method`);
|
|
4810
|
+
}
|
|
4811
|
+
})(query) : {};
|
|
4812
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4813
|
+
if (!test) {
|
|
4814
|
+
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${type}`);
|
|
4815
|
+
}
|
|
4816
|
+
})(typeof type === 'string') : {};
|
|
4518
4817
|
const promise = this.request({
|
|
4519
4818
|
op: 'queryRecord',
|
|
4520
4819
|
data: {
|
|
4521
|
-
type: normalizeModelName(
|
|
4820
|
+
type: normalizeModelName(type),
|
|
4522
4821
|
query,
|
|
4523
4822
|
options: options || {}
|
|
4524
4823
|
},
|
|
@@ -4535,8 +4834,7 @@ class Store extends EmberObject {
|
|
|
4535
4834
|
this type present in the store, even if the adapter only returns a subset
|
|
4536
4835
|
of them.
|
|
4537
4836
|
```app/routes/authors.js
|
|
4538
|
-
|
|
4539
|
-
export default class AuthorsRoute extends Route {
|
|
4837
|
+
export default class AuthorsRoute extends Route {
|
|
4540
4838
|
model(params) {
|
|
4541
4839
|
return this.store.findAll('author');
|
|
4542
4840
|
}
|
|
@@ -4609,8 +4907,7 @@ class Store extends EmberObject {
|
|
|
4609
4907
|
boolean value for `backgroundReload` in the options object for
|
|
4610
4908
|
`findAll`.
|
|
4611
4909
|
```app/routes/post/edit.js
|
|
4612
|
-
|
|
4613
|
-
export default class PostEditRoute extends Route {
|
|
4910
|
+
export default class PostEditRoute extends Route {
|
|
4614
4911
|
model() {
|
|
4615
4912
|
return this.store.findAll('post', { backgroundReload: false });
|
|
4616
4913
|
}
|
|
@@ -4619,8 +4916,7 @@ class Store extends EmberObject {
|
|
|
4619
4916
|
If you pass an object on the `adapterOptions` property of the options
|
|
4620
4917
|
argument it will be passed to you adapter via the `snapshotRecordArray`
|
|
4621
4918
|
```app/routes/posts.js
|
|
4622
|
-
|
|
4623
|
-
export default class PostsRoute extends Route {
|
|
4919
|
+
export default class PostsRoute extends Route {
|
|
4624
4920
|
model(params) {
|
|
4625
4921
|
return this.store.findAll('post', {
|
|
4626
4922
|
adapterOptions: { subscribe: false }
|
|
@@ -4653,8 +4949,7 @@ class Store extends EmberObject {
|
|
|
4653
4949
|
model, when we retrieve all of the post records we can have the server also return
|
|
4654
4950
|
all of the posts' comments in the same request:
|
|
4655
4951
|
```app/routes/posts.js
|
|
4656
|
-
|
|
4657
|
-
export default class PostsRoute extends Route {
|
|
4952
|
+
export default class PostsRoute extends Route {
|
|
4658
4953
|
model() {
|
|
4659
4954
|
return this.store.findAll('post', { include: 'comments' });
|
|
4660
4955
|
}
|
|
@@ -4665,8 +4960,7 @@ class Store extends EmberObject {
|
|
|
4665
4960
|
using a dot-separated sequence of relationship names. So to request both the posts'
|
|
4666
4961
|
comments and the authors of those comments the request would look like this:
|
|
4667
4962
|
```app/routes/posts.js
|
|
4668
|
-
|
|
4669
|
-
export default class PostsRoute extends Route {
|
|
4963
|
+
export default class PostsRoute extends Route {
|
|
4670
4964
|
model() {
|
|
4671
4965
|
return this.store.findAll('post', { include: 'comments,comments.author' });
|
|
4672
4966
|
}
|
|
@@ -4676,20 +4970,29 @@ class Store extends EmberObject {
|
|
|
4676
4970
|
@since 1.13.0
|
|
4677
4971
|
@method findAll
|
|
4678
4972
|
@public
|
|
4679
|
-
@param {
|
|
4680
|
-
@param {
|
|
4973
|
+
@param {string} type the name of the resource
|
|
4974
|
+
@param {object} options
|
|
4681
4975
|
@return {Promise} promise
|
|
4682
4976
|
*/
|
|
4683
|
-
|
|
4684
|
-
|
|
4977
|
+
|
|
4978
|
+
findAll(type, options = {}) {
|
|
4979
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
4685
4980
|
assertDestroyingStore(this, 'findAll');
|
|
4686
4981
|
}
|
|
4687
|
-
|
|
4688
|
-
|
|
4982
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4983
|
+
if (!test) {
|
|
4984
|
+
throw new Error(`You need to pass a model name to the store's findAll method`);
|
|
4985
|
+
}
|
|
4986
|
+
})(type) : {};
|
|
4987
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4988
|
+
if (!test) {
|
|
4989
|
+
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${type}`);
|
|
4990
|
+
}
|
|
4991
|
+
})(typeof type === 'string') : {};
|
|
4689
4992
|
const promise = this.request({
|
|
4690
4993
|
op: 'findAll',
|
|
4691
4994
|
data: {
|
|
4692
|
-
type: normalizeModelName(
|
|
4995
|
+
type: normalizeModelName(type),
|
|
4693
4996
|
options: options || {}
|
|
4694
4997
|
},
|
|
4695
4998
|
cacheOptions: {
|
|
@@ -4716,17 +5019,25 @@ class Store extends EmberObject {
|
|
|
4716
5019
|
@since 1.13.0
|
|
4717
5020
|
@method peekAll
|
|
4718
5021
|
@public
|
|
4719
|
-
@param {
|
|
5022
|
+
@param {string} type the name of the resource
|
|
4720
5023
|
@return {RecordArray}
|
|
4721
5024
|
*/
|
|
4722
|
-
|
|
4723
|
-
|
|
5025
|
+
|
|
5026
|
+
peekAll(type) {
|
|
5027
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
4724
5028
|
assertDestroyingStore(this, 'peekAll');
|
|
4725
5029
|
}
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
5030
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5031
|
+
if (!test) {
|
|
5032
|
+
throw new Error(`You need to pass a model name to the store's peekAll method`);
|
|
5033
|
+
}
|
|
5034
|
+
})(type) : {};
|
|
5035
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5036
|
+
if (!test) {
|
|
5037
|
+
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${type}`);
|
|
5038
|
+
}
|
|
5039
|
+
})(typeof type === 'string') : {};
|
|
5040
|
+
return this.recordArrayManager.liveArrayFor(normalizeModelName(type));
|
|
4730
5041
|
}
|
|
4731
5042
|
|
|
4732
5043
|
/**
|
|
@@ -4738,16 +5049,21 @@ class Store extends EmberObject {
|
|
|
4738
5049
|
store.unloadAll('post');
|
|
4739
5050
|
```
|
|
4740
5051
|
@method unloadAll
|
|
5052
|
+
@param {string} type the name of the resource
|
|
4741
5053
|
@public
|
|
4742
|
-
@param {String} modelName
|
|
4743
5054
|
*/
|
|
4744
|
-
|
|
4745
|
-
|
|
5055
|
+
|
|
5056
|
+
unloadAll(type) {
|
|
5057
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
4746
5058
|
assertDestroyedStoreOnly(this, 'unloadAll');
|
|
4747
5059
|
}
|
|
4748
|
-
|
|
5060
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5061
|
+
if (!test) {
|
|
5062
|
+
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${String(type)}`);
|
|
5063
|
+
}
|
|
5064
|
+
})(!type || typeof type === 'string') : {};
|
|
4749
5065
|
this._join(() => {
|
|
4750
|
-
if (
|
|
5066
|
+
if (type === undefined) {
|
|
4751
5067
|
// destroy the graph before unloadAll
|
|
4752
5068
|
// since then we avoid churning relationships
|
|
4753
5069
|
// during unload
|
|
@@ -4755,8 +5071,7 @@ class Store extends EmberObject {
|
|
|
4755
5071
|
this.recordArrayManager.clear();
|
|
4756
5072
|
this._instanceCache.clear();
|
|
4757
5073
|
} else {
|
|
4758
|
-
|
|
4759
|
-
this._instanceCache.clear(normalizedModelName);
|
|
5074
|
+
this._instanceCache.clear(normalizeModelName(type));
|
|
4760
5075
|
}
|
|
4761
5076
|
});
|
|
4762
5077
|
}
|
|
@@ -4893,7 +5208,7 @@ class Store extends EmberObject {
|
|
|
4893
5208
|
*/
|
|
4894
5209
|
|
|
4895
5210
|
push(data) {
|
|
4896
|
-
if (macroCondition(
|
|
5211
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
4897
5212
|
assertDestroyingStore(this, 'push');
|
|
4898
5213
|
}
|
|
4899
5214
|
const pushed = this._push(data, false);
|
|
@@ -4915,10 +5230,10 @@ class Store extends EmberObject {
|
|
|
4915
5230
|
@return {StableRecordIdentifier|Array<StableRecordIdentifier>|null} identifiers for the primary records that had data loaded
|
|
4916
5231
|
*/
|
|
4917
5232
|
_push(jsonApiDoc, asyncFlush) {
|
|
4918
|
-
if (macroCondition(
|
|
5233
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
4919
5234
|
assertDestroyingStore(this, '_push');
|
|
4920
5235
|
}
|
|
4921
|
-
if (macroCondition(
|
|
5236
|
+
if (macroCondition(getGlobalConfig().WarpDrive.debug.LOG_PAYLOADS)) {
|
|
4922
5237
|
try {
|
|
4923
5238
|
const data = JSON.parse(JSON.stringify(jsonApiDoc));
|
|
4924
5239
|
// eslint-disable-next-line no-console
|
|
@@ -4944,17 +5259,23 @@ class Store extends EmberObject {
|
|
|
4944
5259
|
/**
|
|
4945
5260
|
* Trigger a save for a Record.
|
|
4946
5261
|
*
|
|
5262
|
+
* Returns a promise resolving with the same record when the save is complete.
|
|
5263
|
+
*
|
|
4947
5264
|
* @method saveRecord
|
|
4948
5265
|
* @public
|
|
4949
|
-
* @param {
|
|
5266
|
+
* @param {unknown} record
|
|
4950
5267
|
* @param options
|
|
4951
|
-
* @return {Promise<
|
|
5268
|
+
* @return {Promise<record>}
|
|
4952
5269
|
*/
|
|
4953
5270
|
saveRecord(record, options = {}) {
|
|
4954
|
-
if (macroCondition(
|
|
5271
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
4955
5272
|
assertDestroyingStore(this, 'saveRecord');
|
|
4956
5273
|
}
|
|
4957
|
-
|
|
5274
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5275
|
+
if (!test) {
|
|
5276
|
+
throw new Error(`Unable to initiate save for a record in a disconnected state`);
|
|
5277
|
+
}
|
|
5278
|
+
})(storeFor(record)) : {};
|
|
4958
5279
|
const identifier = recordIdentifierFor(record);
|
|
4959
5280
|
const cache = this.cache;
|
|
4960
5281
|
if (!identifier) {
|
|
@@ -4962,8 +5283,11 @@ class Store extends EmberObject {
|
|
|
4962
5283
|
// but just in case we reject here to prevent bad things.
|
|
4963
5284
|
return Promise.reject(new Error(`Record Is Disconnected`));
|
|
4964
5285
|
}
|
|
4965
|
-
|
|
4966
|
-
|
|
5286
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5287
|
+
if (!test) {
|
|
5288
|
+
throw new Error(`Cannot initiate a save request for an unloaded record: ${identifier.lid}`);
|
|
5289
|
+
}
|
|
5290
|
+
})(this._instanceCache.recordIsLoaded(identifier)) : {};
|
|
4967
5291
|
if (resourceIsFullyDeleted(this._instanceCache, identifier)) {
|
|
4968
5292
|
return Promise.resolve(record);
|
|
4969
5293
|
}
|
|
@@ -4987,11 +5311,6 @@ class Store extends EmberObject {
|
|
|
4987
5311
|
[SkipCache]: true
|
|
4988
5312
|
}
|
|
4989
5313
|
};
|
|
4990
|
-
|
|
4991
|
-
// we lie here on the type because legacy doesn't have enough context
|
|
4992
|
-
cache.willCommit(identifier, {
|
|
4993
|
-
request
|
|
4994
|
-
});
|
|
4995
5314
|
return this.request(request).then(document => document.content);
|
|
4996
5315
|
}
|
|
4997
5316
|
|
|
@@ -5021,14 +5340,12 @@ class Store extends EmberObject {
|
|
|
5021
5340
|
} = this._instanceCache;
|
|
5022
5341
|
if (!cache) {
|
|
5023
5342
|
cache = this._instanceCache.cache = this.createCache(this._instanceCache._storeWrapper);
|
|
5024
|
-
if (macroCondition(
|
|
5343
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
5025
5344
|
cache = new CacheManager(cache);
|
|
5026
5345
|
}
|
|
5027
5346
|
}
|
|
5028
5347
|
return cache;
|
|
5029
5348
|
}
|
|
5030
|
-
|
|
5031
|
-
// @ts-expect-error
|
|
5032
5349
|
destroy() {
|
|
5033
5350
|
if (this.isDestroyed) {
|
|
5034
5351
|
// @ember/test-helpers will call destroy multiple times
|
|
@@ -5047,16 +5364,67 @@ class Store extends EmberObject {
|
|
|
5047
5364
|
return new this(args);
|
|
5048
5365
|
}
|
|
5049
5366
|
}
|
|
5367
|
+
if (macroCondition(getGlobalConfig().WarpDrive.deprecations.ENABLE_LEGACY_SCHEMA_SERVICE)) {
|
|
5368
|
+
Store.prototype.getSchemaDefinitionService = function () {
|
|
5369
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5370
|
+
if (!test) {
|
|
5371
|
+
throw new Error(`You must registerSchemaDefinitionService with the store to use custom model classes`);
|
|
5372
|
+
}
|
|
5373
|
+
})(this._schema) : {};
|
|
5374
|
+
deprecate(`Use \`store.schema\` instead of \`store.getSchemaDefinitionService()\``, false, {
|
|
5375
|
+
id: 'ember-data:schema-service-updates',
|
|
5376
|
+
until: '5.0',
|
|
5377
|
+
for: 'ember-data',
|
|
5378
|
+
since: {
|
|
5379
|
+
available: '5.4',
|
|
5380
|
+
enabled: '5.4'
|
|
5381
|
+
}
|
|
5382
|
+
});
|
|
5383
|
+
return this._schema;
|
|
5384
|
+
};
|
|
5385
|
+
Store.prototype.registerSchemaDefinitionService = function (schema) {
|
|
5386
|
+
deprecate(`Use \`store.createSchemaService\` instead of \`store.registerSchemaDefinitionService()\``, false, {
|
|
5387
|
+
id: 'ember-data:schema-service-updates',
|
|
5388
|
+
until: '5.0',
|
|
5389
|
+
for: 'ember-data',
|
|
5390
|
+
since: {
|
|
5391
|
+
available: '5.4',
|
|
5392
|
+
enabled: '5.4'
|
|
5393
|
+
}
|
|
5394
|
+
});
|
|
5395
|
+
this._schema = schema;
|
|
5396
|
+
};
|
|
5397
|
+
Store.prototype.registerSchema = function (schema) {
|
|
5398
|
+
deprecate(`Use \`store.createSchemaService\` instead of \`store.registerSchema()\``, false, {
|
|
5399
|
+
id: 'ember-data:schema-service-updates',
|
|
5400
|
+
until: '5.0',
|
|
5401
|
+
for: 'ember-data',
|
|
5402
|
+
since: {
|
|
5403
|
+
available: '5.4',
|
|
5404
|
+
enabled: '5.4'
|
|
5405
|
+
}
|
|
5406
|
+
});
|
|
5407
|
+
this._schema = schema;
|
|
5408
|
+
};
|
|
5409
|
+
}
|
|
5050
5410
|
let assertDestroyingStore;
|
|
5051
5411
|
let assertDestroyedStoreOnly;
|
|
5052
|
-
if (macroCondition(
|
|
5412
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
5053
5413
|
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
5054
5414
|
assertDestroyingStore = function assertDestroyingStore(store, method) {
|
|
5055
|
-
|
|
5415
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5416
|
+
if (!test) {
|
|
5417
|
+
throw new Error(`Attempted to call store.${method}(), but the store instance has already been destroyed.`);
|
|
5418
|
+
}
|
|
5419
|
+
})(!(store.isDestroying || store.isDestroyed)) : {};
|
|
5056
5420
|
};
|
|
5057
5421
|
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
5058
5422
|
assertDestroyedStoreOnly = function assertDestroyedStoreOnly(store, method) {
|
|
5059
|
-
|
|
5423
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5424
|
+
if (!test) {
|
|
5425
|
+
throw new Error(`Attempted to call store.${method}(), but the store instance has already been destroyed.`);
|
|
5426
|
+
}
|
|
5427
|
+
})(!store.isDestroyed) : {};
|
|
5060
5428
|
};
|
|
5061
5429
|
}
|
|
5062
5430
|
function isMaybeIdentifier(maybeIdentifier) {
|
|
@@ -5066,33 +5434,38 @@ function normalizeProperties(store, identifier, properties) {
|
|
|
5066
5434
|
// assert here
|
|
5067
5435
|
if (properties !== undefined) {
|
|
5068
5436
|
if ('id' in properties) {
|
|
5069
|
-
|
|
5437
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5438
|
+
if (!test) {
|
|
5439
|
+
throw new Error(`expected id to be a string or null`);
|
|
5440
|
+
}
|
|
5441
|
+
})(properties.id !== undefined) : {};
|
|
5070
5442
|
}
|
|
5071
|
-
|
|
5443
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5444
|
+
if (!test) {
|
|
5445
|
+
throw new Error(`You passed '${typeof properties}' as properties for record creation instead of an object.`);
|
|
5446
|
+
}
|
|
5447
|
+
})(typeof properties === 'object' && properties !== null) : {};
|
|
5072
5448
|
const {
|
|
5073
5449
|
type
|
|
5074
5450
|
} = identifier;
|
|
5075
5451
|
|
|
5076
5452
|
// convert relationship Records to RecordDatas before passing to RecordData
|
|
5077
|
-
const defs = store.
|
|
5453
|
+
const defs = store.schema.fields({
|
|
5078
5454
|
type
|
|
5079
5455
|
});
|
|
5080
|
-
if (defs
|
|
5456
|
+
if (defs.size) {
|
|
5081
5457
|
const keys = Object.keys(properties);
|
|
5082
|
-
let relationshipValue;
|
|
5083
5458
|
for (let i = 0; i < keys.length; i++) {
|
|
5084
5459
|
const prop = keys[i];
|
|
5085
|
-
const
|
|
5086
|
-
if (
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
}
|
|
5091
|
-
relationshipValue = extractIdentifiersFromRecords(properties[prop]);
|
|
5092
|
-
} else {
|
|
5093
|
-
relationshipValue = extractIdentifierFromRecord(properties[prop]);
|
|
5460
|
+
const field = defs.get(prop);
|
|
5461
|
+
if (!field) continue;
|
|
5462
|
+
if (field.kind === 'hasMany') {
|
|
5463
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
5464
|
+
assertRecordsPassedToHasMany(properties[prop]);
|
|
5094
5465
|
}
|
|
5095
|
-
properties[prop] =
|
|
5466
|
+
properties[prop] = extractIdentifiersFromRecords(properties[prop]);
|
|
5467
|
+
} else if (field.kind === 'belongsTo') {
|
|
5468
|
+
properties[prop] = extractIdentifierFromRecord(properties[prop]);
|
|
5096
5469
|
}
|
|
5097
5470
|
}
|
|
5098
5471
|
}
|
|
@@ -5100,8 +5473,16 @@ function normalizeProperties(store, identifier, properties) {
|
|
|
5100
5473
|
return properties;
|
|
5101
5474
|
}
|
|
5102
5475
|
function assertRecordsPassedToHasMany(records) {
|
|
5103
|
-
|
|
5104
|
-
|
|
5476
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5477
|
+
if (!test) {
|
|
5478
|
+
throw new Error(`You must pass an array of records to set a hasMany relationship`);
|
|
5479
|
+
}
|
|
5480
|
+
})(Array.isArray(records)) : {};
|
|
5481
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5482
|
+
if (!test) {
|
|
5483
|
+
throw new Error(`All elements of a hasMany relationship must be instances of Model, you passed ${records.map(r => `${typeof r}`).join(', ')}`);
|
|
5484
|
+
}
|
|
5485
|
+
})(function () {
|
|
5105
5486
|
return records.every(record => {
|
|
5106
5487
|
try {
|
|
5107
5488
|
recordIdentifierFor(record);
|
|
@@ -5110,7 +5491,7 @@ function assertRecordsPassedToHasMany(records) {
|
|
|
5110
5491
|
return false;
|
|
5111
5492
|
}
|
|
5112
5493
|
});
|
|
5113
|
-
}());
|
|
5494
|
+
}()) : {};
|
|
5114
5495
|
}
|
|
5115
5496
|
function extractIdentifiersFromRecords(records) {
|
|
5116
5497
|
return records.map(record => extractIdentifierFromRecord(record));
|
|
@@ -5122,6 +5503,10 @@ function extractIdentifierFromRecord(recordOrPromiseRecord) {
|
|
|
5122
5503
|
const extract = recordIdentifierFor;
|
|
5123
5504
|
return extract(recordOrPromiseRecord);
|
|
5124
5505
|
}
|
|
5506
|
+
|
|
5507
|
+
/**
|
|
5508
|
+
* @module @ember-data/store
|
|
5509
|
+
*/
|
|
5125
5510
|
function urlFromLink(link) {
|
|
5126
5511
|
if (typeof link === 'string') return link;
|
|
5127
5512
|
return link.href;
|
|
@@ -5139,69 +5524,79 @@ function urlFromLink(link) {
|
|
|
5139
5524
|
* @public
|
|
5140
5525
|
* @class Document
|
|
5141
5526
|
*/
|
|
5142
|
-
var _store = /*#__PURE__*/_classPrivateFieldKey("store");
|
|
5143
|
-
var _request = /*#__PURE__*/_classPrivateFieldKey("request");
|
|
5144
5527
|
class Document {
|
|
5528
|
+
/**
|
|
5529
|
+
* The links object for this document, if any
|
|
5530
|
+
*
|
|
5531
|
+
* e.g.
|
|
5532
|
+
*
|
|
5533
|
+
* ```
|
|
5534
|
+
* {
|
|
5535
|
+
* self: '/articles?page[number]=3',
|
|
5536
|
+
* }
|
|
5537
|
+
* ```
|
|
5538
|
+
*
|
|
5539
|
+
* @property links
|
|
5540
|
+
* @type {object|undefined} - a links object
|
|
5541
|
+
* @public
|
|
5542
|
+
*/
|
|
5543
|
+
|
|
5544
|
+
/**
|
|
5545
|
+
* The primary data for this document, if any.
|
|
5546
|
+
*
|
|
5547
|
+
* If this document has no primary data (e.g. because it is an error document)
|
|
5548
|
+
* this property will be `undefined`.
|
|
5549
|
+
*
|
|
5550
|
+
* For collections this will be an array of record instances,
|
|
5551
|
+
* for single resource requests it will be a single record instance or null.
|
|
5552
|
+
*
|
|
5553
|
+
* @property data
|
|
5554
|
+
* @public
|
|
5555
|
+
* @type {object|Array<object>|null|undefined} - a data object
|
|
5556
|
+
*/
|
|
5557
|
+
|
|
5558
|
+
/**
|
|
5559
|
+
* The errors returned by the API for this request, if any
|
|
5560
|
+
*
|
|
5561
|
+
* @property errors
|
|
5562
|
+
* @public
|
|
5563
|
+
* @type {object|undefined} - an errors object
|
|
5564
|
+
*/
|
|
5565
|
+
|
|
5566
|
+
/**
|
|
5567
|
+
* The meta object for this document, if any
|
|
5568
|
+
*
|
|
5569
|
+
* @property meta
|
|
5570
|
+
* @public
|
|
5571
|
+
* @type {object|undefined} - a meta object
|
|
5572
|
+
*/
|
|
5573
|
+
|
|
5574
|
+
/**
|
|
5575
|
+
* The identifier associated with this document, if any
|
|
5576
|
+
*
|
|
5577
|
+
* @property identifier
|
|
5578
|
+
* @public
|
|
5579
|
+
* @type {StableDocumentIdentifier|null}
|
|
5580
|
+
*/
|
|
5581
|
+
|
|
5582
|
+
#store;
|
|
5145
5583
|
constructor(store, identifier) {
|
|
5146
|
-
|
|
5147
|
-
value: _request2
|
|
5148
|
-
});
|
|
5149
|
-
/**
|
|
5150
|
-
* The links object for this document, if any
|
|
5151
|
-
*
|
|
5152
|
-
* e.g.
|
|
5153
|
-
*
|
|
5154
|
-
* ```
|
|
5155
|
-
* {
|
|
5156
|
-
* self: '/articles?page[number]=3',
|
|
5157
|
-
* }
|
|
5158
|
-
* ```
|
|
5159
|
-
*
|
|
5160
|
-
* @property links
|
|
5161
|
-
* @type {object|undefined} - a links object
|
|
5162
|
-
* @public
|
|
5163
|
-
*/
|
|
5164
|
-
/**
|
|
5165
|
-
* The primary data for this document, if any.
|
|
5166
|
-
*
|
|
5167
|
-
* If this document has no primary data (e.g. because it is an error document)
|
|
5168
|
-
* this property will be `undefined`.
|
|
5169
|
-
*
|
|
5170
|
-
* For collections this will be an array of record instances,
|
|
5171
|
-
* for single resource requests it will be a single record instance or null.
|
|
5172
|
-
*
|
|
5173
|
-
* @property data
|
|
5174
|
-
* @public
|
|
5175
|
-
* @type {object|Array<object>|null|undefined} - a data object
|
|
5176
|
-
*/
|
|
5177
|
-
/**
|
|
5178
|
-
* The errors returned by the API for this request, if any
|
|
5179
|
-
*
|
|
5180
|
-
* @property errors
|
|
5181
|
-
* @public
|
|
5182
|
-
* @type {object|undefined} - an errors object
|
|
5183
|
-
*/
|
|
5184
|
-
/**
|
|
5185
|
-
* The meta object for this document, if any
|
|
5186
|
-
*
|
|
5187
|
-
* @property meta
|
|
5188
|
-
* @public
|
|
5189
|
-
* @type {object|undefined} - a meta object
|
|
5190
|
-
*/
|
|
5191
|
-
/**
|
|
5192
|
-
* The identifier associated with this document, if any
|
|
5193
|
-
*
|
|
5194
|
-
* @property identifier
|
|
5195
|
-
* @public
|
|
5196
|
-
* @type {StableDocumentIdentifier|null}
|
|
5197
|
-
*/
|
|
5198
|
-
Object.defineProperty(this, _store, {
|
|
5199
|
-
writable: true,
|
|
5200
|
-
value: void 0
|
|
5201
|
-
});
|
|
5202
|
-
_classPrivateFieldBase(this, _store)[_store] = store;
|
|
5584
|
+
this.#store = store;
|
|
5203
5585
|
this.identifier = identifier;
|
|
5204
5586
|
}
|
|
5587
|
+
async #request(link, options) {
|
|
5588
|
+
const href = this.links?.[link];
|
|
5589
|
+
if (!href) {
|
|
5590
|
+
return null;
|
|
5591
|
+
}
|
|
5592
|
+
options.method = options.method || 'GET';
|
|
5593
|
+
Object.assign(options, {
|
|
5594
|
+
url: urlFromLink(href)
|
|
5595
|
+
});
|
|
5596
|
+
const response = await this.#store.request(options);
|
|
5597
|
+
return response.content;
|
|
5598
|
+
}
|
|
5599
|
+
|
|
5205
5600
|
/**
|
|
5206
5601
|
* Fetches the related link for this document, returning a promise that resolves
|
|
5207
5602
|
* with the document when the request completes. If no related link is present,
|
|
@@ -5213,10 +5608,14 @@ class Document {
|
|
|
5213
5608
|
* @return Promise<Document>
|
|
5214
5609
|
*/
|
|
5215
5610
|
fetch(options = {}) {
|
|
5216
|
-
|
|
5611
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5612
|
+
if (!test) {
|
|
5613
|
+
throw new Error(`No self or related link`);
|
|
5614
|
+
}
|
|
5615
|
+
})(this.links?.related || this.links?.self) : {};
|
|
5217
5616
|
options.cacheOptions = options.cacheOptions || {};
|
|
5218
5617
|
options.cacheOptions.key = this.identifier?.lid;
|
|
5219
|
-
return
|
|
5618
|
+
return this.#request(this.links.related ? 'related' : 'self', options);
|
|
5220
5619
|
}
|
|
5221
5620
|
|
|
5222
5621
|
/**
|
|
@@ -5230,7 +5629,7 @@ class Document {
|
|
|
5230
5629
|
* @return Promise<Document | null>
|
|
5231
5630
|
*/
|
|
5232
5631
|
next(options = {}) {
|
|
5233
|
-
return
|
|
5632
|
+
return this.#request('next', options);
|
|
5234
5633
|
}
|
|
5235
5634
|
|
|
5236
5635
|
/**
|
|
@@ -5244,7 +5643,7 @@ class Document {
|
|
|
5244
5643
|
* @return Promise<Document | null>
|
|
5245
5644
|
*/
|
|
5246
5645
|
prev(options = {}) {
|
|
5247
|
-
return
|
|
5646
|
+
return this.#request('prev', options);
|
|
5248
5647
|
}
|
|
5249
5648
|
|
|
5250
5649
|
/**
|
|
@@ -5258,7 +5657,7 @@ class Document {
|
|
|
5258
5657
|
* @return Promise<Document | null>
|
|
5259
5658
|
*/
|
|
5260
5659
|
first(options = {}) {
|
|
5261
|
-
return
|
|
5660
|
+
return this.#request('first', options);
|
|
5262
5661
|
}
|
|
5263
5662
|
|
|
5264
5663
|
/**
|
|
@@ -5272,7 +5671,7 @@ class Document {
|
|
|
5272
5671
|
* @return Promise<Document | null>
|
|
5273
5672
|
*/
|
|
5274
5673
|
last(options = {}) {
|
|
5275
|
-
return
|
|
5674
|
+
return this.#request('last', options);
|
|
5276
5675
|
}
|
|
5277
5676
|
|
|
5278
5677
|
/**
|
|
@@ -5306,17 +5705,6 @@ class Document {
|
|
|
5306
5705
|
return data;
|
|
5307
5706
|
}
|
|
5308
5707
|
}
|
|
5309
|
-
async function _request2(link, options) {
|
|
5310
|
-
const href = this.links?.[link];
|
|
5311
|
-
if (!href) {
|
|
5312
|
-
return null;
|
|
5313
|
-
}
|
|
5314
|
-
options.method = options.method || 'GET';
|
|
5315
|
-
const response = await _classPrivateFieldBase(this, _store)[_store].request(Object.assign(options, {
|
|
5316
|
-
url: urlFromLink(href)
|
|
5317
|
-
}));
|
|
5318
|
-
return response.content;
|
|
5319
|
-
}
|
|
5320
5708
|
defineSignal(Document.prototype, 'data');
|
|
5321
5709
|
defineSignal(Document.prototype, 'links');
|
|
5322
5710
|
defineSignal(Document.prototype, 'errors');
|
|
@@ -5337,10 +5725,9 @@ defineSignal(Document.prototype, 'meta');
|
|
|
5337
5725
|
* Implementing this service allows you to programatically define
|
|
5338
5726
|
* when a request should be considered expired.
|
|
5339
5727
|
*
|
|
5340
|
-
* @class <Interface>
|
|
5728
|
+
* @class <Interface> CachePolicy
|
|
5341
5729
|
* @public
|
|
5342
5730
|
*/
|
|
5343
|
-
|
|
5344
5731
|
const MUTATION_OPS = new Set(['createRecord', 'updateRecord', 'deleteRecord']);
|
|
5345
5732
|
function isErrorDocument(document) {
|
|
5346
5733
|
return 'errors' in document;
|
|
@@ -5349,6 +5736,14 @@ function maybeUpdateUiObjects(store, request, options, document, isFromCache) {
|
|
|
5349
5736
|
const {
|
|
5350
5737
|
identifier
|
|
5351
5738
|
} = options;
|
|
5739
|
+
if (!document) {
|
|
5740
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5741
|
+
if (!test) {
|
|
5742
|
+
throw new Error(`The CacheHandler expected response content but none was found`);
|
|
5743
|
+
}
|
|
5744
|
+
})(!options.shouldHydrate) : {};
|
|
5745
|
+
return document;
|
|
5746
|
+
}
|
|
5352
5747
|
if (isErrorDocument(document)) {
|
|
5353
5748
|
if (!identifier && !options.shouldHydrate) {
|
|
5354
5749
|
return document;
|
|
@@ -5446,7 +5841,7 @@ function calcShouldBackgroundFetch(store, request, willFetch, identifier) {
|
|
|
5446
5841
|
const {
|
|
5447
5842
|
cacheOptions
|
|
5448
5843
|
} = request;
|
|
5449
|
-
return
|
|
5844
|
+
return cacheOptions?.backgroundReload || (store.lifetimes && identifier ? store.lifetimes.isSoftExpired(identifier, store) : false);
|
|
5450
5845
|
}
|
|
5451
5846
|
function isMutation(request) {
|
|
5452
5847
|
return Boolean(request.op && MUTATION_OPS.has(request.op));
|
|
@@ -5461,8 +5856,14 @@ function fetchContentAndHydrate(next, context, identifier, shouldFetch, shouldBa
|
|
|
5461
5856
|
isMut = true;
|
|
5462
5857
|
// TODO should we handle multiple records in request.records by iteratively calling willCommit for each
|
|
5463
5858
|
const record = context.request.data?.record || context.request.records?.[0];
|
|
5464
|
-
|
|
5465
|
-
|
|
5859
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5860
|
+
if (!test) {
|
|
5861
|
+
throw new Error(`Expected to receive a list of records included in the ${context.request.op} request`);
|
|
5862
|
+
}
|
|
5863
|
+
})(record || !shouldHydrate) : {};
|
|
5864
|
+
if (record) {
|
|
5865
|
+
store.cache.willCommit(record, context);
|
|
5866
|
+
}
|
|
5466
5867
|
}
|
|
5467
5868
|
if (store.lifetimes?.willRequest) {
|
|
5468
5869
|
store.lifetimes.willRequest(context.request, identifier, store);
|
|
@@ -5474,7 +5875,15 @@ function fetchContentAndHydrate(next, context, identifier, shouldFetch, shouldBa
|
|
|
5474
5875
|
store._join(() => {
|
|
5475
5876
|
if (isMutation(context.request)) {
|
|
5476
5877
|
const record = context.request.data?.record || context.request.records?.[0];
|
|
5477
|
-
|
|
5878
|
+
if (record) {
|
|
5879
|
+
response = store.cache.didCommit(record, document);
|
|
5880
|
+
|
|
5881
|
+
// a mutation combined with a 204 has no cache impact when no known records were involved
|
|
5882
|
+
// a createRecord with a 201 with an empty response and no known records should similarly
|
|
5883
|
+
// have no cache impact
|
|
5884
|
+
} else if (isCacheAffecting(document)) {
|
|
5885
|
+
response = store.cache.put(document);
|
|
5886
|
+
}
|
|
5478
5887
|
} else {
|
|
5479
5888
|
response = store.cache.put(document);
|
|
5480
5889
|
}
|
|
@@ -5536,7 +5945,11 @@ function fetchContentAndHydrate(next, context, identifier, shouldFetch, shouldBa
|
|
|
5536
5945
|
if (!isMut) {
|
|
5537
5946
|
return promise;
|
|
5538
5947
|
}
|
|
5539
|
-
|
|
5948
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5949
|
+
if (!test) {
|
|
5950
|
+
throw new Error(`Expected a mutation`);
|
|
5951
|
+
}
|
|
5952
|
+
})(isMutation(context.request)) : {};
|
|
5540
5953
|
|
|
5541
5954
|
// for mutations we need to enqueue the promise with the requestStateService
|
|
5542
5955
|
// TODO should we enque a request per record in records?
|
|
@@ -5549,12 +5962,62 @@ function fetchContentAndHydrate(next, context, identifier, shouldFetch, shouldBa
|
|
|
5549
5962
|
}]
|
|
5550
5963
|
});
|
|
5551
5964
|
}
|
|
5965
|
+
function isAggregateError(error) {
|
|
5966
|
+
return error instanceof AggregateError || error.name === 'AggregateError' && Array.isArray(error.errors);
|
|
5967
|
+
}
|
|
5968
|
+
// TODO @runspired, consider if we should deep freeze errors (potentially only in debug) vs cloning them
|
|
5552
5969
|
function cloneError(error) {
|
|
5553
|
-
const
|
|
5970
|
+
const isAggregate = isAggregateError(error);
|
|
5971
|
+
const cloned = isAggregate ? new AggregateError(structuredClone(error.errors), error.message) : new Error(error.message);
|
|
5554
5972
|
cloned.stack = error.stack;
|
|
5555
5973
|
cloned.error = error.error;
|
|
5974
|
+
|
|
5975
|
+
// copy over enumerable properties
|
|
5976
|
+
Object.assign(cloned, error);
|
|
5556
5977
|
return cloned;
|
|
5557
5978
|
}
|
|
5979
|
+
|
|
5980
|
+
/**
|
|
5981
|
+
* A CacheHandler that adds support for using an EmberData Cache with a RequestManager.
|
|
5982
|
+
*
|
|
5983
|
+
* This handler will only run when a request has supplied a `store` instance. Requests
|
|
5984
|
+
* issued by the store via `store.request()` will automatically have the `store` instance
|
|
5985
|
+
* attached to the request.
|
|
5986
|
+
*
|
|
5987
|
+
* ```ts
|
|
5988
|
+
* requestManager.request({
|
|
5989
|
+
* store: store,
|
|
5990
|
+
* url: '/api/posts',
|
|
5991
|
+
* method: 'GET'
|
|
5992
|
+
* });
|
|
5993
|
+
* ```
|
|
5994
|
+
*
|
|
5995
|
+
* When this handler elects to handle a request, it will return the raw `StructuredDocument`
|
|
5996
|
+
* unless the request has `[EnableHydration]` set to `true`. In this case, the handler will
|
|
5997
|
+
* return a `Document` instance that will automatically update the UI when the cache is updated
|
|
5998
|
+
* in the future and will hydrate any identifiers in the StructuredDocument into Record instances.
|
|
5999
|
+
*
|
|
6000
|
+
* When issuing a request via the store, [EnableHydration] is automatically set to `true`. This
|
|
6001
|
+
* means that if desired you can issue requests that utilize the cache without needing to also
|
|
6002
|
+
* utilize Record instances if desired.
|
|
6003
|
+
*
|
|
6004
|
+
* Said differently, you could elect to issue all requests via a RequestManager, without ever using
|
|
6005
|
+
* the store directly, by setting [EnableHydration] to `true` and providing a store instance. Not
|
|
6006
|
+
* necessarily the most useful thing, but the decoupled nature of the RequestManager and incremental-feature
|
|
6007
|
+
* approach of EmberData allows for this flexibility.
|
|
6008
|
+
*
|
|
6009
|
+
* ```ts
|
|
6010
|
+
* import { EnableHydration } from '@warp-drive/core-types/request';
|
|
6011
|
+
*
|
|
6012
|
+
* requestManager.request({
|
|
6013
|
+
* store: store,
|
|
6014
|
+
* url: '/api/posts',
|
|
6015
|
+
* method: 'GET',
|
|
6016
|
+
* [EnableHydration]: true
|
|
6017
|
+
* });
|
|
6018
|
+
*
|
|
6019
|
+
* @typedoc
|
|
6020
|
+
*/
|
|
5558
6021
|
const CacheHandler = {
|
|
5559
6022
|
request(context, next) {
|
|
5560
6023
|
// if we have no cache or no cache-key skip cache handling
|
|
@@ -5577,7 +6040,13 @@ const CacheHandler = {
|
|
|
5577
6040
|
const promise = fetchContentAndHydrate(next, context, identifier, false, true);
|
|
5578
6041
|
store.requestManager._pending.set(context.id, promise);
|
|
5579
6042
|
}
|
|
6043
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
6044
|
+
if (!test) {
|
|
6045
|
+
throw new Error(`Expected a peeked request to be present`);
|
|
6046
|
+
}
|
|
6047
|
+
})(peeked) : {};
|
|
5580
6048
|
const shouldHydrate = context.request[EnableHydration] || false;
|
|
6049
|
+
context.setResponse(peeked.response);
|
|
5581
6050
|
if ('error' in peeked) {
|
|
5582
6051
|
const content = shouldHydrate ? maybeUpdateUiObjects(store, context.request, {
|
|
5583
6052
|
shouldHydrate,
|
|
@@ -5587,10 +6056,11 @@ const CacheHandler = {
|
|
|
5587
6056
|
newError.content = content;
|
|
5588
6057
|
throw newError;
|
|
5589
6058
|
}
|
|
5590
|
-
|
|
6059
|
+
const result = shouldHydrate ? maybeUpdateUiObjects(store, context.request, {
|
|
5591
6060
|
shouldHydrate,
|
|
5592
6061
|
identifier
|
|
5593
|
-
}, peeked.content, true) : peeked.content
|
|
6062
|
+
}, peeked.content, true) : peeked.content;
|
|
6063
|
+
return result;
|
|
5594
6064
|
}
|
|
5595
6065
|
};
|
|
5596
6066
|
function copyDocumentProperties(target, source) {
|
|
@@ -5604,4 +6074,17 @@ function copyDocumentProperties(target, source) {
|
|
|
5604
6074
|
target.errors = source.errors;
|
|
5605
6075
|
}
|
|
5606
6076
|
}
|
|
5607
|
-
|
|
6077
|
+
function isCacheAffecting(document) {
|
|
6078
|
+
if (!isMutation(document.request)) {
|
|
6079
|
+
return true;
|
|
6080
|
+
}
|
|
6081
|
+
// a mutation combined with a 204 has no cache impact when no known records were involved
|
|
6082
|
+
// a createRecord with a 201 with an empty response and no known records should similarly
|
|
6083
|
+
// have no cache impact
|
|
6084
|
+
|
|
6085
|
+
if (document.request.op === 'createRecord' && document.response?.status === 201) {
|
|
6086
|
+
return document.content ? Object.keys(document.content).length > 0 : false;
|
|
6087
|
+
}
|
|
6088
|
+
return document.response?.status !== 204;
|
|
6089
|
+
}
|
|
6090
|
+
export { ARRAY_SIGNAL as A, CacheHandler as C, IdentifierArray as I, MUTATE as M, RecordArrayManager as R, Store as S, _clearCaches as _, setIdentifierGenerationMethod as a, setIdentifierUpdateMethod as b, setIdentifierForgetMethod as c, setIdentifierResetMethod as d, setKeyInfoForResource as e, constructResource as f, coerceId as g, ensureStringId as h, isStableIdentifier as i, Collection as j, SOURCE as k, fastPush as l, removeRecordDataFor as m, notifyArray as n, setRecordIdentifier as o, peekCache as p, StoreMap as q, recordIdentifierFor as r, storeFor as s, setCacheFor as t, normalizeModelName as u };
|