@ember-data/store 4.8.0-alpha.4 → 4.8.0-alpha.5
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/caches/identifier-cache.ts +41 -34
- package/addon/-private/caches/instance-cache.ts +44 -49
- package/addon/-private/caches/record-data-for.ts +1 -6
- package/addon/-private/index.ts +0 -1
- package/addon/-private/legacy-model-support/shim-model-class.ts +10 -8
- package/addon/-private/managers/record-array-manager.ts +202 -325
- package/addon/-private/managers/record-data-store-wrapper.ts +12 -10
- package/addon/-private/managers/record-notification-manager.ts +30 -12
- package/addon/-private/network/fetch-manager.ts +2 -2
- package/addon/-private/network/finders.js +11 -6
- package/addon/-private/network/request-cache.ts +20 -17
- package/addon/-private/network/snapshot-record-array.ts +9 -26
- package/addon/-private/record-arrays/adapter-populated-record-array.ts +12 -41
- package/addon/-private/record-arrays/record-array.ts +32 -71
- package/addon/-private/store-service.ts +88 -50
- package/addon/-private/utils/is-non-empty-string.ts +1 -1
- package/package.json +5 -5
- package/addon/-private/backburner.js +0 -25
- package/addon/-private/utils/weak-cache.ts +0 -125
|
@@ -25,9 +25,8 @@ import coerceId from '../utils/coerce-id';
|
|
|
25
25
|
import { DEBUG_CLIENT_ORIGINATED, DEBUG_IDENTIFIER_BUCKET } from '../utils/identifer-debug-consts';
|
|
26
26
|
import isNonEmptyString from '../utils/is-non-empty-string';
|
|
27
27
|
import normalizeModelName from '../utils/normalize-model-name';
|
|
28
|
-
import WeakCache from '../utils/weak-cache';
|
|
29
28
|
|
|
30
|
-
const IDENTIFIERS = new
|
|
29
|
+
const IDENTIFIERS = new Set();
|
|
31
30
|
|
|
32
31
|
export function isStableIdentifier(identifier: Object): identifier is StableRecordIdentifier {
|
|
33
32
|
return IDENTIFIERS.has(identifier);
|
|
@@ -56,7 +55,7 @@ interface KeyOptions {
|
|
|
56
55
|
id: IdentifierMap;
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
type IdentifierMap =
|
|
58
|
+
type IdentifierMap = Map<string, StableRecordIdentifier>;
|
|
60
59
|
type TypeMap = ConfidentDict<KeyOptions>;
|
|
61
60
|
export type MergeMethod = (
|
|
62
61
|
targetIdentifier: StableRecordIdentifier,
|
|
@@ -85,12 +84,15 @@ export function setIdentifierResetMethod(method: ResetMethod | null): void {
|
|
|
85
84
|
configuredResetMethod = method;
|
|
86
85
|
}
|
|
87
86
|
|
|
87
|
+
type WithLid = { lid: string };
|
|
88
|
+
type WithId = { id: string | null; type: string };
|
|
89
|
+
|
|
88
90
|
function defaultGenerationMethod(data: ResourceData | { type: string }, bucket: IdentifierBucket): string {
|
|
89
|
-
if (
|
|
90
|
-
return data.lid;
|
|
91
|
+
if (isNonEmptyString((data as WithLid).lid)) {
|
|
92
|
+
return (data as WithLid).lid;
|
|
91
93
|
}
|
|
92
|
-
if (
|
|
93
|
-
let { type, id } = data;
|
|
94
|
+
if ((data as WithId).id !== undefined) {
|
|
95
|
+
let { type, id } = data as WithId;
|
|
94
96
|
// TODO: add test for id not a string
|
|
95
97
|
if (isNonEmptyString(coerceId(id))) {
|
|
96
98
|
return `@lid:${normalizeModelName(type)}-${id}`;
|
|
@@ -103,7 +105,7 @@ function defaultEmptyCallback(...args: any[]): any {}
|
|
|
103
105
|
|
|
104
106
|
let DEBUG_MAP;
|
|
105
107
|
if (DEBUG) {
|
|
106
|
-
DEBUG_MAP = new
|
|
108
|
+
DEBUG_MAP = new WeakMap<StableRecordIdentifier, StableRecordIdentifier>();
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
/**
|
|
@@ -121,7 +123,7 @@ if (DEBUG) {
|
|
|
121
123
|
*/
|
|
122
124
|
export class IdentifierCache {
|
|
123
125
|
_cache = {
|
|
124
|
-
lids:
|
|
126
|
+
lids: new Map<string, StableRecordIdentifier>(),
|
|
125
127
|
types: Object.create(null) as TypeMap,
|
|
126
128
|
};
|
|
127
129
|
declare _generate: GenerationMethod;
|
|
@@ -129,6 +131,7 @@ export class IdentifierCache {
|
|
|
129
131
|
declare _forget: ForgetMethod;
|
|
130
132
|
declare _reset: ResetMethod;
|
|
131
133
|
declare _merge: MergeMethod;
|
|
134
|
+
declare _isDefaultConfig: boolean;
|
|
132
135
|
|
|
133
136
|
constructor() {
|
|
134
137
|
// we cache the user configuredGenerationMethod at init because it must
|
|
@@ -138,6 +141,7 @@ export class IdentifierCache {
|
|
|
138
141
|
this._forget = configuredForgetMethod || defaultEmptyCallback;
|
|
139
142
|
this._reset = configuredResetMethod || defaultEmptyCallback;
|
|
140
143
|
this._merge = defaultEmptyCallback;
|
|
144
|
+
this._isDefaultConfig = !configuredGenerationMethod;
|
|
141
145
|
}
|
|
142
146
|
|
|
143
147
|
/**
|
|
@@ -167,7 +171,7 @@ export class IdentifierCache {
|
|
|
167
171
|
if (isStableIdentifier(resource)) {
|
|
168
172
|
if (DEBUG) {
|
|
169
173
|
// TODO should we instead just treat this case as a new generation skipping the short circuit?
|
|
170
|
-
if (!
|
|
174
|
+
if (!this._cache.lids.has(resource.lid) || this._cache.lids.get(resource.lid) !== resource) {
|
|
171
175
|
throw new Error(`The supplied identifier ${resource} does not belong to this store instance`);
|
|
172
176
|
}
|
|
173
177
|
}
|
|
@@ -179,7 +183,7 @@ export class IdentifierCache {
|
|
|
179
183
|
}
|
|
180
184
|
|
|
181
185
|
let lid = coerceId(resource.lid);
|
|
182
|
-
let identifier: StableRecordIdentifier | undefined = lid !== null ? this._cache.lids
|
|
186
|
+
let identifier: StableRecordIdentifier | undefined = lid !== null ? this._cache.lids.get(lid) : undefined;
|
|
183
187
|
|
|
184
188
|
if (identifier !== undefined) {
|
|
185
189
|
if (LOG_IDENTIFIERS) {
|
|
@@ -210,13 +214,13 @@ export class IdentifierCache {
|
|
|
210
214
|
|
|
211
215
|
// go straight for the stable RecordIdentifier key'd to `lid`
|
|
212
216
|
if (lid !== null) {
|
|
213
|
-
identifier = keyOptions.lid
|
|
217
|
+
identifier = keyOptions.lid.get(lid);
|
|
214
218
|
}
|
|
215
219
|
|
|
216
220
|
// we may have not seen this resource before
|
|
217
221
|
// but just in case we check our own secondary lookup (`id`)
|
|
218
222
|
if (identifier === undefined && id !== null) {
|
|
219
|
-
identifier = keyOptions.id
|
|
223
|
+
identifier = keyOptions.id.get(id);
|
|
220
224
|
}
|
|
221
225
|
|
|
222
226
|
if (identifier === undefined) {
|
|
@@ -233,12 +237,12 @@ export class IdentifierCache {
|
|
|
233
237
|
// different than expected
|
|
234
238
|
if (lid !== null && newLid !== lid) {
|
|
235
239
|
throw new Error(`You should not change the <lid> of a RecordIdentifier`);
|
|
236
|
-
} else if (lid === null) {
|
|
240
|
+
} else if (lid === null && !this._isDefaultConfig) {
|
|
237
241
|
// allow configuration to tell us that we have
|
|
238
242
|
// seen this `lid` before. E.g. a secondary lookup
|
|
239
243
|
// connects this resource to a previously seen
|
|
240
244
|
// resource.
|
|
241
|
-
identifier = keyOptions.lid
|
|
245
|
+
identifier = keyOptions.lid.get(newLid);
|
|
242
246
|
}
|
|
243
247
|
|
|
244
248
|
if (shouldGenerate === true) {
|
|
@@ -250,16 +254,16 @@ export class IdentifierCache {
|
|
|
250
254
|
if (DEBUG) {
|
|
251
255
|
// realistically if you hit this it means you changed `type` :/
|
|
252
256
|
// TODO consider how to handle type change assertions more gracefully
|
|
253
|
-
if (this._cache.lids
|
|
257
|
+
if (this._cache.lids.has(identifier.lid)) {
|
|
254
258
|
throw new Error(`You should not change the <type> of a RecordIdentifier`);
|
|
255
259
|
}
|
|
256
260
|
}
|
|
257
|
-
this._cache.lids
|
|
261
|
+
this._cache.lids.set(identifier.lid, identifier);
|
|
258
262
|
|
|
259
263
|
// populate our primary lookup table
|
|
260
264
|
// TODO consider having the `lid` cache be
|
|
261
265
|
// one level up
|
|
262
|
-
keyOptions.lid
|
|
266
|
+
keyOptions.lid.set(identifier.lid, identifier);
|
|
263
267
|
|
|
264
268
|
if (LOG_IDENTIFIERS && shouldGenerate) {
|
|
265
269
|
// eslint-disable-next-line no-console
|
|
@@ -281,7 +285,7 @@ export class IdentifierCache {
|
|
|
281
285
|
// because they may not match and we prefer
|
|
282
286
|
// what we've set via resource data
|
|
283
287
|
if (identifier.id !== null) {
|
|
284
|
-
keyOptions.id
|
|
288
|
+
keyOptions.id.set(identifier.id, identifier);
|
|
285
289
|
|
|
286
290
|
// TODO allow filling out of `id` here
|
|
287
291
|
// for the `username` non-client created
|
|
@@ -355,14 +359,17 @@ export class IdentifierCache {
|
|
|
355
359
|
|
|
356
360
|
// populate our unique table
|
|
357
361
|
if (DEBUG) {
|
|
358
|
-
if (this._cache.lids
|
|
362
|
+
if (this._cache.lids.has(identifier.lid)) {
|
|
359
363
|
throw new Error(`The lid generated for the new record is not unique as it matches an existing identifier`);
|
|
360
364
|
}
|
|
361
365
|
}
|
|
362
|
-
this._cache.lids
|
|
366
|
+
this._cache.lids.set(identifier.lid, identifier);
|
|
363
367
|
|
|
364
368
|
// populate the type+lid cache
|
|
365
|
-
keyOptions.lid
|
|
369
|
+
keyOptions.lid.set(newLid, identifier);
|
|
370
|
+
if (data.id) {
|
|
371
|
+
keyOptions.id.set(data.id, identifier);
|
|
372
|
+
}
|
|
366
373
|
|
|
367
374
|
if (LOG_IDENTIFIERS) {
|
|
368
375
|
// eslint-disable-next-line no-console
|
|
@@ -448,10 +455,10 @@ export class IdentifierCache {
|
|
|
448
455
|
);
|
|
449
456
|
}
|
|
450
457
|
let keyOptions = getTypeIndex(this._cache.types, identifier.type);
|
|
451
|
-
keyOptions.id
|
|
458
|
+
keyOptions.id.set(newId, identifier);
|
|
452
459
|
|
|
453
460
|
if (id !== null) {
|
|
454
|
-
keyOptions.id
|
|
461
|
+
keyOptions.id.delete(id);
|
|
455
462
|
}
|
|
456
463
|
} else if (LOG_IDENTIFIERS) {
|
|
457
464
|
// eslint-disable-next-line no-console
|
|
@@ -480,10 +487,10 @@ export class IdentifierCache {
|
|
|
480
487
|
this.forgetRecordIdentifier(abandoned);
|
|
481
488
|
|
|
482
489
|
// ensure a secondary cache entry for this id for the identifier we do keep
|
|
483
|
-
keyOptions.id
|
|
490
|
+
keyOptions.id.set(newId, kept);
|
|
484
491
|
// ensure a secondary cache entry for this id for the abandoned identifier's type we do keep
|
|
485
492
|
let baseKeyOptions = getTypeIndex(this._cache.types, existingIdentifier.type);
|
|
486
|
-
baseKeyOptions.id
|
|
493
|
+
baseKeyOptions.id.set(newId, kept);
|
|
487
494
|
|
|
488
495
|
// make sure that the `lid` on the data we are processing matches the lid we kept
|
|
489
496
|
data.lid = kept.lid;
|
|
@@ -507,10 +514,10 @@ export class IdentifierCache {
|
|
|
507
514
|
let identifier = this.getOrCreateRecordIdentifier(identifierObject);
|
|
508
515
|
let keyOptions = getTypeIndex(this._cache.types, identifier.type);
|
|
509
516
|
if (identifier.id !== null) {
|
|
510
|
-
keyOptions.id
|
|
517
|
+
keyOptions.id.delete(identifier.id);
|
|
511
518
|
}
|
|
512
|
-
this._cache.lids
|
|
513
|
-
keyOptions.lid
|
|
519
|
+
this._cache.lids.delete(identifier.lid);
|
|
520
|
+
keyOptions.lid.delete(identifier.lid);
|
|
514
521
|
|
|
515
522
|
IDENTIFIERS.delete(identifierObject);
|
|
516
523
|
this._forget(identifier, 'record');
|
|
@@ -530,8 +537,8 @@ function getTypeIndex(typeMap: TypeMap, type: string): KeyOptions {
|
|
|
530
537
|
|
|
531
538
|
if (typeIndex === undefined) {
|
|
532
539
|
typeIndex = {
|
|
533
|
-
lid:
|
|
534
|
-
id:
|
|
540
|
+
lid: new Map(),
|
|
541
|
+
id: new Map(),
|
|
535
542
|
};
|
|
536
543
|
typeMap[type] = typeIndex;
|
|
537
544
|
}
|
|
@@ -650,7 +657,7 @@ function detectMerge(
|
|
|
650
657
|
const { id, type, lid } = identifier;
|
|
651
658
|
if (id !== null && id !== newId && newId !== null) {
|
|
652
659
|
let keyOptions = getTypeIndex(typesCache, identifier.type);
|
|
653
|
-
let existingIdentifier = keyOptions.id
|
|
660
|
+
let existingIdentifier = keyOptions.id.get(newId);
|
|
654
661
|
|
|
655
662
|
return existingIdentifier !== undefined ? existingIdentifier : false;
|
|
656
663
|
} else {
|
|
@@ -658,12 +665,12 @@ function detectMerge(
|
|
|
658
665
|
|
|
659
666
|
// If the ids and type are the same but lid is not the same, we should trigger a merge of the identifiers
|
|
660
667
|
if (id !== null && id === newId && newType === type && data.lid && data.lid !== lid) {
|
|
661
|
-
let existingIdentifier = lids
|
|
668
|
+
let existingIdentifier = lids.get(data.lid);
|
|
662
669
|
return existingIdentifier !== undefined ? existingIdentifier : false;
|
|
663
670
|
// If the lids are the same, and ids are the same, but types are different we should trigger a merge of the identifiers
|
|
664
671
|
} else if (id !== null && id === newId && newType && newType !== type && data.lid && data.lid === lid) {
|
|
665
672
|
let keyOptions = getTypeIndex(typesCache, newType);
|
|
666
|
-
let existingIdentifier = keyOptions.id
|
|
673
|
+
let existingIdentifier = keyOptions.id.get(id);
|
|
667
674
|
return existingIdentifier !== undefined ? existingIdentifier : false;
|
|
668
675
|
}
|
|
669
676
|
}
|
|
@@ -37,7 +37,6 @@ import { assertIdentifierHasId } from '../store-service';
|
|
|
37
37
|
import coerceId, { ensureStringId } from '../utils/coerce-id';
|
|
38
38
|
import constructResource from '../utils/construct-resource';
|
|
39
39
|
import normalizeModelName from '../utils/normalize-model-name';
|
|
40
|
-
import WeakCache, { DebugWeakCache } from '../utils/weak-cache';
|
|
41
40
|
import { removeRecordDataFor, setRecordDataFor } from './record-data-for';
|
|
42
41
|
|
|
43
42
|
let _peekGraph: peekGraph;
|
|
@@ -54,10 +53,7 @@ if (HAS_RECORD_DATA_PACKAGE) {
|
|
|
54
53
|
@module @ember-data/store
|
|
55
54
|
*/
|
|
56
55
|
|
|
57
|
-
const RecordCache = new
|
|
58
|
-
if (DEBUG) {
|
|
59
|
-
RecordCache._expectMsg = (key: RecordInstance) => `${String(key)} is not a record instantiated by @ember-data/store`;
|
|
60
|
-
}
|
|
56
|
+
const RecordCache = new Map<RecordInstance, StableRecordIdentifier>();
|
|
61
57
|
|
|
62
58
|
export function peekRecordIdentifier(record: RecordInstance): StableRecordIdentifier | undefined {
|
|
63
59
|
return RecordCache.get(record);
|
|
@@ -83,7 +79,8 @@ export function peekRecordIdentifier(record: RecordInstance): StableRecordIdenti
|
|
|
83
79
|
@returns {StableRecordIdentifier}
|
|
84
80
|
*/
|
|
85
81
|
export function recordIdentifierFor(record: RecordInstance): StableRecordIdentifier {
|
|
86
|
-
|
|
82
|
+
assert(`${String(record)} is not a record instantiated by @ember-data/store`, RecordCache.has(record));
|
|
83
|
+
return RecordCache.get(record)!;
|
|
87
84
|
}
|
|
88
85
|
|
|
89
86
|
export function setRecordIdentifier(record: RecordInstance, identifier: StableRecordIdentifier): void {
|
|
@@ -102,7 +99,7 @@ export function setRecordIdentifier(record: RecordInstance, identifier: StableRe
|
|
|
102
99
|
RecordCache.set(record, identifier);
|
|
103
100
|
}
|
|
104
101
|
|
|
105
|
-
export const StoreMap = new
|
|
102
|
+
export const StoreMap = new Map<RecordInstance, Store>();
|
|
106
103
|
|
|
107
104
|
export function storeFor(record: RecordInstance): Store | undefined {
|
|
108
105
|
const store = StoreMap.get(record);
|
|
@@ -117,33 +114,32 @@ export function storeFor(record: RecordInstance): Store | undefined {
|
|
|
117
114
|
type Caches = {
|
|
118
115
|
record: Map<StableRecordIdentifier, RecordInstance>;
|
|
119
116
|
recordData: Map<StableRecordIdentifier, RecordData>;
|
|
120
|
-
reference:
|
|
117
|
+
reference: WeakMap<StableRecordIdentifier, RecordReference>;
|
|
121
118
|
};
|
|
122
119
|
|
|
123
120
|
export class InstanceCache {
|
|
124
121
|
declare store: Store;
|
|
125
122
|
declare _storeWrapper: RecordDataStoreWrapper;
|
|
126
|
-
declare peekList: Dict<Set<StableRecordIdentifier>>;
|
|
127
123
|
declare __recordDataFor: (resource: RecordIdentifier) => RecordData;
|
|
128
124
|
|
|
129
125
|
declare __cacheManager: NonSingletonRecordDataManager;
|
|
130
126
|
__instances: Caches = {
|
|
131
127
|
record: new Map<StableRecordIdentifier, RecordInstance>(),
|
|
132
128
|
recordData: new Map<StableRecordIdentifier, RecordData>(),
|
|
133
|
-
reference: new
|
|
129
|
+
reference: new WeakMap<StableRecordIdentifier, RecordReference>(),
|
|
134
130
|
};
|
|
135
131
|
|
|
136
132
|
recordIsLoaded(identifier: StableRecordIdentifier, filterDeleted: boolean = false) {
|
|
137
|
-
const recordData = this.
|
|
133
|
+
const recordData = this.__instances.recordData.get(identifier);
|
|
138
134
|
if (!recordData) {
|
|
139
135
|
return false;
|
|
140
136
|
}
|
|
141
137
|
const isNew = recordData.isNew(identifier);
|
|
142
|
-
const isEmpty = recordData.isEmpty
|
|
138
|
+
const isEmpty = recordData.isEmpty(identifier);
|
|
143
139
|
|
|
144
140
|
// if we are new we must consider ourselves loaded
|
|
145
141
|
if (isNew) {
|
|
146
|
-
return
|
|
142
|
+
return !recordData.isDeleted(identifier);
|
|
147
143
|
}
|
|
148
144
|
// even if we have a past request, if we are now empty we are not loaded
|
|
149
145
|
// typically this is true after an unloadRecord call
|
|
@@ -152,23 +148,27 @@ export class InstanceCache {
|
|
|
152
148
|
// we should consider allowing for something to be loaded that is simply "not empty".
|
|
153
149
|
// which is how RecordState currently handles this case; however, RecordState is buggy
|
|
154
150
|
// in that it does not account for unloading.
|
|
155
|
-
|
|
151
|
+
return filterDeleted && recordData.isDeletionCommitted(identifier) ? false : !isEmpty;
|
|
156
152
|
|
|
153
|
+
/*
|
|
157
154
|
const req = this.store.getRequestStateService();
|
|
158
155
|
const fulfilled = req.getLastRequestForRecord(identifier);
|
|
156
|
+
const isLocallyLoaded = !isEmpty;
|
|
159
157
|
const isLoading =
|
|
160
|
-
|
|
158
|
+
!isLocallyLoaded &&
|
|
159
|
+
fulfilled === null &&
|
|
160
|
+
req.getPendingRequestsForRecord(identifier).some((req) => req.type === 'query');
|
|
161
161
|
|
|
162
162
|
if (isEmpty || (filterDeleted && recordData.isDeletionCommitted(identifier)) || isLoading) {
|
|
163
163
|
return false;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
return true;
|
|
167
|
+
*/
|
|
167
168
|
}
|
|
168
169
|
|
|
169
170
|
constructor(store: Store) {
|
|
170
171
|
this.store = store;
|
|
171
|
-
this.peekList = Object.create(null) as Dict<Set<StableRecordIdentifier>>;
|
|
172
172
|
|
|
173
173
|
this._storeWrapper = new RecordDataStoreWrapper(this.store);
|
|
174
174
|
this.__recordDataFor = (resource: RecordIdentifier) => {
|
|
@@ -177,10 +177,6 @@ export class InstanceCache {
|
|
|
177
177
|
return this.getRecordData(identifier);
|
|
178
178
|
};
|
|
179
179
|
|
|
180
|
-
this.__instances.reference._generator = (identifier) => {
|
|
181
|
-
return new RecordReference(this.store, identifier);
|
|
182
|
-
};
|
|
183
|
-
|
|
184
180
|
store.identifierCache.__configureMerge(
|
|
185
181
|
(identifier: StableRecordIdentifier, matchedIdentifier: StableRecordIdentifier, resourceData) => {
|
|
186
182
|
let intendedIdentifier = identifier;
|
|
@@ -228,7 +224,6 @@ export class InstanceCache {
|
|
|
228
224
|
// remove "other" from cache
|
|
229
225
|
if (otherHasRecord) {
|
|
230
226
|
// TODO probably need to release other things
|
|
231
|
-
this.peekList[altIdentifier.type]?.delete(altIdentifier);
|
|
232
227
|
}
|
|
233
228
|
|
|
234
229
|
if (imRecordData === null && otherRecordData === null) {
|
|
@@ -244,14 +239,11 @@ export class InstanceCache {
|
|
|
244
239
|
if (imRecordData) {
|
|
245
240
|
// TODO check if we are retained in any async relationships
|
|
246
241
|
// TODO probably need to release other things
|
|
247
|
-
this.peekList[intendedIdentifier.type]?.delete(intendedIdentifier);
|
|
248
242
|
// im.destroy();
|
|
249
243
|
}
|
|
250
244
|
imRecordData = otherRecordData!;
|
|
251
245
|
// TODO do we need to notify the id change?
|
|
252
246
|
// TODO swap recordIdentifierFor result?
|
|
253
|
-
this.peekList[intendedIdentifier.type] = this.peekList[intendedIdentifier.type] || new Set();
|
|
254
|
-
this.peekList[intendedIdentifier.type]!.add(intendedIdentifier);
|
|
255
247
|
|
|
256
248
|
// just use im
|
|
257
249
|
} else {
|
|
@@ -285,7 +277,7 @@ export class InstanceCache {
|
|
|
285
277
|
}
|
|
286
278
|
|
|
287
279
|
getRecord(identifier: StableRecordIdentifier, properties?: CreateRecordProperties): RecordInstance {
|
|
288
|
-
let record = this.
|
|
280
|
+
let record = this.__instances.record.get(identifier);
|
|
289
281
|
|
|
290
282
|
if (!record) {
|
|
291
283
|
const recordData = this.getRecordData(identifier);
|
|
@@ -311,7 +303,7 @@ export class InstanceCache {
|
|
|
311
303
|
}
|
|
312
304
|
|
|
313
305
|
getRecordData(identifier: StableRecordIdentifier): RecordData {
|
|
314
|
-
let recordData = this.
|
|
306
|
+
let recordData = this.__instances.recordData.get(identifier);
|
|
315
307
|
|
|
316
308
|
if (!recordData) {
|
|
317
309
|
if (DEPRECATE_V1CACHE_STORE_APIS && this.store.createRecordDataFor.length > 2) {
|
|
@@ -354,8 +346,6 @@ export class InstanceCache {
|
|
|
354
346
|
setRecordDataFor(identifier, recordData);
|
|
355
347
|
|
|
356
348
|
this.__instances.recordData.set(identifier, recordData);
|
|
357
|
-
this.peekList[identifier.type] = this.peekList[identifier.type] || new Set();
|
|
358
|
-
this.peekList[identifier.type]!.add(identifier);
|
|
359
349
|
if (LOG_INSTANCE_CACHE) {
|
|
360
350
|
// eslint-disable-next-line no-console
|
|
361
351
|
console.log(`InstanceCache: created RecordData for ${String(identifier)}`);
|
|
@@ -366,7 +356,14 @@ export class InstanceCache {
|
|
|
366
356
|
}
|
|
367
357
|
|
|
368
358
|
getReference(identifier: StableRecordIdentifier) {
|
|
369
|
-
|
|
359
|
+
let cache = this.__instances.reference;
|
|
360
|
+
let reference = cache.get(identifier);
|
|
361
|
+
|
|
362
|
+
if (!reference) {
|
|
363
|
+
reference = new RecordReference(this.store, identifier);
|
|
364
|
+
cache.set(identifier, reference);
|
|
365
|
+
}
|
|
366
|
+
return reference;
|
|
370
367
|
}
|
|
371
368
|
|
|
372
369
|
createSnapshot(identifier: StableRecordIdentifier, options: FindOptions = {}): Snapshot {
|
|
@@ -411,10 +408,9 @@ export class InstanceCache {
|
|
|
411
408
|
}
|
|
412
409
|
|
|
413
410
|
// TODO is this join still necessary?
|
|
414
|
-
this.store.
|
|
415
|
-
const record = this.
|
|
416
|
-
const recordData = this.
|
|
417
|
-
this.peekList[identifier.type]?.delete(identifier);
|
|
411
|
+
this.store._join(() => {
|
|
412
|
+
const record = this.__instances.record.get(identifier);
|
|
413
|
+
const recordData = this.__instances.recordData.get(identifier);
|
|
418
414
|
|
|
419
415
|
if (record) {
|
|
420
416
|
this.store.teardownRecord(record);
|
|
@@ -438,7 +434,7 @@ export class InstanceCache {
|
|
|
438
434
|
}
|
|
439
435
|
|
|
440
436
|
this.store._fetchManager.clearEntries(identifier);
|
|
441
|
-
this.store.recordArrayManager.
|
|
437
|
+
this.store.recordArrayManager.identifierRemoved(identifier);
|
|
442
438
|
if (LOG_INSTANCE_CACHE) {
|
|
443
439
|
// eslint-disable-next-line no-console
|
|
444
440
|
console.log(`InstanceCache: unloaded RecordData for ${String(identifier)}`);
|
|
@@ -449,20 +445,19 @@ export class InstanceCache {
|
|
|
449
445
|
}
|
|
450
446
|
|
|
451
447
|
clear(type?: string) {
|
|
448
|
+
const typeCache = this.store.identifierCache._cache.types;
|
|
452
449
|
if (type === undefined) {
|
|
453
|
-
|
|
454
|
-
|
|
450
|
+
this.__instances.recordData.forEach((value, identifier) => {
|
|
451
|
+
this.unloadRecord(identifier);
|
|
452
|
+
});
|
|
455
453
|
} else {
|
|
456
|
-
let identifiers =
|
|
454
|
+
let identifiers = typeCache[type]?.lid;
|
|
455
|
+
const rds = this.__instances.recordData;
|
|
457
456
|
if (identifiers) {
|
|
458
457
|
identifiers.forEach((identifier) => {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
// signal it is actually trying to give us.
|
|
463
|
-
// this.cache.delete(identifier);
|
|
464
|
-
this.peekList[identifier.type]!.delete(identifier);
|
|
465
|
-
this.unloadRecord(identifier);
|
|
458
|
+
if (rds.has(identifier)) {
|
|
459
|
+
this.unloadRecord(identifier);
|
|
460
|
+
}
|
|
466
461
|
// TODO we don't remove the identifier, should we?
|
|
467
462
|
});
|
|
468
463
|
}
|
|
@@ -479,7 +474,7 @@ export class InstanceCache {
|
|
|
479
474
|
const isLoading = _isLoading(this, identifier);
|
|
480
475
|
|
|
481
476
|
if (options.preload) {
|
|
482
|
-
this.store.
|
|
477
|
+
this.store._join(() => {
|
|
483
478
|
preloadData(this.store, identifier, options.preload!);
|
|
484
479
|
});
|
|
485
480
|
}
|
|
@@ -589,7 +584,7 @@ export class InstanceCache {
|
|
|
589
584
|
recordData.pushData(identifier, data, hasRecord);
|
|
590
585
|
|
|
591
586
|
if (!isUpdate) {
|
|
592
|
-
this.store.recordArrayManager.
|
|
587
|
+
this.store.recordArrayManager.identifierAdded(identifier);
|
|
593
588
|
}
|
|
594
589
|
|
|
595
590
|
return identifier as StableExistingRecordIdentifier;
|
|
@@ -603,7 +598,7 @@ function _recordDataIsFullDeleted(identifier: StableRecordIdentifier, recordData
|
|
|
603
598
|
}
|
|
604
599
|
|
|
605
600
|
export function recordDataIsFullyDeleted(cache: InstanceCache, identifier: StableRecordIdentifier): boolean {
|
|
606
|
-
let recordData = cache.
|
|
601
|
+
let recordData = cache.__instances.recordData.get(identifier);
|
|
607
602
|
return !recordData || _recordDataIsFullDeleted(identifier, recordData);
|
|
608
603
|
}
|
|
609
604
|
|
|
@@ -678,13 +673,13 @@ function _convertPreloadRelationshipToJSON(
|
|
|
678
673
|
}
|
|
679
674
|
|
|
680
675
|
function _isEmpty(cache: InstanceCache, identifier: StableRecordIdentifier): boolean {
|
|
681
|
-
const recordData = cache.
|
|
676
|
+
const recordData = cache.__instances.recordData.get(identifier);
|
|
682
677
|
if (!recordData) {
|
|
683
678
|
return true;
|
|
684
679
|
}
|
|
685
680
|
const isNew = recordData.isNew(identifier);
|
|
686
681
|
const isDeleted = recordData.isDeleted(identifier);
|
|
687
|
-
const isEmpty = recordData.isEmpty
|
|
682
|
+
const isEmpty = recordData.isEmpty(identifier);
|
|
688
683
|
|
|
689
684
|
return (!isNew || isDeleted) && isEmpty;
|
|
690
685
|
}
|
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
import { assert } from '@ember/debug';
|
|
2
|
-
import { DEBUG } from '@glimmer/env';
|
|
3
2
|
|
|
4
3
|
import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
|
|
5
4
|
import type { RecordData } from '@ember-data/types/q/record-data';
|
|
6
5
|
import type { RecordInstance } from '@ember-data/types/q/record-instance';
|
|
7
6
|
|
|
8
|
-
import WeakCache from '../utils/weak-cache';
|
|
9
|
-
|
|
10
7
|
/*
|
|
11
8
|
* Returns the RecordData instance associated with a given
|
|
12
9
|
* Model or Identifier
|
|
13
10
|
*/
|
|
14
11
|
|
|
15
|
-
const RecordDataForIdentifierCache = new
|
|
16
|
-
DEBUG ? 'recordData' : ''
|
|
17
|
-
);
|
|
12
|
+
const RecordDataForIdentifierCache = new Map<StableRecordIdentifier | RecordInstance, RecordData>();
|
|
18
13
|
|
|
19
14
|
export function setRecordDataFor(identifier: StableRecordIdentifier | RecordInstance, recordData: RecordData): void {
|
|
20
15
|
assert(
|
package/addon/-private/index.ts
CHANGED
|
@@ -53,4 +53,3 @@ export { default as SnapshotRecordArray } from './network/snapshot-record-array'
|
|
|
53
53
|
|
|
54
54
|
// leaked for private use / test use, should investigate removing
|
|
55
55
|
export { default as recordDataFor, removeRecordDataFor } from './caches/record-data-for';
|
|
56
|
-
export { default as WeakCache } from './utils/weak-cache';
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import { DEBUG } from '@glimmer/env';
|
|
2
|
-
|
|
3
1
|
import type { ModelSchema } from '@ember-data/types/q/ds-model';
|
|
4
2
|
import type { AttributeSchema, RelationshipSchema } from '@ember-data/types/q/record-data-schemas';
|
|
5
3
|
import type { Dict } from '@ember-data/types/q/utils';
|
|
6
4
|
|
|
7
5
|
import type Store from '../store-service';
|
|
8
|
-
import WeakCache from '../utils/weak-cache';
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
// if modelFor turns out to be a bottleneck we should replace with a Map
|
|
8
|
+
// and clear it during store teardown.
|
|
9
|
+
const AvailableShims = new WeakMap<Store, Dict<ShimModelClass>>();
|
|
10
|
+
|
|
14
11
|
export function getShimClass(store: Store, modelName: string): ShimModelClass {
|
|
15
|
-
let shims = AvailableShims.
|
|
12
|
+
let shims = AvailableShims.get(store);
|
|
13
|
+
|
|
14
|
+
if (!shims) {
|
|
15
|
+
shims = Object.create(null) as Dict<ShimModelClass>;
|
|
16
|
+
AvailableShims.set(store, shims);
|
|
17
|
+
}
|
|
16
18
|
let shim = shims[modelName];
|
|
17
19
|
if (shim === undefined) {
|
|
18
20
|
shim = shims[modelName] = new ShimModelClass(store, modelName);
|