@ember-data/store 4.6.1 → 4.7.0
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/-debug/index.js +35 -13
- package/addon/-private/{identifier-cache.ts → caches/identifier-cache.ts} +148 -73
- package/addon/-private/caches/instance-cache.ts +690 -0
- package/addon/-private/{record-data-for.ts → caches/record-data-for.ts} +2 -7
- package/addon/-private/index.ts +44 -24
- package/addon/-private/{model → legacy-model-support}/record-reference.ts +15 -13
- package/addon/-private/{schema-definition-service.ts → legacy-model-support/schema-definition-service.ts} +13 -9
- package/addon/-private/{model → legacy-model-support}/shim-model-class.ts +18 -11
- package/addon/-private/managers/record-array-manager.ts +377 -0
- package/addon/-private/managers/record-data-manager.ts +845 -0
- package/addon/-private/managers/record-data-store-wrapper.ts +421 -0
- package/addon/-private/managers/record-notification-manager.ts +109 -0
- package/addon/-private/network/fetch-manager.ts +567 -0
- package/addon/-private/{finders.js → network/finders.js} +14 -17
- package/addon/-private/{request-cache.ts → network/request-cache.ts} +21 -18
- package/addon/-private/{snapshot-record-array.ts → network/snapshot-record-array.ts} +14 -31
- package/addon/-private/{snapshot.ts → network/snapshot.ts} +40 -49
- package/addon/-private/{promise-proxies.ts → proxies/promise-proxies.ts} +76 -15
- package/addon/-private/{promise-proxy-base.js → proxies/promise-proxy-base.js} +0 -0
- package/addon/-private/record-arrays/identifier-array.ts +924 -0
- package/addon/-private/{core-store.ts → store-service.ts} +574 -215
- package/addon/-private/{coerce-id.ts → utils/coerce-id.ts} +1 -1
- package/addon/-private/{common.js → utils/common.js} +1 -2
- package/addon/-private/utils/construct-resource.ts +2 -2
- package/addon/-private/{identifer-debug-consts.ts → utils/identifer-debug-consts.ts} +0 -0
- package/addon/-private/utils/is-non-empty-string.ts +1 -1
- package/addon/-private/{normalize-model-name.ts → utils/normalize-model-name.ts} +1 -3
- package/addon/-private/utils/promise-record.ts +5 -6
- package/addon/-private/{serializer-response.ts → utils/serializer-response.ts} +2 -2
- package/addon/-private/utils/uuid-polyfill.ts +73 -0
- package/package.json +12 -8
- package/addon/-private/backburner.js +0 -25
- package/addon/-private/errors-utils.js +0 -146
- package/addon/-private/fetch-manager.ts +0 -597
- package/addon/-private/identity-map.ts +0 -54
- package/addon/-private/instance-cache.ts +0 -387
- package/addon/-private/internal-model-factory.ts +0 -359
- package/addon/-private/internal-model-map.ts +0 -121
- package/addon/-private/model/internal-model.ts +0 -602
- package/addon/-private/record-array-manager.ts +0 -444
- package/addon/-private/record-arrays/adapter-populated-record-array.ts +0 -130
- package/addon/-private/record-arrays/record-array.ts +0 -318
- package/addon/-private/record-data-store-wrapper.ts +0 -243
- package/addon/-private/record-notification-manager.ts +0 -73
- package/addon/-private/weak-cache.ts +0 -125
|
@@ -1,444 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
@module @ember-data/store
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { A } from '@ember/array';
|
|
6
|
-
import { assert } from '@ember/debug';
|
|
7
|
-
import { set } from '@ember/object';
|
|
8
|
-
import { _backburner as emberBackburner } from '@ember/runloop';
|
|
9
|
-
import { DEBUG } from '@glimmer/env';
|
|
10
|
-
|
|
11
|
-
// import isStableIdentifier from '../identifiers/is-stable-identifier';
|
|
12
|
-
import type { CollectionResourceDocument, Meta } from '@ember-data/types/q/ember-data-json-api';
|
|
13
|
-
import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
|
|
14
|
-
import type { Dict } from '@ember-data/types/q/utils';
|
|
15
|
-
|
|
16
|
-
import type Store from './core-store';
|
|
17
|
-
import { internalModelFactoryFor } from './internal-model-factory';
|
|
18
|
-
import AdapterPopulatedRecordArray from './record-arrays/adapter-populated-record-array';
|
|
19
|
-
import RecordArray from './record-arrays/record-array';
|
|
20
|
-
import WeakCache from './weak-cache';
|
|
21
|
-
|
|
22
|
-
const RecordArraysCache = new WeakCache<StableRecordIdentifier, Set<RecordArray>>(DEBUG ? 'record-arrays' : '');
|
|
23
|
-
RecordArraysCache._generator = () => new Set();
|
|
24
|
-
export function recordArraysForIdentifier(identifier: StableRecordIdentifier): Set<RecordArray> {
|
|
25
|
-
return RecordArraysCache.lookup(identifier);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const pendingForIdentifier: Set<StableRecordIdentifier> = new Set([]);
|
|
29
|
-
|
|
30
|
-
function getIdentifier(identifier: StableRecordIdentifier): StableRecordIdentifier {
|
|
31
|
-
// during dematerialization we will get an identifier that
|
|
32
|
-
// has already been removed from the identifiers cache
|
|
33
|
-
// so it will not behave as if stable. This is a bug we should fix.
|
|
34
|
-
// if (!isStableIdentifier(identifierOrInternalModel)) {
|
|
35
|
-
// console.log({ unstable: i });
|
|
36
|
-
// }
|
|
37
|
-
|
|
38
|
-
return identifier;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function shouldIncludeInRecordArrays(store: Store, identifier: StableRecordIdentifier): boolean {
|
|
42
|
-
const cache = internalModelFactoryFor(store);
|
|
43
|
-
const internalModel = cache.peek(identifier);
|
|
44
|
-
|
|
45
|
-
if (internalModel === null) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
return !internalModel.isHiddenFromRecordArrays();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
@class RecordArrayManager
|
|
53
|
-
@internal
|
|
54
|
-
*/
|
|
55
|
-
class RecordArrayManager {
|
|
56
|
-
declare store: Store;
|
|
57
|
-
declare isDestroying: boolean;
|
|
58
|
-
declare isDestroyed: boolean;
|
|
59
|
-
declare _liveRecordArrays: Dict<RecordArray>;
|
|
60
|
-
declare _pendingIdentifiers: Dict<StableRecordIdentifier[]>;
|
|
61
|
-
declare _adapterPopulatedRecordArrays: RecordArray[];
|
|
62
|
-
|
|
63
|
-
constructor(options: { store: Store }) {
|
|
64
|
-
this.store = options.store;
|
|
65
|
-
this.isDestroying = false;
|
|
66
|
-
this.isDestroyed = false;
|
|
67
|
-
this._liveRecordArrays = Object.create(null) as Dict<RecordArray>;
|
|
68
|
-
this._pendingIdentifiers = Object.create(null) as Dict<StableRecordIdentifier[]>;
|
|
69
|
-
this._adapterPopulatedRecordArrays = [];
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* @method getRecordArraysForIdentifier
|
|
74
|
-
* @internal
|
|
75
|
-
* @param {StableIdentifier} param
|
|
76
|
-
* @return {RecordArray} array
|
|
77
|
-
*/
|
|
78
|
-
getRecordArraysForIdentifier(identifier: StableRecordIdentifier): Set<RecordArray> {
|
|
79
|
-
return recordArraysForIdentifier(identifier);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
_flushPendingIdentifiersForModelName(modelName: string, identifiers: StableRecordIdentifier[]): void {
|
|
83
|
-
if (this.isDestroying || this.isDestroyed) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
let identifiersToRemove: StableRecordIdentifier[] = [];
|
|
87
|
-
|
|
88
|
-
for (let j = 0; j < identifiers.length; j++) {
|
|
89
|
-
let i = identifiers[j];
|
|
90
|
-
// mark identifiers, so they can once again be processed by the
|
|
91
|
-
// recordArrayManager
|
|
92
|
-
pendingForIdentifier.delete(i);
|
|
93
|
-
// build up a set of models to ensure we have purged correctly;
|
|
94
|
-
let isIncluded = shouldIncludeInRecordArrays(this.store, i);
|
|
95
|
-
if (!isIncluded) {
|
|
96
|
-
identifiersToRemove.push(i);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
let array = this._liveRecordArrays[modelName];
|
|
101
|
-
if (array) {
|
|
102
|
-
// TODO: skip if it only changed
|
|
103
|
-
// process liveRecordArrays
|
|
104
|
-
updateLiveRecordArray(this.store, array, identifiers);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// process adapterPopulatedRecordArrays
|
|
108
|
-
if (identifiersToRemove.length > 0) {
|
|
109
|
-
removeFromAdapterPopulatedRecordArrays(this.store, identifiersToRemove);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
_flush() {
|
|
114
|
-
let pending = this._pendingIdentifiers;
|
|
115
|
-
this._pendingIdentifiers = Object.create(null) as Dict<StableRecordIdentifier[]>;
|
|
116
|
-
|
|
117
|
-
for (let modelName in pending) {
|
|
118
|
-
this._flushPendingIdentifiersForModelName(modelName, pending[modelName]!);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
_syncLiveRecordArray(array: RecordArray, modelName: string) {
|
|
123
|
-
assert(
|
|
124
|
-
`recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`,
|
|
125
|
-
typeof modelName === 'string'
|
|
126
|
-
);
|
|
127
|
-
let pending = this._pendingIdentifiers[modelName];
|
|
128
|
-
|
|
129
|
-
if (!Array.isArray(pending)) {
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
let hasNoPotentialDeletions = pending.length === 0;
|
|
133
|
-
let map = internalModelFactoryFor(this.store).modelMapFor(modelName);
|
|
134
|
-
let hasNoInsertionsOrRemovals = map.length === array.length;
|
|
135
|
-
|
|
136
|
-
/*
|
|
137
|
-
Ideally the recordArrayManager has knowledge of the changes to be applied to
|
|
138
|
-
liveRecordArrays, and is capable of strategically flushing those changes and applying
|
|
139
|
-
small diffs if desired. However, until we've refactored recordArrayManager, this dirty
|
|
140
|
-
check prevents us from unnecessarily wiping out live record arrays returned by peekAll.
|
|
141
|
-
*/
|
|
142
|
-
if (hasNoPotentialDeletions && hasNoInsertionsOrRemovals) {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
this._flushPendingIdentifiersForModelName(modelName, pending);
|
|
147
|
-
delete this._pendingIdentifiers[modelName];
|
|
148
|
-
|
|
149
|
-
let identifiers = this._visibleIdentifiersByType(modelName);
|
|
150
|
-
let identifiersToAdd: StableRecordIdentifier[] = [];
|
|
151
|
-
for (let i = 0; i < identifiers.length; i++) {
|
|
152
|
-
let identifier = identifiers[i];
|
|
153
|
-
let recordArrays = recordArraysForIdentifier(identifier);
|
|
154
|
-
if (recordArrays.has(array) === false) {
|
|
155
|
-
recordArrays.add(array);
|
|
156
|
-
identifiersToAdd.push(identifier);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (identifiersToAdd.length) {
|
|
161
|
-
array._pushIdentifiers(identifiersToAdd);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
_didUpdateAll(modelName: string): void {
|
|
166
|
-
let recordArray = this._liveRecordArrays[modelName];
|
|
167
|
-
if (recordArray) {
|
|
168
|
-
set(recordArray, 'isUpdating', false);
|
|
169
|
-
// TODO potentially we should sync here, currently
|
|
170
|
-
// this occurs as a side-effect of individual records updating
|
|
171
|
-
// this._syncLiveRecordArray(recordArray, modelName);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
Get the `RecordArray` for a modelName, which contains all loaded records of
|
|
177
|
-
given modelName.
|
|
178
|
-
|
|
179
|
-
@method liveRecordArrayFor
|
|
180
|
-
@internal
|
|
181
|
-
@param {String} modelName
|
|
182
|
-
@return {RecordArray}
|
|
183
|
-
*/
|
|
184
|
-
liveRecordArrayFor(modelName: string): RecordArray {
|
|
185
|
-
assert(
|
|
186
|
-
`recordArrayManger.liveRecordArrayFor expects modelName not modelClass as the param`,
|
|
187
|
-
typeof modelName === 'string'
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
let array = this._liveRecordArrays[modelName];
|
|
191
|
-
|
|
192
|
-
if (array) {
|
|
193
|
-
// if the array already exists, synchronize
|
|
194
|
-
this._syncLiveRecordArray(array, modelName);
|
|
195
|
-
} else {
|
|
196
|
-
// if the array is being newly created merely create it with its initial
|
|
197
|
-
// content already set. This prevents unneeded change events.
|
|
198
|
-
let identifiers = this._visibleIdentifiersByType(modelName);
|
|
199
|
-
array = this.createRecordArray(modelName, identifiers);
|
|
200
|
-
this._liveRecordArrays[modelName] = array;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return array;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
_visibleIdentifiersByType(modelName: string) {
|
|
207
|
-
let all = internalModelFactoryFor(this.store).modelMapFor(modelName).recordIdentifiers;
|
|
208
|
-
let visible: StableRecordIdentifier[] = [];
|
|
209
|
-
for (let i = 0; i < all.length; i++) {
|
|
210
|
-
let identifier = all[i];
|
|
211
|
-
let shouldInclude = shouldIncludeInRecordArrays(this.store, identifier);
|
|
212
|
-
|
|
213
|
-
if (shouldInclude) {
|
|
214
|
-
visible.push(identifier);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
return visible;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
Create a `RecordArray` for a modelName.
|
|
222
|
-
|
|
223
|
-
@method createRecordArray
|
|
224
|
-
@internal
|
|
225
|
-
@param {String} modelName
|
|
226
|
-
@param {Array} [identifiers]
|
|
227
|
-
@return {RecordArray}
|
|
228
|
-
*/
|
|
229
|
-
createRecordArray(modelName: string, identifiers: StableRecordIdentifier[] = []): RecordArray {
|
|
230
|
-
assert(
|
|
231
|
-
`recordArrayManger.createRecordArray expects modelName not modelClass as the param`,
|
|
232
|
-
typeof modelName === 'string'
|
|
233
|
-
);
|
|
234
|
-
|
|
235
|
-
let array = RecordArray.create({
|
|
236
|
-
modelName,
|
|
237
|
-
content: A(identifiers || []),
|
|
238
|
-
store: this.store,
|
|
239
|
-
isLoaded: true,
|
|
240
|
-
manager: this,
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
if (Array.isArray(identifiers)) {
|
|
244
|
-
this._associateWithRecordArray(identifiers, array);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return array;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
Create a `AdapterPopulatedRecordArray` for a modelName with given query.
|
|
252
|
-
|
|
253
|
-
@method createAdapterPopulatedRecordArray
|
|
254
|
-
@internal
|
|
255
|
-
@param {String} modelName
|
|
256
|
-
@param {Object} query
|
|
257
|
-
@return {AdapterPopulatedRecordArray}
|
|
258
|
-
*/
|
|
259
|
-
createAdapterPopulatedRecordArray(
|
|
260
|
-
modelName: string,
|
|
261
|
-
query: Dict<unknown> | undefined,
|
|
262
|
-
identifiers: StableRecordIdentifier[],
|
|
263
|
-
payload?: CollectionResourceDocument
|
|
264
|
-
): AdapterPopulatedRecordArray {
|
|
265
|
-
assert(
|
|
266
|
-
`recordArrayManger.createAdapterPopulatedRecordArray expects modelName not modelClass as the first param, received ${modelName}`,
|
|
267
|
-
typeof modelName === 'string'
|
|
268
|
-
);
|
|
269
|
-
|
|
270
|
-
let array: AdapterPopulatedRecordArray;
|
|
271
|
-
if (Array.isArray(identifiers)) {
|
|
272
|
-
array = AdapterPopulatedRecordArray.create({
|
|
273
|
-
modelName,
|
|
274
|
-
query: query,
|
|
275
|
-
content: A(identifiers),
|
|
276
|
-
store: this.store,
|
|
277
|
-
manager: this,
|
|
278
|
-
isLoaded: true,
|
|
279
|
-
isUpdating: false,
|
|
280
|
-
// TODO this assign kills the root reference but a deep-copy would be required
|
|
281
|
-
// for both meta and links to actually not be by-ref. We whould likely change
|
|
282
|
-
// this to a dev-only deep-freeze.
|
|
283
|
-
meta: Object.assign({} as Meta, payload?.meta),
|
|
284
|
-
links: Object.assign({}, payload?.links),
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
this._associateWithRecordArray(identifiers, array);
|
|
288
|
-
} else {
|
|
289
|
-
array = AdapterPopulatedRecordArray.create({
|
|
290
|
-
modelName,
|
|
291
|
-
query: query,
|
|
292
|
-
content: A<StableRecordIdentifier>(),
|
|
293
|
-
isLoaded: false,
|
|
294
|
-
store: this.store,
|
|
295
|
-
manager: this,
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
this._adapterPopulatedRecordArrays.push(array);
|
|
300
|
-
|
|
301
|
-
return array;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
Unregister a RecordArray.
|
|
306
|
-
So manager will not update this array.
|
|
307
|
-
|
|
308
|
-
@method unregisterRecordArray
|
|
309
|
-
@internal
|
|
310
|
-
@param {RecordArray} array
|
|
311
|
-
*/
|
|
312
|
-
unregisterRecordArray(array: RecordArray): void {
|
|
313
|
-
let modelName = array.modelName;
|
|
314
|
-
|
|
315
|
-
// remove from adapter populated record array
|
|
316
|
-
let removedFromAdapterPopulated = removeFromArray(this._adapterPopulatedRecordArrays, array);
|
|
317
|
-
|
|
318
|
-
if (!removedFromAdapterPopulated) {
|
|
319
|
-
let liveRecordArrayForType = this._liveRecordArrays[modelName];
|
|
320
|
-
// unregister live record array
|
|
321
|
-
if (liveRecordArrayForType) {
|
|
322
|
-
if (array === liveRecordArrayForType) {
|
|
323
|
-
delete this._liveRecordArrays[modelName];
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* @method _associateWithRecordArray
|
|
331
|
-
* @internal
|
|
332
|
-
* @param {StableIdentifier} identifiers
|
|
333
|
-
* @param {RecordArray} array
|
|
334
|
-
*/
|
|
335
|
-
_associateWithRecordArray(identifiers: StableRecordIdentifier[], array: RecordArray): void {
|
|
336
|
-
for (let i = 0, l = identifiers.length; i < l; i++) {
|
|
337
|
-
let identifier = identifiers[i];
|
|
338
|
-
identifier = getIdentifier(identifier);
|
|
339
|
-
let recordArrays = this.getRecordArraysForIdentifier(identifier);
|
|
340
|
-
recordArrays.add(array);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
@method recordDidChange
|
|
346
|
-
@internal
|
|
347
|
-
*/
|
|
348
|
-
recordDidChange(identifier: StableRecordIdentifier): void {
|
|
349
|
-
if (this.isDestroying || this.isDestroyed) {
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
let modelName = identifier.type;
|
|
353
|
-
identifier = getIdentifier(identifier);
|
|
354
|
-
|
|
355
|
-
if (pendingForIdentifier.has(identifier)) {
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
pendingForIdentifier.add(identifier);
|
|
360
|
-
|
|
361
|
-
let pending = this._pendingIdentifiers;
|
|
362
|
-
let models = (pending[modelName] = pending[modelName] || []);
|
|
363
|
-
if (models.push(identifier) !== 1) {
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// TODO do we still need this schedule?
|
|
368
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
369
|
-
emberBackburner.schedule('actions', this, this._flush);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
willDestroy() {
|
|
373
|
-
Object.keys(this._liveRecordArrays).forEach((modelName) => this._liveRecordArrays[modelName]!.destroy());
|
|
374
|
-
this._adapterPopulatedRecordArrays.forEach((entry) => entry.destroy());
|
|
375
|
-
this.isDestroyed = true;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
destroy() {
|
|
379
|
-
this.isDestroying = true;
|
|
380
|
-
// TODO do we still need this schedule?
|
|
381
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
382
|
-
emberBackburner.schedule('actions', this, this.willDestroy);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
function removeFromArray(array: RecordArray[], item: RecordArray): boolean {
|
|
387
|
-
let index = array.indexOf(item);
|
|
388
|
-
|
|
389
|
-
if (index !== -1) {
|
|
390
|
-
array.splice(index, 1);
|
|
391
|
-
return true;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
return false;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
function updateLiveRecordArray(store: Store, recordArray: RecordArray, identifiers: StableRecordIdentifier[]): void {
|
|
398
|
-
let identifiersToAdd: StableRecordIdentifier[] = [];
|
|
399
|
-
let identifiersToRemove: StableRecordIdentifier[] = [];
|
|
400
|
-
|
|
401
|
-
for (let i = 0; i < identifiers.length; i++) {
|
|
402
|
-
let identifier = identifiers[i];
|
|
403
|
-
let shouldInclude = shouldIncludeInRecordArrays(store, identifier);
|
|
404
|
-
let recordArrays = recordArraysForIdentifier(identifier);
|
|
405
|
-
|
|
406
|
-
if (shouldInclude) {
|
|
407
|
-
if (!recordArrays.has(recordArray)) {
|
|
408
|
-
identifiersToAdd.push(identifier);
|
|
409
|
-
recordArrays.add(recordArray);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
if (!shouldInclude) {
|
|
414
|
-
identifiersToRemove.push(identifier);
|
|
415
|
-
recordArrays.delete(recordArray);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
if (identifiersToAdd.length > 0) {
|
|
420
|
-
recordArray._pushIdentifiers(identifiersToAdd);
|
|
421
|
-
}
|
|
422
|
-
if (identifiersToRemove.length > 0) {
|
|
423
|
-
recordArray._removeIdentifiers(identifiersToRemove);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
function removeFromAdapterPopulatedRecordArrays(store: Store, identifiers: StableRecordIdentifier[]): void {
|
|
428
|
-
for (let i = 0; i < identifiers.length; i++) {
|
|
429
|
-
removeFromAll(store, identifiers[i]);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
function removeFromAll(store: Store, identifier: StableRecordIdentifier): void {
|
|
434
|
-
identifier = getIdentifier(identifier);
|
|
435
|
-
const recordArrays = recordArraysForIdentifier(identifier);
|
|
436
|
-
|
|
437
|
-
recordArrays.forEach(function (recordArray) {
|
|
438
|
-
recordArray._removeIdentifiers([identifier]);
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
recordArrays.clear();
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
export default RecordArrayManager;
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import type NativeArray from '@ember/array/-private/native-array';
|
|
2
|
-
import { assert } from '@ember/debug';
|
|
3
|
-
|
|
4
|
-
import type { CollectionResourceDocument, Links, Meta, PaginationLinks } from '@ember-data/types/q/ember-data-json-api';
|
|
5
|
-
import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
|
|
6
|
-
import type { RecordInstance } from '@ember-data/types/q/record-instance';
|
|
7
|
-
import type { FindOptions } from '@ember-data/types/q/store';
|
|
8
|
-
import type { Dict } from '@ember-data/types/q/utils';
|
|
9
|
-
|
|
10
|
-
import type Store from '../core-store';
|
|
11
|
-
import type { PromiseArray } from '../promise-proxies';
|
|
12
|
-
import { promiseArray } from '../promise-proxies';
|
|
13
|
-
import type RecordArrayManager from '../record-array-manager';
|
|
14
|
-
import SnapshotRecordArray from '../snapshot-record-array';
|
|
15
|
-
import RecordArray from './record-array';
|
|
16
|
-
|
|
17
|
-
export interface AdapterPopulatedRecordArrayCreateArgs {
|
|
18
|
-
modelName: string;
|
|
19
|
-
store: Store;
|
|
20
|
-
manager: RecordArrayManager;
|
|
21
|
-
content: NativeArray<StableRecordIdentifier>;
|
|
22
|
-
isLoaded: boolean;
|
|
23
|
-
query?: Dict<unknown>;
|
|
24
|
-
meta?: Meta;
|
|
25
|
-
links?: Links | PaginationLinks | null;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
@module @ember-data/store
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
Represents an ordered list of records whose order and membership is
|
|
34
|
-
determined by the adapter. For example, a query sent to the adapter
|
|
35
|
-
may trigger a search on the server, whose results would be loaded
|
|
36
|
-
into an instance of the `AdapterPopulatedRecordArray`.
|
|
37
|
-
|
|
38
|
-
This class should not be imported and instantiated by consuming applications.
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
If you want to update the array and get the latest records from the
|
|
43
|
-
adapter, you can invoke [`update()`](AdapterPopulatedRecordArray/methods/update?anchor=update):
|
|
44
|
-
|
|
45
|
-
Example
|
|
46
|
-
|
|
47
|
-
```javascript
|
|
48
|
-
// GET /users?isAdmin=true
|
|
49
|
-
store.query('user', { isAdmin: true }).then(function(admins) {
|
|
50
|
-
|
|
51
|
-
admins.then(function() {
|
|
52
|
-
console.log(admins.get("length")); // 42
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
// somewhere later in the app code, when new admins have been created
|
|
56
|
-
// in the meantime
|
|
57
|
-
//
|
|
58
|
-
// GET /users?isAdmin=true
|
|
59
|
-
admins.update().then(function() {
|
|
60
|
-
admins.get('isUpdating'); // false
|
|
61
|
-
console.log(admins.get("length")); // 123
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
admins.get('isUpdating'); // true
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
@class AdapterPopulatedRecordArray
|
|
69
|
-
@public
|
|
70
|
-
@extends RecordArray
|
|
71
|
-
*/
|
|
72
|
-
export default class AdapterPopulatedRecordArray extends RecordArray {
|
|
73
|
-
declare links: Links | PaginationLinks | null;
|
|
74
|
-
declare meta: Dict<unknown> | null;
|
|
75
|
-
declare query: Dict<unknown> | null;
|
|
76
|
-
|
|
77
|
-
init(props?: AdapterPopulatedRecordArrayCreateArgs) {
|
|
78
|
-
assert(`Cannot initialize AdapterPopulatedRecordArray with isUpdating`, !props || !('isUpdating' in props));
|
|
79
|
-
super.init();
|
|
80
|
-
this.query = this.query || null;
|
|
81
|
-
this.links = this.links || null;
|
|
82
|
-
this.meta = this.meta || null;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
replace() {
|
|
86
|
-
throw new Error(`The result of a server query (on ${this.modelName}) is immutable.`);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
_update(): PromiseArray<RecordInstance, AdapterPopulatedRecordArray> {
|
|
90
|
-
const { store, query } = this;
|
|
91
|
-
|
|
92
|
-
// TODO save options from initial request?
|
|
93
|
-
return promiseArray(store.query(this.modelName, query, { _recordArray: this }));
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
_setObjects(identifiers: StableRecordIdentifier[], payload: CollectionResourceDocument) {
|
|
97
|
-
// TODO: initial load should not cause change events at all, only
|
|
98
|
-
// subsequent. This requires changing the public api of adapter.query, but
|
|
99
|
-
// hopefully we can do that soon.
|
|
100
|
-
this.content.setObjects(identifiers);
|
|
101
|
-
|
|
102
|
-
this.setProperties({
|
|
103
|
-
isLoaded: true,
|
|
104
|
-
isUpdating: false,
|
|
105
|
-
// TODO this assign kills the root reference but a deep-copy would be required
|
|
106
|
-
// for both meta and links to actually not be by-ref. We whould likely change
|
|
107
|
-
// this to a dev-only deep-freeze.
|
|
108
|
-
meta: Object.assign({}, payload.meta),
|
|
109
|
-
links: Object.assign({}, payload.links),
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
this.manager._associateWithRecordArray(identifiers, this);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
_createSnapshot(options: FindOptions) {
|
|
116
|
-
// this is private for users, but public for ember-data internals
|
|
117
|
-
// meta will only be present for an AdapterPopulatedRecordArray
|
|
118
|
-
return new SnapshotRecordArray(this, this.meta, options);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
@method _setIdentifiers
|
|
123
|
-
@param {StableRecordIdentifier[]} identifiers
|
|
124
|
-
@param {Object} payload normalized payload
|
|
125
|
-
@private
|
|
126
|
-
*/
|
|
127
|
-
_setIdentifiers(identifiers: StableRecordIdentifier[], payload: CollectionResourceDocument): void {
|
|
128
|
-
this._setObjects(identifiers, payload);
|
|
129
|
-
}
|
|
130
|
-
}
|