@ember-data/store 5.4.0-alpha.2 → 5.4.0-alpha.20
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 -4
- package/addon/-private.js +1 -1
- package/addon/{store-service-0a03d2a4.js → cache-handler-XLbbNJdo.js} +1110 -991
- package/addon/cache-handler-XLbbNJdo.js.map +1 -0
- package/addon/index.js +1 -1
- package/addon/index.js.map +1 -1
- package/package.json +69 -41
- package/addon/store-service-0a03d2a4.js.map +0 -1
|
@@ -1,365 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getOwner } from '@ember/application';
|
|
3
|
-
import { assert, deprecate, warn } from '@ember/debug';
|
|
1
|
+
import { deprecate, assert, warn } from '@ember/debug';
|
|
4
2
|
import EmberObject from '@ember/object';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { SkipCache, EnableHydration } from '@warp-drive/core-types/request';
|
|
4
|
+
import { macroCondition, getOwnConfig } from '@embroider/macros';
|
|
5
|
+
import { CACHE_OWNER, DEBUG_STALE_CACHE_OWNER, DEBUG_CLIENT_ORIGINATED, DEBUG_IDENTIFIER_BUCKET } from '@warp-drive/core-types/identifier';
|
|
7
6
|
import { dasherize } from '@ember/string';
|
|
8
|
-
import { addToTransaction, subscribe, addTransactionCB } from '@ember-data/tracking/-private';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { dirtyTag } from '@glimmer/validator';
|
|
12
|
-
import Ember from 'ember';
|
|
13
|
-
function _initializerDefineProperty(target, property, descriptor, context) {
|
|
14
|
-
if (!descriptor) return;
|
|
15
|
-
Object.defineProperty(target, property, {
|
|
16
|
-
enumerable: descriptor.enumerable,
|
|
17
|
-
configurable: descriptor.configurable,
|
|
18
|
-
writable: descriptor.writable,
|
|
19
|
-
value: descriptor.initializer ? descriptor.initializer.call(context) : void 0
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
function _classPrivateFieldBase(receiver, privateKey) {
|
|
23
|
-
if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {
|
|
24
|
-
throw new TypeError("attempted to use private field on non-instance");
|
|
25
|
-
}
|
|
26
|
-
return receiver;
|
|
27
|
-
}
|
|
28
|
-
var id = 0;
|
|
29
|
-
function _classPrivateFieldKey(name) {
|
|
30
|
-
return "__private_" + id++ + "_" + name;
|
|
31
|
-
}
|
|
32
|
-
function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
|
|
33
|
-
var desc = {};
|
|
34
|
-
Object.keys(descriptor).forEach(function (key) {
|
|
35
|
-
desc[key] = descriptor[key];
|
|
36
|
-
});
|
|
37
|
-
desc.enumerable = !!desc.enumerable;
|
|
38
|
-
desc.configurable = !!desc.configurable;
|
|
39
|
-
if ('value' in desc || desc.initializer) {
|
|
40
|
-
desc.writable = true;
|
|
41
|
-
}
|
|
42
|
-
desc = decorators.slice().reverse().reduce(function (desc, decorator) {
|
|
43
|
-
return decorator(target, property, desc) || desc;
|
|
44
|
-
}, desc);
|
|
45
|
-
if (context && desc.initializer !== void 0) {
|
|
46
|
-
desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
|
|
47
|
-
desc.initializer = undefined;
|
|
48
|
-
}
|
|
49
|
-
if (desc.initializer === void 0) {
|
|
50
|
-
Object.defineProperty(target, property, desc);
|
|
51
|
-
desc = null;
|
|
52
|
-
}
|
|
53
|
-
return desc;
|
|
54
|
-
}
|
|
55
|
-
var _class$2, _descriptor$2, _descriptor2$1, _descriptor3, _descriptor4, _store, _request;
|
|
56
|
-
function urlFromLink(link) {
|
|
57
|
-
if (typeof link === 'string') return link;
|
|
58
|
-
return link.href;
|
|
59
|
-
}
|
|
60
|
-
let Document = (_class$2 = (_store = /*#__PURE__*/_classPrivateFieldKey("store"), _request = /*#__PURE__*/_classPrivateFieldKey("request"), class Document {
|
|
61
|
-
constructor(store, identifier) {
|
|
62
|
-
Object.defineProperty(this, _request, {
|
|
63
|
-
value: _request2
|
|
64
|
-
});
|
|
65
|
-
_initializerDefineProperty(this, "links", _descriptor$2, this);
|
|
66
|
-
_initializerDefineProperty(this, "data", _descriptor2$1, this);
|
|
67
|
-
_initializerDefineProperty(this, "errors", _descriptor3, this);
|
|
68
|
-
_initializerDefineProperty(this, "meta", _descriptor4, this);
|
|
69
|
-
Object.defineProperty(this, _store, {
|
|
70
|
-
writable: true,
|
|
71
|
-
value: void 0
|
|
72
|
-
});
|
|
73
|
-
_classPrivateFieldBase(this, _store)[_store] = store;
|
|
74
|
-
this.identifier = identifier;
|
|
75
|
-
}
|
|
76
|
-
fetch(options = {}) {
|
|
77
|
-
assert(`No self link`, this.links?.self);
|
|
78
|
-
options.cacheOptions = options.cacheOptions || {};
|
|
79
|
-
options.cacheOptions.key = this.identifier?.lid;
|
|
80
|
-
return _classPrivateFieldBase(this, _request)[_request]('self', options);
|
|
81
|
-
}
|
|
82
|
-
next(options) {
|
|
83
|
-
return _classPrivateFieldBase(this, _request)[_request]('next', options);
|
|
84
|
-
}
|
|
85
|
-
prev(options) {
|
|
86
|
-
return _classPrivateFieldBase(this, _request)[_request]('prev', options);
|
|
87
|
-
}
|
|
88
|
-
first(options) {
|
|
89
|
-
return _classPrivateFieldBase(this, _request)[_request]('first', options);
|
|
90
|
-
}
|
|
91
|
-
last(options) {
|
|
92
|
-
return _classPrivateFieldBase(this, _request)[_request]('last', options);
|
|
93
|
-
}
|
|
94
|
-
toJSON() {
|
|
95
|
-
const data = {};
|
|
96
|
-
data.identifier = this.identifier;
|
|
97
|
-
if (this.data !== undefined) {
|
|
98
|
-
data.data = this.data;
|
|
99
|
-
}
|
|
100
|
-
if (this.links !== undefined) {
|
|
101
|
-
data.links = this.links;
|
|
102
|
-
}
|
|
103
|
-
if (this.errors !== undefined) {
|
|
104
|
-
data.errors = this.errors;
|
|
105
|
-
}
|
|
106
|
-
if (this.meta !== undefined) {
|
|
107
|
-
data.meta = this.meta;
|
|
108
|
-
}
|
|
109
|
-
return data;
|
|
110
|
-
}
|
|
111
|
-
}), (_descriptor$2 = _applyDecoratedDescriptor(_class$2.prototype, "links", [tracked], {
|
|
112
|
-
configurable: true,
|
|
113
|
-
enumerable: true,
|
|
114
|
-
writable: true,
|
|
115
|
-
initializer: null
|
|
116
|
-
}), _descriptor2$1 = _applyDecoratedDescriptor(_class$2.prototype, "data", [tracked], {
|
|
117
|
-
configurable: true,
|
|
118
|
-
enumerable: true,
|
|
119
|
-
writable: true,
|
|
120
|
-
initializer: null
|
|
121
|
-
}), _descriptor3 = _applyDecoratedDescriptor(_class$2.prototype, "errors", [tracked], {
|
|
122
|
-
configurable: true,
|
|
123
|
-
enumerable: true,
|
|
124
|
-
writable: true,
|
|
125
|
-
initializer: null
|
|
126
|
-
}), _descriptor4 = _applyDecoratedDescriptor(_class$2.prototype, "meta", [tracked], {
|
|
127
|
-
configurable: true,
|
|
128
|
-
enumerable: true,
|
|
129
|
-
writable: true,
|
|
130
|
-
initializer: null
|
|
131
|
-
})), _class$2);
|
|
132
|
-
async function _request2(link, options = {}) {
|
|
133
|
-
const href = this.links?.[link];
|
|
134
|
-
if (!href) {
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
const response = await _classPrivateFieldBase(this, _store)[_store].request(Object.assign(options, {
|
|
138
|
-
url: urlFromLink(href)
|
|
139
|
-
}));
|
|
140
|
-
return response.content;
|
|
141
|
-
}
|
|
142
|
-
function isErrorDocument(document) {
|
|
143
|
-
return 'errors' in document;
|
|
144
|
-
}
|
|
145
|
-
function maybeUpdateUiObjects(store, request, options, document, isFromCache) {
|
|
146
|
-
const {
|
|
147
|
-
identifier
|
|
148
|
-
} = options;
|
|
149
|
-
if (isErrorDocument(document)) {
|
|
150
|
-
if (!identifier && !options.shouldHydrate) {
|
|
151
|
-
return document;
|
|
152
|
-
}
|
|
153
|
-
let doc;
|
|
154
|
-
if (identifier) {
|
|
155
|
-
doc = store._documentCache.get(identifier);
|
|
156
|
-
}
|
|
157
|
-
if (!doc) {
|
|
158
|
-
doc = new Document(store, identifier);
|
|
159
|
-
copyDocumentProperties(doc, document);
|
|
160
|
-
if (identifier) {
|
|
161
|
-
store._documentCache.set(identifier, doc);
|
|
162
|
-
}
|
|
163
|
-
} else if (!isFromCache) {
|
|
164
|
-
doc.data = undefined;
|
|
165
|
-
copyDocumentProperties(doc, document);
|
|
166
|
-
}
|
|
167
|
-
return options.shouldHydrate ? doc : document;
|
|
168
|
-
}
|
|
169
|
-
if (Array.isArray(document.data)) {
|
|
170
|
-
const {
|
|
171
|
-
recordArrayManager
|
|
172
|
-
} = store;
|
|
173
|
-
if (!identifier) {
|
|
174
|
-
if (!options.shouldHydrate) {
|
|
175
|
-
return document;
|
|
176
|
-
}
|
|
177
|
-
const data = recordArrayManager.createArray({
|
|
178
|
-
type: request.url,
|
|
179
|
-
identifiers: document.data,
|
|
180
|
-
doc: document,
|
|
181
|
-
query: request
|
|
182
|
-
});
|
|
183
|
-
const doc = new Document(store, null);
|
|
184
|
-
doc.data = data;
|
|
185
|
-
doc.meta = document.meta;
|
|
186
|
-
doc.links = document.links;
|
|
187
|
-
return doc;
|
|
188
|
-
}
|
|
189
|
-
let managed = recordArrayManager._keyedArrays.get(identifier.lid);
|
|
190
|
-
if (!managed) {
|
|
191
|
-
managed = recordArrayManager.createArray({
|
|
192
|
-
type: identifier.lid,
|
|
193
|
-
identifiers: document.data,
|
|
194
|
-
doc: document
|
|
195
|
-
});
|
|
196
|
-
recordArrayManager._keyedArrays.set(identifier.lid, managed);
|
|
197
|
-
const doc = new Document(store, identifier);
|
|
198
|
-
doc.data = managed;
|
|
199
|
-
doc.meta = document.meta;
|
|
200
|
-
doc.links = document.links;
|
|
201
|
-
store._documentCache.set(identifier, doc);
|
|
202
|
-
return options.shouldHydrate ? doc : document;
|
|
203
|
-
} else {
|
|
204
|
-
const doc = store._documentCache.get(identifier);
|
|
205
|
-
if (!isFromCache) {
|
|
206
|
-
recordArrayManager.populateManagedArray(managed, document.data, document);
|
|
207
|
-
doc.data = managed;
|
|
208
|
-
doc.meta = document.meta;
|
|
209
|
-
doc.links = document.links;
|
|
210
|
-
}
|
|
211
|
-
return options.shouldHydrate ? doc : document;
|
|
212
|
-
}
|
|
213
|
-
} else {
|
|
214
|
-
if (!identifier && !options.shouldHydrate) {
|
|
215
|
-
return document;
|
|
216
|
-
}
|
|
217
|
-
const data = document.data ? store.peekRecord(document.data) : null;
|
|
218
|
-
let doc;
|
|
219
|
-
if (identifier) {
|
|
220
|
-
doc = store._documentCache.get(identifier);
|
|
221
|
-
}
|
|
222
|
-
if (!doc) {
|
|
223
|
-
doc = new Document(store, identifier);
|
|
224
|
-
doc.data = data;
|
|
225
|
-
copyDocumentProperties(doc, document);
|
|
226
|
-
if (identifier) {
|
|
227
|
-
store._documentCache.set(identifier, doc);
|
|
228
|
-
}
|
|
229
|
-
} else if (!isFromCache) {
|
|
230
|
-
doc.data = data;
|
|
231
|
-
copyDocumentProperties(doc, document);
|
|
232
|
-
}
|
|
233
|
-
return options.shouldHydrate ? doc : document;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
function calcShouldFetch(store, request, hasCachedValue, identifier) {
|
|
237
|
-
const {
|
|
238
|
-
cacheOptions
|
|
239
|
-
} = request;
|
|
240
|
-
return cacheOptions?.reload || !hasCachedValue || (store.lifetimes && identifier ? store.lifetimes.isHardExpired(identifier) : false);
|
|
241
|
-
}
|
|
242
|
-
function calcShouldBackgroundFetch(store, request, willFetch, identifier) {
|
|
243
|
-
const {
|
|
244
|
-
cacheOptions
|
|
245
|
-
} = request;
|
|
246
|
-
return !willFetch && (cacheOptions?.backgroundReload || (store.lifetimes && identifier ? store.lifetimes.isSoftExpired(identifier) : false));
|
|
247
|
-
}
|
|
248
|
-
function fetchContentAndHydrate(next, context, identifier, shouldFetch, shouldBackgroundFetch) {
|
|
249
|
-
const {
|
|
250
|
-
store
|
|
251
|
-
} = context.request;
|
|
252
|
-
const shouldHydrate = context.request[Symbol.for('ember-data:enable-hydration')] || false;
|
|
253
|
-
return next(context.request).then(document => {
|
|
254
|
-
store.requestManager._pending.delete(context.id);
|
|
255
|
-
store._enableAsyncFlush = true;
|
|
256
|
-
let response;
|
|
257
|
-
store._join(() => {
|
|
258
|
-
response = store.cache.put(document);
|
|
259
|
-
response = maybeUpdateUiObjects(store, context.request, {
|
|
260
|
-
shouldHydrate,
|
|
261
|
-
shouldFetch,
|
|
262
|
-
shouldBackgroundFetch,
|
|
263
|
-
identifier
|
|
264
|
-
}, response, false);
|
|
265
|
-
});
|
|
266
|
-
store._enableAsyncFlush = null;
|
|
267
|
-
if (shouldFetch) {
|
|
268
|
-
return response;
|
|
269
|
-
} else if (shouldBackgroundFetch) {
|
|
270
|
-
store.notifications._flush();
|
|
271
|
-
}
|
|
272
|
-
}, error => {
|
|
273
|
-
store.requestManager._pending.delete(context.id);
|
|
274
|
-
if (context.request.signal?.aborted) {
|
|
275
|
-
throw error;
|
|
276
|
-
}
|
|
277
|
-
store.requestManager._pending.delete(context.id);
|
|
278
|
-
store._enableAsyncFlush = true;
|
|
279
|
-
let response;
|
|
280
|
-
store._join(() => {
|
|
281
|
-
response = store.cache.put(error);
|
|
282
|
-
response = maybeUpdateUiObjects(store, context.request, {
|
|
283
|
-
shouldHydrate,
|
|
284
|
-
shouldFetch,
|
|
285
|
-
shouldBackgroundFetch,
|
|
286
|
-
identifier
|
|
287
|
-
}, response, false);
|
|
288
|
-
});
|
|
289
|
-
store._enableAsyncFlush = null;
|
|
290
|
-
if (!shouldBackgroundFetch) {
|
|
291
|
-
const newError = cloneError(error);
|
|
292
|
-
newError.content = response;
|
|
293
|
-
throw newError;
|
|
294
|
-
} else {
|
|
295
|
-
store.notifications._flush();
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
function cloneError(error) {
|
|
300
|
-
const cloned = new Error(error.message);
|
|
301
|
-
cloned.stack = error.stack;
|
|
302
|
-
cloned.error = error.error;
|
|
303
|
-
return cloned;
|
|
304
|
-
}
|
|
305
|
-
const SkipCache = Symbol.for('ember-data:skip-cache');
|
|
306
|
-
const EnableHydration = Symbol.for('ember-data:enable-hydration');
|
|
307
|
-
const CacheHandler = {
|
|
308
|
-
request(context, next) {
|
|
309
|
-
// if we have no cache or no cache-key skip cache handling
|
|
310
|
-
if (!context.request.store || context.request.cacheOptions?.[SkipCache]) {
|
|
311
|
-
return next(context.request);
|
|
312
|
-
}
|
|
313
|
-
const {
|
|
314
|
-
store
|
|
315
|
-
} = context.request;
|
|
316
|
-
const identifier = store.identifierCache.getOrCreateDocumentIdentifier(context.request);
|
|
317
|
-
const peeked = identifier ? store.cache.peekRequest(identifier) : null;
|
|
318
|
-
|
|
319
|
-
// determine if we should skip cache
|
|
320
|
-
if (calcShouldFetch(store, context.request, !!peeked, identifier)) {
|
|
321
|
-
return fetchContentAndHydrate(next, context, identifier, true, false);
|
|
322
|
-
}
|
|
7
|
+
import { defineSignal, addToTransaction, createSignal, subscribe, createArrayTags, addTransactionCB } from '@ember-data/tracking/-private';
|
|
8
|
+
import { _backburner } from '@ember/runloop';
|
|
9
|
+
import { compat } from '@ember-data/tracking';
|
|
323
10
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
store.requestManager._pending.set(context.id, promise);
|
|
328
|
-
}
|
|
329
|
-
const shouldHydrate = context.request[EnableHydration] || false;
|
|
330
|
-
if ('error' in peeked) {
|
|
331
|
-
const content = shouldHydrate ? maybeUpdateUiObjects(store, context.request, {
|
|
332
|
-
shouldHydrate,
|
|
333
|
-
identifier
|
|
334
|
-
}, peeked.content, true) : peeked.content;
|
|
335
|
-
const newError = cloneError(peeked);
|
|
336
|
-
newError.content = content;
|
|
337
|
-
throw newError;
|
|
338
|
-
}
|
|
339
|
-
return Promise.resolve(shouldHydrate ? maybeUpdateUiObjects(store, context.request, {
|
|
340
|
-
shouldHydrate,
|
|
341
|
-
identifier
|
|
342
|
-
}, peeked.content, true) : peeked.content);
|
|
343
|
-
}
|
|
344
|
-
};
|
|
345
|
-
function copyDocumentProperties(target, source) {
|
|
346
|
-
if ('links' in source) {
|
|
347
|
-
target.links = source.links;
|
|
348
|
-
}
|
|
349
|
-
if ('meta' in source) {
|
|
350
|
-
target.meta = source.meta;
|
|
351
|
-
}
|
|
352
|
-
if ('errors' in source) {
|
|
353
|
-
target.errors = source.errors;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
11
|
+
/**
|
|
12
|
+
@module @ember-data/store
|
|
13
|
+
*/
|
|
356
14
|
|
|
357
|
-
// Used by the store to normalize IDs entering the store. Despite the fact
|
|
358
|
-
// that developers may provide IDs as numbers (e.g., `store.findRecord('person', 1)`),
|
|
359
|
-
// it is important that internally we use strings, since IDs may be serialized
|
|
360
|
-
// and lose type information. For example, Ember's router may put a record's
|
|
361
|
-
// ID into the URL, and if we later try to deserialize that URL and find the
|
|
362
|
-
// corresponding record, we will not know if it is a string or a number.
|
|
363
15
|
function coerceId(id) {
|
|
364
16
|
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_NON_STRICT_ID)) {
|
|
365
17
|
let normalized;
|
|
@@ -392,10 +44,6 @@ function ensureStringId(id) {
|
|
|
392
44
|
assert(`Expected id to be a string or number, received ${String(id)}`, normalized !== null);
|
|
393
45
|
return normalized;
|
|
394
46
|
}
|
|
395
|
-
|
|
396
|
-
// provided for additional debuggability
|
|
397
|
-
const DEBUG_CLIENT_ORIGINATED = Symbol('record-originated-on-client');
|
|
398
|
-
const DEBUG_IDENTIFIER_BUCKET = Symbol('identifier-bucket');
|
|
399
47
|
function normalizeModelName(type) {
|
|
400
48
|
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_NON_STRICT_TYPES)) {
|
|
401
49
|
const result = dasherize(type);
|
|
@@ -424,7 +72,7 @@ function installPolyfill() {
|
|
|
424
72
|
// we might be able to optimize this by requesting more bytes than we need at a time
|
|
425
73
|
const rng = function () {
|
|
426
74
|
// WHATWG crypto RNG - http://wiki.whatwg.org/wiki/Crypto
|
|
427
|
-
|
|
75
|
+
const rnds8 = new Uint8Array(16);
|
|
428
76
|
if (!CRYPTO.getRandomValues && !isFastBoot) {
|
|
429
77
|
throw new Error(`Unable to generate bytes for UUID`);
|
|
430
78
|
}
|
|
@@ -440,12 +88,12 @@ function installPolyfill() {
|
|
|
440
88
|
byteToHex[i] = (i + 0x100).toString(16).substr(1);
|
|
441
89
|
}
|
|
442
90
|
const bytesToUuid = function (buf) {
|
|
443
|
-
|
|
91
|
+
const bth = byteToHex;
|
|
444
92
|
// join used to fix memory issue caused by concatenation: https://bugs.chromium.org/p/v8/issues/detail?id=3175#c4
|
|
445
93
|
return [bth[buf[0]], bth[buf[1]], bth[buf[2]], bth[buf[3]], '-', bth[buf[4]], bth[buf[5]], '-', bth[buf[6]], bth[buf[7]], '-', bth[buf[8]], bth[buf[9]], '-', bth[buf[10]], bth[buf[11]], bth[buf[12]], bth[buf[13]], bth[buf[14]], bth[buf[15]]].join('');
|
|
446
94
|
};
|
|
447
95
|
CRYPTO.randomUUID = function uuidv4() {
|
|
448
|
-
|
|
96
|
+
const rnds = rng();
|
|
449
97
|
|
|
450
98
|
// Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
|
|
451
99
|
rnds[6] = rnds[6] & 0x0f | 0x40;
|
|
@@ -476,7 +124,7 @@ function hasType(resource) {
|
|
|
476
124
|
const IDENTIFIERS = new Set();
|
|
477
125
|
const DOCUMENTS = new Set();
|
|
478
126
|
function isStableIdentifier(identifier) {
|
|
479
|
-
return IDENTIFIERS.has(identifier);
|
|
127
|
+
return identifier[CACHE_OWNER] !== undefined || IDENTIFIERS.has(identifier);
|
|
480
128
|
}
|
|
481
129
|
function isDocumentIdentifier(identifier) {
|
|
482
130
|
return DOCUMENTS.has(identifier);
|
|
@@ -499,6 +147,7 @@ function freeze(obj) {
|
|
|
499
147
|
|
|
500
148
|
// type IdentifierTypeLookup = { all: Set<StableRecordIdentifier>; id: Map<string, StableRecordIdentifier> };
|
|
501
149
|
// type IdentifiersByType = Map<string, IdentifierTypeLookup>;
|
|
150
|
+
|
|
502
151
|
let configuredForgetMethod;
|
|
503
152
|
let configuredGenerationMethod;
|
|
504
153
|
let configuredResetMethod;
|
|
@@ -519,6 +168,7 @@ function setIdentifierResetMethod(method) {
|
|
|
519
168
|
// Map<type, Map<id, lid>>
|
|
520
169
|
|
|
521
170
|
const NEW_IDENTIFIERS = new Map();
|
|
171
|
+
let IDENTIFIER_CACHE_ID = 0;
|
|
522
172
|
function updateTypeIdMapping(typeMap, identifier, id) {
|
|
523
173
|
let idMap = typeMap.get(identifier.type);
|
|
524
174
|
if (!idMap) {
|
|
@@ -601,10 +251,12 @@ class IdentifierCache {
|
|
|
601
251
|
this._merge = defaultMergeMethod;
|
|
602
252
|
this._keyInfoForResource = defaultKeyInfoMethod;
|
|
603
253
|
this._isDefaultConfig = !configuredGenerationMethod;
|
|
254
|
+
this._id = IDENTIFIER_CACHE_ID++;
|
|
604
255
|
this._cache = {
|
|
605
256
|
resources: new Map(),
|
|
606
257
|
resourcesByType: Object.create(null),
|
|
607
|
-
documents: new Map()
|
|
258
|
+
documents: new Map(),
|
|
259
|
+
polymorphicLidBackMap: new Map()
|
|
608
260
|
};
|
|
609
261
|
}
|
|
610
262
|
|
|
@@ -658,7 +310,7 @@ class IdentifierCache {
|
|
|
658
310
|
console.log(`Identifiers: ${lid ? 'no ' : ''}lid ${lid ? lid + ' ' : ''}determined for resource`, resource);
|
|
659
311
|
}
|
|
660
312
|
let identifier = /*#__NOINLINE__*/getIdentifierFromLid(this._cache, lid, resource);
|
|
661
|
-
if (identifier !==
|
|
313
|
+
if (identifier !== null) {
|
|
662
314
|
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
663
315
|
// eslint-disable-next-line no-console
|
|
664
316
|
console.groupEnd();
|
|
@@ -676,11 +328,13 @@ class IdentifierCache {
|
|
|
676
328
|
// if we still don't have an identifier, time to generate one
|
|
677
329
|
if (shouldGenerate === 2) {
|
|
678
330
|
resource.lid = lid;
|
|
331
|
+
resource[CACHE_OWNER] = this._id;
|
|
679
332
|
identifier = /*#__NOINLINE__*/makeStableRecordIdentifier(resource, 'record', false);
|
|
680
333
|
} else {
|
|
681
334
|
// we lie a bit here as a memory optimization
|
|
682
335
|
const keyInfo = this._keyInfoForResource(resource, null);
|
|
683
336
|
keyInfo.lid = lid;
|
|
337
|
+
keyInfo[CACHE_OWNER] = this._id;
|
|
684
338
|
identifier = /*#__NOINLINE__*/makeStableRecordIdentifier(keyInfo, 'record', false);
|
|
685
339
|
}
|
|
686
340
|
addResourceToCache(this._cache, identifier);
|
|
@@ -698,7 +352,7 @@ class IdentifierCache {
|
|
|
698
352
|
*
|
|
699
353
|
* @method peekRecordIdentifier
|
|
700
354
|
* @param resource
|
|
701
|
-
* @
|
|
355
|
+
* @return {StableRecordIdentifier | undefined}
|
|
702
356
|
* @private
|
|
703
357
|
*/
|
|
704
358
|
peekRecordIdentifier(resource) {
|
|
@@ -710,7 +364,7 @@ class IdentifierCache {
|
|
|
710
364
|
Returns `null` if the request does not have a `cacheKey` or `url`.
|
|
711
365
|
@method getOrCreateDocumentIdentifier
|
|
712
366
|
@param request
|
|
713
|
-
@
|
|
367
|
+
@return {StableDocumentIdentifier | null}
|
|
714
368
|
@public
|
|
715
369
|
*/
|
|
716
370
|
getOrCreateDocumentIdentifier(request) {
|
|
@@ -744,7 +398,7 @@ class IdentifierCache {
|
|
|
744
398
|
- this referential stability of the object itself is guaranteed
|
|
745
399
|
@method getOrCreateRecordIdentifier
|
|
746
400
|
@param resource
|
|
747
|
-
@
|
|
401
|
+
@return {StableRecordIdentifier}
|
|
748
402
|
@public
|
|
749
403
|
*/
|
|
750
404
|
getOrCreateRecordIdentifier(resource) {
|
|
@@ -759,15 +413,16 @@ class IdentifierCache {
|
|
|
759
413
|
with the signature `generateMethod({ type }, 'record')`.
|
|
760
414
|
@method createIdentifierForNewRecord
|
|
761
415
|
@param data
|
|
762
|
-
@
|
|
416
|
+
@return {StableRecordIdentifier}
|
|
763
417
|
@public
|
|
764
418
|
*/
|
|
765
419
|
createIdentifierForNewRecord(data) {
|
|
766
|
-
|
|
767
|
-
|
|
420
|
+
const newLid = this._generate(data, 'record');
|
|
421
|
+
const identifier = /*#__NOINLINE__*/makeStableRecordIdentifier({
|
|
768
422
|
id: data.id || null,
|
|
769
423
|
type: data.type,
|
|
770
|
-
lid: newLid
|
|
424
|
+
lid: newLid,
|
|
425
|
+
[CACHE_OWNER]: this._id
|
|
771
426
|
}, 'record', true);
|
|
772
427
|
|
|
773
428
|
// populate our unique table
|
|
@@ -801,7 +456,7 @@ class IdentifierCache {
|
|
|
801
456
|
@method updateRecordIdentifier
|
|
802
457
|
@param identifierObject
|
|
803
458
|
@param data
|
|
804
|
-
@
|
|
459
|
+
@return {StableRecordIdentifier}
|
|
805
460
|
@public
|
|
806
461
|
*/
|
|
807
462
|
updateRecordIdentifier(identifierObject, data) {
|
|
@@ -821,7 +476,7 @@ class IdentifierCache {
|
|
|
821
476
|
}
|
|
822
477
|
}
|
|
823
478
|
if (existingIdentifier) {
|
|
824
|
-
|
|
479
|
+
const generatedIdentifier = identifier;
|
|
825
480
|
identifier = this._mergeRecordIdentifiers(keyInfo, generatedIdentifier, existingIdentifier, data);
|
|
826
481
|
|
|
827
482
|
// make sure that the `lid` on the data we are processing matches the lid we kept
|
|
@@ -833,7 +488,7 @@ class IdentifierCache {
|
|
|
833
488
|
console.log(`Identifiers: merged identifiers ${generatedIdentifier.lid} and ${existingIdentifier.lid} for resource into ${identifier.lid}`, data);
|
|
834
489
|
}
|
|
835
490
|
}
|
|
836
|
-
|
|
491
|
+
const id = identifier.id;
|
|
837
492
|
/*#__NOINLINE__*/
|
|
838
493
|
performRecordIdentifierUpdate(identifier, keyInfo, data, this._update);
|
|
839
494
|
const newId = identifier.id;
|
|
@@ -867,16 +522,32 @@ class IdentifierCache {
|
|
|
867
522
|
const kept = this._merge(identifier, existingIdentifier, data);
|
|
868
523
|
const abandoned = kept === identifier ? existingIdentifier : identifier;
|
|
869
524
|
|
|
525
|
+
// get any backreferences before forgetting this identifier, as it will be removed from the cache
|
|
526
|
+
// and we will no longer be able to find them
|
|
527
|
+
const abandonedBackReferences = this._cache.polymorphicLidBackMap.get(abandoned.lid);
|
|
528
|
+
// delete the backreferences for the abandoned identifier so that forgetRecordIdentifier
|
|
529
|
+
// does not try to remove them.
|
|
530
|
+
if (abandonedBackReferences) this._cache.polymorphicLidBackMap.delete(abandoned.lid);
|
|
531
|
+
|
|
870
532
|
// cleanup the identifier we no longer need
|
|
871
533
|
this.forgetRecordIdentifier(abandoned);
|
|
872
534
|
|
|
873
|
-
// ensure a secondary cache entry for
|
|
874
|
-
|
|
535
|
+
// ensure a secondary cache entry for the original lid for the abandoned identifier
|
|
536
|
+
this._cache.resources.set(abandoned.lid, kept);
|
|
875
537
|
|
|
876
|
-
//
|
|
877
|
-
//
|
|
878
|
-
|
|
538
|
+
// backReferences let us know which other identifiers are pointing at this identifier
|
|
539
|
+
// so we can delete them later if we forget this identifier
|
|
540
|
+
const keptBackReferences = this._cache.polymorphicLidBackMap.get(kept.lid) ?? [];
|
|
541
|
+
keptBackReferences.push(abandoned.lid);
|
|
879
542
|
|
|
543
|
+
// update the backreferences from the abandoned identifier to be for the kept identifier
|
|
544
|
+
if (abandonedBackReferences) {
|
|
545
|
+
abandonedBackReferences.forEach(lid => {
|
|
546
|
+
keptBackReferences.push(lid);
|
|
547
|
+
this._cache.resources.set(lid, kept);
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
this._cache.polymorphicLidBackMap.set(kept.lid, keptBackReferences);
|
|
880
551
|
return kept;
|
|
881
552
|
}
|
|
882
553
|
|
|
@@ -899,6 +570,17 @@ class IdentifierCache {
|
|
|
899
570
|
}
|
|
900
571
|
this._cache.resources.delete(identifier.lid);
|
|
901
572
|
typeSet.lid.delete(identifier.lid);
|
|
573
|
+
const backReferences = this._cache.polymorphicLidBackMap.get(identifier.lid);
|
|
574
|
+
if (backReferences) {
|
|
575
|
+
backReferences.forEach(lid => {
|
|
576
|
+
this._cache.resources.delete(lid);
|
|
577
|
+
});
|
|
578
|
+
this._cache.polymorphicLidBackMap.delete(identifier.lid);
|
|
579
|
+
}
|
|
580
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
581
|
+
identifier[DEBUG_STALE_CACHE_OWNER] = identifier[CACHE_OWNER];
|
|
582
|
+
}
|
|
583
|
+
identifier[CACHE_OWNER] = undefined;
|
|
902
584
|
IDENTIFIERS.delete(identifier);
|
|
903
585
|
this._forget(identifier, 'record');
|
|
904
586
|
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
@@ -929,15 +611,33 @@ function makeStableRecordIdentifier(recordIdentifier, bucket, clientOriginated)
|
|
|
929
611
|
get type() {
|
|
930
612
|
return recordIdentifier.type;
|
|
931
613
|
},
|
|
932
|
-
|
|
614
|
+
get [CACHE_OWNER]() {
|
|
615
|
+
return recordIdentifier[CACHE_OWNER];
|
|
616
|
+
},
|
|
617
|
+
set [CACHE_OWNER](value) {
|
|
618
|
+
recordIdentifier[CACHE_OWNER] = value;
|
|
619
|
+
},
|
|
620
|
+
get [DEBUG_STALE_CACHE_OWNER]() {
|
|
621
|
+
return recordIdentifier[DEBUG_STALE_CACHE_OWNER];
|
|
622
|
+
},
|
|
623
|
+
set [DEBUG_STALE_CACHE_OWNER](value) {
|
|
624
|
+
recordIdentifier[DEBUG_STALE_CACHE_OWNER] = value;
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
Object.defineProperty(wrapper, 'toString', {
|
|
628
|
+
enumerable: false,
|
|
629
|
+
value: () => {
|
|
933
630
|
const {
|
|
934
631
|
type,
|
|
935
632
|
id,
|
|
936
633
|
lid
|
|
937
634
|
} = recordIdentifier;
|
|
938
635
|
return `${clientOriginated ? '[CLIENT_ORIGINATED] ' : ''}${String(type)}:${String(id)} (${lid})`;
|
|
939
|
-
}
|
|
940
|
-
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
Object.defineProperty(wrapper, 'toJSON', {
|
|
639
|
+
enumerable: false,
|
|
640
|
+
value: () => {
|
|
941
641
|
const {
|
|
942
642
|
type,
|
|
943
643
|
id,
|
|
@@ -949,7 +649,7 @@ function makeStableRecordIdentifier(recordIdentifier, bucket, clientOriginated)
|
|
|
949
649
|
lid
|
|
950
650
|
};
|
|
951
651
|
}
|
|
952
|
-
};
|
|
652
|
+
});
|
|
953
653
|
wrapper[DEBUG_CLIENT_ORIGINATED] = clientOriginated;
|
|
954
654
|
wrapper[DEBUG_IDENTIFIER_BUCKET] = bucket;
|
|
955
655
|
IDENTIFIERS.add(wrapper);
|
|
@@ -967,7 +667,7 @@ function performRecordIdentifierUpdate(identifier, keyInfo, data, updateFn) {
|
|
|
967
667
|
} = keyInfo;
|
|
968
668
|
|
|
969
669
|
// get the mutable instance behind our proxy wrapper
|
|
970
|
-
|
|
670
|
+
const wrapper = identifier;
|
|
971
671
|
identifier = DEBUG_MAP.get(wrapper);
|
|
972
672
|
if (hasLid(data)) {
|
|
973
673
|
const lid = data.lid;
|
|
@@ -1022,7 +722,7 @@ function detectMerge(cache, keyInfo, identifier, data) {
|
|
|
1022
722
|
// we trigger a merge of the identifiers
|
|
1023
723
|
// though probably we should just throw an error here
|
|
1024
724
|
if (id !== null && id === newId && newType === type && hasLid(data) && data.lid !== lid) {
|
|
1025
|
-
return cache
|
|
725
|
+
return getIdentifierFromLid(cache, data.lid, data) || false;
|
|
1026
726
|
|
|
1027
727
|
// If the lids are the same, and ids are the same, but types are different we should trigger a merge of the identifiers
|
|
1028
728
|
} else if (id !== null && id === newId && newType && newType !== type && hasLid(data) && data.lid === lid) {
|
|
@@ -1039,7 +739,7 @@ function getIdentifierFromLid(cache, lid, resource) {
|
|
|
1039
739
|
// eslint-disable-next-line no-console
|
|
1040
740
|
console.log(`Identifiers: cache ${identifier ? 'HIT' : 'MISS'} - Non-Stable ${lid}`, resource);
|
|
1041
741
|
}
|
|
1042
|
-
return identifier;
|
|
742
|
+
return identifier || null;
|
|
1043
743
|
}
|
|
1044
744
|
function addResourceToCache(cache, identifier) {
|
|
1045
745
|
cache.resources.set(identifier.lid, identifier);
|
|
@@ -1056,28 +756,27 @@ function addResourceToCache(cache, identifier) {
|
|
|
1056
756
|
typeSet.id.set(identifier.id, identifier);
|
|
1057
757
|
}
|
|
1058
758
|
}
|
|
1059
|
-
var _class$1, _descriptor$1;
|
|
1060
759
|
|
|
1061
760
|
/**
|
|
1062
761
|
@module @ember-data/store
|
|
1063
762
|
*/
|
|
763
|
+
|
|
1064
764
|
/**
|
|
1065
765
|
@module @ember-data/store
|
|
1066
766
|
*/
|
|
767
|
+
|
|
1067
768
|
/**
|
|
1068
769
|
A `RecordReference` is a low-level API that allows users and
|
|
1069
770
|
addon authors to perform meta-operations on a record.
|
|
1070
771
|
|
|
1071
772
|
@class RecordReference
|
|
1072
773
|
@public
|
|
1073
|
-
@extends Reference
|
|
1074
774
|
*/
|
|
1075
|
-
|
|
775
|
+
class RecordReference {
|
|
1076
776
|
constructor(store, identifier) {
|
|
1077
777
|
// unsubscribe token given to us by the notification manager
|
|
1078
778
|
this.___token = void 0;
|
|
1079
779
|
this.___identifier = void 0;
|
|
1080
|
-
_initializerDefineProperty(this, "_ref", _descriptor$1, this);
|
|
1081
780
|
this.store = store;
|
|
1082
781
|
this.___identifier = identifier;
|
|
1083
782
|
this.___token = store.notifications.subscribe(identifier, (_, bucket, notifiedKey) => {
|
|
@@ -1245,14 +944,8 @@ let RecordReference = (_class$1 = class RecordReference {
|
|
|
1245
944
|
}
|
|
1246
945
|
assert(`Unable to fetch record of type ${this.type} without an id`);
|
|
1247
946
|
}
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
enumerable: true,
|
|
1251
|
-
writable: true,
|
|
1252
|
-
initializer: function () {
|
|
1253
|
-
return 0;
|
|
1254
|
-
}
|
|
1255
|
-
}), _class$1);
|
|
947
|
+
}
|
|
948
|
+
defineSignal(RecordReference.prototype, '_ref');
|
|
1256
949
|
|
|
1257
950
|
/**
|
|
1258
951
|
@module @ember-data/store
|
|
@@ -1283,6 +976,8 @@ class CacheCapabilitiesManager {
|
|
|
1283
976
|
if (this._store._cbs) {
|
|
1284
977
|
this._store._schedule('notify', () => this._flushNotifications());
|
|
1285
978
|
} else {
|
|
979
|
+
// TODO @runspired determine if relationship mutations should schedule
|
|
980
|
+
// into join/run vs immediate flush
|
|
1286
981
|
this._flushNotifications();
|
|
1287
982
|
}
|
|
1288
983
|
}
|
|
@@ -1290,7 +985,7 @@ class CacheCapabilitiesManager {
|
|
|
1290
985
|
if (this._willNotify === false) {
|
|
1291
986
|
return;
|
|
1292
987
|
}
|
|
1293
|
-
|
|
988
|
+
const pending = this._pendingNotifies;
|
|
1294
989
|
this._pendingNotifies = new Map();
|
|
1295
990
|
this._willNotify = false;
|
|
1296
991
|
pending.forEach((set, identifier) => {
|
|
@@ -1314,6 +1009,9 @@ class CacheCapabilitiesManager {
|
|
|
1314
1009
|
getSchemaDefinitionService() {
|
|
1315
1010
|
return this._store.getSchemaDefinitionService();
|
|
1316
1011
|
}
|
|
1012
|
+
get schema() {
|
|
1013
|
+
return this._store.schema;
|
|
1014
|
+
}
|
|
1317
1015
|
setRecordId(identifier, id) {
|
|
1318
1016
|
assert(`Expected a stable identifier`, isStableIdentifier(identifier));
|
|
1319
1017
|
this._store._instanceCache.setRecordId(identifier, id);
|
|
@@ -1347,6 +1045,9 @@ function peekCache(instance) {
|
|
|
1347
1045
|
}
|
|
1348
1046
|
return null;
|
|
1349
1047
|
}
|
|
1048
|
+
function isDestroyable(record) {
|
|
1049
|
+
return Boolean(record && typeof record === 'object' && typeof record.destroy === 'function');
|
|
1050
|
+
}
|
|
1350
1051
|
|
|
1351
1052
|
/**
|
|
1352
1053
|
@module @ember-data/store
|
|
@@ -1374,7 +1075,7 @@ function peekRecordIdentifier(record) {
|
|
|
1374
1075
|
@static
|
|
1375
1076
|
@for @ember-data/store
|
|
1376
1077
|
@param {Object} record a record instance previously obstained from the store.
|
|
1377
|
-
@
|
|
1078
|
+
@return {StableRecordIdentifier}
|
|
1378
1079
|
*/
|
|
1379
1080
|
function recordIdentifierFor(record) {
|
|
1380
1081
|
assert(`${String(record)} is not a record instantiated by @ember-data/store`, RecordCache.has(record));
|
|
@@ -1421,11 +1122,11 @@ class InstanceCache {
|
|
|
1421
1122
|
// @ts-expect-error TODO this needs to be fixed
|
|
1422
1123
|
'type' in resourceData && identifier.type === resourceData.type ? identifier : matchedIdentifier;
|
|
1423
1124
|
}
|
|
1424
|
-
|
|
1125
|
+
const staleIdentifier = identifier === keptIdentifier ? matchedIdentifier : identifier;
|
|
1425
1126
|
|
|
1426
1127
|
// check for duplicate entities
|
|
1427
|
-
|
|
1428
|
-
|
|
1128
|
+
const keptHasRecord = this.__instances.record.has(keptIdentifier);
|
|
1129
|
+
const staleHasRecord = this.__instances.record.has(staleIdentifier);
|
|
1429
1130
|
|
|
1430
1131
|
// we cannot merge entities when both have records
|
|
1431
1132
|
// (this may not be strictly true, we could probably swap the cache data the record points at)
|
|
@@ -1479,7 +1180,7 @@ class InstanceCache {
|
|
|
1479
1180
|
return record;
|
|
1480
1181
|
}
|
|
1481
1182
|
getReference(identifier) {
|
|
1482
|
-
|
|
1183
|
+
const cache = this.__instances.reference;
|
|
1483
1184
|
let reference = cache.get(identifier);
|
|
1484
1185
|
if (!reference) {
|
|
1485
1186
|
reference = new RecordReference(this.store, identifier);
|
|
@@ -1510,7 +1211,7 @@ class InstanceCache {
|
|
|
1510
1211
|
}
|
|
1511
1212
|
disconnect(identifier) {
|
|
1512
1213
|
const record = this.__instances.record.get(identifier);
|
|
1513
|
-
assert('Cannot destroy record while it is still materialized', !record || record.isDestroyed || record.isDestroying);
|
|
1214
|
+
assert('Cannot destroy record while it is still materialized', !isDestroyable(record) || record.isDestroyed || record.isDestroying);
|
|
1514
1215
|
this.store._graph?.remove(identifier);
|
|
1515
1216
|
this.store.identifierCache.forgetRecordIdentifier(identifier);
|
|
1516
1217
|
removeRecordDataFor(identifier);
|
|
@@ -1578,7 +1279,7 @@ class InstanceCache {
|
|
|
1578
1279
|
});
|
|
1579
1280
|
} else {
|
|
1580
1281
|
const typeCache = cache.resourcesByType;
|
|
1581
|
-
|
|
1282
|
+
const identifiers = typeCache[type]?.lid;
|
|
1582
1283
|
if (identifiers) {
|
|
1583
1284
|
identifiers.forEach(identifier => {
|
|
1584
1285
|
// if (rds.has(identifier)) {
|
|
@@ -1596,7 +1297,7 @@ class InstanceCache {
|
|
|
1596
1297
|
type,
|
|
1597
1298
|
lid
|
|
1598
1299
|
} = identifier;
|
|
1599
|
-
|
|
1300
|
+
const oldId = identifier.id;
|
|
1600
1301
|
|
|
1601
1302
|
// ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record)
|
|
1602
1303
|
assert(`'${type}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null));
|
|
@@ -1615,7 +1316,7 @@ class InstanceCache {
|
|
|
1615
1316
|
// eslint-disable-next-line no-console
|
|
1616
1317
|
console.log(`InstanceCache: updating id to '${id}' for record ${String(identifier)}`);
|
|
1617
1318
|
}
|
|
1618
|
-
|
|
1319
|
+
const existingIdentifier = this.store.identifierCache.peekRecordIdentifier({
|
|
1619
1320
|
type,
|
|
1620
1321
|
id
|
|
1621
1322
|
});
|
|
@@ -1654,13 +1355,13 @@ function resourceIsFullyDeleted(instanceCache, identifier) {
|
|
|
1654
1355
|
*/
|
|
1655
1356
|
|
|
1656
1357
|
function preloadData(store, identifier, preload) {
|
|
1657
|
-
|
|
1358
|
+
const jsonPayload = {};
|
|
1658
1359
|
//TODO(Igor) consider the polymorphic case
|
|
1659
1360
|
const schemas = store.getSchemaDefinitionService();
|
|
1660
1361
|
const relationships = schemas.relationshipsDefinitionFor(identifier);
|
|
1661
1362
|
Object.keys(preload).forEach(key => {
|
|
1662
|
-
|
|
1663
|
-
|
|
1363
|
+
const preloadValue = preload[key];
|
|
1364
|
+
const relationshipMeta = relationships[key];
|
|
1664
1365
|
if (relationshipMeta) {
|
|
1665
1366
|
if (!jsonPayload.relationships) {
|
|
1666
1367
|
jsonPayload.relationships = {};
|
|
@@ -1729,7 +1430,7 @@ function getShimClass(store, modelName) {
|
|
|
1729
1430
|
}
|
|
1730
1431
|
function mapFromHash(hash) {
|
|
1731
1432
|
const map = new Map();
|
|
1732
|
-
for (
|
|
1433
|
+
for (const i in hash) {
|
|
1733
1434
|
if (Object.prototype.hasOwnProperty.call(hash, i)) {
|
|
1734
1435
|
map.set(i, hash[i]);
|
|
1735
1436
|
}
|
|
@@ -1744,31 +1445,31 @@ class ShimModelClass {
|
|
|
1744
1445
|
this.modelName = modelName;
|
|
1745
1446
|
}
|
|
1746
1447
|
get fields() {
|
|
1747
|
-
|
|
1448
|
+
const attrs = this.__store.getSchemaDefinitionService().attributesDefinitionFor({
|
|
1748
1449
|
type: this.modelName
|
|
1749
1450
|
});
|
|
1750
|
-
|
|
1451
|
+
const relationships = this.__store.getSchemaDefinitionService().relationshipsDefinitionFor({
|
|
1751
1452
|
type: this.modelName
|
|
1752
1453
|
});
|
|
1753
|
-
|
|
1454
|
+
const fields = new Map();
|
|
1754
1455
|
Object.keys(attrs).forEach(key => fields.set(key, 'attribute'));
|
|
1755
1456
|
Object.keys(relationships).forEach(key => fields.set(key, relationships[key].kind));
|
|
1756
1457
|
return fields;
|
|
1757
1458
|
}
|
|
1758
1459
|
get attributes() {
|
|
1759
|
-
|
|
1460
|
+
const attrs = this.__store.getSchemaDefinitionService().attributesDefinitionFor({
|
|
1760
1461
|
type: this.modelName
|
|
1761
1462
|
});
|
|
1762
1463
|
return mapFromHash(attrs);
|
|
1763
1464
|
}
|
|
1764
1465
|
get relationshipsByName() {
|
|
1765
|
-
|
|
1466
|
+
const relationships = this.__store.getSchemaDefinitionService().relationshipsDefinitionFor({
|
|
1766
1467
|
type: this.modelName
|
|
1767
1468
|
});
|
|
1768
1469
|
return mapFromHash(relationships);
|
|
1769
1470
|
}
|
|
1770
1471
|
eachAttribute(callback, binding) {
|
|
1771
|
-
|
|
1472
|
+
const attrDefs = this.__store.getSchemaDefinitionService().attributesDefinitionFor({
|
|
1772
1473
|
type: this.modelName
|
|
1773
1474
|
});
|
|
1774
1475
|
Object.keys(attrDefs).forEach(key => {
|
|
@@ -1776,7 +1477,7 @@ class ShimModelClass {
|
|
|
1776
1477
|
});
|
|
1777
1478
|
}
|
|
1778
1479
|
eachRelationship(callback, binding) {
|
|
1779
|
-
|
|
1480
|
+
const relationshipDefs = this.__store.getSchemaDefinitionService().relationshipsDefinitionFor({
|
|
1780
1481
|
type: this.modelName
|
|
1781
1482
|
});
|
|
1782
1483
|
Object.keys(relationshipDefs).forEach(key => {
|
|
@@ -1794,6 +1495,16 @@ class ShimModelClass {
|
|
|
1794
1495
|
});
|
|
1795
1496
|
}
|
|
1796
1497
|
}
|
|
1498
|
+
function _classPrivateFieldBase(receiver, privateKey) {
|
|
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
|
+
}
|
|
1797
1508
|
var _cache = /*#__PURE__*/_classPrivateFieldKey("cache");
|
|
1798
1509
|
/**
|
|
1799
1510
|
* The CacheManager wraps a Cache enforcing that only
|
|
@@ -1820,16 +1531,6 @@ class CacheManager {
|
|
|
1820
1531
|
writable: true,
|
|
1821
1532
|
value: void 0
|
|
1822
1533
|
});
|
|
1823
|
-
/**
|
|
1824
|
-
* Query the cache for whether a given resource has been deleted and that deletion
|
|
1825
|
-
* has also been persisted.
|
|
1826
|
-
*
|
|
1827
|
-
* @method isDeletionCommitted
|
|
1828
|
-
* @public
|
|
1829
|
-
* @param identifier
|
|
1830
|
-
* @returns {boolean}
|
|
1831
|
-
*/
|
|
1832
|
-
this.isDel = void 0;
|
|
1833
1534
|
_classPrivateFieldBase(this, _cache)[_cache] = cache;
|
|
1834
1535
|
}
|
|
1835
1536
|
|
|
@@ -1843,7 +1544,7 @@ class CacheManager {
|
|
|
1843
1544
|
* semantics, `put` has `replace` semantics similar to
|
|
1844
1545
|
* the `http` method `PUT`
|
|
1845
1546
|
*
|
|
1846
|
-
* the individually
|
|
1547
|
+
* the individually cacheable
|
|
1847
1548
|
* e resource data it may contain
|
|
1848
1549
|
* should upsert, but the document data surrounding it should
|
|
1849
1550
|
* fully replace any existing information
|
|
@@ -1856,7 +1557,7 @@ class CacheManager {
|
|
|
1856
1557
|
*
|
|
1857
1558
|
* @method put
|
|
1858
1559
|
* @param {StructuredDocument} doc
|
|
1859
|
-
* @
|
|
1560
|
+
* @return {ResourceDocument}
|
|
1860
1561
|
* @public
|
|
1861
1562
|
*/
|
|
1862
1563
|
put(doc) {
|
|
@@ -1872,7 +1573,7 @@ class CacheManager {
|
|
|
1872
1573
|
* @method patch
|
|
1873
1574
|
* @public
|
|
1874
1575
|
* @param op the operation to perform
|
|
1875
|
-
* @
|
|
1576
|
+
* @return {void}
|
|
1876
1577
|
*/
|
|
1877
1578
|
patch(op) {
|
|
1878
1579
|
_classPrivateFieldBase(this, _cache)[_cache].patch(op);
|
|
@@ -1907,7 +1608,7 @@ class CacheManager {
|
|
|
1907
1608
|
* An implementation might want to do this because
|
|
1908
1609
|
* de-referencing records which read from their own
|
|
1909
1610
|
* blob is generally safer because the record does
|
|
1910
|
-
* not require
|
|
1611
|
+
* not require retaining connections to the Store
|
|
1911
1612
|
* and Cache to present data on a per-field basis.
|
|
1912
1613
|
*
|
|
1913
1614
|
* This generally takes the place of `getAttr` as
|
|
@@ -1920,7 +1621,7 @@ class CacheManager {
|
|
|
1920
1621
|
* @method peek
|
|
1921
1622
|
* @public
|
|
1922
1623
|
* @param {StableRecordIdentifier | StableDocumentIdentifier} identifier
|
|
1923
|
-
* @
|
|
1624
|
+
* @return {ResourceDocument | ResourceBlob | null} the known resource data
|
|
1924
1625
|
*/
|
|
1925
1626
|
|
|
1926
1627
|
peek(identifier) {
|
|
@@ -1933,7 +1634,7 @@ class CacheManager {
|
|
|
1933
1634
|
*
|
|
1934
1635
|
* @method peekRequest
|
|
1935
1636
|
* @param {StableDocumentIdentifier}
|
|
1936
|
-
* @
|
|
1637
|
+
* @return {StableDocumentIdentifier | null}
|
|
1937
1638
|
* @public
|
|
1938
1639
|
*/
|
|
1939
1640
|
peekRequest(identifier) {
|
|
@@ -1948,7 +1649,7 @@ class CacheManager {
|
|
|
1948
1649
|
* @param identifier
|
|
1949
1650
|
* @param data
|
|
1950
1651
|
* @param hasRecord
|
|
1951
|
-
* @
|
|
1652
|
+
* @return {void | string[]} if `hasRecord` is true then calculated key changes should be returned
|
|
1952
1653
|
*/
|
|
1953
1654
|
upsert(identifier, data, hasRecord) {
|
|
1954
1655
|
return _classPrivateFieldBase(this, _cache)[_cache].upsert(identifier, data, hasRecord);
|
|
@@ -1966,7 +1667,7 @@ class CacheManager {
|
|
|
1966
1667
|
*
|
|
1967
1668
|
* @method fork
|
|
1968
1669
|
* @public
|
|
1969
|
-
* @
|
|
1670
|
+
* @return Promise<Cache>
|
|
1970
1671
|
*/
|
|
1971
1672
|
fork() {
|
|
1972
1673
|
return _classPrivateFieldBase(this, _cache)[_cache].fork();
|
|
@@ -1982,7 +1683,7 @@ class CacheManager {
|
|
|
1982
1683
|
* @method merge
|
|
1983
1684
|
* @param {Cache} cache
|
|
1984
1685
|
* @public
|
|
1985
|
-
* @
|
|
1686
|
+
* @return Promise<void>
|
|
1986
1687
|
*/
|
|
1987
1688
|
merge(cache) {
|
|
1988
1689
|
return _classPrivateFieldBase(this, _cache)[_cache].merge(cache);
|
|
@@ -2034,7 +1735,7 @@ class CacheManager {
|
|
|
2034
1735
|
* via `cache.hydrate`.
|
|
2035
1736
|
*
|
|
2036
1737
|
* @method dump
|
|
2037
|
-
* @
|
|
1738
|
+
* @return {Promise<ReadableStream>}
|
|
2038
1739
|
* @public
|
|
2039
1740
|
*/
|
|
2040
1741
|
dump() {
|
|
@@ -2055,7 +1756,7 @@ class CacheManager {
|
|
|
2055
1756
|
*
|
|
2056
1757
|
* @method hydrate
|
|
2057
1758
|
* @param {ReadableStream} stream
|
|
2058
|
-
* @
|
|
1759
|
+
* @return {Promise<void>}
|
|
2059
1760
|
* @public
|
|
2060
1761
|
*/
|
|
2061
1762
|
hydrate(stream) {
|
|
@@ -2069,7 +1770,7 @@ class CacheManager {
|
|
|
2069
1770
|
// ================
|
|
2070
1771
|
|
|
2071
1772
|
/**
|
|
2072
|
-
* [
|
|
1773
|
+
* [LIFECYCLE] Signal to the cache that a new record has been instantiated on the client
|
|
2073
1774
|
*
|
|
2074
1775
|
* It returns properties from options that should be set on the record during the create
|
|
2075
1776
|
* process. This return value behavior is deprecated.
|
|
@@ -2143,7 +1844,7 @@ class CacheManager {
|
|
|
2143
1844
|
* @public
|
|
2144
1845
|
* @param identifier
|
|
2145
1846
|
* @param propertyName
|
|
2146
|
-
* @
|
|
1847
|
+
* @return {unknown}
|
|
2147
1848
|
*/
|
|
2148
1849
|
getAttr(identifier, propertyName) {
|
|
2149
1850
|
return _classPrivateFieldBase(this, _cache)[_cache].getAttr(identifier, propertyName);
|
|
@@ -2168,7 +1869,7 @@ class CacheManager {
|
|
|
2168
1869
|
* @method changedAttrs
|
|
2169
1870
|
* @public
|
|
2170
1871
|
* @param identifier
|
|
2171
|
-
* @
|
|
1872
|
+
* @return
|
|
2172
1873
|
*/
|
|
2173
1874
|
changedAttrs(identifier) {
|
|
2174
1875
|
return _classPrivateFieldBase(this, _cache)[_cache].changedAttrs(identifier);
|
|
@@ -2180,7 +1881,7 @@ class CacheManager {
|
|
|
2180
1881
|
* @method hasChangedAttrs
|
|
2181
1882
|
* @public
|
|
2182
1883
|
* @param identifier
|
|
2183
|
-
* @
|
|
1884
|
+
* @return {boolean}
|
|
2184
1885
|
*/
|
|
2185
1886
|
hasChangedAttrs(identifier) {
|
|
2186
1887
|
return _classPrivateFieldBase(this, _cache)[_cache].hasChangedAttrs(identifier);
|
|
@@ -2192,7 +1893,7 @@ class CacheManager {
|
|
|
2192
1893
|
* @method rollbackAttrs
|
|
2193
1894
|
* @public
|
|
2194
1895
|
* @param identifier
|
|
2195
|
-
* @
|
|
1896
|
+
* @return the names of attributes that were restored
|
|
2196
1897
|
*/
|
|
2197
1898
|
rollbackAttrs(identifier) {
|
|
2198
1899
|
return _classPrivateFieldBase(this, _cache)[_cache].rollbackAttrs(identifier);
|
|
@@ -2201,6 +1902,65 @@ class CacheManager {
|
|
|
2201
1902
|
// Relationships
|
|
2202
1903
|
// =============
|
|
2203
1904
|
|
|
1905
|
+
/**
|
|
1906
|
+
* Query the cache for the changes to relationships of a resource.
|
|
1907
|
+
*
|
|
1908
|
+
* Returns a map of relationship names to RelationshipDiff objects.
|
|
1909
|
+
*
|
|
1910
|
+
* ```ts
|
|
1911
|
+
* type RelationshipDiff =
|
|
1912
|
+
| {
|
|
1913
|
+
kind: 'collection';
|
|
1914
|
+
remoteState: StableRecordIdentifier[];
|
|
1915
|
+
additions: Set<StableRecordIdentifier>;
|
|
1916
|
+
removals: Set<StableRecordIdentifier>;
|
|
1917
|
+
localState: StableRecordIdentifier[];
|
|
1918
|
+
reordered: boolean;
|
|
1919
|
+
}
|
|
1920
|
+
| {
|
|
1921
|
+
kind: 'resource';
|
|
1922
|
+
remoteState: StableRecordIdentifier | null;
|
|
1923
|
+
localState: StableRecordIdentifier | null;
|
|
1924
|
+
};
|
|
1925
|
+
```
|
|
1926
|
+
*
|
|
1927
|
+
* @method changedRelationships
|
|
1928
|
+
* @public
|
|
1929
|
+
* @param {StableRecordIdentifier} identifier
|
|
1930
|
+
* @return {Map<string, RelationshipDiff>}
|
|
1931
|
+
*/
|
|
1932
|
+
changedRelationships(identifier) {
|
|
1933
|
+
return _classPrivateFieldBase(this, _cache)[_cache].changedRelationships(identifier);
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
/**
|
|
1937
|
+
* Query the cache for whether any mutated attributes exist
|
|
1938
|
+
*
|
|
1939
|
+
* @method hasChangedRelationships
|
|
1940
|
+
* @public
|
|
1941
|
+
* @param {StableRecordIdentifier} identifier
|
|
1942
|
+
* @return {boolean}
|
|
1943
|
+
*/
|
|
1944
|
+
hasChangedRelationships(identifier) {
|
|
1945
|
+
return _classPrivateFieldBase(this, _cache)[_cache].hasChangedRelationships(identifier);
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
/**
|
|
1949
|
+
* Tell the cache to discard any uncommitted mutations to relationships.
|
|
1950
|
+
*
|
|
1951
|
+
* This will also discard the change on any appropriate inverses.
|
|
1952
|
+
*
|
|
1953
|
+
* This method is a candidate to become a mutation
|
|
1954
|
+
*
|
|
1955
|
+
* @method rollbackRelationships
|
|
1956
|
+
* @public
|
|
1957
|
+
* @param {StableRecordIdentifier} identifier
|
|
1958
|
+
* @return {string[]} the names of relationships that were restored
|
|
1959
|
+
*/
|
|
1960
|
+
rollbackRelationships(identifier) {
|
|
1961
|
+
return _classPrivateFieldBase(this, _cache)[_cache].rollbackRelationships(identifier);
|
|
1962
|
+
}
|
|
1963
|
+
|
|
2204
1964
|
/**
|
|
2205
1965
|
* Query the cache for the current state of a relationship property
|
|
2206
1966
|
*
|
|
@@ -2208,7 +1968,7 @@ class CacheManager {
|
|
|
2208
1968
|
* @public
|
|
2209
1969
|
* @param identifier
|
|
2210
1970
|
* @param propertyName
|
|
2211
|
-
* @
|
|
1971
|
+
* @return resource relationship object
|
|
2212
1972
|
*/
|
|
2213
1973
|
getRelationship(identifier, propertyName) {
|
|
2214
1974
|
return _classPrivateFieldBase(this, _cache)[_cache].getRelationship(identifier, propertyName);
|
|
@@ -2236,7 +1996,7 @@ class CacheManager {
|
|
|
2236
1996
|
* @method getErrors
|
|
2237
1997
|
* @public
|
|
2238
1998
|
* @param identifier
|
|
2239
|
-
* @
|
|
1999
|
+
* @return
|
|
2240
2000
|
*/
|
|
2241
2001
|
getErrors(identifier) {
|
|
2242
2002
|
return _classPrivateFieldBase(this, _cache)[_cache].getErrors(identifier);
|
|
@@ -2248,7 +2008,7 @@ class CacheManager {
|
|
|
2248
2008
|
* @method isEmpty
|
|
2249
2009
|
* @public
|
|
2250
2010
|
* @param identifier
|
|
2251
|
-
* @
|
|
2011
|
+
* @return {boolean}
|
|
2252
2012
|
*/
|
|
2253
2013
|
isEmpty(identifier) {
|
|
2254
2014
|
return _classPrivateFieldBase(this, _cache)[_cache].isEmpty(identifier);
|
|
@@ -2261,7 +2021,7 @@ class CacheManager {
|
|
|
2261
2021
|
* @method isNew
|
|
2262
2022
|
* @public
|
|
2263
2023
|
* @param identifier
|
|
2264
|
-
* @
|
|
2024
|
+
* @return {boolean}
|
|
2265
2025
|
*/
|
|
2266
2026
|
isNew(identifier) {
|
|
2267
2027
|
return _classPrivateFieldBase(this, _cache)[_cache].isNew(identifier);
|
|
@@ -2274,15 +2034,29 @@ class CacheManager {
|
|
|
2274
2034
|
* @method isDeleted
|
|
2275
2035
|
* @public
|
|
2276
2036
|
* @param identifier
|
|
2277
|
-
* @
|
|
2037
|
+
* @return {boolean}
|
|
2278
2038
|
*/
|
|
2279
2039
|
isDeleted(identifier) {
|
|
2280
2040
|
return _classPrivateFieldBase(this, _cache)[_cache].isDeleted(identifier);
|
|
2281
2041
|
}
|
|
2042
|
+
|
|
2043
|
+
/**
|
|
2044
|
+
* Query the cache for whether a given resource has been deleted and that deletion
|
|
2045
|
+
* has also been persisted.
|
|
2046
|
+
*
|
|
2047
|
+
* @method isDeletionCommitted
|
|
2048
|
+
* @public
|
|
2049
|
+
* @param identifier
|
|
2050
|
+
* @return {boolean}
|
|
2051
|
+
*/
|
|
2282
2052
|
isDeletionCommitted(identifier) {
|
|
2283
2053
|
return _classPrivateFieldBase(this, _cache)[_cache].isDeletionCommitted(identifier);
|
|
2284
2054
|
}
|
|
2285
2055
|
}
|
|
2056
|
+
|
|
2057
|
+
/**
|
|
2058
|
+
* @module @ember-data/store
|
|
2059
|
+
*/
|
|
2286
2060
|
let tokenId = 0;
|
|
2287
2061
|
const CacheOperations = new Set(['added', 'removed', 'state', 'updated']);
|
|
2288
2062
|
function isCacheOperationValue(value) {
|
|
@@ -2293,7 +2067,7 @@ function runLoopIsFlushing() {
|
|
|
2293
2067
|
return !!_backburner.currentInstance && _backburner._autorun !== true;
|
|
2294
2068
|
}
|
|
2295
2069
|
function _unsubscribe(tokens, token, cache) {
|
|
2296
|
-
|
|
2070
|
+
const identifier = tokens.get(token);
|
|
2297
2071
|
if (macroCondition(getOwnConfig().debug.LOG_NOTIFICATIONS)) {
|
|
2298
2072
|
if (!identifier) {
|
|
2299
2073
|
// eslint-disable-next-line no-console
|
|
@@ -2352,7 +2126,7 @@ class NotificationManager {
|
|
|
2352
2126
|
* @public
|
|
2353
2127
|
* @param {StableDocumentIdentifier | StableRecordIdentifier | 'resource' | 'document'} identifier
|
|
2354
2128
|
* @param {NotificationCallback | ResourceOperationCallback | DocumentOperationCallback} callback
|
|
2355
|
-
* @
|
|
2129
|
+
* @return {UnsubscribeToken} an opaque token to be used with unsubscribe
|
|
2356
2130
|
*/
|
|
2357
2131
|
|
|
2358
2132
|
subscribe(identifier, callback) {
|
|
@@ -2362,7 +2136,7 @@ class NotificationManager {
|
|
|
2362
2136
|
map = new Map();
|
|
2363
2137
|
this._cache.set(identifier, map);
|
|
2364
2138
|
}
|
|
2365
|
-
|
|
2139
|
+
const unsubToken = macroCondition(getOwnConfig().env.DEBUG) ? {
|
|
2366
2140
|
_tokenRef: tokenId++
|
|
2367
2141
|
} : {};
|
|
2368
2142
|
map.set(unsubToken, callback);
|
|
@@ -2415,7 +2189,7 @@ class NotificationManager {
|
|
|
2415
2189
|
this._buffered.set(identifier, buffer);
|
|
2416
2190
|
}
|
|
2417
2191
|
buffer.push([value, key]);
|
|
2418
|
-
|
|
2192
|
+
this._scheduleNotify();
|
|
2419
2193
|
}
|
|
2420
2194
|
return hasSubscribers;
|
|
2421
2195
|
}
|
|
@@ -2457,14 +2231,14 @@ class NotificationManager {
|
|
|
2457
2231
|
|
|
2458
2232
|
// TODO for documents this will need to switch based on Identifier kind
|
|
2459
2233
|
if (isCacheOperationValue(value)) {
|
|
2460
|
-
|
|
2234
|
+
const callbackMap = this._cache.get(isDocumentIdentifier(identifier) ? 'document' : 'resource');
|
|
2461
2235
|
if (callbackMap) {
|
|
2462
2236
|
callbackMap.forEach(cb => {
|
|
2463
2237
|
cb(identifier, value);
|
|
2464
2238
|
});
|
|
2465
2239
|
}
|
|
2466
2240
|
}
|
|
2467
|
-
|
|
2241
|
+
const callbackMap = this._cache.get(identifier);
|
|
2468
2242
|
if (!callbackMap || !callbackMap.size) {
|
|
2469
2243
|
return false;
|
|
2470
2244
|
}
|
|
@@ -2474,13 +2248,36 @@ class NotificationManager {
|
|
|
2474
2248
|
});
|
|
2475
2249
|
return true;
|
|
2476
2250
|
}
|
|
2477
|
-
destroy() {
|
|
2478
|
-
this.isDestroyed = true;
|
|
2479
|
-
this._tokens.clear();
|
|
2480
|
-
this._cache.clear();
|
|
2251
|
+
destroy() {
|
|
2252
|
+
this.isDestroyed = true;
|
|
2253
|
+
this._tokens.clear();
|
|
2254
|
+
this._cache.clear();
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
|
|
2258
|
+
var desc = {};
|
|
2259
|
+
Object.keys(descriptor).forEach(function (key) {
|
|
2260
|
+
desc[key] = descriptor[key];
|
|
2261
|
+
});
|
|
2262
|
+
desc.enumerable = !!desc.enumerable;
|
|
2263
|
+
desc.configurable = !!desc.configurable;
|
|
2264
|
+
if ('value' in desc || desc.initializer) {
|
|
2265
|
+
desc.writable = true;
|
|
2266
|
+
}
|
|
2267
|
+
desc = decorators.slice().reverse().reduce(function (desc, decorator) {
|
|
2268
|
+
return decorator(target, property, desc) || desc;
|
|
2269
|
+
}, desc);
|
|
2270
|
+
if (context && desc.initializer !== void 0) {
|
|
2271
|
+
desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
|
|
2272
|
+
desc.initializer = undefined;
|
|
2273
|
+
}
|
|
2274
|
+
if (desc.initializer === void 0) {
|
|
2275
|
+
Object.defineProperty(target, property, desc);
|
|
2276
|
+
desc = null;
|
|
2481
2277
|
}
|
|
2278
|
+
return desc;
|
|
2482
2279
|
}
|
|
2483
|
-
var _class
|
|
2280
|
+
var _class;
|
|
2484
2281
|
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']);
|
|
2485
2282
|
const ARRAY_SETTER_METHODS = new Set(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
|
|
2486
2283
|
const SYNC_PROPS = new Set(['[]', 'length', 'links', 'meta']);
|
|
@@ -2490,19 +2287,16 @@ function isArrayGetter(prop) {
|
|
|
2490
2287
|
function isArraySetter(prop) {
|
|
2491
2288
|
return ARRAY_SETTER_METHODS.has(prop);
|
|
2492
2289
|
}
|
|
2493
|
-
|
|
2290
|
+
function isSelfProp(self, prop) {
|
|
2291
|
+
return prop in self;
|
|
2292
|
+
}
|
|
2293
|
+
const ARRAY_SIGNAL = Symbol('#signal');
|
|
2494
2294
|
const SOURCE = Symbol('#source');
|
|
2495
2295
|
const MUTATE = Symbol('#update');
|
|
2496
2296
|
const NOTIFY = Symbol('#notify');
|
|
2497
2297
|
const IS_COLLECTION = Symbol.for('Collection');
|
|
2498
2298
|
function notifyArray(arr) {
|
|
2499
|
-
addToTransaction(arr[
|
|
2500
|
-
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_COMPUTED_CHAINS)) {
|
|
2501
|
-
// eslint-disable-next-line
|
|
2502
|
-
dirtyTag(tagForProperty(arr, 'length'));
|
|
2503
|
-
// eslint-disable-next-line
|
|
2504
|
-
dirtyTag(tagForProperty(arr, '[]'));
|
|
2505
|
-
}
|
|
2299
|
+
addToTransaction(arr[ARRAY_SIGNAL]);
|
|
2506
2300
|
}
|
|
2507
2301
|
function convertToInt(prop) {
|
|
2508
2302
|
if (typeof prop === 'symbol') return null;
|
|
@@ -2510,29 +2304,6 @@ function convertToInt(prop) {
|
|
|
2510
2304
|
if (isNaN(num)) return null;
|
|
2511
2305
|
return num % 1 === 0 ? num : null;
|
|
2512
2306
|
}
|
|
2513
|
-
let Tag = (_class = class Tag {
|
|
2514
|
-
/*
|
|
2515
|
-
* whether this was part of a transaction when last mutated
|
|
2516
|
-
*/
|
|
2517
|
-
|
|
2518
|
-
constructor() {
|
|
2519
|
-
_initializerDefineProperty(this, "ref", _descriptor, this);
|
|
2520
|
-
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
2521
|
-
const [arr, prop] = arguments;
|
|
2522
|
-
this._debug_base = arr.constructor.name + ':' + String(arr.modelName);
|
|
2523
|
-
this._debug_prop = prop;
|
|
2524
|
-
}
|
|
2525
|
-
this.shouldReset = false;
|
|
2526
|
-
this.t = false;
|
|
2527
|
-
}
|
|
2528
|
-
}, _descriptor = _applyDecoratedDescriptor(_class.prototype, "ref", [tracked], {
|
|
2529
|
-
configurable: true,
|
|
2530
|
-
enumerable: true,
|
|
2531
|
-
writable: true,
|
|
2532
|
-
initializer: function () {
|
|
2533
|
-
return null;
|
|
2534
|
-
}
|
|
2535
|
-
}), _class);
|
|
2536
2307
|
function safeForEach(instance, arr, store, callback, target) {
|
|
2537
2308
|
if (target === undefined) {
|
|
2538
2309
|
target = null;
|
|
@@ -2565,7 +2336,7 @@ function safeForEach(instance, arr, store, callback, target) {
|
|
|
2565
2336
|
@class RecordArray
|
|
2566
2337
|
@public
|
|
2567
2338
|
*/
|
|
2568
|
-
let IdentifierArray = (
|
|
2339
|
+
let IdentifierArray = (_class = class IdentifierArray {
|
|
2569
2340
|
[NOTIFY]() {
|
|
2570
2341
|
notifyArray(this);
|
|
2571
2342
|
}
|
|
@@ -2593,14 +2364,6 @@ let IdentifierArray = (_class3 = class IdentifierArray {
|
|
|
2593
2364
|
set length(value) {
|
|
2594
2365
|
this[SOURCE].length = value;
|
|
2595
2366
|
}
|
|
2596
|
-
|
|
2597
|
-
// here to support computed chains
|
|
2598
|
-
// and {{#each}}
|
|
2599
|
-
get '[]'() {
|
|
2600
|
-
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_COMPUTED_CHAINS)) {
|
|
2601
|
-
return this;
|
|
2602
|
-
}
|
|
2603
|
-
}
|
|
2604
2367
|
constructor(options) {
|
|
2605
2368
|
/**
|
|
2606
2369
|
The flag to signal a `RecordArray` is currently loading data.
|
|
@@ -2615,7 +2378,6 @@ let IdentifierArray = (_class3 = class IdentifierArray {
|
|
|
2615
2378
|
@public
|
|
2616
2379
|
@type Boolean
|
|
2617
2380
|
*/
|
|
2618
|
-
_initializerDefineProperty(this, "isUpdating", _descriptor2, this);
|
|
2619
2381
|
this.isLoaded = true;
|
|
2620
2382
|
this.isDestroying = false;
|
|
2621
2383
|
this.isDestroyed = false;
|
|
@@ -2623,16 +2385,15 @@ let IdentifierArray = (_class3 = class IdentifierArray {
|
|
|
2623
2385
|
this[IS_COLLECTION] = true;
|
|
2624
2386
|
this[SOURCE] = void 0;
|
|
2625
2387
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
2626
|
-
|
|
2388
|
+
const self = this;
|
|
2627
2389
|
this.modelName = options.type;
|
|
2628
2390
|
this.store = options.store;
|
|
2629
2391
|
this._manager = options.manager;
|
|
2630
2392
|
this[SOURCE] = options.identifiers;
|
|
2631
|
-
|
|
2632
|
-
this[IDENTIFIER_ARRAY_TAG] = macroCondition(getOwnConfig().env.DEBUG) ? new Tag(this, 'length') : new Tag();
|
|
2393
|
+
this[ARRAY_SIGNAL] = createSignal(this, 'length');
|
|
2633
2394
|
const store = options.store;
|
|
2634
2395
|
const boundFns = new Map();
|
|
2635
|
-
const
|
|
2396
|
+
const _SIGNAL = this[ARRAY_SIGNAL];
|
|
2636
2397
|
const PrivateState = {
|
|
2637
2398
|
links: options.links || null,
|
|
2638
2399
|
meta: options.meta || null
|
|
@@ -2645,40 +2406,40 @@ let IdentifierArray = (_class3 = class IdentifierArray {
|
|
|
2645
2406
|
|
|
2646
2407
|
const proxy = new Proxy(this[SOURCE], {
|
|
2647
2408
|
get(target, prop, receiver) {
|
|
2648
|
-
|
|
2649
|
-
if (
|
|
2409
|
+
const index = convertToInt(prop);
|
|
2410
|
+
if (_SIGNAL.shouldReset && (index !== null || SYNC_PROPS.has(prop) || isArrayGetter(prop))) {
|
|
2650
2411
|
options.manager._syncArray(receiver);
|
|
2651
|
-
|
|
2652
|
-
|
|
2412
|
+
_SIGNAL.t = false;
|
|
2413
|
+
_SIGNAL.shouldReset = false;
|
|
2653
2414
|
}
|
|
2654
2415
|
if (index !== null) {
|
|
2655
2416
|
const identifier = target[index];
|
|
2656
2417
|
if (!transaction) {
|
|
2657
|
-
subscribe(
|
|
2418
|
+
subscribe(_SIGNAL);
|
|
2658
2419
|
}
|
|
2659
2420
|
return identifier && store._instanceCache.getRecord(identifier);
|
|
2660
2421
|
}
|
|
2661
|
-
if (prop === 'meta') return subscribe(
|
|
2662
|
-
if (prop === 'links') return subscribe(
|
|
2663
|
-
if (prop === '[]') return subscribe(
|
|
2422
|
+
if (prop === 'meta') return subscribe(_SIGNAL), PrivateState.meta;
|
|
2423
|
+
if (prop === 'links') return subscribe(_SIGNAL), PrivateState.links;
|
|
2424
|
+
if (prop === '[]') return subscribe(_SIGNAL), receiver;
|
|
2664
2425
|
if (isArrayGetter(prop)) {
|
|
2665
2426
|
let fn = boundFns.get(prop);
|
|
2666
2427
|
if (fn === undefined) {
|
|
2667
2428
|
if (prop === 'forEach') {
|
|
2668
2429
|
fn = function () {
|
|
2669
|
-
subscribe(
|
|
2430
|
+
subscribe(_SIGNAL);
|
|
2670
2431
|
transaction = true;
|
|
2671
|
-
|
|
2432
|
+
const result = safeForEach(receiver, target, store, arguments[0], arguments[1]);
|
|
2672
2433
|
transaction = false;
|
|
2673
2434
|
return result;
|
|
2674
2435
|
};
|
|
2675
2436
|
} else {
|
|
2676
2437
|
fn = function () {
|
|
2677
|
-
subscribe(
|
|
2438
|
+
subscribe(_SIGNAL);
|
|
2678
2439
|
// array functions must run through Reflect to work properly
|
|
2679
2440
|
// binding via other means will not work.
|
|
2680
2441
|
transaction = true;
|
|
2681
|
-
|
|
2442
|
+
const result = Reflect.apply(target[prop], receiver, arguments);
|
|
2682
2443
|
transaction = false;
|
|
2683
2444
|
return result;
|
|
2684
2445
|
};
|
|
@@ -2700,10 +2461,7 @@ let IdentifierArray = (_class3 = class IdentifierArray {
|
|
|
2700
2461
|
const args = Array.prototype.slice.call(arguments);
|
|
2701
2462
|
assert(`Cannot start a new array transaction while a previous transaction is underway`, !transaction);
|
|
2702
2463
|
transaction = true;
|
|
2703
|
-
|
|
2704
|
-
self[MUTATE](prop, args, result);
|
|
2705
|
-
addToTransaction(_TAG);
|
|
2706
|
-
// TODO handle cache updates
|
|
2464
|
+
const result = self[MUTATE](target, receiver, prop, args, _SIGNAL);
|
|
2707
2465
|
transaction = false;
|
|
2708
2466
|
return result;
|
|
2709
2467
|
};
|
|
@@ -2711,16 +2469,16 @@ let IdentifierArray = (_class3 = class IdentifierArray {
|
|
|
2711
2469
|
}
|
|
2712
2470
|
return fn;
|
|
2713
2471
|
}
|
|
2714
|
-
if (prop
|
|
2715
|
-
if (prop === NOTIFY || prop ===
|
|
2472
|
+
if (isSelfProp(self, prop)) {
|
|
2473
|
+
if (prop === NOTIFY || prop === ARRAY_SIGNAL || prop === SOURCE) {
|
|
2716
2474
|
return self[prop];
|
|
2717
2475
|
}
|
|
2718
2476
|
let fn = boundFns.get(prop);
|
|
2719
2477
|
if (fn) return fn;
|
|
2720
|
-
|
|
2478
|
+
const outcome = self[prop];
|
|
2721
2479
|
if (typeof outcome === 'function') {
|
|
2722
2480
|
fn = function () {
|
|
2723
|
-
subscribe(
|
|
2481
|
+
subscribe(_SIGNAL);
|
|
2724
2482
|
// array functions must run through Reflect to work properly
|
|
2725
2483
|
// binding via other means will not work.
|
|
2726
2484
|
return Reflect.apply(outcome, receiver, arguments);
|
|
@@ -2728,17 +2486,16 @@ let IdentifierArray = (_class3 = class IdentifierArray {
|
|
|
2728
2486
|
boundFns.set(prop, fn);
|
|
2729
2487
|
return fn;
|
|
2730
2488
|
}
|
|
2731
|
-
return subscribe(
|
|
2489
|
+
return subscribe(_SIGNAL), outcome;
|
|
2732
2490
|
}
|
|
2733
2491
|
return target[prop];
|
|
2734
2492
|
},
|
|
2735
|
-
|
|
2493
|
+
// FIXME: Should this get a generic like get above?
|
|
2494
|
+
set(target, prop, value, receiver) {
|
|
2736
2495
|
if (prop === 'length') {
|
|
2737
2496
|
if (!transaction && value === 0) {
|
|
2738
2497
|
transaction = true;
|
|
2739
|
-
|
|
2740
|
-
Reflect.set(target, prop, value);
|
|
2741
|
-
self[MUTATE]('length 0', []);
|
|
2498
|
+
self[MUTATE](target, receiver, 'length 0', [], _SIGNAL);
|
|
2742
2499
|
transaction = false;
|
|
2743
2500
|
return true;
|
|
2744
2501
|
} else if (transaction) {
|
|
@@ -2755,9 +2512,22 @@ let IdentifierArray = (_class3 = class IdentifierArray {
|
|
|
2755
2512
|
PrivateState.meta = value || null;
|
|
2756
2513
|
return true;
|
|
2757
2514
|
}
|
|
2758
|
-
|
|
2515
|
+
const index = convertToInt(prop);
|
|
2516
|
+
|
|
2517
|
+
// we do not allow "holey" arrays and so if the index is
|
|
2518
|
+
// greater than length then we will disallow setting it.
|
|
2519
|
+
// however, there is a special case for "unshift" with more than
|
|
2520
|
+
// one item being inserted since current items will be moved to the
|
|
2521
|
+
// new indices first.
|
|
2522
|
+
// we "loosely" detect this by just checking whether we are in
|
|
2523
|
+
// a transaction.
|
|
2759
2524
|
if (index === null || index > target.length) {
|
|
2760
|
-
if (
|
|
2525
|
+
if (index !== null && transaction) {
|
|
2526
|
+
const identifier = recordIdentifierFor(value);
|
|
2527
|
+
assert(`Cannot set index ${index} past the end of the array.`, isStableIdentifier(identifier));
|
|
2528
|
+
target[index] = identifier;
|
|
2529
|
+
return true;
|
|
2530
|
+
} else if (isSelfProp(self, prop)) {
|
|
2761
2531
|
self[prop] = value;
|
|
2762
2532
|
return true;
|
|
2763
2533
|
}
|
|
@@ -2767,12 +2537,30 @@ let IdentifierArray = (_class3 = class IdentifierArray {
|
|
|
2767
2537
|
assert(`Mutating ${String(prop)} on this RecordArray is not allowed.`, options.allowMutation);
|
|
2768
2538
|
return false;
|
|
2769
2539
|
}
|
|
2770
|
-
|
|
2771
|
-
|
|
2540
|
+
const original = target[index];
|
|
2541
|
+
const newIdentifier = extractIdentifierFromRecord$1(value);
|
|
2772
2542
|
target[index] = newIdentifier;
|
|
2543
|
+
assert(`Expected a record`, isStableIdentifier(newIdentifier));
|
|
2544
|
+
// We generate "transactions" whenever a setter method on the array
|
|
2545
|
+
// is called and might bulk update multiple array cells. Fundamentally,
|
|
2546
|
+
// all array operations decompose into individual cell replacements.
|
|
2547
|
+
// e.g. a push is really a "replace cell at next index with new value"
|
|
2548
|
+
// or a splice is "shift all values left/right by X and set out of new
|
|
2549
|
+
// bounds cells to undefined"
|
|
2550
|
+
//
|
|
2551
|
+
// so, if we are in a transaction, then this is not a user generated change
|
|
2552
|
+
// but one generated by a setter method. In this case we want to only apply
|
|
2553
|
+
// the change to the target array and not call the MUTATE method.
|
|
2554
|
+
// If there is no transaction though, then this means the user themselves has
|
|
2555
|
+
// directly changed the value of a specific index and we need to thus generate
|
|
2556
|
+
// a mutation for that change.
|
|
2557
|
+
// e.g. "arr.push(newVal)" is handled by a "addToRelatedRecords" mutation within
|
|
2558
|
+
// a transaction.
|
|
2559
|
+
// while "arr[arr.length] = newVal;" is handled by this replace cell code path.
|
|
2773
2560
|
if (!transaction) {
|
|
2774
|
-
self[MUTATE]('replace cell', [index, original, newIdentifier]);
|
|
2775
|
-
|
|
2561
|
+
self[MUTATE](target, receiver, 'replace cell', [index, original, newIdentifier], _SIGNAL);
|
|
2562
|
+
} else {
|
|
2563
|
+
target[index] = newIdentifier;
|
|
2776
2564
|
}
|
|
2777
2565
|
return true;
|
|
2778
2566
|
},
|
|
@@ -2787,12 +2575,7 @@ let IdentifierArray = (_class3 = class IdentifierArray {
|
|
|
2787
2575
|
return IdentifierArray.prototype;
|
|
2788
2576
|
}
|
|
2789
2577
|
});
|
|
2790
|
-
|
|
2791
|
-
const meta = Ember.meta(this);
|
|
2792
|
-
meta.hasMixin = mixin => {
|
|
2793
|
-
assert(`Do not call A() on EmberData RecordArrays`);
|
|
2794
|
-
};
|
|
2795
|
-
}
|
|
2578
|
+
createArrayTags(proxy, _SIGNAL);
|
|
2796
2579
|
this[NOTIFY] = this[NOTIFY].bind(proxy);
|
|
2797
2580
|
return proxy;
|
|
2798
2581
|
}
|
|
@@ -2817,8 +2600,8 @@ let IdentifierArray = (_class3 = class IdentifierArray {
|
|
|
2817
2600
|
return this._updatingPromise;
|
|
2818
2601
|
}
|
|
2819
2602
|
this.isUpdating = true;
|
|
2820
|
-
|
|
2821
|
-
updatingPromise.finally(() => {
|
|
2603
|
+
const updatingPromise = this._update();
|
|
2604
|
+
void updatingPromise.finally(() => {
|
|
2822
2605
|
this._updatingPromise = null;
|
|
2823
2606
|
if (this.isDestroying || this.isDestroyed) {
|
|
2824
2607
|
return;
|
|
@@ -2856,17 +2639,23 @@ let IdentifierArray = (_class3 = class IdentifierArray {
|
|
|
2856
2639
|
@return {Promise<IdentifierArray>} promise
|
|
2857
2640
|
*/
|
|
2858
2641
|
save() {
|
|
2859
|
-
|
|
2642
|
+
const promise = Promise.all(this.map(record => this.store.saveRecord(record))).then(() => this);
|
|
2860
2643
|
return promise;
|
|
2861
2644
|
}
|
|
2862
|
-
},
|
|
2863
|
-
|
|
2645
|
+
}, _applyDecoratedDescriptor(_class.prototype, "length", [compat], Object.getOwnPropertyDescriptor(_class.prototype, "length"), _class.prototype), _class); // this will error if someone tries to call
|
|
2646
|
+
// A(identifierArray) since it is not configurable
|
|
2647
|
+
// which is preferable to the `meta` override we used
|
|
2648
|
+
// before which required importing all of Ember
|
|
2649
|
+
const desc = {
|
|
2864
2650
|
enumerable: true,
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
return
|
|
2651
|
+
configurable: false,
|
|
2652
|
+
get: function () {
|
|
2653
|
+
return this;
|
|
2868
2654
|
}
|
|
2869
|
-
}
|
|
2655
|
+
};
|
|
2656
|
+
compat(desc);
|
|
2657
|
+
Object.defineProperty(IdentifierArray.prototype, '[]', desc);
|
|
2658
|
+
defineSignal(IdentifierArray.prototype, 'isUpdating', false);
|
|
2870
2659
|
class Collection extends IdentifierArray {
|
|
2871
2660
|
constructor(options) {
|
|
2872
2661
|
super(options);
|
|
@@ -2898,7 +2687,8 @@ class Collection extends IdentifierArray {
|
|
|
2898
2687
|
Collection.prototype.query = null;
|
|
2899
2688
|
|
|
2900
2689
|
// Ensure instanceof works correctly
|
|
2901
|
-
//Object.setPrototypeOf(IdentifierArray.prototype, Array.prototype);
|
|
2690
|
+
// Object.setPrototypeOf(IdentifierArray.prototype, Array.prototype);
|
|
2691
|
+
|
|
2902
2692
|
function assertRecordPassedToHasMany(record) {
|
|
2903
2693
|
assert(`All elements of a hasMany relationship must be instances of Model, you passed $${typeof record}`, function () {
|
|
2904
2694
|
try {
|
|
@@ -2920,7 +2710,6 @@ function extractIdentifierFromRecord$1(record) {
|
|
|
2920
2710
|
/**
|
|
2921
2711
|
@module @ember-data/store
|
|
2922
2712
|
*/
|
|
2923
|
-
|
|
2924
2713
|
const FAKE_ARR = {};
|
|
2925
2714
|
const SLICE_BATCH_SIZE = 1200;
|
|
2926
2715
|
/**
|
|
@@ -2963,7 +2752,7 @@ const SLICE_BATCH_SIZE = 1200;
|
|
|
2963
2752
|
*/
|
|
2964
2753
|
function fastPush(target, source) {
|
|
2965
2754
|
let startLength = 0;
|
|
2966
|
-
|
|
2755
|
+
const newLength = source.length;
|
|
2967
2756
|
while (newLength - startLength > SLICE_BATCH_SIZE) {
|
|
2968
2757
|
// eslint-disable-next-line prefer-spread
|
|
2969
2758
|
target.push.apply(target, source.slice(startLength, startLength + SLICE_BATCH_SIZE));
|
|
@@ -3020,8 +2809,8 @@ class RecordArrayManager {
|
|
|
3020
2809
|
*/
|
|
3021
2810
|
liveArrayFor(type) {
|
|
3022
2811
|
let array = this._live.get(type);
|
|
3023
|
-
|
|
3024
|
-
|
|
2812
|
+
const identifiers = [];
|
|
2813
|
+
const staged = this._staged.get(type);
|
|
3025
2814
|
if (staged) {
|
|
3026
2815
|
staged.forEach((value, key) => {
|
|
3027
2816
|
if (value === 'add') {
|
|
@@ -3044,7 +2833,7 @@ class RecordArrayManager {
|
|
|
3044
2833
|
return array;
|
|
3045
2834
|
}
|
|
3046
2835
|
createArray(config) {
|
|
3047
|
-
|
|
2836
|
+
const options = {
|
|
3048
2837
|
type: config.type,
|
|
3049
2838
|
links: config.doc?.links || null,
|
|
3050
2839
|
meta: config.doc?.meta || null,
|
|
@@ -3055,7 +2844,7 @@ class RecordArrayManager {
|
|
|
3055
2844
|
store: this.store,
|
|
3056
2845
|
manager: this
|
|
3057
2846
|
};
|
|
3058
|
-
|
|
2847
|
+
const array = new Collection(options);
|
|
3059
2848
|
this._managed.add(array);
|
|
3060
2849
|
this._set.set(array, new Set(options.identifiers || []));
|
|
3061
2850
|
if (config.identifiers) {
|
|
@@ -3067,7 +2856,7 @@ class RecordArrayManager {
|
|
|
3067
2856
|
if (array === FAKE_ARR) {
|
|
3068
2857
|
return;
|
|
3069
2858
|
}
|
|
3070
|
-
|
|
2859
|
+
const tag = array[ARRAY_SIGNAL];
|
|
3071
2860
|
if (!tag.shouldReset) {
|
|
3072
2861
|
tag.shouldReset = true;
|
|
3073
2862
|
addTransactionCB(array[NOTIFY]);
|
|
@@ -3079,11 +2868,11 @@ class RecordArrayManager {
|
|
|
3079
2868
|
if (this.isDestroying || this.isDestroyed) {
|
|
3080
2869
|
return;
|
|
3081
2870
|
}
|
|
3082
|
-
|
|
2871
|
+
const liveArray = this._live.get(identifier.type);
|
|
3083
2872
|
const allPending = this._pending;
|
|
3084
|
-
|
|
2873
|
+
const pending = new Map();
|
|
3085
2874
|
if (includeManaged) {
|
|
3086
|
-
|
|
2875
|
+
const managed = this._identifiers.get(identifier);
|
|
3087
2876
|
if (managed) {
|
|
3088
2877
|
managed.forEach(arr => {
|
|
3089
2878
|
let changes = allPending.get(arr);
|
|
@@ -3138,10 +2927,10 @@ class RecordArrayManager {
|
|
|
3138
2927
|
associate(this._identifiers, array, identifiers);
|
|
3139
2928
|
}
|
|
3140
2929
|
identifierAdded(identifier) {
|
|
3141
|
-
|
|
2930
|
+
const changeSets = this._getPendingFor(identifier, false);
|
|
3142
2931
|
if (changeSets) {
|
|
3143
2932
|
changeSets.forEach((changes, array) => {
|
|
3144
|
-
|
|
2933
|
+
const existing = changes.get(identifier);
|
|
3145
2934
|
if (existing === 'del') {
|
|
3146
2935
|
changes.delete(identifier);
|
|
3147
2936
|
} else {
|
|
@@ -3152,10 +2941,10 @@ class RecordArrayManager {
|
|
|
3152
2941
|
}
|
|
3153
2942
|
}
|
|
3154
2943
|
identifierRemoved(identifier) {
|
|
3155
|
-
|
|
2944
|
+
const changeSets = this._getPendingFor(identifier, true, true);
|
|
3156
2945
|
if (changeSets) {
|
|
3157
2946
|
changeSets.forEach((changes, array) => {
|
|
3158
|
-
|
|
2947
|
+
const existing = changes.get(identifier);
|
|
3159
2948
|
if (existing === 'add') {
|
|
3160
2949
|
changes.delete(identifier);
|
|
3161
2950
|
} else {
|
|
@@ -3166,7 +2955,7 @@ class RecordArrayManager {
|
|
|
3166
2955
|
}
|
|
3167
2956
|
}
|
|
3168
2957
|
identifierChanged(identifier) {
|
|
3169
|
-
|
|
2958
|
+
const newState = this.store._instanceCache.recordIsLoaded(identifier, true);
|
|
3170
2959
|
|
|
3171
2960
|
// if the change matches the most recent direct added/removed
|
|
3172
2961
|
// state, then we can ignore it
|
|
@@ -3193,13 +2982,12 @@ class RecordArrayManager {
|
|
|
3193
2982
|
this.clear(false);
|
|
3194
2983
|
this._live.clear();
|
|
3195
2984
|
this.isDestroyed = true;
|
|
3196
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
3197
2985
|
this.store.notifications.unsubscribe(this._subscription);
|
|
3198
2986
|
}
|
|
3199
2987
|
}
|
|
3200
2988
|
function associate(ArraysCache, array, identifiers) {
|
|
3201
2989
|
for (let i = 0; i < identifiers.length; i++) {
|
|
3202
|
-
|
|
2990
|
+
const identifier = identifiers[i];
|
|
3203
2991
|
let cache = ArraysCache.get(identifier);
|
|
3204
2992
|
if (!cache) {
|
|
3205
2993
|
cache = new Set();
|
|
@@ -3214,13 +3002,13 @@ function disassociate(ArraysCache, array, identifiers) {
|
|
|
3214
3002
|
}
|
|
3215
3003
|
}
|
|
3216
3004
|
function disassociateIdentifier(ArraysCache, array, identifier) {
|
|
3217
|
-
|
|
3005
|
+
const cache = ArraysCache.get(identifier);
|
|
3218
3006
|
if (cache) {
|
|
3219
3007
|
cache.delete(array);
|
|
3220
3008
|
}
|
|
3221
3009
|
}
|
|
3222
3010
|
function sync(array, changes, arraySet) {
|
|
3223
|
-
|
|
3011
|
+
const state = array[SOURCE];
|
|
3224
3012
|
const adds = [];
|
|
3225
3013
|
const removes = [];
|
|
3226
3014
|
changes.forEach((value, key) => {
|
|
@@ -3234,13 +3022,13 @@ function sync(array, changes, arraySet) {
|
|
|
3234
3022
|
} else {
|
|
3235
3023
|
if (arraySet.has(key)) {
|
|
3236
3024
|
removes.push(key);
|
|
3025
|
+
arraySet.delete(key);
|
|
3237
3026
|
}
|
|
3238
3027
|
}
|
|
3239
3028
|
});
|
|
3240
3029
|
if (removes.length) {
|
|
3241
3030
|
if (removes.length === state.length) {
|
|
3242
3031
|
state.length = 0;
|
|
3243
|
-
arraySet.clear();
|
|
3244
3032
|
// changing the reference breaks the Proxy
|
|
3245
3033
|
// state = array[SOURCE] = [];
|
|
3246
3034
|
} else {
|
|
@@ -3267,6 +3055,9 @@ function sync(array, changes, arraySet) {
|
|
|
3267
3055
|
}
|
|
3268
3056
|
}
|
|
3269
3057
|
|
|
3058
|
+
/**
|
|
3059
|
+
* @module @ember-data/store
|
|
3060
|
+
*/
|
|
3270
3061
|
const Touching = Symbol('touching');
|
|
3271
3062
|
const RequestPromise = Symbol('promise');
|
|
3272
3063
|
const EMPTY_ARR = macroCondition(getOwnConfig().env.DEBUG) ? Object.freeze([]) : [];
|
|
@@ -3294,14 +3085,14 @@ class RequestStateService {
|
|
|
3294
3085
|
this._done.delete(identifier);
|
|
3295
3086
|
}
|
|
3296
3087
|
_enqueue(promise, queryRequest) {
|
|
3297
|
-
|
|
3088
|
+
const query = queryRequest.data[0];
|
|
3298
3089
|
if (hasRecordIdentifier(query)) {
|
|
3299
3090
|
const identifier = query.recordIdentifier;
|
|
3300
|
-
|
|
3091
|
+
const type = query.op === 'saveRecord' ? 'mutation' : 'query';
|
|
3301
3092
|
if (!this._pending.has(identifier)) {
|
|
3302
3093
|
this._pending.set(identifier, []);
|
|
3303
3094
|
}
|
|
3304
|
-
|
|
3095
|
+
const request = {
|
|
3305
3096
|
state: 'pending',
|
|
3306
3097
|
request: queryRequest,
|
|
3307
3098
|
type
|
|
@@ -3312,7 +3103,7 @@ class RequestStateService {
|
|
|
3312
3103
|
this._triggerSubscriptions(request);
|
|
3313
3104
|
return promise.then(result => {
|
|
3314
3105
|
this._dequeue(identifier, request);
|
|
3315
|
-
|
|
3106
|
+
const finalizedRequest = {
|
|
3316
3107
|
state: 'fulfilled',
|
|
3317
3108
|
request: queryRequest,
|
|
3318
3109
|
type,
|
|
@@ -3326,7 +3117,7 @@ class RequestStateService {
|
|
|
3326
3117
|
return result;
|
|
3327
3118
|
}, error => {
|
|
3328
3119
|
this._dequeue(identifier, request);
|
|
3329
|
-
|
|
3120
|
+
const finalizedRequest = {
|
|
3330
3121
|
state: 'rejected',
|
|
3331
3122
|
request: queryRequest,
|
|
3332
3123
|
type,
|
|
@@ -3375,7 +3166,7 @@ class RequestStateService {
|
|
|
3375
3166
|
_addDone(request) {
|
|
3376
3167
|
request[Touching].forEach(identifier => {
|
|
3377
3168
|
// TODO add support for multiple
|
|
3378
|
-
|
|
3169
|
+
const requestDataOp = request.request.data[0].op;
|
|
3379
3170
|
let requests = this._done.get(identifier);
|
|
3380
3171
|
if (requests) {
|
|
3381
3172
|
requests = requests.filter(req => {
|
|
@@ -3439,7 +3230,7 @@ class RequestStateService {
|
|
|
3439
3230
|
* @method getPendingRequestsForRecord
|
|
3440
3231
|
* @public
|
|
3441
3232
|
* @param {StableRecordIdentifier} identifier
|
|
3442
|
-
* @
|
|
3233
|
+
* @return {RequestState[]} an array of request states for any pending requests for the given identifier
|
|
3443
3234
|
*/
|
|
3444
3235
|
getPendingRequestsForRecord(identifier) {
|
|
3445
3236
|
return this._pending.get(identifier) || EMPTY_ARR;
|
|
@@ -3451,10 +3242,10 @@ class RequestStateService {
|
|
|
3451
3242
|
* @method getLastRequestForRecord
|
|
3452
3243
|
* @public
|
|
3453
3244
|
* @param {StableRecordIdentifier} identifier
|
|
3454
|
-
* @
|
|
3245
|
+
* @return {RequestState | null} the state of the most recent request for the given identifier
|
|
3455
3246
|
*/
|
|
3456
3247
|
getLastRequestForRecord(identifier) {
|
|
3457
|
-
|
|
3248
|
+
const requests = this._done.get(identifier);
|
|
3458
3249
|
if (requests) {
|
|
3459
3250
|
return requests[requests.length - 1];
|
|
3460
3251
|
}
|
|
@@ -3466,7 +3257,7 @@ function isNonEmptyString(str) {
|
|
|
3466
3257
|
}
|
|
3467
3258
|
function constructResource(type, id, lid) {
|
|
3468
3259
|
if (typeof type === 'object' && type !== null) {
|
|
3469
|
-
|
|
3260
|
+
const resource = type;
|
|
3470
3261
|
if (isStableIdentifier(resource)) {
|
|
3471
3262
|
return resource;
|
|
3472
3263
|
}
|
|
@@ -3501,6 +3292,11 @@ function constructResource(type, id, lid) {
|
|
|
3501
3292
|
}
|
|
3502
3293
|
}
|
|
3503
3294
|
|
|
3295
|
+
/**
|
|
3296
|
+
@module @ember-data/store
|
|
3297
|
+
*/
|
|
3298
|
+
// this import location is deprecated but breaks in 4.8 and older
|
|
3299
|
+
|
|
3504
3300
|
/**
|
|
3505
3301
|
* A Store coordinates interaction between your application, a [Cache](https://api.emberjs.com/ember-data/release/classes/%3CInterface%3E%20Cache),
|
|
3506
3302
|
* and sources of data (such as your API or a local persistence layer)
|
|
@@ -3519,7 +3315,10 @@ function constructResource(type, id, lid) {
|
|
|
3519
3315
|
|
|
3520
3316
|
@class Store
|
|
3521
3317
|
@public
|
|
3522
|
-
*/
|
|
3318
|
+
*/
|
|
3319
|
+
|
|
3320
|
+
// @ts-expect-error
|
|
3321
|
+
|
|
3523
3322
|
class Store extends EmberObject {
|
|
3524
3323
|
/**
|
|
3525
3324
|
* Provides access to the NotificationManager associated
|
|
@@ -3651,8 +3450,6 @@ class Store extends EmberObject {
|
|
|
3651
3450
|
// private
|
|
3652
3451
|
this._requestCache = new RequestStateService(this);
|
|
3653
3452
|
this._instanceCache = new InstanceCache(this);
|
|
3654
|
-
this._adapterCache = Object.create(null);
|
|
3655
|
-
this._serializerCache = Object.create(null);
|
|
3656
3453
|
this._documentCache = new Map();
|
|
3657
3454
|
this.isDestroying = false;
|
|
3658
3455
|
this.isDestroyed = false;
|
|
@@ -3710,7 +3507,7 @@ class Store extends EmberObject {
|
|
|
3710
3507
|
* that have been initiated for a given identifier.
|
|
3711
3508
|
*
|
|
3712
3509
|
* @method getRequestStateService
|
|
3713
|
-
* @
|
|
3510
|
+
* @return {RequestStateService}
|
|
3714
3511
|
* @public
|
|
3715
3512
|
*/
|
|
3716
3513
|
getRequestStateService() {
|
|
@@ -3735,10 +3532,11 @@ class Store extends EmberObject {
|
|
|
3735
3532
|
* inserting the response into the cache and handing
|
|
3736
3533
|
* back a Future which resolves to a ResponseDocument
|
|
3737
3534
|
*
|
|
3738
|
-
*
|
|
3535
|
+
* ## Cache Keys
|
|
3739
3536
|
*
|
|
3740
|
-
* Only GET requests
|
|
3741
|
-
*
|
|
3537
|
+
* Only GET requests with a url or requests with an explicit
|
|
3538
|
+
* cache key (`cacheOptions.key`) will have the request result
|
|
3539
|
+
* and document cached.
|
|
3742
3540
|
*
|
|
3743
3541
|
* The cache key used is `requestConfig.cacheOptions.key`
|
|
3744
3542
|
* if present, falling back to `requestconfig.url`.
|
|
@@ -3749,16 +3547,44 @@ class Store extends EmberObject {
|
|
|
3749
3547
|
* via the `POST` method `requestConfig.cacheOptions.key`
|
|
3750
3548
|
* MUST be supplied for the document to be cached.
|
|
3751
3549
|
*
|
|
3550
|
+
* ## Requesting Without a Cache Key
|
|
3551
|
+
*
|
|
3552
|
+
* Resource data within the request is always updated in the cache,
|
|
3553
|
+
* regardless of whether a cache key is present for the request.
|
|
3554
|
+
*
|
|
3555
|
+
* ## Fulfilling From Cache
|
|
3556
|
+
*
|
|
3557
|
+
* When a cache-key is determined, the request may fulfill
|
|
3558
|
+
* from cache provided the cache is not stale.
|
|
3559
|
+
*
|
|
3560
|
+
* Cache staleness is determined by the configured LifetimesService
|
|
3561
|
+
* with priority given to the `cacheOptions.reload` and
|
|
3562
|
+
* `cacheOptions.backgroundReload` on the request if present.
|
|
3563
|
+
*
|
|
3564
|
+
* If the cache data has soft expired or the request asks for a background
|
|
3565
|
+
* reload, the request will fulfill from cache if possible and
|
|
3566
|
+
* make a non-blocking request in the background to update the cache.
|
|
3567
|
+
*
|
|
3568
|
+
* If the cache data has hard expired or the request asks for a reload,
|
|
3569
|
+
* the request will not fulfill from cache and will make a blocking
|
|
3570
|
+
* request to update the cache.
|
|
3571
|
+
*
|
|
3572
|
+
* ## The Response
|
|
3573
|
+
*
|
|
3574
|
+
* The primary difference between `requestManager.request` and `store.request`
|
|
3575
|
+
* is that `store.request` will attempt to hydrate the response content into
|
|
3576
|
+
* a response Document containing RecordInstances.
|
|
3577
|
+
*
|
|
3752
3578
|
* @method request
|
|
3753
3579
|
* @param {StoreRequestInput} requestConfig
|
|
3754
|
-
* @
|
|
3580
|
+
* @return {Future}
|
|
3755
3581
|
* @public
|
|
3756
3582
|
*/
|
|
3757
3583
|
request(requestConfig) {
|
|
3758
3584
|
// we lazily set the cache handler when we issue the first request
|
|
3759
3585
|
// because constructor doesn't allow for this to run after
|
|
3760
3586
|
// the user has had the chance to set the prop.
|
|
3761
|
-
|
|
3587
|
+
const opts = {
|
|
3762
3588
|
store: this,
|
|
3763
3589
|
[EnableHydration]: true
|
|
3764
3590
|
};
|
|
@@ -3810,7 +3636,7 @@ class Store extends EmberObject {
|
|
|
3810
3636
|
* @param createRecordArgs
|
|
3811
3637
|
* @param recordDataFor deprecated use this.cache
|
|
3812
3638
|
* @param notificationManager deprecated use this.notifications
|
|
3813
|
-
* @
|
|
3639
|
+
* @return A record instance
|
|
3814
3640
|
* @public
|
|
3815
3641
|
*/
|
|
3816
3642
|
|
|
@@ -4018,43 +3844,41 @@ class Store extends EmberObject {
|
|
|
4018
3844
|
//
|
|
4019
3845
|
// to remove this, we would need to move to a new `async` API.
|
|
4020
3846
|
let record;
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
};
|
|
3847
|
+
this._join(() => {
|
|
3848
|
+
const normalizedModelName = normalizeModelName(modelName);
|
|
3849
|
+
const properties = {
|
|
3850
|
+
...inputProperties
|
|
3851
|
+
};
|
|
4027
3852
|
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
3853
|
+
// If the passed properties do not include a primary key,
|
|
3854
|
+
// give the adapter an opportunity to generate one. Typically,
|
|
3855
|
+
// client-side ID generators will use something like uuid.js
|
|
3856
|
+
// to avoid conflicts.
|
|
4032
3857
|
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
}
|
|
3858
|
+
if (properties.id === null || properties.id === undefined) {
|
|
3859
|
+
const adapter = this.adapterFor?.(modelName, true);
|
|
3860
|
+
if (adapter && adapter.generateIdForRecord) {
|
|
3861
|
+
properties.id = adapter.generateIdForRecord(this, modelName, properties);
|
|
3862
|
+
} else {
|
|
3863
|
+
properties.id = null;
|
|
4040
3864
|
}
|
|
3865
|
+
}
|
|
4041
3866
|
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
});
|
|
3867
|
+
// Coerce ID to a string
|
|
3868
|
+
properties.id = coerceId(properties.id);
|
|
3869
|
+
const resource = {
|
|
3870
|
+
type: normalizedModelName,
|
|
3871
|
+
id: properties.id
|
|
3872
|
+
};
|
|
3873
|
+
if (resource.id) {
|
|
3874
|
+
const identifier = this.identifierCache.peekRecordIdentifier(resource);
|
|
3875
|
+
assert(`The id ${String(properties.id)} has already been used with another '${normalizedModelName}' record.`, !identifier);
|
|
3876
|
+
}
|
|
3877
|
+
const identifier = this.identifierCache.createIdentifierForNewRecord(resource);
|
|
3878
|
+
const cache = this.cache;
|
|
3879
|
+
const createOptions = normalizeProperties(this, identifier, properties);
|
|
3880
|
+
const resultProps = cache.clientDidCreate(identifier, createOptions);
|
|
3881
|
+
record = this._instanceCache.getRecord(identifier, resultProps);
|
|
4058
3882
|
});
|
|
4059
3883
|
return record;
|
|
4060
3884
|
}
|
|
@@ -4082,9 +3906,7 @@ class Store extends EmberObject {
|
|
|
4082
3906
|
this._join(() => {
|
|
4083
3907
|
cache.setIsDeleted(identifier, true);
|
|
4084
3908
|
if (cache.isNew(identifier)) {
|
|
4085
|
-
|
|
4086
|
-
this._instanceCache.unloadRecord(identifier);
|
|
4087
|
-
});
|
|
3909
|
+
this._instanceCache.unloadRecord(identifier);
|
|
4088
3910
|
}
|
|
4089
3911
|
});
|
|
4090
3912
|
}
|
|
@@ -4166,8 +3988,7 @@ class Store extends EmberObject {
|
|
|
4166
3988
|
In your adapter you can then access this id without triggering a network request via the
|
|
4167
3989
|
snapshot:
|
|
4168
3990
|
```app/adapters/application.js
|
|
4169
|
-
|
|
4170
|
-
export default class Adapter extends EmberObject {
|
|
3991
|
+
export default class Adapter {
|
|
4171
3992
|
findRecord(store, schema, id, snapshot) {
|
|
4172
3993
|
let type = schema.modelName;
|
|
4173
3994
|
if (type === 'comment')
|
|
@@ -4176,6 +3997,9 @@ class Store extends EmberObject {
|
|
|
4176
3997
|
.then(response => response.json())
|
|
4177
3998
|
}
|
|
4178
3999
|
}
|
|
4000
|
+
static create() {
|
|
4001
|
+
return new this();
|
|
4002
|
+
}
|
|
4179
4003
|
}
|
|
4180
4004
|
```
|
|
4181
4005
|
This could also be achieved by supplying the post id to the adapter via the adapterOptions
|
|
@@ -4189,9 +4013,8 @@ class Store extends EmberObject {
|
|
|
4189
4013
|
}
|
|
4190
4014
|
```
|
|
4191
4015
|
```app/adapters/application.js
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
findRecord(store, schema, id, snapshot) {
|
|
4016
|
+
export default class Adapter {
|
|
4017
|
+
findRecord(store, schema, id, snapshot) {
|
|
4195
4018
|
let type = schema.modelName;
|
|
4196
4019
|
if (type === 'comment')
|
|
4197
4020
|
let postId = snapshot.adapterOptions.post;
|
|
@@ -4199,6 +4022,9 @@ class Store extends EmberObject {
|
|
|
4199
4022
|
.then(response => response.json())
|
|
4200
4023
|
}
|
|
4201
4024
|
}
|
|
4025
|
+
static create() {
|
|
4026
|
+
return new this();
|
|
4027
|
+
}
|
|
4202
4028
|
}
|
|
4203
4029
|
```
|
|
4204
4030
|
If you have access to the post model you can also pass the model itself to preload:
|
|
@@ -4325,9 +4151,8 @@ class Store extends EmberObject {
|
|
|
4325
4151
|
}
|
|
4326
4152
|
```
|
|
4327
4153
|
```app/adapters/application.js
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
findRecord(store, schema, id, snapshot) {
|
|
4154
|
+
export default class Adapter {
|
|
4155
|
+
findRecord(store, schema, id, snapshot) {
|
|
4331
4156
|
let type = schema.modelName;
|
|
4332
4157
|
if (type === 'post')
|
|
4333
4158
|
let includes = snapshot.adapterOptions.include;
|
|
@@ -4335,6 +4160,9 @@ class Store extends EmberObject {
|
|
|
4335
4160
|
.then(response => response.json())
|
|
4336
4161
|
}
|
|
4337
4162
|
}
|
|
4163
|
+
static create() {
|
|
4164
|
+
return new this();
|
|
4165
|
+
}
|
|
4338
4166
|
}
|
|
4339
4167
|
```
|
|
4340
4168
|
In this case, the post's comments would then be available in your template as
|
|
@@ -4478,7 +4306,7 @@ class Store extends EmberObject {
|
|
|
4478
4306
|
resourceIdentifier = constructResource(type, normalizedId);
|
|
4479
4307
|
}
|
|
4480
4308
|
assert('getReference expected to receive either a resource identifier or type and id as arguments', isMaybeIdentifier(resourceIdentifier));
|
|
4481
|
-
|
|
4309
|
+
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resourceIdentifier);
|
|
4482
4310
|
return this._instanceCache.getReference(identifier);
|
|
4483
4311
|
}
|
|
4484
4312
|
|
|
@@ -4897,7 +4725,7 @@ class Store extends EmberObject {
|
|
|
4897
4725
|
}
|
|
4898
4726
|
assert(`You need to pass a model name to the store's peekAll method`, modelName);
|
|
4899
4727
|
assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string');
|
|
4900
|
-
|
|
4728
|
+
const type = normalizeModelName(modelName);
|
|
4901
4729
|
return this.recordArrayManager.liveArrayFor(type);
|
|
4902
4730
|
}
|
|
4903
4731
|
|
|
@@ -4927,7 +4755,7 @@ class Store extends EmberObject {
|
|
|
4927
4755
|
this.recordArrayManager.clear();
|
|
4928
4756
|
this._instanceCache.clear();
|
|
4929
4757
|
} else {
|
|
4930
|
-
|
|
4758
|
+
const normalizedModelName = normalizeModelName(modelName);
|
|
4931
4759
|
this._instanceCache.clear(normalizedModelName);
|
|
4932
4760
|
}
|
|
4933
4761
|
});
|
|
@@ -5068,10 +4896,9 @@ class Store extends EmberObject {
|
|
|
5068
4896
|
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5069
4897
|
assertDestroyingStore(this, 'push');
|
|
5070
4898
|
}
|
|
5071
|
-
|
|
4899
|
+
const pushed = this._push(data, false);
|
|
5072
4900
|
if (Array.isArray(pushed)) {
|
|
5073
|
-
|
|
5074
|
-
return records;
|
|
4901
|
+
return pushed.map(identifier => this._instanceCache.getRecord(identifier));
|
|
5075
4902
|
}
|
|
5076
4903
|
if (pushed === null) {
|
|
5077
4904
|
return null;
|
|
@@ -5093,396 +4920,688 @@ class Store extends EmberObject {
|
|
|
5093
4920
|
}
|
|
5094
4921
|
if (macroCondition(getOwnConfig().debug.LOG_PAYLOADS)) {
|
|
5095
4922
|
try {
|
|
5096
|
-
|
|
5097
|
-
// eslint-disable-next-line no-console
|
|
5098
|
-
console.log('EmberData | Payload - push', data);
|
|
5099
|
-
} catch (e) {
|
|
5100
|
-
// eslint-disable-next-line no-console
|
|
5101
|
-
console.log('EmberData | Payload - push', jsonApiDoc);
|
|
4923
|
+
const data = JSON.parse(JSON.stringify(jsonApiDoc));
|
|
4924
|
+
// eslint-disable-next-line no-console
|
|
4925
|
+
console.log('EmberData | Payload - push', data);
|
|
4926
|
+
} catch (e) {
|
|
4927
|
+
// eslint-disable-next-line no-console
|
|
4928
|
+
console.log('EmberData | Payload - push', jsonApiDoc);
|
|
4929
|
+
}
|
|
4930
|
+
}
|
|
4931
|
+
if (asyncFlush) {
|
|
4932
|
+
this._enableAsyncFlush = true;
|
|
4933
|
+
}
|
|
4934
|
+
let ret;
|
|
4935
|
+
this._join(() => {
|
|
4936
|
+
ret = this.cache.put({
|
|
4937
|
+
content: jsonApiDoc
|
|
4938
|
+
});
|
|
4939
|
+
});
|
|
4940
|
+
this._enableAsyncFlush = null;
|
|
4941
|
+
return 'data' in ret ? ret.data : null;
|
|
4942
|
+
}
|
|
4943
|
+
|
|
4944
|
+
/**
|
|
4945
|
+
* Trigger a save for a Record.
|
|
4946
|
+
*
|
|
4947
|
+
* @method saveRecord
|
|
4948
|
+
* @public
|
|
4949
|
+
* @param {RecordInstance} record
|
|
4950
|
+
* @param options
|
|
4951
|
+
* @return {Promise<RecordInstance>}
|
|
4952
|
+
*/
|
|
4953
|
+
saveRecord(record, options = {}) {
|
|
4954
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
4955
|
+
assertDestroyingStore(this, 'saveRecord');
|
|
4956
|
+
}
|
|
4957
|
+
assert(`Unable to initate save for a record in a disconnected state`, storeFor(record));
|
|
4958
|
+
const identifier = recordIdentifierFor(record);
|
|
4959
|
+
const cache = this.cache;
|
|
4960
|
+
if (!identifier) {
|
|
4961
|
+
// this commonly means we're disconnected
|
|
4962
|
+
// but just in case we reject here to prevent bad things.
|
|
4963
|
+
return Promise.reject(new Error(`Record Is Disconnected`));
|
|
4964
|
+
}
|
|
4965
|
+
// TODO we used to check if the record was destroyed here
|
|
4966
|
+
assert(`Cannot initiate a save request for an unloaded record: ${identifier.lid}`, this._instanceCache.recordIsLoaded(identifier));
|
|
4967
|
+
if (resourceIsFullyDeleted(this._instanceCache, identifier)) {
|
|
4968
|
+
return Promise.resolve(record);
|
|
4969
|
+
}
|
|
4970
|
+
if (!options) {
|
|
4971
|
+
options = {};
|
|
4972
|
+
}
|
|
4973
|
+
let operation = 'updateRecord';
|
|
4974
|
+
if (cache.isNew(identifier)) {
|
|
4975
|
+
operation = 'createRecord';
|
|
4976
|
+
} else if (cache.isDeleted(identifier)) {
|
|
4977
|
+
operation = 'deleteRecord';
|
|
4978
|
+
}
|
|
4979
|
+
const request = {
|
|
4980
|
+
op: operation,
|
|
4981
|
+
data: {
|
|
4982
|
+
options,
|
|
4983
|
+
record: identifier
|
|
4984
|
+
},
|
|
4985
|
+
records: [identifier],
|
|
4986
|
+
cacheOptions: {
|
|
4987
|
+
[SkipCache]: true
|
|
4988
|
+
}
|
|
4989
|
+
};
|
|
4990
|
+
|
|
4991
|
+
// we lie here on the type because legacy doesn't have enough context
|
|
4992
|
+
cache.willCommit(identifier, {
|
|
4993
|
+
request
|
|
4994
|
+
});
|
|
4995
|
+
return this.request(request).then(document => document.content);
|
|
4996
|
+
}
|
|
4997
|
+
|
|
4998
|
+
/**
|
|
4999
|
+
* Instantiation hook allowing applications or addons to configure the store
|
|
5000
|
+
* to utilize a custom Cache implementation.
|
|
5001
|
+
*
|
|
5002
|
+
* This hook should not be called directly by consuming applications or libraries.
|
|
5003
|
+
* Use `Store.cache` to access the Cache instance.
|
|
5004
|
+
*
|
|
5005
|
+
* @method createCache (hook)
|
|
5006
|
+
* @public
|
|
5007
|
+
* @param storeWrapper
|
|
5008
|
+
* @return {Cache}
|
|
5009
|
+
*/
|
|
5010
|
+
|
|
5011
|
+
/**
|
|
5012
|
+
* Returns the cache instance associated to this Store, instantiates the Cache
|
|
5013
|
+
* if necessary via `Store.createCache`
|
|
5014
|
+
*
|
|
5015
|
+
* @property {Cache} cache
|
|
5016
|
+
* @public
|
|
5017
|
+
*/
|
|
5018
|
+
get cache() {
|
|
5019
|
+
let {
|
|
5020
|
+
cache
|
|
5021
|
+
} = this._instanceCache;
|
|
5022
|
+
if (!cache) {
|
|
5023
|
+
cache = this._instanceCache.cache = this.createCache(this._instanceCache._storeWrapper);
|
|
5024
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5025
|
+
cache = new CacheManager(cache);
|
|
5026
|
+
}
|
|
5027
|
+
}
|
|
5028
|
+
return cache;
|
|
5029
|
+
}
|
|
5030
|
+
|
|
5031
|
+
// @ts-expect-error
|
|
5032
|
+
destroy() {
|
|
5033
|
+
if (this.isDestroyed) {
|
|
5034
|
+
// @ember/test-helpers will call destroy multiple times
|
|
5035
|
+
return;
|
|
5036
|
+
}
|
|
5037
|
+
this.isDestroying = true;
|
|
5038
|
+
this._graph?.destroy();
|
|
5039
|
+
this._graph = undefined;
|
|
5040
|
+
this.notifications.destroy();
|
|
5041
|
+
this.recordArrayManager.destroy();
|
|
5042
|
+
this.identifierCache.destroy();
|
|
5043
|
+
this.unloadAll();
|
|
5044
|
+
this.isDestroyed = true;
|
|
5045
|
+
}
|
|
5046
|
+
static create(args) {
|
|
5047
|
+
return new this(args);
|
|
5048
|
+
}
|
|
5049
|
+
}
|
|
5050
|
+
let assertDestroyingStore;
|
|
5051
|
+
let assertDestroyedStoreOnly;
|
|
5052
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5053
|
+
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
5054
|
+
assertDestroyingStore = function assertDestroyingStore(store, method) {
|
|
5055
|
+
assert(`Attempted to call store.${method}(), but the store instance has already been destroyed.`, !(store.isDestroying || store.isDestroyed));
|
|
5056
|
+
};
|
|
5057
|
+
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
5058
|
+
assertDestroyedStoreOnly = function assertDestroyedStoreOnly(store, method) {
|
|
5059
|
+
assert(`Attempted to call store.${method}(), but the store instance has already been destroyed.`, !store.isDestroyed);
|
|
5060
|
+
};
|
|
5061
|
+
}
|
|
5062
|
+
function isMaybeIdentifier(maybeIdentifier) {
|
|
5063
|
+
return Boolean(maybeIdentifier !== null && typeof maybeIdentifier === 'object' && ('id' in maybeIdentifier && 'type' in maybeIdentifier && maybeIdentifier.id && maybeIdentifier.type || maybeIdentifier.lid));
|
|
5064
|
+
}
|
|
5065
|
+
function normalizeProperties(store, identifier, properties) {
|
|
5066
|
+
// assert here
|
|
5067
|
+
if (properties !== undefined) {
|
|
5068
|
+
if ('id' in properties) {
|
|
5069
|
+
assert(`expected id to be a string or null`, properties.id !== undefined);
|
|
5070
|
+
}
|
|
5071
|
+
assert(`You passed '${typeof properties}' as properties for record creation instead of an object.`, typeof properties === 'object' && properties !== null);
|
|
5072
|
+
const {
|
|
5073
|
+
type
|
|
5074
|
+
} = identifier;
|
|
5075
|
+
|
|
5076
|
+
// convert relationship Records to RecordDatas before passing to RecordData
|
|
5077
|
+
const defs = store.getSchemaDefinitionService().relationshipsDefinitionFor({
|
|
5078
|
+
type
|
|
5079
|
+
});
|
|
5080
|
+
if (defs !== null) {
|
|
5081
|
+
const keys = Object.keys(properties);
|
|
5082
|
+
let relationshipValue;
|
|
5083
|
+
for (let i = 0; i < keys.length; i++) {
|
|
5084
|
+
const prop = keys[i];
|
|
5085
|
+
const def = defs[prop];
|
|
5086
|
+
if (def !== undefined) {
|
|
5087
|
+
if (def.kind === 'hasMany') {
|
|
5088
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5089
|
+
assertRecordsPassedToHasMany(properties[prop]);
|
|
5090
|
+
}
|
|
5091
|
+
relationshipValue = extractIdentifiersFromRecords(properties[prop]);
|
|
5092
|
+
} else {
|
|
5093
|
+
relationshipValue = extractIdentifierFromRecord(properties[prop]);
|
|
5094
|
+
}
|
|
5095
|
+
properties[prop] = relationshipValue;
|
|
5096
|
+
}
|
|
5097
|
+
}
|
|
5098
|
+
}
|
|
5099
|
+
}
|
|
5100
|
+
return properties;
|
|
5101
|
+
}
|
|
5102
|
+
function assertRecordsPassedToHasMany(records) {
|
|
5103
|
+
assert(`You must pass an array of records to set a hasMany relationship`, Array.isArray(records));
|
|
5104
|
+
assert(`All elements of a hasMany relationship must be instances of Model, you passed ${records.map(r => `${typeof r}`).join(', ')}`, function () {
|
|
5105
|
+
return records.every(record => {
|
|
5106
|
+
try {
|
|
5107
|
+
recordIdentifierFor(record);
|
|
5108
|
+
return true;
|
|
5109
|
+
} catch {
|
|
5110
|
+
return false;
|
|
5102
5111
|
}
|
|
5103
|
-
}
|
|
5104
|
-
if (asyncFlush) {
|
|
5105
|
-
this._enableAsyncFlush = true;
|
|
5106
|
-
}
|
|
5107
|
-
let ret;
|
|
5108
|
-
this._join(() => {
|
|
5109
|
-
ret = this.cache.put({
|
|
5110
|
-
content: jsonApiDoc
|
|
5111
|
-
});
|
|
5112
5112
|
});
|
|
5113
|
-
|
|
5114
|
-
|
|
5113
|
+
}());
|
|
5114
|
+
}
|
|
5115
|
+
function extractIdentifiersFromRecords(records) {
|
|
5116
|
+
return records.map(record => extractIdentifierFromRecord(record));
|
|
5117
|
+
}
|
|
5118
|
+
function extractIdentifierFromRecord(recordOrPromiseRecord) {
|
|
5119
|
+
if (!recordOrPromiseRecord) {
|
|
5120
|
+
return null;
|
|
5115
5121
|
}
|
|
5122
|
+
const extract = recordIdentifierFor;
|
|
5123
|
+
return extract(recordOrPromiseRecord);
|
|
5124
|
+
}
|
|
5125
|
+
function urlFromLink(link) {
|
|
5126
|
+
if (typeof link === 'string') return link;
|
|
5127
|
+
return link.href;
|
|
5128
|
+
}
|
|
5116
5129
|
|
|
5130
|
+
/**
|
|
5131
|
+
* A Document is a class that wraps the response content from a request to the API
|
|
5132
|
+
* returned by `Cache.put` or `Cache.peek`, converting resource-identifiers into
|
|
5133
|
+
* record instances.
|
|
5134
|
+
*
|
|
5135
|
+
* It is not directly instantiated by the user, and its properties should not
|
|
5136
|
+
* be directly modified. Whether individual properties are mutable or not is
|
|
5137
|
+
* determined by the record instance itself.
|
|
5138
|
+
*
|
|
5139
|
+
* @public
|
|
5140
|
+
* @class Document
|
|
5141
|
+
*/
|
|
5142
|
+
var _store = /*#__PURE__*/_classPrivateFieldKey("store");
|
|
5143
|
+
var _request = /*#__PURE__*/_classPrivateFieldKey("request");
|
|
5144
|
+
class Document {
|
|
5145
|
+
constructor(store, identifier) {
|
|
5146
|
+
Object.defineProperty(this, _request, {
|
|
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;
|
|
5203
|
+
this.identifier = identifier;
|
|
5204
|
+
}
|
|
5117
5205
|
/**
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
],
|
|
5133
|
-
comments: [
|
|
5134
|
-
{ id: 2, commentBody: "Insightful comment" }
|
|
5135
|
-
]
|
|
5136
|
-
}
|
|
5137
|
-
store.pushPayload(pushData);
|
|
5138
|
-
```
|
|
5139
|
-
By default, the data will be deserialized using a default
|
|
5140
|
-
serializer (the application serializer if it exists).
|
|
5141
|
-
Alternatively, `pushPayload` will accept a model type which
|
|
5142
|
-
will determine which serializer will process the payload.
|
|
5143
|
-
```app/serializers/application.js
|
|
5144
|
-
import RESTSerializer from '@ember-data/serializer/rest';
|
|
5145
|
-
export default class ApplicationSerializer extends RESTSerializer;
|
|
5146
|
-
```
|
|
5147
|
-
```app/serializers/post.js
|
|
5148
|
-
import JSONSerializer from '@ember-data/serializer/json';
|
|
5149
|
-
export default JSONSerializer;
|
|
5150
|
-
```
|
|
5151
|
-
```js
|
|
5152
|
-
store.pushPayload(pushData); // Will use the application serializer
|
|
5153
|
-
store.pushPayload('post', pushData); // Will use the post serializer
|
|
5154
|
-
```
|
|
5155
|
-
@method pushPayload
|
|
5156
|
-
@public
|
|
5157
|
-
@param {String} modelName Optionally, a model type used to determine which serializer will be used
|
|
5158
|
-
@param {Object} inputPayload
|
|
5159
|
-
*/
|
|
5160
|
-
// TODO @runspired @deprecate pushPayload in favor of looking up the serializer
|
|
5161
|
-
pushPayload(modelName, inputPayload) {
|
|
5162
|
-
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5163
|
-
assertDestroyingStore(this, 'pushPayload');
|
|
5164
|
-
}
|
|
5165
|
-
const payload = inputPayload || modelName;
|
|
5166
|
-
const normalizedModelName = inputPayload ? normalizeModelName(modelName) : 'application';
|
|
5167
|
-
const serializer = this.serializerFor(normalizedModelName);
|
|
5168
|
-
assert(`You cannot use 'store.pushPayload(<type>, <payload>)' unless the serializer for '${normalizedModelName}' defines 'pushPayload'`, serializer && typeof serializer.pushPayload === 'function');
|
|
5169
|
-
serializer.pushPayload(this, payload);
|
|
5206
|
+
* Fetches the related link for this document, returning a promise that resolves
|
|
5207
|
+
* with the document when the request completes. If no related link is present,
|
|
5208
|
+
* will fallback to the self link if present
|
|
5209
|
+
*
|
|
5210
|
+
* @method fetch
|
|
5211
|
+
* @public
|
|
5212
|
+
* @param {object} options
|
|
5213
|
+
* @return Promise<Document>
|
|
5214
|
+
*/
|
|
5215
|
+
fetch(options = {}) {
|
|
5216
|
+
assert(`No self or related link`, this.links?.related || this.links?.self);
|
|
5217
|
+
options.cacheOptions = options.cacheOptions || {};
|
|
5218
|
+
options.cacheOptions.key = this.identifier?.lid;
|
|
5219
|
+
return _classPrivateFieldBase(this, _request)[_request](this.links.related ? 'related' : 'self', options);
|
|
5170
5220
|
}
|
|
5171
5221
|
|
|
5172
5222
|
/**
|
|
5173
|
-
*
|
|
5223
|
+
* Fetches the next link for this document, returning a promise that resolves
|
|
5224
|
+
* with the new document when the request completes, or null if there is no
|
|
5225
|
+
* next link.
|
|
5174
5226
|
*
|
|
5175
|
-
* @method
|
|
5227
|
+
* @method next
|
|
5176
5228
|
* @public
|
|
5177
|
-
* @param {
|
|
5178
|
-
* @
|
|
5179
|
-
* @returns {Promise<RecordInstance>}
|
|
5229
|
+
* @param {object} options
|
|
5230
|
+
* @return Promise<Document | null>
|
|
5180
5231
|
*/
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
}
|
|
5185
|
-
assert(`Unable to initate save for a record in a disconnected state`, storeFor(record));
|
|
5186
|
-
let identifier = recordIdentifierFor(record);
|
|
5187
|
-
const cache = this.cache;
|
|
5188
|
-
if (!identifier) {
|
|
5189
|
-
// this commonly means we're disconnected
|
|
5190
|
-
// but just in case we reject here to prevent bad things.
|
|
5191
|
-
return Promise.reject(`Record Is Disconnected`);
|
|
5192
|
-
}
|
|
5193
|
-
// TODO we used to check if the record was destroyed here
|
|
5194
|
-
assert(`Cannot initiate a save request for an unloaded record: ${identifier.lid}`, this._instanceCache.recordIsLoaded(identifier));
|
|
5195
|
-
if (resourceIsFullyDeleted(this._instanceCache, identifier)) {
|
|
5196
|
-
return Promise.resolve(record);
|
|
5197
|
-
}
|
|
5198
|
-
if (!options) {
|
|
5199
|
-
options = {};
|
|
5200
|
-
}
|
|
5201
|
-
let operation = 'updateRecord';
|
|
5202
|
-
if (cache.isNew(identifier)) {
|
|
5203
|
-
operation = 'createRecord';
|
|
5204
|
-
} else if (cache.isDeleted(identifier)) {
|
|
5205
|
-
operation = 'deleteRecord';
|
|
5206
|
-
}
|
|
5207
|
-
const request = {
|
|
5208
|
-
op: operation,
|
|
5209
|
-
data: {
|
|
5210
|
-
options,
|
|
5211
|
-
record: identifier
|
|
5212
|
-
},
|
|
5213
|
-
cacheOptions: {
|
|
5214
|
-
[SkipCache]: true
|
|
5215
|
-
}
|
|
5216
|
-
};
|
|
5232
|
+
next(options = {}) {
|
|
5233
|
+
return _classPrivateFieldBase(this, _request)[_request]('next', options);
|
|
5234
|
+
}
|
|
5217
5235
|
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5236
|
+
/**
|
|
5237
|
+
* Fetches the prev link for this document, returning a promise that resolves
|
|
5238
|
+
* with the new document when the request completes, or null if there is no
|
|
5239
|
+
* prev link.
|
|
5240
|
+
*
|
|
5241
|
+
* @method prev
|
|
5242
|
+
* @public
|
|
5243
|
+
* @param {object} options
|
|
5244
|
+
* @return Promise<Document | null>
|
|
5245
|
+
*/
|
|
5246
|
+
prev(options = {}) {
|
|
5247
|
+
return _classPrivateFieldBase(this, _request)[_request]('prev', options);
|
|
5223
5248
|
}
|
|
5224
5249
|
|
|
5225
5250
|
/**
|
|
5226
|
-
*
|
|
5227
|
-
*
|
|
5251
|
+
* Fetches the first link for this document, returning a promise that resolves
|
|
5252
|
+
* with the new document when the request completes, or null if there is no
|
|
5253
|
+
* first link.
|
|
5228
5254
|
*
|
|
5229
|
-
*
|
|
5230
|
-
*
|
|
5255
|
+
* @method first
|
|
5256
|
+
* @public
|
|
5257
|
+
* @param {object} options
|
|
5258
|
+
* @return Promise<Document | null>
|
|
5259
|
+
*/
|
|
5260
|
+
first(options = {}) {
|
|
5261
|
+
return _classPrivateFieldBase(this, _request)[_request]('first', options);
|
|
5262
|
+
}
|
|
5263
|
+
|
|
5264
|
+
/**
|
|
5265
|
+
* Fetches the last link for this document, returning a promise that resolves
|
|
5266
|
+
* with the new document when the request completes, or null if there is no
|
|
5267
|
+
* last link.
|
|
5231
5268
|
*
|
|
5232
|
-
* @method
|
|
5269
|
+
* @method last
|
|
5233
5270
|
* @public
|
|
5234
|
-
* @param
|
|
5235
|
-
* @
|
|
5271
|
+
* @param {object} options
|
|
5272
|
+
* @return Promise<Document | null>
|
|
5236
5273
|
*/
|
|
5274
|
+
last(options = {}) {
|
|
5275
|
+
return _classPrivateFieldBase(this, _request)[_request]('last', options);
|
|
5276
|
+
}
|
|
5237
5277
|
|
|
5238
5278
|
/**
|
|
5239
|
-
*
|
|
5240
|
-
* if necessary via `Store.createCache`
|
|
5279
|
+
* Implemented for `JSON.stringify` support.
|
|
5241
5280
|
*
|
|
5242
|
-
*
|
|
5281
|
+
* Returns the JSON representation of the document wrapper.
|
|
5282
|
+
*
|
|
5283
|
+
* This is a shallow serialization, it does not deeply serialize
|
|
5284
|
+
* the document's contents, leaving that to the individual record
|
|
5285
|
+
* instances to determine how to do, if at all.
|
|
5286
|
+
*
|
|
5287
|
+
* @method toJSON
|
|
5243
5288
|
* @public
|
|
5289
|
+
* @return
|
|
5244
5290
|
*/
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
cache = this._instanceCache.cache = this.createCache(this._instanceCache._storeWrapper);
|
|
5251
|
-
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5252
|
-
cache = new CacheManager(cache);
|
|
5253
|
-
}
|
|
5291
|
+
toJSON() {
|
|
5292
|
+
const data = {};
|
|
5293
|
+
data.identifier = this.identifier;
|
|
5294
|
+
if (this.data !== undefined) {
|
|
5295
|
+
data.data = this.data;
|
|
5254
5296
|
}
|
|
5255
|
-
|
|
5297
|
+
if (this.links !== undefined) {
|
|
5298
|
+
data.links = this.links;
|
|
5299
|
+
}
|
|
5300
|
+
if (this.errors !== undefined) {
|
|
5301
|
+
data.errors = this.errors;
|
|
5302
|
+
}
|
|
5303
|
+
if (this.meta !== undefined) {
|
|
5304
|
+
data.meta = this.meta;
|
|
5305
|
+
}
|
|
5306
|
+
return data;
|
|
5307
|
+
}
|
|
5308
|
+
}
|
|
5309
|
+
async function _request2(link, options) {
|
|
5310
|
+
const href = this.links?.[link];
|
|
5311
|
+
if (!href) {
|
|
5312
|
+
return null;
|
|
5256
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
|
+
defineSignal(Document.prototype, 'data');
|
|
5321
|
+
defineSignal(Document.prototype, 'links');
|
|
5322
|
+
defineSignal(Document.prototype, 'errors');
|
|
5323
|
+
defineSignal(Document.prototype, 'meta');
|
|
5257
5324
|
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5325
|
+
/**
|
|
5326
|
+
* @module @ember-data/store
|
|
5327
|
+
*/
|
|
5328
|
+
|
|
5329
|
+
/**
|
|
5330
|
+
* A service which an application may provide to the store via
|
|
5331
|
+
* the store's `lifetimes` property to configure the behavior
|
|
5332
|
+
* of the CacheHandler.
|
|
5333
|
+
*
|
|
5334
|
+
* The default behavior for request lifetimes is to never expire
|
|
5335
|
+
* unless manually refreshed via `cacheOptions.reload` or `cacheOptions.backgroundReload`.
|
|
5336
|
+
*
|
|
5337
|
+
* Implementing this service allows you to programatically define
|
|
5338
|
+
* when a request should be considered expired.
|
|
5339
|
+
*
|
|
5340
|
+
* @class <Interface> LifetimesService
|
|
5341
|
+
* @public
|
|
5342
|
+
*/
|
|
5343
|
+
|
|
5344
|
+
const MUTATION_OPS = new Set(['createRecord', 'updateRecord', 'deleteRecord']);
|
|
5345
|
+
function isErrorDocument(document) {
|
|
5346
|
+
return 'errors' in document;
|
|
5347
|
+
}
|
|
5348
|
+
function maybeUpdateUiObjects(store, request, options, document, isFromCache) {
|
|
5349
|
+
const {
|
|
5350
|
+
identifier
|
|
5351
|
+
} = options;
|
|
5352
|
+
if (isErrorDocument(document)) {
|
|
5353
|
+
if (!identifier && !options.shouldHydrate) {
|
|
5354
|
+
return document;
|
|
5355
|
+
}
|
|
5356
|
+
let doc;
|
|
5357
|
+
if (identifier) {
|
|
5358
|
+
doc = store._documentCache.get(identifier);
|
|
5359
|
+
}
|
|
5360
|
+
if (!doc) {
|
|
5361
|
+
doc = new Document(store, identifier);
|
|
5362
|
+
copyDocumentProperties(doc, document);
|
|
5363
|
+
if (identifier) {
|
|
5364
|
+
store._documentCache.set(identifier, doc);
|
|
5365
|
+
}
|
|
5366
|
+
} else if (!isFromCache) {
|
|
5367
|
+
doc.data = undefined;
|
|
5368
|
+
copyDocumentProperties(doc, document);
|
|
5369
|
+
}
|
|
5370
|
+
return options.shouldHydrate ? doc : document;
|
|
5371
|
+
}
|
|
5372
|
+
if (Array.isArray(document.data)) {
|
|
5373
|
+
const {
|
|
5374
|
+
recordArrayManager
|
|
5375
|
+
} = store;
|
|
5376
|
+
if (!identifier) {
|
|
5377
|
+
if (!options.shouldHydrate) {
|
|
5378
|
+
return document;
|
|
5379
|
+
}
|
|
5380
|
+
const data = recordArrayManager.createArray({
|
|
5381
|
+
type: request.url,
|
|
5382
|
+
identifiers: document.data,
|
|
5383
|
+
doc: document,
|
|
5384
|
+
query: request
|
|
5385
|
+
});
|
|
5386
|
+
const doc = new Document(store, null);
|
|
5387
|
+
doc.data = data;
|
|
5388
|
+
doc.meta = document.meta;
|
|
5389
|
+
doc.links = document.links;
|
|
5390
|
+
return doc;
|
|
5279
5391
|
}
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
assertDestroyingStore(this, 'adapterFor');
|
|
5392
|
+
let managed = recordArrayManager._keyedArrays.get(identifier.lid);
|
|
5393
|
+
if (!managed) {
|
|
5394
|
+
managed = recordArrayManager.createArray({
|
|
5395
|
+
type: identifier.lid,
|
|
5396
|
+
identifiers: document.data,
|
|
5397
|
+
doc: document
|
|
5398
|
+
});
|
|
5399
|
+
recordArrayManager._keyedArrays.set(identifier.lid, managed);
|
|
5400
|
+
const doc = new Document(store, identifier);
|
|
5401
|
+
doc.data = managed;
|
|
5402
|
+
doc.meta = document.meta;
|
|
5403
|
+
doc.links = document.links;
|
|
5404
|
+
store._documentCache.set(identifier, doc);
|
|
5405
|
+
return options.shouldHydrate ? doc : document;
|
|
5406
|
+
} else {
|
|
5407
|
+
const doc = store._documentCache.get(identifier);
|
|
5408
|
+
if (!isFromCache) {
|
|
5409
|
+
recordArrayManager.populateManagedArray(managed, document.data, document);
|
|
5410
|
+
doc.data = managed;
|
|
5411
|
+
doc.meta = document.meta;
|
|
5412
|
+
doc.links = document.links;
|
|
5413
|
+
}
|
|
5414
|
+
return options.shouldHydrate ? doc : document;
|
|
5304
5415
|
}
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
let {
|
|
5309
|
-
_adapterCache
|
|
5310
|
-
} = this;
|
|
5311
|
-
let adapter = _adapterCache[normalizedModelName];
|
|
5312
|
-
if (adapter) {
|
|
5313
|
-
return adapter;
|
|
5416
|
+
} else {
|
|
5417
|
+
if (!identifier && !options.shouldHydrate) {
|
|
5418
|
+
return document;
|
|
5314
5419
|
}
|
|
5315
|
-
const
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
if (adapter !== undefined) {
|
|
5320
|
-
_adapterCache[normalizedModelName] = adapter;
|
|
5321
|
-
return adapter;
|
|
5420
|
+
const data = document.data ? store.peekRecord(document.data) : null;
|
|
5421
|
+
let doc;
|
|
5422
|
+
if (identifier) {
|
|
5423
|
+
doc = store._documentCache.get(identifier);
|
|
5322
5424
|
}
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5425
|
+
if (!doc) {
|
|
5426
|
+
doc = new Document(store, identifier);
|
|
5427
|
+
doc.data = data;
|
|
5428
|
+
copyDocumentProperties(doc, document);
|
|
5429
|
+
if (identifier) {
|
|
5430
|
+
store._documentCache.set(identifier, doc);
|
|
5431
|
+
}
|
|
5432
|
+
} else if (!isFromCache) {
|
|
5433
|
+
doc.data = data;
|
|
5434
|
+
copyDocumentProperties(doc, document);
|
|
5330
5435
|
}
|
|
5331
|
-
|
|
5436
|
+
return options.shouldHydrate ? doc : document;
|
|
5332
5437
|
}
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5438
|
+
}
|
|
5439
|
+
function calcShouldFetch(store, request, hasCachedValue, identifier) {
|
|
5440
|
+
const {
|
|
5441
|
+
cacheOptions
|
|
5442
|
+
} = request;
|
|
5443
|
+
return request.op && MUTATION_OPS.has(request.op) || cacheOptions?.reload || !hasCachedValue || (store.lifetimes && identifier ? store.lifetimes.isHardExpired(identifier, store) : false);
|
|
5444
|
+
}
|
|
5445
|
+
function calcShouldBackgroundFetch(store, request, willFetch, identifier) {
|
|
5446
|
+
const {
|
|
5447
|
+
cacheOptions
|
|
5448
|
+
} = request;
|
|
5449
|
+
return !willFetch && (cacheOptions?.backgroundReload || (store.lifetimes && identifier ? store.lifetimes.isSoftExpired(identifier, store) : false));
|
|
5450
|
+
}
|
|
5451
|
+
function isMutation(request) {
|
|
5452
|
+
return Boolean(request.op && MUTATION_OPS.has(request.op));
|
|
5453
|
+
}
|
|
5454
|
+
function fetchContentAndHydrate(next, context, identifier, shouldFetch, shouldBackgroundFetch) {
|
|
5455
|
+
const {
|
|
5456
|
+
store
|
|
5457
|
+
} = context.request;
|
|
5458
|
+
const shouldHydrate = context.request[EnableHydration] || false;
|
|
5459
|
+
let isMut = false;
|
|
5460
|
+
if (isMutation(context.request)) {
|
|
5461
|
+
isMut = true;
|
|
5462
|
+
// TODO should we handle multiple records in request.records by iteratively calling willCommit for each
|
|
5463
|
+
const record = context.request.data?.record || context.request.records?.[0];
|
|
5464
|
+
assert(`Expected to receive a list of records included in the ${context.request.op} request`, record);
|
|
5465
|
+
store.cache.willCommit(record, context);
|
|
5466
|
+
}
|
|
5467
|
+
if (store.lifetimes?.willRequest) {
|
|
5468
|
+
store.lifetimes.willRequest(context.request, identifier, store);
|
|
5469
|
+
}
|
|
5470
|
+
const promise = next(context.request).then(document => {
|
|
5471
|
+
store.requestManager._pending.delete(context.id);
|
|
5472
|
+
store._enableAsyncFlush = true;
|
|
5473
|
+
let response;
|
|
5474
|
+
store._join(() => {
|
|
5475
|
+
if (isMutation(context.request)) {
|
|
5476
|
+
const record = context.request.data?.record || context.request.records?.[0];
|
|
5477
|
+
response = store.cache.didCommit(record, document);
|
|
5478
|
+
} else {
|
|
5479
|
+
response = store.cache.put(document);
|
|
5480
|
+
}
|
|
5481
|
+
response = maybeUpdateUiObjects(store, context.request, {
|
|
5482
|
+
shouldHydrate,
|
|
5483
|
+
shouldFetch,
|
|
5484
|
+
shouldBackgroundFetch,
|
|
5485
|
+
identifier
|
|
5486
|
+
}, response, false);
|
|
5487
|
+
});
|
|
5488
|
+
store._enableAsyncFlush = null;
|
|
5489
|
+
if (store.lifetimes?.didRequest) {
|
|
5490
|
+
store.lifetimes.didRequest(context.request, document.response, identifier, store);
|
|
5369
5491
|
}
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
_serializerCache[normalizedModelName] = serializer;
|
|
5375
|
-
_serializerCache.application = serializer;
|
|
5376
|
-
return serializer;
|
|
5492
|
+
if (shouldFetch) {
|
|
5493
|
+
return response;
|
|
5494
|
+
} else if (shouldBackgroundFetch) {
|
|
5495
|
+
store.notifications._flush();
|
|
5377
5496
|
}
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
destroy() {
|
|
5383
|
-
if (this.isDestroyed) {
|
|
5384
|
-
// @ember/test-helpers will call destroy multiple times
|
|
5385
|
-
return;
|
|
5497
|
+
}, error => {
|
|
5498
|
+
store.requestManager._pending.delete(context.id);
|
|
5499
|
+
if (context.request.signal?.aborted) {
|
|
5500
|
+
throw error;
|
|
5386
5501
|
}
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
if (
|
|
5392
|
-
|
|
5502
|
+
store.requestManager._pending.delete(context.id);
|
|
5503
|
+
store._enableAsyncFlush = true;
|
|
5504
|
+
let response;
|
|
5505
|
+
store._join(() => {
|
|
5506
|
+
if (isMutation(context.request)) {
|
|
5507
|
+
// TODO similar to didCommit we should spec this to be similar to cache.put for handling full response
|
|
5508
|
+
// currently we let the response remain undefiend.
|
|
5509
|
+
const errors = error && error.content && typeof error.content === 'object' && 'errors' in error.content && Array.isArray(error.content.errors) ? error.content.errors : undefined;
|
|
5510
|
+
const record = context.request.data?.record || context.request.records?.[0];
|
|
5511
|
+
store.cache.commitWasRejected(record, errors);
|
|
5512
|
+
// re-throw the original error to preserve `errors` property.
|
|
5513
|
+
throw error;
|
|
5514
|
+
} else {
|
|
5515
|
+
response = store.cache.put(error);
|
|
5516
|
+
response = maybeUpdateUiObjects(store, context.request, {
|
|
5517
|
+
shouldHydrate,
|
|
5518
|
+
shouldFetch,
|
|
5519
|
+
shouldBackgroundFetch,
|
|
5520
|
+
identifier
|
|
5521
|
+
}, response, false);
|
|
5393
5522
|
}
|
|
5523
|
+
});
|
|
5524
|
+
store._enableAsyncFlush = null;
|
|
5525
|
+
if (identifier && store.lifetimes?.didRequest) {
|
|
5526
|
+
store.lifetimes.didRequest(context.request, error.response, identifier, store);
|
|
5394
5527
|
}
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5528
|
+
if (!shouldBackgroundFetch) {
|
|
5529
|
+
const newError = cloneError(error);
|
|
5530
|
+
newError.content = response;
|
|
5531
|
+
throw newError;
|
|
5532
|
+
} else {
|
|
5533
|
+
store.notifications._flush();
|
|
5400
5534
|
}
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
this.recordArrayManager.destroy();
|
|
5405
|
-
this.identifierCache.destroy();
|
|
5406
|
-
this.unloadAll();
|
|
5407
|
-
this.isDestroyed = true;
|
|
5408
|
-
}
|
|
5409
|
-
static create(args) {
|
|
5410
|
-
return new this(args);
|
|
5535
|
+
});
|
|
5536
|
+
if (!isMut) {
|
|
5537
|
+
return promise;
|
|
5411
5538
|
}
|
|
5539
|
+
assert(`Expected a mutation`, isMutation(context.request));
|
|
5540
|
+
|
|
5541
|
+
// for mutations we need to enqueue the promise with the requestStateService
|
|
5542
|
+
// TODO should we enque a request per record in records?
|
|
5543
|
+
const record = context.request.data?.record || context.request.records?.[0];
|
|
5544
|
+
return store._requestCache._enqueue(promise, {
|
|
5545
|
+
data: [{
|
|
5546
|
+
op: 'saveRecord',
|
|
5547
|
+
recordIdentifier: record,
|
|
5548
|
+
options: undefined
|
|
5549
|
+
}]
|
|
5550
|
+
});
|
|
5412
5551
|
}
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
assert(`Attempted to call store.${method}(), but the store instance has already been destroyed.`, !(store.isDestroying || store.isDestroyed));
|
|
5419
|
-
};
|
|
5420
|
-
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
5421
|
-
assertDestroyedStoreOnly = function assertDestroyedStoreOnly(store, method) {
|
|
5422
|
-
assert(`Attempted to call store.${method}(), but the store instance has already been destroyed.`, !store.isDestroyed);
|
|
5423
|
-
};
|
|
5424
|
-
}
|
|
5425
|
-
function isMaybeIdentifier(maybeIdentifier) {
|
|
5426
|
-
return Boolean(maybeIdentifier !== null && typeof maybeIdentifier === 'object' && ('id' in maybeIdentifier && 'type' in maybeIdentifier && maybeIdentifier.id && maybeIdentifier.type || maybeIdentifier.lid));
|
|
5552
|
+
function cloneError(error) {
|
|
5553
|
+
const cloned = new Error(error.message);
|
|
5554
|
+
cloned.stack = error.stack;
|
|
5555
|
+
cloned.error = error.error;
|
|
5556
|
+
return cloned;
|
|
5427
5557
|
}
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
if (
|
|
5432
|
-
|
|
5558
|
+
const CacheHandler = {
|
|
5559
|
+
request(context, next) {
|
|
5560
|
+
// if we have no cache or no cache-key skip cache handling
|
|
5561
|
+
if (!context.request.store || context.request.cacheOptions?.[SkipCache]) {
|
|
5562
|
+
return next(context.request);
|
|
5433
5563
|
}
|
|
5434
|
-
assert(`You passed '${typeof properties}' as properties for record creation instead of an object.`, typeof properties === 'object' && properties !== null);
|
|
5435
5564
|
const {
|
|
5436
|
-
|
|
5437
|
-
} =
|
|
5565
|
+
store
|
|
5566
|
+
} = context.request;
|
|
5567
|
+
const identifier = store.identifierCache.getOrCreateDocumentIdentifier(context.request);
|
|
5568
|
+
const peeked = identifier ? store.cache.peekRequest(identifier) : null;
|
|
5438
5569
|
|
|
5439
|
-
//
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
}
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
properties[prop] = relationshipValue;
|
|
5459
|
-
}
|
|
5460
|
-
}
|
|
5570
|
+
// determine if we should skip cache
|
|
5571
|
+
if (calcShouldFetch(store, context.request, !!peeked, identifier)) {
|
|
5572
|
+
return fetchContentAndHydrate(next, context, identifier, true, false);
|
|
5573
|
+
}
|
|
5574
|
+
|
|
5575
|
+
// if we have not skipped cache, determine if we should update behind the scenes
|
|
5576
|
+
if (calcShouldBackgroundFetch(store, context.request, false, identifier)) {
|
|
5577
|
+
const promise = fetchContentAndHydrate(next, context, identifier, false, true);
|
|
5578
|
+
store.requestManager._pending.set(context.id, promise);
|
|
5579
|
+
}
|
|
5580
|
+
const shouldHydrate = context.request[EnableHydration] || false;
|
|
5581
|
+
if ('error' in peeked) {
|
|
5582
|
+
const content = shouldHydrate ? maybeUpdateUiObjects(store, context.request, {
|
|
5583
|
+
shouldHydrate,
|
|
5584
|
+
identifier
|
|
5585
|
+
}, peeked.content, true) : peeked.content;
|
|
5586
|
+
const newError = cloneError(peeked);
|
|
5587
|
+
newError.content = content;
|
|
5588
|
+
throw newError;
|
|
5461
5589
|
}
|
|
5590
|
+
return Promise.resolve(shouldHydrate ? maybeUpdateUiObjects(store, context.request, {
|
|
5591
|
+
shouldHydrate,
|
|
5592
|
+
identifier
|
|
5593
|
+
}, peeked.content, true) : peeked.content);
|
|
5462
5594
|
}
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
return false;
|
|
5474
|
-
}
|
|
5475
|
-
});
|
|
5476
|
-
}());
|
|
5477
|
-
}
|
|
5478
|
-
function extractIdentifiersFromRecords(records) {
|
|
5479
|
-
return records.map(record => extractIdentifierFromRecord(record));
|
|
5480
|
-
}
|
|
5481
|
-
function extractIdentifierFromRecord(recordOrPromiseRecord) {
|
|
5482
|
-
if (!recordOrPromiseRecord) {
|
|
5483
|
-
return null;
|
|
5595
|
+
};
|
|
5596
|
+
function copyDocumentProperties(target, source) {
|
|
5597
|
+
if ('links' in source) {
|
|
5598
|
+
target.links = source.links;
|
|
5599
|
+
}
|
|
5600
|
+
if ('meta' in source) {
|
|
5601
|
+
target.meta = source.meta;
|
|
5602
|
+
}
|
|
5603
|
+
if ('errors' in source) {
|
|
5604
|
+
target.errors = source.errors;
|
|
5484
5605
|
}
|
|
5485
|
-
const extract = recordIdentifierFor;
|
|
5486
|
-
return extract(recordOrPromiseRecord);
|
|
5487
5606
|
}
|
|
5488
|
-
export { 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, coerceId as e, Collection as f, SOURCE as g,
|
|
5607
|
+
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, coerceId as e, Collection as f, SOURCE as g, fastPush as h, isStableIdentifier as i, removeRecordDataFor as j, setRecordIdentifier as k, StoreMap as l, setCacheFor as m, notifyArray as n, normalizeModelName as o, peekCache as p, recordIdentifierFor as r, storeFor as s };
|