@ember-data/store 4.10.0-alpha.2 → 4.10.0-alpha.21
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/addon/-private.js +1 -0
- package/addon/-private.js.map +1 -0
- package/addon/index-12e1fcb9.js +7660 -0
- package/addon/index-12e1fcb9.js.map +1 -0
- package/addon/index.js +1 -0
- package/addon/index.js.map +1 -0
- package/addon-main.js +90 -0
- package/package.json +44 -15
- package/addon/-private/caches/identifier-cache.ts +0 -686
- package/addon/-private/caches/instance-cache.ts +0 -695
- package/addon/-private/caches/record-data-for.ts +0 -34
- package/addon/-private/index.ts +0 -59
- package/addon/-private/legacy-model-support/record-reference.ts +0 -240
- package/addon/-private/legacy-model-support/schema-definition-service.ts +0 -148
- package/addon/-private/legacy-model-support/shim-model-class.ts +0 -97
- package/addon/-private/managers/record-array-manager.ts +0 -379
- package/addon/-private/managers/record-data-manager.ts +0 -845
- package/addon/-private/managers/record-data-store-wrapper.ts +0 -425
- package/addon/-private/managers/record-notification-manager.ts +0 -111
- package/addon/-private/network/fetch-manager.ts +0 -567
- package/addon/-private/network/finders.js +0 -104
- package/addon/-private/network/request-cache.ts +0 -132
- package/addon/-private/network/snapshot-record-array.ts +0 -209
- package/addon/-private/network/snapshot.ts +0 -563
- package/addon/-private/proxies/promise-proxies.ts +0 -228
- package/addon/-private/proxies/promise-proxy-base.js +0 -7
- package/addon/-private/record-arrays/identifier-array.ts +0 -929
- package/addon/-private/store-service.ts +0 -2896
- package/addon/-private/utils/coerce-id.ts +0 -41
- package/addon/-private/utils/common.js +0 -65
- package/addon/-private/utils/construct-resource.ts +0 -61
- package/addon/-private/utils/identifer-debug-consts.ts +0 -3
- package/addon/-private/utils/is-non-empty-string.ts +0 -3
- package/addon/-private/utils/normalize-model-name.ts +0 -21
- package/addon/-private/utils/promise-record.ts +0 -15
- package/addon/-private/utils/serializer-response.ts +0 -86
- package/addon/-private/utils/uuid-polyfill.ts +0 -73
- package/addon/index.ts +0 -14
- package/index.js +0 -49
|
@@ -1,379 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
@module @ember-data/store
|
|
3
|
-
*/
|
|
4
|
-
import { addToTransaction } from '@ember-data/tracking/-private';
|
|
5
|
-
import type { CollectionResourceDocument } from '@ember-data/types/q/ember-data-json-api';
|
|
6
|
-
import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
|
|
7
|
-
import type { Dict } from '@ember-data/types/q/utils';
|
|
8
|
-
|
|
9
|
-
import IdentifierArray, {
|
|
10
|
-
Collection,
|
|
11
|
-
CollectionCreateOptions,
|
|
12
|
-
IDENTIFIER_ARRAY_TAG,
|
|
13
|
-
SOURCE,
|
|
14
|
-
} from '../record-arrays/identifier-array';
|
|
15
|
-
import type Store from '../store-service';
|
|
16
|
-
|
|
17
|
-
const RecordArraysCache = new Map<StableRecordIdentifier, Set<Collection>>();
|
|
18
|
-
const FAKE_ARR = {};
|
|
19
|
-
|
|
20
|
-
const SLICE_BATCH_SIZE = 1200;
|
|
21
|
-
/**
|
|
22
|
-
* This is a clever optimization.
|
|
23
|
-
*
|
|
24
|
-
* clever optimizations rarely stand the test of time, so if you're
|
|
25
|
-
* ever curious or think something better is possible please benchmark
|
|
26
|
-
* and discuss. The benchmark for this at the time of writing is in
|
|
27
|
-
* `scripts/benchmark-push.js`
|
|
28
|
-
*
|
|
29
|
-
* This approach turns out to be 150x faster in Chrome and node than
|
|
30
|
-
* simply using push or concat. It's highly susceptible to the specifics
|
|
31
|
-
* of the batch size, and may require tuning.
|
|
32
|
-
*
|
|
33
|
-
* Clever optimizations should always come with a `why`. This optimization
|
|
34
|
-
* exists for two reasons.
|
|
35
|
-
*
|
|
36
|
-
* 1) array.push(...objects) and Array.prototype.push.apply(arr, objects)
|
|
37
|
-
* are susceptible to stack overflows. The size of objects at which this
|
|
38
|
-
* occurs varies by environment, browser, and current stack depth and memory
|
|
39
|
-
* pressure; however, it occurs in all browsers in fairly pristine conditions
|
|
40
|
-
* somewhere around 125k to 200k elements. Since EmberData regularly encounters
|
|
41
|
-
* arrays larger than this in size, we cannot use push.
|
|
42
|
-
*
|
|
43
|
-
* 2) `array.concat` or simply setting the array to a new reference is often an
|
|
44
|
-
* easier approach; however, native Proxy to an array cannot swap it's target array
|
|
45
|
-
* and attempts at juggling multiple array sources have proven to be victim to a number
|
|
46
|
-
* of browser implementation bugs. Should these bugs be addressed then we could
|
|
47
|
-
* simplify to using `concat`, however, do note this is currently 150x faster
|
|
48
|
-
* than concat, and due to the overloaded signature of concat will likely always
|
|
49
|
-
* be faster.
|
|
50
|
-
*
|
|
51
|
-
* Sincerely,
|
|
52
|
-
* - runspired (Chris Thoburn) 08/21/2022
|
|
53
|
-
*
|
|
54
|
-
* @function fastPush
|
|
55
|
-
* @internal
|
|
56
|
-
* @param target the array to push into
|
|
57
|
-
* @param source the items to push into target
|
|
58
|
-
*/
|
|
59
|
-
export function fastPush<T>(target: T[], source: T[]) {
|
|
60
|
-
let startLength = 0;
|
|
61
|
-
let newLength = source.length;
|
|
62
|
-
while (newLength - startLength > SLICE_BATCH_SIZE) {
|
|
63
|
-
// eslint-disable-next-line prefer-spread
|
|
64
|
-
target.push.apply(target, source.slice(startLength, startLength + SLICE_BATCH_SIZE));
|
|
65
|
-
startLength += SLICE_BATCH_SIZE;
|
|
66
|
-
}
|
|
67
|
-
// eslint-disable-next-line prefer-spread
|
|
68
|
-
target.push.apply(target, source.slice(startLength));
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
type ChangeSet = Map<StableRecordIdentifier, 'add' | 'del'>;
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
@class RecordArrayManager
|
|
75
|
-
@internal
|
|
76
|
-
*/
|
|
77
|
-
class RecordArrayManager {
|
|
78
|
-
declare store: Store;
|
|
79
|
-
declare isDestroying: boolean;
|
|
80
|
-
declare isDestroyed: boolean;
|
|
81
|
-
declare _live: Map<string, IdentifierArray>;
|
|
82
|
-
declare _managed: Set<IdentifierArray>;
|
|
83
|
-
declare _pending: Map<IdentifierArray, ChangeSet>;
|
|
84
|
-
declare _identifiers: Map<StableRecordIdentifier, Set<Collection>>;
|
|
85
|
-
declare _staged: Map<string, ChangeSet>;
|
|
86
|
-
|
|
87
|
-
constructor(options: { store: Store }) {
|
|
88
|
-
this.store = options.store;
|
|
89
|
-
this.isDestroying = false;
|
|
90
|
-
this.isDestroyed = false;
|
|
91
|
-
this._live = new Map();
|
|
92
|
-
this._managed = new Set();
|
|
93
|
-
this._pending = new Map();
|
|
94
|
-
this._staged = new Map();
|
|
95
|
-
this._identifiers = RecordArraysCache;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
_syncArray(array: IdentifierArray) {
|
|
99
|
-
const pending = this._pending.get(array);
|
|
100
|
-
|
|
101
|
-
if (!pending || this.isDestroying || this.isDestroyed) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
sync(array, pending);
|
|
106
|
-
this._pending.delete(array);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
Get the `RecordArray` for a modelName, which contains all loaded records of
|
|
111
|
-
given modelName.
|
|
112
|
-
|
|
113
|
-
@method liveArrayFor
|
|
114
|
-
@internal
|
|
115
|
-
@param {String} modelName
|
|
116
|
-
@return {RecordArray}
|
|
117
|
-
*/
|
|
118
|
-
liveArrayFor(type: string): IdentifierArray {
|
|
119
|
-
let array = this._live.get(type);
|
|
120
|
-
let identifiers: StableRecordIdentifier[] = [];
|
|
121
|
-
let staged = this._staged.get(type);
|
|
122
|
-
if (staged) {
|
|
123
|
-
staged.forEach((value, key) => {
|
|
124
|
-
if (value === 'add') {
|
|
125
|
-
identifiers.push(key);
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
this._staged.delete(type);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (!array) {
|
|
132
|
-
array = new IdentifierArray({
|
|
133
|
-
type,
|
|
134
|
-
identifiers,
|
|
135
|
-
store: this.store,
|
|
136
|
-
allowMutation: false,
|
|
137
|
-
manager: this,
|
|
138
|
-
});
|
|
139
|
-
this._live.set(type, array);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return array;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
createArray(config: {
|
|
146
|
-
type: string;
|
|
147
|
-
query?: Dict<unknown>;
|
|
148
|
-
identifiers?: StableRecordIdentifier[];
|
|
149
|
-
doc?: CollectionResourceDocument;
|
|
150
|
-
}): Collection {
|
|
151
|
-
let options: CollectionCreateOptions = {
|
|
152
|
-
type: config.type,
|
|
153
|
-
links: config.doc?.links || null,
|
|
154
|
-
meta: config.doc?.meta || null,
|
|
155
|
-
query: config.query || null,
|
|
156
|
-
identifiers: config.identifiers || [],
|
|
157
|
-
isLoaded: !!config.identifiers?.length,
|
|
158
|
-
allowMutation: false,
|
|
159
|
-
store: this.store,
|
|
160
|
-
manager: this,
|
|
161
|
-
};
|
|
162
|
-
let array = new Collection(options);
|
|
163
|
-
this._managed.add(array);
|
|
164
|
-
if (config.identifiers) {
|
|
165
|
-
associate(array, config.identifiers);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return array;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
dirtyArray(array: IdentifierArray, delta: number): void {
|
|
172
|
-
if (array === FAKE_ARR) {
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
let tag = array[IDENTIFIER_ARRAY_TAG];
|
|
176
|
-
if (!tag.shouldReset) {
|
|
177
|
-
tag.shouldReset = true;
|
|
178
|
-
addToTransaction(tag);
|
|
179
|
-
} else if (delta > 0 && tag.t) {
|
|
180
|
-
addToTransaction(tag);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
_getPendingFor(
|
|
185
|
-
identifier: StableRecordIdentifier,
|
|
186
|
-
includeManaged: boolean,
|
|
187
|
-
isRemove?: boolean
|
|
188
|
-
): Map<IdentifierArray, ChangeSet> | void {
|
|
189
|
-
if (this.isDestroying || this.isDestroyed) {
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
let liveArray = this._live.get(identifier.type);
|
|
194
|
-
const allPending = this._pending;
|
|
195
|
-
let pending: Map<IdentifierArray, ChangeSet> = new Map();
|
|
196
|
-
|
|
197
|
-
if (includeManaged) {
|
|
198
|
-
let managed = RecordArraysCache.get(identifier);
|
|
199
|
-
if (managed) {
|
|
200
|
-
managed.forEach((arr) => {
|
|
201
|
-
let changes = allPending.get(arr);
|
|
202
|
-
if (!changes) {
|
|
203
|
-
changes = new Map();
|
|
204
|
-
allPending.set(arr, changes);
|
|
205
|
-
}
|
|
206
|
-
pending.set(arr, changes);
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// during unloadAll we can ignore removes since we've already
|
|
212
|
-
// cleared the array.
|
|
213
|
-
if (liveArray && liveArray[SOURCE].length === 0 && isRemove) {
|
|
214
|
-
const pendingLive = allPending.get(liveArray);
|
|
215
|
-
if (!pendingLive || pendingLive.size === 0) {
|
|
216
|
-
return pending;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (!liveArray) {
|
|
221
|
-
// start building a changeset for when we eventually
|
|
222
|
-
// do have a live array
|
|
223
|
-
let changes = this._staged.get(identifier.type);
|
|
224
|
-
if (!changes) {
|
|
225
|
-
changes = new Map();
|
|
226
|
-
this._staged.set(identifier.type, changes);
|
|
227
|
-
}
|
|
228
|
-
pending.set(FAKE_ARR as IdentifierArray, changes);
|
|
229
|
-
} else {
|
|
230
|
-
let changes = allPending.get(liveArray);
|
|
231
|
-
if (!changes) {
|
|
232
|
-
changes = new Map();
|
|
233
|
-
allPending.set(liveArray, changes);
|
|
234
|
-
}
|
|
235
|
-
pending.set(liveArray, changes);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return pending;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
populateManagedArray(array: Collection, identifiers: StableRecordIdentifier[], payload: CollectionResourceDocument) {
|
|
242
|
-
this._pending.delete(array);
|
|
243
|
-
const source = array[SOURCE];
|
|
244
|
-
const old = source.slice();
|
|
245
|
-
source.length = 0;
|
|
246
|
-
fastPush(source, identifiers);
|
|
247
|
-
array[IDENTIFIER_ARRAY_TAG].ref = null;
|
|
248
|
-
array.meta = payload.meta || null;
|
|
249
|
-
array.links = payload.links || null;
|
|
250
|
-
array.isLoaded = true;
|
|
251
|
-
|
|
252
|
-
disassociate(array, old);
|
|
253
|
-
associate(array, identifiers);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
identifierAdded(identifier: StableRecordIdentifier): void {
|
|
257
|
-
let changeSets = this._getPendingFor(identifier, false);
|
|
258
|
-
if (changeSets) {
|
|
259
|
-
changeSets.forEach((changes, array) => {
|
|
260
|
-
let existing = changes.get(identifier);
|
|
261
|
-
if (existing === 'del') {
|
|
262
|
-
changes.delete(identifier);
|
|
263
|
-
} else {
|
|
264
|
-
changes.set(identifier, 'add');
|
|
265
|
-
|
|
266
|
-
this.dirtyArray(array, changes.size);
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
identifierRemoved(identifier: StableRecordIdentifier): void {
|
|
273
|
-
let changeSets = this._getPendingFor(identifier, true, true);
|
|
274
|
-
if (changeSets) {
|
|
275
|
-
changeSets.forEach((changes, array) => {
|
|
276
|
-
let existing = changes.get(identifier);
|
|
277
|
-
if (existing === 'add') {
|
|
278
|
-
changes.delete(identifier);
|
|
279
|
-
} else {
|
|
280
|
-
changes.set(identifier, 'del');
|
|
281
|
-
|
|
282
|
-
this.dirtyArray(array, changes.size);
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
identifierChanged(identifier: StableRecordIdentifier): void {
|
|
289
|
-
let newState = this.store._instanceCache.recordIsLoaded(identifier, true);
|
|
290
|
-
|
|
291
|
-
if (newState) {
|
|
292
|
-
this.identifierAdded(identifier);
|
|
293
|
-
} else {
|
|
294
|
-
this.identifierRemoved(identifier);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
clear() {
|
|
299
|
-
this._live.forEach((array) => array.destroy());
|
|
300
|
-
this._managed.forEach((array) => array.destroy());
|
|
301
|
-
this._managed.clear();
|
|
302
|
-
RecordArraysCache.clear();
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
destroy() {
|
|
306
|
-
this.isDestroying = true;
|
|
307
|
-
this.clear();
|
|
308
|
-
this._live.clear();
|
|
309
|
-
this.isDestroyed = true;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function associate(array: Collection, identifiers: StableRecordIdentifier[]) {
|
|
314
|
-
for (let i = 0; i < identifiers.length; i++) {
|
|
315
|
-
let identifier = identifiers[i];
|
|
316
|
-
let cache = RecordArraysCache.get(identifier);
|
|
317
|
-
if (!cache) {
|
|
318
|
-
cache = new Set();
|
|
319
|
-
RecordArraysCache.set(identifier, cache);
|
|
320
|
-
}
|
|
321
|
-
cache.add(array);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
function disassociate(array: Collection, identifiers: StableRecordIdentifier[]) {
|
|
326
|
-
for (let i = 0; i < identifiers.length; i++) {
|
|
327
|
-
disassociateIdentifier(array, identifiers[i]);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
export function disassociateIdentifier(array: Collection, identifier: StableRecordIdentifier) {
|
|
332
|
-
let cache = RecordArraysCache.get(identifier);
|
|
333
|
-
if (cache) {
|
|
334
|
-
cache.delete(array);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
function sync(array: IdentifierArray, changes: Map<StableRecordIdentifier, 'add' | 'del'>) {
|
|
339
|
-
let state = array[SOURCE];
|
|
340
|
-
const adds: StableRecordIdentifier[] = [];
|
|
341
|
-
const removes: StableRecordIdentifier[] = [];
|
|
342
|
-
changes.forEach((value, key) => {
|
|
343
|
-
if (value === 'add') {
|
|
344
|
-
// likely we want to keep a Set along-side
|
|
345
|
-
if (state.includes(key)) {
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
adds.push(key);
|
|
349
|
-
} else {
|
|
350
|
-
removes.push(key);
|
|
351
|
-
}
|
|
352
|
-
});
|
|
353
|
-
if (removes.length) {
|
|
354
|
-
if (removes.length === state.length) {
|
|
355
|
-
state.length = 0;
|
|
356
|
-
// changing the reference breaks the Proxy
|
|
357
|
-
// state = array[SOURCE] = [];
|
|
358
|
-
} else {
|
|
359
|
-
removes.forEach((i) => {
|
|
360
|
-
state.splice(state.indexOf(i), 1);
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
if (adds.length) {
|
|
366
|
-
fastPush(state, adds);
|
|
367
|
-
// changing the reference breaks the Proxy
|
|
368
|
-
// else we could do this
|
|
369
|
-
/*
|
|
370
|
-
if (state.length === 0) {
|
|
371
|
-
array[SOURCE] = adds;
|
|
372
|
-
} else {
|
|
373
|
-
array[SOURCE] = state.concat(adds);
|
|
374
|
-
}
|
|
375
|
-
*/
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
export default RecordArrayManager;
|