@ember-data/store 4.1.0-alpha.9 → 4.2.0-alpha.2
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/identifiers/cache.ts +3 -5
- package/addon/-private/identifiers/utils/uuid-v4.ts +0 -13
- package/addon/-private/index.ts +0 -1
- package/addon/-private/system/core-store.ts +151 -513
- package/addon/-private/system/ds-model-store.ts +14 -65
- package/addon/-private/system/fetch-manager.ts +10 -6
- package/addon/-private/system/model/internal-model.ts +123 -360
- package/addon/-private/system/model/states.js +3 -9
- package/addon/-private/system/record-array-manager.js +5 -33
- package/addon/-private/system/record-arrays/adapter-populated-record-array.js +2 -3
- package/addon/-private/system/record-notification-manager.ts +14 -6
- package/addon/-private/system/references/{belongs-to.js → belongs-to.ts} +83 -19
- package/addon/-private/system/references/{has-many.js → has-many.ts} +126 -49
- package/addon/-private/system/references/record.ts +37 -6
- package/addon/-private/system/references/reference.ts +4 -26
- package/addon/-private/system/request-cache.ts +6 -7
- package/addon/-private/system/snapshot.ts +23 -50
- package/addon/-private/system/store/finders.js +6 -69
- package/addon/-private/system/store/record-data-store-wrapper.ts +17 -24
- package/addon/-private/ts-interfaces/ds-model.ts +1 -0
- package/addon/-private/ts-interfaces/fetch-manager.ts +4 -0
- package/addon/-private/ts-interfaces/identifier.ts +2 -3
- package/index.js +3 -0
- package/package.json +13 -12
- package/addon/-private/utils/symbol.ts +0 -33
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { assert } from '@ember/debug';
|
|
5
5
|
|
|
6
|
-
import { REQUEST_SERVICE } from '@ember-data/canary-features';
|
|
7
6
|
/*
|
|
8
7
|
This file encapsulates the various states that a record can transition
|
|
9
8
|
through during its lifecycle.
|
|
@@ -431,6 +430,8 @@ createdState.uncommitted.rollback = function (internalModel) {
|
|
|
431
430
|
};
|
|
432
431
|
|
|
433
432
|
createdState.uncommitted.pushedData = function (internalModel) {
|
|
433
|
+
// TODO @runspired consider where to do this once we kill off state machine
|
|
434
|
+
internalModel.store._notificationManager.notify(internalModel.identifier, 'identity');
|
|
434
435
|
internalModel.transitionTo('loaded.updated.uncommitted');
|
|
435
436
|
internalModel.triggerLater('didLoad');
|
|
436
437
|
};
|
|
@@ -494,9 +495,6 @@ const RootState = {
|
|
|
494
495
|
|
|
495
496
|
// EVENTS
|
|
496
497
|
loadingData(internalModel, promise) {
|
|
497
|
-
if (!REQUEST_SERVICE) {
|
|
498
|
-
internalModel._promiseProxy = promise;
|
|
499
|
-
}
|
|
500
498
|
internalModel.transitionTo('loading');
|
|
501
499
|
},
|
|
502
500
|
|
|
@@ -587,11 +585,7 @@ const RootState = {
|
|
|
587
585
|
internalModel.transitionTo('updated.inFlight');
|
|
588
586
|
},
|
|
589
587
|
|
|
590
|
-
reloadRecord(
|
|
591
|
-
if (!REQUEST_SERVICE) {
|
|
592
|
-
resolve(internalModel.store._reloadRecord(internalModel, options));
|
|
593
|
-
}
|
|
594
|
-
},
|
|
588
|
+
reloadRecord() {},
|
|
595
589
|
|
|
596
590
|
deleteRecord(internalModel) {
|
|
597
591
|
internalModel.transitionTo('deleted.uncommitted');
|
|
@@ -5,11 +5,8 @@
|
|
|
5
5
|
import { A } from '@ember/array';
|
|
6
6
|
import { assert } from '@ember/debug';
|
|
7
7
|
import { get, set } from '@ember/object';
|
|
8
|
-
import { assign } from '@ember/polyfills';
|
|
9
8
|
import { _backburner as emberBackburner } from '@ember/runloop';
|
|
10
9
|
|
|
11
|
-
import { REMOVE_RECORD_ARRAY_MANAGER_LEGACY_COMPAT } from '@ember-data/canary-features';
|
|
12
|
-
|
|
13
10
|
import isStableIdentifier from '../identifiers/is-stable-identifier';
|
|
14
11
|
import { AdapterPopulatedRecordArray, RecordArray } from './record-arrays';
|
|
15
12
|
import { internalModelFactoryFor } from './store/internal-model-factory';
|
|
@@ -28,11 +25,10 @@ export function recordArraysForIdentifier(identifierOrInternalModel) {
|
|
|
28
25
|
}
|
|
29
26
|
|
|
30
27
|
const pendingForIdentifier = new Set([]);
|
|
31
|
-
const IMDematerializing = new WeakMap();
|
|
32
28
|
|
|
33
29
|
const getIdentifier = function getIdentifier(identifierOrInternalModel) {
|
|
34
30
|
let i = identifierOrInternalModel;
|
|
35
|
-
if (!
|
|
31
|
+
if (!isStableIdentifier(identifierOrInternalModel)) {
|
|
36
32
|
// identifier may actually be an internalModel
|
|
37
33
|
// but during materialization we will get an identifier that
|
|
38
34
|
// has already been removed from the identifiers cache yet
|
|
@@ -43,18 +39,7 @@ const getIdentifier = function getIdentifier(identifierOrInternalModel) {
|
|
|
43
39
|
return i;
|
|
44
40
|
};
|
|
45
41
|
|
|
46
|
-
// REMOVE_RECORD_ARRAY_MANAGER_LEGACY_COMPAT only
|
|
47
42
|
const peekIMCache = function peekIMCache(cache, identifier) {
|
|
48
|
-
if (!REMOVE_RECORD_ARRAY_MANAGER_LEGACY_COMPAT) {
|
|
49
|
-
let im = IMDematerializing.get(identifier);
|
|
50
|
-
if (im === undefined) {
|
|
51
|
-
// if not im._isDematerializing
|
|
52
|
-
im = cache.peek(identifier);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return im;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
43
|
return cache.peek(identifier);
|
|
59
44
|
};
|
|
60
45
|
|
|
@@ -281,8 +266,8 @@ class RecordArrayManager {
|
|
|
281
266
|
manager: this,
|
|
282
267
|
isLoaded: true,
|
|
283
268
|
isUpdating: false,
|
|
284
|
-
meta:
|
|
285
|
-
links:
|
|
269
|
+
meta: { ...payload.meta },
|
|
270
|
+
links: { ...payload.links },
|
|
286
271
|
});
|
|
287
272
|
|
|
288
273
|
this._associateWithRecordArray(identifiers, array);
|
|
@@ -352,14 +337,6 @@ class RecordArrayManager {
|
|
|
352
337
|
let modelName = identifier.type;
|
|
353
338
|
identifier = getIdentifier(identifier);
|
|
354
339
|
|
|
355
|
-
if (!REMOVE_RECORD_ARRAY_MANAGER_LEGACY_COMPAT) {
|
|
356
|
-
const cache = internalModelFactoryFor(this.store);
|
|
357
|
-
const im = peekIMCache(cache, identifier);
|
|
358
|
-
if (im && im._isDematerializing) {
|
|
359
|
-
IMDematerializing.set(identifier, im);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
340
|
if (pendingForIdentifier.has(identifier)) {
|
|
364
341
|
return;
|
|
365
342
|
}
|
|
@@ -429,15 +406,10 @@ const updateLiveRecordArray = function updateLiveRecordArray(store, recordArray,
|
|
|
429
406
|
};
|
|
430
407
|
|
|
431
408
|
const pushIdentifiers = function pushIdentifiers(recordArray, identifiers, cache) {
|
|
432
|
-
|
|
433
|
-
// deprecate('not allowed to use this intimate api any more');
|
|
434
|
-
recordArray._pushInternalModels(identifiers.map((i) => peekIMCache(cache, i)));
|
|
435
|
-
} else {
|
|
436
|
-
recordArray._pushIdentifiers(identifiers);
|
|
437
|
-
}
|
|
409
|
+
recordArray._pushIdentifiers(identifiers);
|
|
438
410
|
};
|
|
439
411
|
const removeIdentifiers = function removeIdentifiers(recordArray, identifiers, cache) {
|
|
440
|
-
if (!
|
|
412
|
+
if (!recordArray._removeIdentifiers) {
|
|
441
413
|
// deprecate('not allowed to use this intimate api any more');
|
|
442
414
|
recordArray._removeInternalModels(identifiers.map((i) => peekIMCache(cache, i)));
|
|
443
415
|
} else {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { A } from '@ember/array';
|
|
2
2
|
import { get } from '@ember/object';
|
|
3
|
-
import { assign } from '@ember/polyfills';
|
|
4
3
|
import { once } from '@ember/runloop';
|
|
5
4
|
import { DEBUG } from '@glimmer/env';
|
|
6
5
|
|
|
@@ -86,8 +85,8 @@ let AdapterPopulatedRecordArray = RecordArray.extend({
|
|
|
86
85
|
this.setProperties({
|
|
87
86
|
isLoaded: true,
|
|
88
87
|
isUpdating: false,
|
|
89
|
-
meta:
|
|
90
|
-
links:
|
|
88
|
+
meta: { ...payload.meta },
|
|
89
|
+
links: { ...payload.links },
|
|
91
90
|
});
|
|
92
91
|
|
|
93
92
|
this.manager._associateWithRecordArray(identifiersOrInternalModels, this);
|
|
@@ -4,7 +4,7 @@ import type CoreStore from './core-store';
|
|
|
4
4
|
|
|
5
5
|
type UnsubscribeToken = Object;
|
|
6
6
|
|
|
7
|
-
const Cache = new WeakMap<StableRecordIdentifier, NotificationCallback
|
|
7
|
+
const Cache = new WeakMap<StableRecordIdentifier, Map<UnsubscribeToken, NotificationCallback>>();
|
|
8
8
|
const Tokens = new WeakMap<UnsubscribeToken, StableRecordIdentifier>();
|
|
9
9
|
|
|
10
10
|
export type NotificationType =
|
|
@@ -29,7 +29,8 @@ export function unsubscribe(token: UnsubscribeToken) {
|
|
|
29
29
|
throw new Error('Passed unknown unsubscribe token to unsubscribe');
|
|
30
30
|
}
|
|
31
31
|
Tokens.delete(token);
|
|
32
|
-
Cache.
|
|
32
|
+
const map = Cache.get(identifier);
|
|
33
|
+
map?.delete(token);
|
|
33
34
|
}
|
|
34
35
|
/*
|
|
35
36
|
Currently only support a single callback per identifier
|
|
@@ -39,8 +40,13 @@ export default class NotificationManager {
|
|
|
39
40
|
|
|
40
41
|
subscribe(identifier: RecordIdentifier, callback: NotificationCallback): UnsubscribeToken {
|
|
41
42
|
let stableIdentifier = identifierCacheFor(this.store).getOrCreateRecordIdentifier(identifier);
|
|
42
|
-
Cache.
|
|
43
|
+
let map = Cache.get(stableIdentifier);
|
|
44
|
+
if (map === undefined) {
|
|
45
|
+
map = new Map();
|
|
46
|
+
Cache.set(stableIdentifier, map);
|
|
47
|
+
}
|
|
43
48
|
let unsubToken = {};
|
|
49
|
+
map.set(unsubToken, callback);
|
|
44
50
|
Tokens.set(unsubToken, stableIdentifier);
|
|
45
51
|
return unsubToken;
|
|
46
52
|
}
|
|
@@ -49,11 +55,13 @@ export default class NotificationManager {
|
|
|
49
55
|
notify(identifier: RecordIdentifier, value: 'errors' | 'meta' | 'identity' | 'unload' | 'state'): boolean;
|
|
50
56
|
notify(identifier: RecordIdentifier, value: NotificationType, key?: string): boolean {
|
|
51
57
|
let stableIdentifier = identifierCacheFor(this.store).getOrCreateRecordIdentifier(identifier);
|
|
52
|
-
let
|
|
53
|
-
if (!
|
|
58
|
+
let callbackMap = Cache.get(stableIdentifier);
|
|
59
|
+
if (!callbackMap || !callbackMap.size) {
|
|
54
60
|
return false;
|
|
55
61
|
}
|
|
56
|
-
|
|
62
|
+
callbackMap.forEach((cb) => {
|
|
63
|
+
cb(stableIdentifier, value, key);
|
|
64
|
+
});
|
|
57
65
|
return true;
|
|
58
66
|
}
|
|
59
67
|
}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { deprecate } from '@ember/debug';
|
|
2
|
+
import { dependentKeyCompat } from '@ember/object/compat';
|
|
3
|
+
import { cached, tracked } from '@glimmer/tracking';
|
|
2
4
|
|
|
3
5
|
import { resolve } from 'rsvp';
|
|
4
6
|
|
|
5
7
|
import { DEPRECATE_BELONGS_TO_REFERENCE_PUSH } from '@ember-data/private-build-infra/deprecations';
|
|
8
|
+
import type { BelongsToRelationship } from '@ember-data/record-data/-private';
|
|
6
9
|
import { assertPolymorphicType } from '@ember-data/store/-debug';
|
|
7
10
|
|
|
11
|
+
import { SingleResourceDocument } from '../../ts-interfaces/ember-data-json-api';
|
|
12
|
+
import { StableRecordIdentifier } from '../../ts-interfaces/identifier';
|
|
13
|
+
import CoreStore from '../core-store';
|
|
14
|
+
import { NotificationType, unsubscribe } from '../record-notification-manager';
|
|
8
15
|
import { internalModelFactoryFor, peekRecordIdentifier, recordIdentifierFor } from '../store/internal-model-factory';
|
|
16
|
+
import RecordReference from './record';
|
|
9
17
|
import Reference from './reference';
|
|
10
18
|
|
|
11
19
|
/**
|
|
@@ -22,17 +30,77 @@ import Reference from './reference';
|
|
|
22
30
|
@extends Reference
|
|
23
31
|
*/
|
|
24
32
|
export default class BelongsToReference extends Reference {
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
declare key: string;
|
|
34
|
+
declare belongsToRelationship: BelongsToRelationship;
|
|
35
|
+
declare type: string;
|
|
36
|
+
declare parent: RecordReference;
|
|
37
|
+
declare parentIdentifier: StableRecordIdentifier;
|
|
38
|
+
|
|
39
|
+
// unsubscribe tokens given to us by the notification manager
|
|
40
|
+
#token!: Object;
|
|
41
|
+
#relatedToken: Object | null = null;
|
|
42
|
+
|
|
43
|
+
@tracked _ref = 0;
|
|
44
|
+
|
|
45
|
+
constructor(
|
|
46
|
+
store: CoreStore,
|
|
47
|
+
parentIdentifier: StableRecordIdentifier,
|
|
48
|
+
belongsToRelationship: BelongsToRelationship,
|
|
49
|
+
key: string
|
|
50
|
+
) {
|
|
51
|
+
super(store, parentIdentifier);
|
|
27
52
|
this.key = key;
|
|
28
53
|
this.belongsToRelationship = belongsToRelationship;
|
|
29
54
|
this.type = belongsToRelationship.definition.type;
|
|
30
|
-
|
|
31
|
-
this.
|
|
55
|
+
const parent = internalModelFactoryFor(store).peek(parentIdentifier);
|
|
56
|
+
this.parent = parent!.recordReference;
|
|
57
|
+
this.parentIdentifier = parentIdentifier;
|
|
58
|
+
|
|
59
|
+
this.#token = store._notificationManager.subscribe(
|
|
60
|
+
parentIdentifier,
|
|
61
|
+
(_: StableRecordIdentifier, bucket: NotificationType, notifiedKey?: string) => {
|
|
62
|
+
if ((bucket === 'relationships' || bucket === 'property') && notifiedKey === key) {
|
|
63
|
+
this._ref++;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
);
|
|
32
67
|
|
|
33
68
|
// TODO inverse
|
|
34
69
|
}
|
|
35
70
|
|
|
71
|
+
destroy() {
|
|
72
|
+
unsubscribe(this.#token);
|
|
73
|
+
if (this.#relatedToken) {
|
|
74
|
+
unsubscribe(this.#relatedToken);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@cached
|
|
79
|
+
@dependentKeyCompat
|
|
80
|
+
get _relatedIdentifier(): StableRecordIdentifier | null {
|
|
81
|
+
this._ref; // consume the tracked prop
|
|
82
|
+
if (this.#relatedToken) {
|
|
83
|
+
unsubscribe(this.#relatedToken);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let resource = this._resource();
|
|
87
|
+
if (resource && resource.data) {
|
|
88
|
+
const identifier = this.store.identifierCache.getOrCreateRecordIdentifier(resource.data);
|
|
89
|
+
this.#relatedToken = this.store._notificationManager.subscribe(
|
|
90
|
+
identifier,
|
|
91
|
+
(_: StableRecordIdentifier, bucket: NotificationType, notifiedKey?: string) => {
|
|
92
|
+
if (bucket === 'identity' || ((bucket === 'attributes' || bucket === 'property') && notifiedKey === 'id')) {
|
|
93
|
+
this._ref++;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return identifier;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
36
104
|
/**
|
|
37
105
|
The `id` of the record that this reference refers to. Together, the
|
|
38
106
|
`type()` and `id()` methods form a composite key for the identity
|
|
@@ -73,13 +141,8 @@ export default class BelongsToReference extends Reference {
|
|
|
73
141
|
@public
|
|
74
142
|
@return {String} The id of the record in this belongsTo relationship.
|
|
75
143
|
*/
|
|
76
|
-
id() {
|
|
77
|
-
|
|
78
|
-
let resource = this._resource();
|
|
79
|
-
if (resource && resource.data) {
|
|
80
|
-
id = resource.data.id;
|
|
81
|
-
}
|
|
82
|
-
return id;
|
|
144
|
+
id(): string | null {
|
|
145
|
+
return this._relatedIdentifier?.id || null;
|
|
83
146
|
}
|
|
84
147
|
|
|
85
148
|
_resource() {
|
|
@@ -132,10 +195,10 @@ export default class BelongsToReference extends Reference {
|
|
|
132
195
|
@param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship.
|
|
133
196
|
@return {Promise<record>} A promise that resolves with the new value in this belongs-to relationship.
|
|
134
197
|
*/
|
|
135
|
-
push(objectOrPromise) {
|
|
198
|
+
async push(objectOrPromise: Object | SingleResourceDocument): Promise<Object> {
|
|
136
199
|
// TODO deprecate thenable support
|
|
137
200
|
return resolve(objectOrPromise).then((data) => {
|
|
138
|
-
let record;
|
|
201
|
+
let record: Object;
|
|
139
202
|
|
|
140
203
|
if (DEPRECATE_BELONGS_TO_REFERENCE_PUSH && peekRecordIdentifier(data)) {
|
|
141
204
|
deprecate('Pushing a record into a BelongsToReference is deprecated', false, {
|
|
@@ -147,15 +210,16 @@ export default class BelongsToReference extends Reference {
|
|
|
147
210
|
enabled: '3.16',
|
|
148
211
|
},
|
|
149
212
|
});
|
|
150
|
-
record = data;
|
|
213
|
+
record = data as Object;
|
|
151
214
|
} else {
|
|
152
|
-
record = this.store.push(data);
|
|
215
|
+
record = this.store.push(data as SingleResourceDocument);
|
|
153
216
|
}
|
|
154
217
|
|
|
218
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
155
219
|
assertPolymorphicType(
|
|
156
220
|
this.belongsToRelationship.identifier,
|
|
157
221
|
this.belongsToRelationship.definition,
|
|
158
|
-
record
|
|
222
|
+
recordIdentifierFor(record),
|
|
159
223
|
this.store
|
|
160
224
|
);
|
|
161
225
|
|
|
@@ -223,7 +287,7 @@ export default class BelongsToReference extends Reference {
|
|
|
223
287
|
@public
|
|
224
288
|
@return {Model} the record in this relationship
|
|
225
289
|
*/
|
|
226
|
-
value() {
|
|
290
|
+
value(): Object | null {
|
|
227
291
|
let resource = this._resource();
|
|
228
292
|
if (resource && resource.data) {
|
|
229
293
|
let inverseInternalModel = this.store._internalModelForResource(resource.data);
|
|
@@ -299,7 +363,7 @@ export default class BelongsToReference extends Reference {
|
|
|
299
363
|
*/
|
|
300
364
|
load(options) {
|
|
301
365
|
let parentInternalModel = internalModelFactoryFor(this.store).peek(this.parentIdentifier);
|
|
302
|
-
return parentInternalModel
|
|
366
|
+
return parentInternalModel!.getBelongsTo(this.key, options);
|
|
303
367
|
}
|
|
304
368
|
|
|
305
369
|
/**
|
|
@@ -354,7 +418,7 @@ export default class BelongsToReference extends Reference {
|
|
|
354
418
|
*/
|
|
355
419
|
reload(options) {
|
|
356
420
|
let parentInternalModel = internalModelFactoryFor(this.store).peek(this.parentIdentifier);
|
|
357
|
-
return parentInternalModel
|
|
421
|
+
return parentInternalModel!.reloadBelongsTo(this.key, options).then((internalModel) => {
|
|
358
422
|
return this.value();
|
|
359
423
|
});
|
|
360
424
|
}
|
|
@@ -1,10 +1,22 @@
|
|
|
1
|
+
import { dependentKeyCompat } from '@ember/object/compat';
|
|
1
2
|
import { DEBUG } from '@glimmer/env';
|
|
3
|
+
import { cached, tracked } from '@glimmer/tracking';
|
|
2
4
|
|
|
3
5
|
import { resolve } from 'rsvp';
|
|
4
6
|
|
|
7
|
+
import type { ManyRelationship } from '@ember-data/record-data/-private';
|
|
5
8
|
import { assertPolymorphicType } from '@ember-data/store/-debug';
|
|
6
9
|
|
|
10
|
+
import {
|
|
11
|
+
CollectionResourceDocument,
|
|
12
|
+
ExistingResourceObject,
|
|
13
|
+
SingleResourceDocument,
|
|
14
|
+
} from '../../ts-interfaces/ember-data-json-api';
|
|
15
|
+
import { StableRecordIdentifier } from '../../ts-interfaces/identifier';
|
|
16
|
+
import CoreStore from '../core-store';
|
|
17
|
+
import { NotificationType, unsubscribe } from '../record-notification-manager';
|
|
7
18
|
import { internalModelFactoryFor, recordIdentifierFor } from '../store/internal-model-factory';
|
|
19
|
+
import RecordReference from './record';
|
|
8
20
|
import Reference, { internalModelForReference } from './reference';
|
|
9
21
|
|
|
10
22
|
/**
|
|
@@ -20,17 +32,84 @@ import Reference, { internalModelForReference } from './reference';
|
|
|
20
32
|
@extends Reference
|
|
21
33
|
*/
|
|
22
34
|
export default class HasManyReference extends Reference {
|
|
23
|
-
|
|
24
|
-
|
|
35
|
+
declare key: string;
|
|
36
|
+
declare hasManyRelationship: ManyRelationship;
|
|
37
|
+
declare type: string;
|
|
38
|
+
declare parent: RecordReference;
|
|
39
|
+
declare parentIdentifier: StableRecordIdentifier;
|
|
40
|
+
|
|
41
|
+
// unsubscribe tokens given to us by the notification manager
|
|
42
|
+
#token!: Object;
|
|
43
|
+
#relatedTokenMap!: Map<StableRecordIdentifier, Object>;
|
|
44
|
+
|
|
45
|
+
@tracked _ref = 0;
|
|
46
|
+
|
|
47
|
+
constructor(
|
|
48
|
+
store: CoreStore,
|
|
49
|
+
parentIdentifier: StableRecordIdentifier,
|
|
50
|
+
hasManyRelationship: ManyRelationship,
|
|
51
|
+
key: string
|
|
52
|
+
) {
|
|
53
|
+
super(store, parentIdentifier);
|
|
25
54
|
this.key = key;
|
|
26
55
|
this.hasManyRelationship = hasManyRelationship;
|
|
27
56
|
this.type = hasManyRelationship.definition.type;
|
|
28
57
|
|
|
29
|
-
this.parent = internalModelFactoryFor(store).peek(
|
|
58
|
+
this.parent = internalModelFactoryFor(store).peek(parentIdentifier)!.recordReference;
|
|
30
59
|
|
|
60
|
+
this.#token = store._notificationManager.subscribe(
|
|
61
|
+
parentIdentifier,
|
|
62
|
+
(_: StableRecordIdentifier, bucket: NotificationType, notifiedKey?: string) => {
|
|
63
|
+
if ((bucket === 'relationships' || bucket === 'property') && notifiedKey === key) {
|
|
64
|
+
this._ref++;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
this.#relatedTokenMap = new Map();
|
|
31
69
|
// TODO inverse
|
|
32
70
|
}
|
|
33
71
|
|
|
72
|
+
destroy() {
|
|
73
|
+
unsubscribe(this.#token);
|
|
74
|
+
this.#relatedTokenMap.forEach((token) => {
|
|
75
|
+
unsubscribe(token);
|
|
76
|
+
});
|
|
77
|
+
this.#relatedTokenMap.clear();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@cached
|
|
81
|
+
@dependentKeyCompat
|
|
82
|
+
get _relatedIdentifiers(): StableRecordIdentifier[] {
|
|
83
|
+
this._ref; // consume the tracked prop
|
|
84
|
+
|
|
85
|
+
let resource = this._resource();
|
|
86
|
+
|
|
87
|
+
this.#relatedTokenMap.forEach((token) => {
|
|
88
|
+
unsubscribe(token);
|
|
89
|
+
});
|
|
90
|
+
this.#relatedTokenMap.clear();
|
|
91
|
+
|
|
92
|
+
if (resource && resource.data) {
|
|
93
|
+
return resource.data.map((resourceIdentifier) => {
|
|
94
|
+
const identifier = this.store.identifierCache.getOrCreateRecordIdentifier(resourceIdentifier);
|
|
95
|
+
const token = this.store._notificationManager.subscribe(
|
|
96
|
+
identifier,
|
|
97
|
+
(_: StableRecordIdentifier, bucket: NotificationType, notifiedKey?: string) => {
|
|
98
|
+
if (bucket === 'identity' || ((bucket === 'attributes' || bucket === 'property') && notifiedKey === 'id')) {
|
|
99
|
+
this._ref++;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
this.#relatedTokenMap.set(identifier, token);
|
|
105
|
+
|
|
106
|
+
return identifier;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
|
|
34
113
|
_resource() {
|
|
35
114
|
return this.recordData.getHasMany(this.key);
|
|
36
115
|
}
|
|
@@ -77,7 +156,7 @@ export default class HasManyReference extends Reference {
|
|
|
77
156
|
@public
|
|
78
157
|
@return {String} The name of the remote type. This should either be `link` or `ids`
|
|
79
158
|
*/
|
|
80
|
-
remoteType() {
|
|
159
|
+
remoteType(): 'link' | 'ids' {
|
|
81
160
|
let value = this._resource();
|
|
82
161
|
if (value && value.links && value.links.related) {
|
|
83
162
|
return 'link';
|
|
@@ -121,15 +200,8 @@ export default class HasManyReference extends Reference {
|
|
|
121
200
|
@public
|
|
122
201
|
@return {Array} The ids in this has-many relationship
|
|
123
202
|
*/
|
|
124
|
-
ids() {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
let ids = [];
|
|
128
|
-
if (resource.data) {
|
|
129
|
-
ids = resource.data.map((data) => data.id);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return ids;
|
|
203
|
+
ids(): Array<string | null> {
|
|
204
|
+
return this._relatedIdentifiers.map((identifier) => identifier.id);
|
|
133
205
|
}
|
|
134
206
|
|
|
135
207
|
/**
|
|
@@ -177,45 +249,50 @@ export default class HasManyReference extends Reference {
|
|
|
177
249
|
@param {Array|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship.
|
|
178
250
|
@return {ManyArray}
|
|
179
251
|
*/
|
|
180
|
-
push(
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
252
|
+
async push(
|
|
253
|
+
objectOrPromise: ExistingResourceObject[] | CollectionResourceDocument | { data: SingleResourceDocument[] }
|
|
254
|
+
): Promise<any> {
|
|
255
|
+
const payload = await resolve(objectOrPromise);
|
|
256
|
+
let array: Array<ExistingResourceObject | SingleResourceDocument>;
|
|
257
|
+
|
|
258
|
+
if (!Array.isArray(payload) && typeof payload === 'object' && Array.isArray(payload.data)) {
|
|
259
|
+
array = payload.data;
|
|
260
|
+
} else {
|
|
261
|
+
array = payload as ExistingResourceObject[];
|
|
262
|
+
}
|
|
187
263
|
|
|
188
|
-
|
|
264
|
+
const internalModel = internalModelForReference(this)!;
|
|
265
|
+
const { store } = this;
|
|
189
266
|
|
|
190
|
-
|
|
191
|
-
|
|
267
|
+
let identifiers = array.map((obj) => {
|
|
268
|
+
let record;
|
|
269
|
+
if ('data' in obj) {
|
|
270
|
+
// TODO deprecate pushing non-valid JSON:API here
|
|
271
|
+
record = store.push(obj);
|
|
272
|
+
} else {
|
|
273
|
+
record = store.push({ data: obj });
|
|
274
|
+
}
|
|
192
275
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
return recordIdentifierFor(record);
|
|
203
|
-
});
|
|
276
|
+
if (DEBUG) {
|
|
277
|
+
let relationshipMeta = this.hasManyRelationship.definition;
|
|
278
|
+
let identifier = this.hasManyRelationship.identifier;
|
|
279
|
+
assertPolymorphicType(identifier, relationshipMeta, recordIdentifierFor(record), store);
|
|
280
|
+
}
|
|
281
|
+
return recordIdentifierFor(record);
|
|
282
|
+
});
|
|
204
283
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
});
|
|
284
|
+
const { graph, identifier } = this.hasManyRelationship;
|
|
285
|
+
store._backburner.join(() => {
|
|
286
|
+
graph.push({
|
|
287
|
+
op: 'replaceRelatedRecords',
|
|
288
|
+
record: identifier,
|
|
289
|
+
field: this.key,
|
|
290
|
+
value: identifiers,
|
|
213
291
|
});
|
|
214
|
-
|
|
215
|
-
return internalModel.getHasMany(this.key);
|
|
216
|
-
// TODO IGOR it seems wrong that we were returning the many array here
|
|
217
|
-
//return this.hasManyRelationship.manyArray;
|
|
218
292
|
});
|
|
293
|
+
|
|
294
|
+
// TODO IGOR it seems wrong that we were returning the many array here
|
|
295
|
+
return internalModel.getHasMany(this.key);
|
|
219
296
|
}
|
|
220
297
|
|
|
221
298
|
_isLoaded() {
|
|
@@ -275,7 +352,7 @@ export default class HasManyReference extends Reference {
|
|
|
275
352
|
@return {ManyArray}
|
|
276
353
|
*/
|
|
277
354
|
value() {
|
|
278
|
-
let internalModel = internalModelForReference(this)
|
|
355
|
+
let internalModel = internalModelForReference(this)!;
|
|
279
356
|
if (this._isLoaded()) {
|
|
280
357
|
return internalModel.getManyArray(this.key);
|
|
281
358
|
}
|
|
@@ -348,7 +425,7 @@ export default class HasManyReference extends Reference {
|
|
|
348
425
|
this has-many relationship.
|
|
349
426
|
*/
|
|
350
427
|
load(options) {
|
|
351
|
-
let internalModel = internalModelForReference(this)
|
|
428
|
+
let internalModel = internalModelForReference(this)!;
|
|
352
429
|
return internalModel.getHasMany(this.key, options);
|
|
353
430
|
}
|
|
354
431
|
|
|
@@ -403,7 +480,7 @@ export default class HasManyReference extends Reference {
|
|
|
403
480
|
@return {Promise} a promise that resolves with the ManyArray in this has-many relationship.
|
|
404
481
|
*/
|
|
405
482
|
reload(options) {
|
|
406
|
-
let internalModel = internalModelForReference(this)
|
|
483
|
+
let internalModel = internalModelForReference(this)!;
|
|
407
484
|
return internalModel.reloadHasMany(this.key, options);
|
|
408
485
|
}
|
|
409
486
|
}
|