@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,318 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
@module @ember-data/store
|
|
3
|
-
*/
|
|
4
|
-
import type NativeArray from '@ember/array/-private/native-array';
|
|
5
|
-
import ArrayProxy from '@ember/array/proxy';
|
|
6
|
-
import { assert, deprecate } from '@ember/debug';
|
|
7
|
-
import { get, set } from '@ember/object';
|
|
8
|
-
import { tracked } from '@glimmer/tracking';
|
|
9
|
-
|
|
10
|
-
import { Promise } from 'rsvp';
|
|
11
|
-
|
|
12
|
-
import type { RecordArrayManager, Snapshot } from 'ember-data/-private';
|
|
13
|
-
|
|
14
|
-
import { DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS } from '@ember-data/private-build-infra/deprecations';
|
|
15
|
-
import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
|
|
16
|
-
import type { RecordInstance } from '@ember-data/types/q/record-instance';
|
|
17
|
-
import type { FindOptions } from '@ember-data/types/q/store';
|
|
18
|
-
|
|
19
|
-
import type Store from '../core-store';
|
|
20
|
-
import type { PromiseArray } from '../promise-proxies';
|
|
21
|
-
import { promiseArray } from '../promise-proxies';
|
|
22
|
-
import SnapshotRecordArray from '../snapshot-record-array';
|
|
23
|
-
|
|
24
|
-
function recordForIdentifier(store: Store, identifier: StableRecordIdentifier): RecordInstance {
|
|
25
|
-
return store._instanceCache.getRecord(identifier);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface RecordArrayCreateArgs {
|
|
29
|
-
modelName: string;
|
|
30
|
-
store: Store;
|
|
31
|
-
manager: RecordArrayManager;
|
|
32
|
-
content: NativeArray<StableRecordIdentifier>;
|
|
33
|
-
isLoaded: boolean;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
A record array is an array that contains records of a certain modelName. The record
|
|
38
|
-
array materializes records as needed when they are retrieved for the first
|
|
39
|
-
time. You should not create record arrays yourself. Instead, an instance of
|
|
40
|
-
`RecordArray` or its subclasses will be returned by your application's store
|
|
41
|
-
in response to queries.
|
|
42
|
-
|
|
43
|
-
This class should not be imported and instantiated by consuming applications.
|
|
44
|
-
|
|
45
|
-
@class RecordArray
|
|
46
|
-
@public
|
|
47
|
-
@extends Ember.ArrayProxy
|
|
48
|
-
*/
|
|
49
|
-
export default class RecordArray extends ArrayProxy<StableRecordIdentifier, RecordInstance> {
|
|
50
|
-
/**
|
|
51
|
-
The array of client ids backing the record array. When a
|
|
52
|
-
record is requested from the record array, the record
|
|
53
|
-
for the client id at the same index is materialized, if
|
|
54
|
-
necessary, by the store.
|
|
55
|
-
|
|
56
|
-
@property content
|
|
57
|
-
@private
|
|
58
|
-
@type Ember.Array
|
|
59
|
-
*/
|
|
60
|
-
declare content: NativeArray<StableRecordIdentifier>;
|
|
61
|
-
declare _getDeprecatedEventedInfo: () => string;
|
|
62
|
-
declare modelName: string;
|
|
63
|
-
/**
|
|
64
|
-
The flag to signal a `RecordArray` is finished loading data.
|
|
65
|
-
|
|
66
|
-
Example
|
|
67
|
-
|
|
68
|
-
```javascript
|
|
69
|
-
let people = store.peekAll('person');
|
|
70
|
-
people.get('isLoaded'); // true
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
@property isLoaded
|
|
74
|
-
@public
|
|
75
|
-
@type Boolean
|
|
76
|
-
*/
|
|
77
|
-
declare isLoaded: boolean;
|
|
78
|
-
/**
|
|
79
|
-
The store that created this record array.
|
|
80
|
-
|
|
81
|
-
@property store
|
|
82
|
-
@private
|
|
83
|
-
@type Store
|
|
84
|
-
*/
|
|
85
|
-
declare store: Store;
|
|
86
|
-
declare _updatingPromise: PromiseArray<RecordInstance, RecordArray> | null;
|
|
87
|
-
declare manager: RecordArrayManager;
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
The flag to signal a `RecordArray` is currently loading data.
|
|
91
|
-
Example
|
|
92
|
-
```javascript
|
|
93
|
-
let people = store.peekAll('person');
|
|
94
|
-
people.get('isUpdating'); // false
|
|
95
|
-
people.update();
|
|
96
|
-
people.get('isUpdating'); // true
|
|
97
|
-
```
|
|
98
|
-
@property isUpdating
|
|
99
|
-
@public
|
|
100
|
-
@type Boolean
|
|
101
|
-
*/
|
|
102
|
-
@tracked isUpdating: boolean = false;
|
|
103
|
-
|
|
104
|
-
init(props?: RecordArrayCreateArgs) {
|
|
105
|
-
assert(`Cannot initialize RecordArray with isUpdating`, !props || !('isUpdating' in props));
|
|
106
|
-
assert(`Cannot initialize RecordArray with isUpdating`, !props || !('_updatingPromise' in props));
|
|
107
|
-
super.init();
|
|
108
|
-
|
|
109
|
-
// TODO can we get rid of this?
|
|
110
|
-
this.set('content', this.content || null);
|
|
111
|
-
this._updatingPromise = null;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
replace() {
|
|
115
|
-
throw new Error(
|
|
116
|
-
`The result of a server query (for all ${this.modelName} types) is immutable. To modify contents, use toArray()`
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
The modelClass represented by this record array.
|
|
122
|
-
|
|
123
|
-
@property type
|
|
124
|
-
@public
|
|
125
|
-
@deprecated
|
|
126
|
-
@type {subclass of Model}
|
|
127
|
-
*/
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
Retrieves an object from the content by index.
|
|
131
|
-
|
|
132
|
-
@method objectAtContent
|
|
133
|
-
@private
|
|
134
|
-
@param {Number} index
|
|
135
|
-
@return {Model} record
|
|
136
|
-
*/
|
|
137
|
-
objectAtContent(index: number): RecordInstance | undefined {
|
|
138
|
-
let identifier = get(this, 'content').objectAt(index);
|
|
139
|
-
return identifier ? recordForIdentifier(this.store, identifier) : undefined;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
Used to get the latest version of all of the records in this array
|
|
144
|
-
from the adapter.
|
|
145
|
-
|
|
146
|
-
Example
|
|
147
|
-
|
|
148
|
-
```javascript
|
|
149
|
-
let people = store.peekAll('person');
|
|
150
|
-
people.get('isUpdating'); // false
|
|
151
|
-
|
|
152
|
-
people.update().then(function() {
|
|
153
|
-
people.get('isUpdating'); // false
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
people.get('isUpdating'); // true
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
@method update
|
|
160
|
-
@public
|
|
161
|
-
*/
|
|
162
|
-
update(): PromiseArray<RecordInstance, RecordArray> {
|
|
163
|
-
if (this.isUpdating) {
|
|
164
|
-
return this._updatingPromise!;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
this.isUpdating = true;
|
|
168
|
-
|
|
169
|
-
let updatingPromise = this._update();
|
|
170
|
-
updatingPromise.finally(() => {
|
|
171
|
-
this._updatingPromise = null;
|
|
172
|
-
if (this.isDestroying || this.isDestroyed) {
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
this.isUpdating = false;
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
this._updatingPromise = updatingPromise;
|
|
179
|
-
|
|
180
|
-
return updatingPromise;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/*
|
|
184
|
-
Update this RecordArray and return a promise which resolves once the update
|
|
185
|
-
is finished.
|
|
186
|
-
*/
|
|
187
|
-
_update(): PromiseArray<RecordInstance, RecordArray> {
|
|
188
|
-
return this.store.findAll(this.modelName, { reload: true });
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
Saves all of the records in the `RecordArray`.
|
|
193
|
-
|
|
194
|
-
Example
|
|
195
|
-
|
|
196
|
-
```javascript
|
|
197
|
-
let messages = store.peekAll('message');
|
|
198
|
-
messages.forEach(function(message) {
|
|
199
|
-
message.set('hasBeenSeen', true);
|
|
200
|
-
});
|
|
201
|
-
messages.save();
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
@method save
|
|
205
|
-
@public
|
|
206
|
-
@return {PromiseArray} promise
|
|
207
|
-
*/
|
|
208
|
-
save(): PromiseArray<RecordInstance, RecordArray> {
|
|
209
|
-
let promiseLabel = `DS: RecordArray#save ${this.modelName}`;
|
|
210
|
-
let promise = Promise.all(this.invoke('save'), promiseLabel).then(
|
|
211
|
-
() => this,
|
|
212
|
-
null,
|
|
213
|
-
'DS: RecordArray#save return RecordArray'
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
return promiseArray<RecordInstance, RecordArray>(promise);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
@method _unregisterFromManager
|
|
221
|
-
@internal
|
|
222
|
-
*/
|
|
223
|
-
_unregisterFromManager() {
|
|
224
|
-
this.manager.unregisterRecordArray(this);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
willDestroy() {
|
|
228
|
-
this._unregisterFromManager();
|
|
229
|
-
this._dissociateFromOwnRecords();
|
|
230
|
-
// TODO: we should not do work during destroy:
|
|
231
|
-
// * when objects are destroyed, they should simply be left to do
|
|
232
|
-
// * if logic errors do to this, that logic needs to be more careful during
|
|
233
|
-
// teardown (ember provides isDestroying/isDestroyed) for this reason
|
|
234
|
-
// * the exception being: if an dominator has a reference to this object,
|
|
235
|
-
// and must be informed to release e.g. e.g. removing itself from th
|
|
236
|
-
// recordArrayMananger
|
|
237
|
-
set(this, 'content', null as unknown as NativeArray<StableRecordIdentifier>);
|
|
238
|
-
set(this, 'length', 0);
|
|
239
|
-
super.willDestroy();
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
@method _createSnapshot
|
|
244
|
-
@private
|
|
245
|
-
*/
|
|
246
|
-
_createSnapshot(options: FindOptions) {
|
|
247
|
-
// this is private for users, but public for ember-data internals
|
|
248
|
-
// meta will only be present for an AdapterPopulatedRecordArray
|
|
249
|
-
return new SnapshotRecordArray(this, null, options);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
@method _dissociateFromOwnRecords
|
|
254
|
-
@internal
|
|
255
|
-
*/
|
|
256
|
-
_dissociateFromOwnRecords() {
|
|
257
|
-
this.content.forEach((identifier) => {
|
|
258
|
-
let recordArrays = this.manager.getRecordArraysForIdentifier(identifier);
|
|
259
|
-
|
|
260
|
-
if (recordArrays) {
|
|
261
|
-
recordArrays.delete(this);
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
Adds identifiers to the `RecordArray` without duplicates
|
|
268
|
-
|
|
269
|
-
@method _pushIdentifiers
|
|
270
|
-
@internal
|
|
271
|
-
@param {StableRecordIdentifier[]} identifiers
|
|
272
|
-
*/
|
|
273
|
-
_pushIdentifiers(identifiers: StableRecordIdentifier[]): void {
|
|
274
|
-
this.content.pushObjects(identifiers);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
Removes identifiers from the `RecordArray`.
|
|
279
|
-
|
|
280
|
-
@method _removeIdentifiers
|
|
281
|
-
@internal
|
|
282
|
-
@param {StableRecordIdentifier[]} identifiers
|
|
283
|
-
*/
|
|
284
|
-
_removeIdentifiers(identifiers: StableRecordIdentifier[]): void {
|
|
285
|
-
this.content.removeObjects(identifiers);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
@method _takeSnapshot
|
|
290
|
-
@internal
|
|
291
|
-
*/
|
|
292
|
-
_takeSnapshot(): Snapshot[] {
|
|
293
|
-
return this.content.map((identifier) => this.store._instanceCache.createSnapshot(identifier));
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
if (DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS) {
|
|
298
|
-
Object.defineProperty(RecordArray.prototype, 'type', {
|
|
299
|
-
get() {
|
|
300
|
-
deprecate(
|
|
301
|
-
`Using RecordArray.type to access the ModelClass for a record is deprecated. Use store.modelFor(<modelName>) instead.`,
|
|
302
|
-
false,
|
|
303
|
-
{
|
|
304
|
-
id: 'ember-data:deprecate-snapshot-model-class-access',
|
|
305
|
-
until: '5.0',
|
|
306
|
-
for: 'ember-data',
|
|
307
|
-
since: { available: '4.5.0', enabled: '4.5.0' },
|
|
308
|
-
}
|
|
309
|
-
);
|
|
310
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
311
|
-
if (!this.modelName) {
|
|
312
|
-
return null;
|
|
313
|
-
}
|
|
314
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
|
315
|
-
return this.store.modelFor(this.modelName);
|
|
316
|
-
},
|
|
317
|
-
});
|
|
318
|
-
}
|
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
import { importSync } from '@embroider/macros';
|
|
2
|
-
|
|
3
|
-
import type { RelationshipDefinition } from '@ember-data/model/-private/relationship-meta';
|
|
4
|
-
import { HAS_RECORD_DATA_PACKAGE } from '@ember-data/private-build-infra';
|
|
5
|
-
import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
|
|
6
|
-
import type { RecordData } from '@ember-data/types/q/record-data';
|
|
7
|
-
import type {
|
|
8
|
-
AttributesSchema,
|
|
9
|
-
RelationshipSchema,
|
|
10
|
-
RelationshipsSchema,
|
|
11
|
-
} from '@ember-data/types/q/record-data-schemas';
|
|
12
|
-
import type { RecordDataStoreWrapper as StoreWrapper } from '@ember-data/types/q/record-data-store-wrapper';
|
|
13
|
-
|
|
14
|
-
import type Store from './core-store';
|
|
15
|
-
import type { IdentifierCache } from './identifier-cache';
|
|
16
|
-
import { internalModelFactoryFor } from './internal-model-factory';
|
|
17
|
-
import constructResource from './utils/construct-resource';
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
@module @ember-data/store
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
function metaIsRelationshipDefinition(meta: RelationshipSchema): meta is RelationshipDefinition {
|
|
24
|
-
return typeof (meta as RelationshipDefinition)._inverseKey === 'function';
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
let peekGraph;
|
|
28
|
-
if (HAS_RECORD_DATA_PACKAGE) {
|
|
29
|
-
let _peekGraph;
|
|
30
|
-
peekGraph = (wrapper) => {
|
|
31
|
-
_peekGraph =
|
|
32
|
-
_peekGraph ||
|
|
33
|
-
(importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')).peekGraph;
|
|
34
|
-
return _peekGraph(wrapper);
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export default class RecordDataStoreWrapper implements StoreWrapper {
|
|
39
|
-
declare _willNotify: boolean;
|
|
40
|
-
declare _pendingNotifies: Map<StableRecordIdentifier, Map<string, string>>;
|
|
41
|
-
declare _store: Store;
|
|
42
|
-
|
|
43
|
-
constructor(_store: Store) {
|
|
44
|
-
this._store = _store;
|
|
45
|
-
this._willNotify = false;
|
|
46
|
-
this._pendingNotifies = new Map();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
get identifierCache(): IdentifierCache {
|
|
50
|
-
return this._store.identifierCache;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
_scheduleNotification(identifier: StableRecordIdentifier, key: string, kind: 'belongsTo' | 'hasMany') {
|
|
54
|
-
let pending = this._pendingNotifies.get(identifier);
|
|
55
|
-
|
|
56
|
-
if (!pending) {
|
|
57
|
-
pending = new Map();
|
|
58
|
-
this._pendingNotifies.set(identifier, pending);
|
|
59
|
-
}
|
|
60
|
-
pending.set(key, kind);
|
|
61
|
-
|
|
62
|
-
if (this._willNotify === true) {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
this._willNotify = true;
|
|
67
|
-
let backburner: any = this._store._backburner;
|
|
68
|
-
|
|
69
|
-
backburner.schedule('notify', this, this._flushNotifications);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
notifyErrorsChange(type: string, id: string, lid: string | null): void;
|
|
73
|
-
notifyErrorsChange(type: string, id: string | null, lid: string): void;
|
|
74
|
-
notifyErrorsChange(type: string, id: string | null, lid: string | null): void {
|
|
75
|
-
const resource = constructResource(type, id, lid);
|
|
76
|
-
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
|
|
77
|
-
|
|
78
|
-
let internalModel = internalModelFactoryFor(this._store).peek(identifier);
|
|
79
|
-
|
|
80
|
-
if (internalModel) {
|
|
81
|
-
internalModel.notifyErrorsChange();
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
_flushNotifications(): void {
|
|
86
|
-
if (this._willNotify === false) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
let pending = this._pendingNotifies;
|
|
91
|
-
this._pendingNotifies = new Map();
|
|
92
|
-
this._willNotify = false;
|
|
93
|
-
const factory = internalModelFactoryFor(this._store);
|
|
94
|
-
|
|
95
|
-
pending.forEach((map, identifier) => {
|
|
96
|
-
const internalModel = factory.peek(identifier);
|
|
97
|
-
if (internalModel) {
|
|
98
|
-
map.forEach((kind, key) => {
|
|
99
|
-
if (kind === 'belongsTo') {
|
|
100
|
-
internalModel.notifyBelongsToChange(key);
|
|
101
|
-
} else {
|
|
102
|
-
internalModel.notifyHasManyChange(key);
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
attributesDefinitionFor(type: string): AttributesSchema {
|
|
110
|
-
return this._store.getSchemaDefinitionService().attributesDefinitionFor({ type });
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
relationshipsDefinitionFor(type: string): RelationshipsSchema {
|
|
114
|
-
return this._store.getSchemaDefinitionService().relationshipsDefinitionFor({ type });
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
inverseForRelationship(type: string, key: string): string | null {
|
|
118
|
-
const modelClass = this._store.modelFor(type);
|
|
119
|
-
const definition = this.relationshipsDefinitionFor(type)[key];
|
|
120
|
-
if (!definition) {
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (metaIsRelationshipDefinition(definition)) {
|
|
125
|
-
return definition._inverseKey(this._store, modelClass);
|
|
126
|
-
} else if (definition.options && definition.options.inverse !== undefined) {
|
|
127
|
-
return definition.options.inverse;
|
|
128
|
-
} else {
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
inverseIsAsyncForRelationship(type: string, key: string): boolean {
|
|
134
|
-
const modelClass = this._store.modelFor(type);
|
|
135
|
-
const definition = this.relationshipsDefinitionFor(type)[key];
|
|
136
|
-
if (!definition) {
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (definition.options && definition.options.inverse === null) {
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
if ((definition as unknown as { inverseIsAsync?: boolean }).inverseIsAsync !== undefined) {
|
|
144
|
-
// TODO do we need to amend the RFC for this prop?
|
|
145
|
-
// else we should add it to the TS interface and document.
|
|
146
|
-
return !!(definition as unknown as { inverseIsAsync: boolean }).inverseIsAsync;
|
|
147
|
-
} else if (metaIsRelationshipDefinition(definition)) {
|
|
148
|
-
return definition._inverseIsAsync(this._store, modelClass);
|
|
149
|
-
} else {
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
notifyPropertyChange(type: string, id: string | null, lid: string, key?: string): void;
|
|
155
|
-
notifyPropertyChange(type: string, id: string, lid: string | null | undefined, key?: string): void;
|
|
156
|
-
notifyPropertyChange(type: string, id: string | null, lid: string | null | undefined, key?: string): void {
|
|
157
|
-
const resource = constructResource(type, id, lid);
|
|
158
|
-
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
|
|
159
|
-
let internalModel = internalModelFactoryFor(this._store).peek(identifier);
|
|
160
|
-
|
|
161
|
-
if (internalModel) {
|
|
162
|
-
internalModel.notifyAttributes(key ? [key] : []);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
notifyHasManyChange(type: string, id: string | null, lid: string, key: string): void;
|
|
167
|
-
notifyHasManyChange(type: string, id: string, lid: string | null | undefined, key: string): void;
|
|
168
|
-
notifyHasManyChange(type: string, id: string | null, lid: string | null | undefined, key: string): void {
|
|
169
|
-
const resource = constructResource(type, id, lid);
|
|
170
|
-
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
|
|
171
|
-
this._scheduleNotification(identifier, key, 'hasMany');
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
notifyBelongsToChange(type: string, id: string | null, lid: string, key: string): void;
|
|
175
|
-
notifyBelongsToChange(type: string, id: string, lid: string | null | undefined, key: string): void;
|
|
176
|
-
notifyBelongsToChange(type: string, id: string | null, lid: string | null | undefined, key: string): void {
|
|
177
|
-
const resource = constructResource(type, id, lid);
|
|
178
|
-
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
|
|
179
|
-
|
|
180
|
-
this._scheduleNotification(identifier, key, 'belongsTo');
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
notifyStateChange(type: string, id: string, lid: string | null, key?: string): void;
|
|
184
|
-
notifyStateChange(type: string, id: string | null, lid: string, key?: string): void;
|
|
185
|
-
notifyStateChange(type: string, id: string | null, lid: string | null, key?: string): void {
|
|
186
|
-
const resource = constructResource(type, id, lid);
|
|
187
|
-
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
|
|
188
|
-
let internalModel = internalModelFactoryFor(this._store).peek(identifier);
|
|
189
|
-
|
|
190
|
-
if (internalModel) {
|
|
191
|
-
internalModel.notifyStateChange(key);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
recordDataFor(type: string, id: string, lid?: string | null): RecordData;
|
|
196
|
-
recordDataFor(type: string, id: string | null, lid: string): RecordData;
|
|
197
|
-
recordDataFor(type: string): RecordData;
|
|
198
|
-
recordDataFor(type: string, id?: string | null, lid?: string | null): RecordData {
|
|
199
|
-
let identifier: StableRecordIdentifier | { type: string };
|
|
200
|
-
let isCreate: boolean = false;
|
|
201
|
-
if (!id && !lid) {
|
|
202
|
-
isCreate = true;
|
|
203
|
-
identifier = { type };
|
|
204
|
-
} else {
|
|
205
|
-
const resource = constructResource(type, id, lid);
|
|
206
|
-
identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
return this._store._instanceCache.recordDataFor(identifier, isCreate);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
setRecordId(type: string, id: string, lid: string) {
|
|
213
|
-
this._store._instanceCache.setRecordId(type, id, lid);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
isRecordInUse(type: string, id: string | null, lid: string): boolean;
|
|
217
|
-
isRecordInUse(type: string, id: string, lid?: string | null): boolean;
|
|
218
|
-
isRecordInUse(type: string, id: string | null, lid?: string | null): boolean {
|
|
219
|
-
const resource = constructResource(type, id, lid);
|
|
220
|
-
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
|
|
221
|
-
|
|
222
|
-
const record = this._store._instanceCache.peek({ identifier, bucket: 'record' });
|
|
223
|
-
|
|
224
|
-
return record ? !(record.isDestroyed || record.isDestroying) : false;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
disconnectRecord(type: string, id: string | null, lid: string): void;
|
|
228
|
-
disconnectRecord(type: string, id: string, lid?: string | null): void;
|
|
229
|
-
disconnectRecord(type: string, id: string | null, lid?: string | null): void {
|
|
230
|
-
const resource = constructResource(type, id, lid);
|
|
231
|
-
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
|
|
232
|
-
if (HAS_RECORD_DATA_PACKAGE) {
|
|
233
|
-
let graph = peekGraph(this);
|
|
234
|
-
if (graph) {
|
|
235
|
-
graph.remove(identifier);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
let internalModel = internalModelFactoryFor(this._store).peek(identifier);
|
|
239
|
-
if (internalModel) {
|
|
240
|
-
internalModel.destroyFromRecordData();
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { DEBUG } from '@glimmer/env';
|
|
2
|
-
|
|
3
|
-
import type { RecordIdentifier, StableRecordIdentifier } from '@ember-data/types/q/identifier';
|
|
4
|
-
|
|
5
|
-
import type Store from './core-store';
|
|
6
|
-
import WeakCache from './weak-cache';
|
|
7
|
-
|
|
8
|
-
type UnsubscribeToken = Object;
|
|
9
|
-
|
|
10
|
-
const Cache = new WeakCache<StableRecordIdentifier, Map<UnsubscribeToken, NotificationCallback>>(
|
|
11
|
-
DEBUG ? 'subscribers' : ''
|
|
12
|
-
);
|
|
13
|
-
Cache._generator = () => new Map();
|
|
14
|
-
const Tokens = new WeakCache<UnsubscribeToken, StableRecordIdentifier>(DEBUG ? 'identifier' : '');
|
|
15
|
-
|
|
16
|
-
export type NotificationType =
|
|
17
|
-
| 'attributes'
|
|
18
|
-
| 'relationships'
|
|
19
|
-
| 'identity'
|
|
20
|
-
| 'errors'
|
|
21
|
-
| 'meta'
|
|
22
|
-
| 'unload'
|
|
23
|
-
| 'state'
|
|
24
|
-
| 'property'; // 'property' is an internal EmberData only transition period concept.
|
|
25
|
-
|
|
26
|
-
export interface NotificationCallback {
|
|
27
|
-
(identifier: RecordIdentifier, notificationType: 'attributes' | 'relationships' | 'property', key?: string): void;
|
|
28
|
-
(identifier: RecordIdentifier, notificationType: 'errors' | 'meta' | 'identity' | 'unload' | 'state'): void;
|
|
29
|
-
(identifier: StableRecordIdentifier, notificationType: NotificationType, key?: string): void;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function unsubscribe(token: UnsubscribeToken) {
|
|
33
|
-
let identifier = Tokens.get(token);
|
|
34
|
-
if (!identifier) {
|
|
35
|
-
throw new Error('Passed unknown unsubscribe token to unsubscribe');
|
|
36
|
-
}
|
|
37
|
-
Tokens.delete(token);
|
|
38
|
-
const map = Cache.get(identifier);
|
|
39
|
-
map?.delete(token);
|
|
40
|
-
}
|
|
41
|
-
/*
|
|
42
|
-
Currently only support a single callback per identifier
|
|
43
|
-
*/
|
|
44
|
-
export default class NotificationManager {
|
|
45
|
-
constructor(private store: Store) {}
|
|
46
|
-
|
|
47
|
-
subscribe(identifier: RecordIdentifier, callback: NotificationCallback): UnsubscribeToken {
|
|
48
|
-
let stableIdentifier = this.store.identifierCache.getOrCreateRecordIdentifier(identifier);
|
|
49
|
-
let map = Cache.lookup(stableIdentifier);
|
|
50
|
-
let unsubToken = {};
|
|
51
|
-
map.set(unsubToken, callback);
|
|
52
|
-
Tokens.set(unsubToken, stableIdentifier);
|
|
53
|
-
return unsubToken;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
unsubscribe(token: UnsubscribeToken) {
|
|
57
|
-
unsubscribe(token);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
notify(identifier: RecordIdentifier, value: 'attributes' | 'relationships' | 'property', key?: string): boolean;
|
|
61
|
-
notify(identifier: RecordIdentifier, value: 'errors' | 'meta' | 'identity' | 'unload' | 'state'): boolean;
|
|
62
|
-
notify(identifier: RecordIdentifier, value: NotificationType, key?: string): boolean {
|
|
63
|
-
let stableIdentifier = this.store.identifierCache.getOrCreateRecordIdentifier(identifier);
|
|
64
|
-
let callbackMap = Cache.get(stableIdentifier);
|
|
65
|
-
if (!callbackMap || !callbackMap.size) {
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
callbackMap.forEach((cb) => {
|
|
69
|
-
cb(stableIdentifier, value, key);
|
|
70
|
-
});
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
}
|