@ember-data/model 4.8.0-alpha.5 → 4.9.0-alpha.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/-private/deprecated-promise-proxy.ts +54 -0
- package/addon/-private/has-many.js +3 -1
- package/addon/-private/legacy-relationships-support.ts +168 -112
- package/addon/-private/many-array.ts +211 -249
- package/addon/-private/model.js +125 -55
- package/addon/-private/promise-belongs-to.ts +1 -1
- package/addon/-private/promise-many-array.ts +35 -13
- package/addon/-private/promise-proxy-base.js +4 -0
- package/addon/-private/references/belongs-to.ts +22 -3
- package/addon/-private/references/has-many.ts +22 -2
- package/addon/-private/relationship-meta.ts +3 -1
- package/index.js +2 -0
- package/package.json +5 -5
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { deprecate } from '@ember/debug';
|
|
2
|
+
|
|
3
|
+
import { resolve } from 'rsvp';
|
|
4
|
+
|
|
5
|
+
import { PromiseObject } from './promise-proxy-base';
|
|
6
|
+
|
|
7
|
+
function promiseObject<T>(promise: Promise<T>): PromiseObject<T> {
|
|
8
|
+
return PromiseObject.create({
|
|
9
|
+
promise: resolve(promise),
|
|
10
|
+
}) as PromiseObject<T>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// constructor is accessed in some internals but not including it in the copyright for the deprecation
|
|
14
|
+
const ALLOWABLE_METHODS = ['constructor', 'then', 'catch', 'finally'];
|
|
15
|
+
const PROXIED_OBJECT_PROPS = ['content', 'isPending', 'isSettled', 'isRejected', 'isFulfilled', 'promise', 'reason'];
|
|
16
|
+
|
|
17
|
+
export function deprecatedPromiseObject<T>(promise: Promise<T>): PromiseObject<T> {
|
|
18
|
+
const promiseObjectProxy: PromiseObject<T> = promiseObject(promise);
|
|
19
|
+
const handler = {
|
|
20
|
+
get(target: object, prop: string, receiver?: object): unknown {
|
|
21
|
+
if (typeof prop === 'symbol') {
|
|
22
|
+
return Reflect.get(target, prop, receiver);
|
|
23
|
+
}
|
|
24
|
+
if (!ALLOWABLE_METHODS.includes(prop)) {
|
|
25
|
+
deprecate(
|
|
26
|
+
`Accessing ${prop} is deprecated. The return type is being changed fomr PromiseObjectProxy to a Promise. The only available methods to access on this promise are .then, .catch and .finally`,
|
|
27
|
+
false,
|
|
28
|
+
{
|
|
29
|
+
id: 'ember-data:model-save-promise',
|
|
30
|
+
until: '5.0',
|
|
31
|
+
for: '@ember-data/store',
|
|
32
|
+
since: {
|
|
33
|
+
available: '4.4',
|
|
34
|
+
enabled: '4.4',
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const value: unknown = target[prop];
|
|
41
|
+
if (value && typeof value === 'function' && typeof value.bind === 'function') {
|
|
42
|
+
return value.bind(target);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (PROXIED_OBJECT_PROPS.includes(prop)) {
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return undefined;
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return new Proxy(promiseObjectProxy, handler);
|
|
54
|
+
}
|
|
@@ -260,8 +260,10 @@ function hasMany(type, options) {
|
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
const support = lookupLegacySupport(this);
|
|
263
|
+
const manyArray = support.getManyArray(key);
|
|
264
|
+
assert(`You must pass an array of records to set a hasMany relationship`, Array.isArray(records));
|
|
263
265
|
this.store._join(() => {
|
|
264
|
-
|
|
266
|
+
manyArray.splice(0, manyArray.length, ...records);
|
|
265
267
|
});
|
|
266
268
|
|
|
267
269
|
return support.getHasMany(key);
|
|
@@ -1,23 +1,21 @@
|
|
|
1
|
-
import { assert } from '@ember/debug';
|
|
1
|
+
import { assert, deprecate } from '@ember/debug';
|
|
2
2
|
import { DEBUG } from '@glimmer/env';
|
|
3
3
|
|
|
4
4
|
import { importSync } from '@embroider/macros';
|
|
5
5
|
import { all, resolve } from 'rsvp';
|
|
6
6
|
|
|
7
7
|
import { HAS_RECORD_DATA_PACKAGE } from '@ember-data/private-build-infra';
|
|
8
|
+
import { DEPRECATE_PROMISE_PROXIES } from '@ember-data/private-build-infra/deprecations';
|
|
8
9
|
import type { UpgradedMeta } from '@ember-data/record-data/-private/graph/-edge-definition';
|
|
10
|
+
import type { LocalRelationshipOperation } from '@ember-data/record-data/-private/graph/-operations';
|
|
9
11
|
import type { ImplicitRelationship } from '@ember-data/record-data/-private/graph/index';
|
|
10
12
|
import type BelongsToRelationship from '@ember-data/record-data/-private/relationships/state/belongs-to';
|
|
11
13
|
import type ManyRelationship from '@ember-data/record-data/-private/relationships/state/has-many';
|
|
12
14
|
import type Store from '@ember-data/store';
|
|
13
|
-
import { recordIdentifierFor, storeFor } from '@ember-data/store/-private';
|
|
14
|
-
import {
|
|
15
|
+
import { fastPush, isStableIdentifier, recordIdentifierFor, SOURCE, storeFor } from '@ember-data/store/-private';
|
|
16
|
+
import type { NonSingletonRecordDataManager } from '@ember-data/store/-private/managers/record-data-manager';
|
|
15
17
|
import type { DSModel } from '@ember-data/types/q/ds-model';
|
|
16
|
-
import {
|
|
17
|
-
CollectionResourceRelationship,
|
|
18
|
-
ResourceIdentifierObject,
|
|
19
|
-
SingleResourceRelationship,
|
|
20
|
-
} from '@ember-data/types/q/ember-data-json-api';
|
|
18
|
+
import { CollectionResourceRelationship, SingleResourceRelationship } from '@ember-data/types/q/ember-data-json-api';
|
|
21
19
|
import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
|
|
22
20
|
import type { RecordData } from '@ember-data/types/q/record-data';
|
|
23
21
|
import type { JsonApiRelationship } from '@ember-data/types/q/record-data-json-api';
|
|
@@ -27,8 +25,7 @@ import type { Dict } from '@ember-data/types/q/utils';
|
|
|
27
25
|
|
|
28
26
|
import { _findBelongsTo, _findHasMany } from './legacy-data-fetch';
|
|
29
27
|
import { assertIdentifierHasId } from './legacy-data-utils';
|
|
30
|
-
import
|
|
31
|
-
import ManyArray from './many-array';
|
|
28
|
+
import RelatedCollection from './many-array';
|
|
32
29
|
import type { BelongsToProxyCreateArgs, BelongsToProxyMeta } from './promise-belongs-to';
|
|
33
30
|
import PromiseBelongsTo from './promise-belongs-to';
|
|
34
31
|
import type { HasManyProxyCreateArgs } from './promise-many-array';
|
|
@@ -36,7 +33,6 @@ import PromiseManyArray from './promise-many-array';
|
|
|
36
33
|
import BelongsToReference from './references/belongs-to';
|
|
37
34
|
import HasManyReference from './references/has-many';
|
|
38
35
|
|
|
39
|
-
type ManyArrayFactory = { create(args: ManyArrayCreateArgs): ManyArray };
|
|
40
36
|
type PromiseBelongsToFactory = { create(args: BelongsToProxyCreateArgs): PromiseBelongsTo };
|
|
41
37
|
|
|
42
38
|
export class LegacySupport {
|
|
@@ -45,8 +41,8 @@ export class LegacySupport {
|
|
|
45
41
|
declare recordData: RecordData;
|
|
46
42
|
declare references: Dict<BelongsToReference | HasManyReference>;
|
|
47
43
|
declare identifier: StableRecordIdentifier;
|
|
48
|
-
declare _manyArrayCache: Dict<
|
|
49
|
-
declare _relationshipPromisesCache: Dict<Promise<
|
|
44
|
+
declare _manyArrayCache: Dict<RelatedCollection>;
|
|
45
|
+
declare _relationshipPromisesCache: Dict<Promise<RelatedCollection | RecordInstance>>;
|
|
50
46
|
declare _relationshipProxyCache: Dict<PromiseManyArray | PromiseBelongsTo>;
|
|
51
47
|
|
|
52
48
|
declare isDestroying: boolean;
|
|
@@ -58,12 +54,38 @@ export class LegacySupport {
|
|
|
58
54
|
this.identifier = recordIdentifierFor(record);
|
|
59
55
|
this.recordData = this.store._instanceCache.getRecordData(this.identifier);
|
|
60
56
|
|
|
61
|
-
this._manyArrayCache = Object.create(null) as Dict<
|
|
62
|
-
this._relationshipPromisesCache = Object.create(null) as Dict<Promise<
|
|
57
|
+
this._manyArrayCache = Object.create(null) as Dict<RelatedCollection>;
|
|
58
|
+
this._relationshipPromisesCache = Object.create(null) as Dict<Promise<RelatedCollection | RecordInstance>>;
|
|
63
59
|
this._relationshipProxyCache = Object.create(null) as Dict<PromiseManyArray | PromiseBelongsTo>;
|
|
64
60
|
this.references = Object.create(null) as Dict<BelongsToReference>;
|
|
65
61
|
}
|
|
66
62
|
|
|
63
|
+
_syncArray(array: RelatedCollection) {
|
|
64
|
+
// It’s possible the parent side of the relationship may have been destroyed by this point
|
|
65
|
+
if (this.isDestroyed || this.isDestroying) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const currentState = array[SOURCE];
|
|
69
|
+
const identifier = this.identifier;
|
|
70
|
+
|
|
71
|
+
let [identifiers, jsonApi] = this._getCurrentState(identifier, array.key);
|
|
72
|
+
|
|
73
|
+
if (jsonApi.meta) {
|
|
74
|
+
array.meta = jsonApi.meta;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (jsonApi.links) {
|
|
78
|
+
array.links = jsonApi.links;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
currentState.length = 0;
|
|
82
|
+
fastPush(currentState, identifiers);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
updateCache(operation: LocalRelationshipOperation): void {
|
|
86
|
+
this.recordData.update(operation);
|
|
87
|
+
}
|
|
88
|
+
|
|
67
89
|
_findBelongsTo(
|
|
68
90
|
key: string,
|
|
69
91
|
resource: SingleResourceRelationship,
|
|
@@ -104,8 +126,8 @@ export class LegacySupport {
|
|
|
104
126
|
getBelongsTo(key: string, options?: FindOptions): PromiseBelongsTo | RecordInstance | null {
|
|
105
127
|
const { identifier, recordData } = this;
|
|
106
128
|
let resource = recordData.getRelationship(this.identifier, key) as SingleResourceRelationship;
|
|
107
|
-
let relatedIdentifier =
|
|
108
|
-
|
|
129
|
+
let relatedIdentifier = resource && resource.data ? resource.data : null;
|
|
130
|
+
assert(`Expected a stable identifier`, !relatedIdentifier || isStableIdentifier(relatedIdentifier));
|
|
109
131
|
|
|
110
132
|
const store = this.store;
|
|
111
133
|
const graphFor = (
|
|
@@ -128,10 +150,11 @@ export class LegacySupport {
|
|
|
128
150
|
}
|
|
129
151
|
|
|
130
152
|
let promise = this._findBelongsTo(key, resource, relationship, options);
|
|
153
|
+
const isLoaded = relatedIdentifier && store._instanceCache.recordIsLoaded(relatedIdentifier);
|
|
131
154
|
|
|
132
155
|
return this._updatePromiseProxyFor('belongsTo', key, {
|
|
133
156
|
promise,
|
|
134
|
-
content:
|
|
157
|
+
content: isLoaded ? store._instanceCache.getRecord(relatedIdentifier!) : null,
|
|
135
158
|
_belongsToState,
|
|
136
159
|
});
|
|
137
160
|
} else {
|
|
@@ -151,53 +174,100 @@ export class LegacySupport {
|
|
|
151
174
|
}
|
|
152
175
|
|
|
153
176
|
setDirtyBelongsTo(key: string, value: RecordInstance | null) {
|
|
154
|
-
return this.recordData.
|
|
177
|
+
return this.recordData.update(
|
|
178
|
+
{
|
|
179
|
+
op: 'replaceRelatedRecord',
|
|
180
|
+
record: this.identifier,
|
|
181
|
+
field: key,
|
|
182
|
+
value: extractIdentifierFromRecord(value),
|
|
183
|
+
},
|
|
184
|
+
// @ts-expect-error
|
|
185
|
+
true
|
|
186
|
+
);
|
|
155
187
|
}
|
|
156
188
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
189
|
+
_getCurrentState(
|
|
190
|
+
identifier: StableRecordIdentifier,
|
|
191
|
+
field: string
|
|
192
|
+
): [StableRecordIdentifier[], CollectionResourceRelationship] {
|
|
193
|
+
let jsonApi = (this.recordData as NonSingletonRecordDataManager).getRelationship(
|
|
194
|
+
identifier,
|
|
195
|
+
field,
|
|
196
|
+
true
|
|
197
|
+
) as CollectionResourceRelationship;
|
|
198
|
+
const cache = this.store._instanceCache;
|
|
199
|
+
let identifiers: StableRecordIdentifier[] = [];
|
|
200
|
+
if (jsonApi.data) {
|
|
201
|
+
for (let i = 0; i < jsonApi.data.length; i++) {
|
|
202
|
+
const identifier = jsonApi.data[i];
|
|
203
|
+
assert(`Expected a stable identifier`, isStableIdentifier(identifier));
|
|
204
|
+
if (cache.recordIsLoaded(identifier, true)) {
|
|
205
|
+
identifiers.push(identifier);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
165
208
|
}
|
|
166
209
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
});
|
|
180
|
-
this._manyArrayCache[key] = manyArray;
|
|
181
|
-
}
|
|
210
|
+
return [identifiers, jsonApi];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
getManyArray(key: string, definition?: UpgradedMeta): RelatedCollection {
|
|
214
|
+
if (HAS_RECORD_DATA_PACKAGE) {
|
|
215
|
+
let manyArray: RelatedCollection | undefined = this._manyArrayCache[key];
|
|
216
|
+
if (!definition) {
|
|
217
|
+
const graphFor = (
|
|
218
|
+
importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
|
|
219
|
+
).graphFor;
|
|
220
|
+
definition = graphFor(this.store).get(this.identifier, key).definition;
|
|
221
|
+
}
|
|
182
222
|
|
|
183
|
-
|
|
223
|
+
if (!manyArray) {
|
|
224
|
+
const [identifiers, doc] = this._getCurrentState(this.identifier, key);
|
|
225
|
+
|
|
226
|
+
manyArray = new RelatedCollection({
|
|
227
|
+
store: this.store,
|
|
228
|
+
type: definition.type,
|
|
229
|
+
identifier: this.identifier,
|
|
230
|
+
recordData: this.recordData,
|
|
231
|
+
identifiers,
|
|
232
|
+
key,
|
|
233
|
+
meta: doc.meta || null,
|
|
234
|
+
links: doc.links || null,
|
|
235
|
+
isPolymorphic: definition.isPolymorphic,
|
|
236
|
+
isAsync: definition.isAsync,
|
|
237
|
+
_inverseIsAsync: definition.inverseIsAsync,
|
|
238
|
+
manager: this,
|
|
239
|
+
isLoaded: !definition.isAsync,
|
|
240
|
+
allowMutation: true,
|
|
241
|
+
});
|
|
242
|
+
this._manyArrayCache[key] = manyArray;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return manyArray;
|
|
246
|
+
}
|
|
247
|
+
assert('hasMany only works with the @ember-data/record-data package');
|
|
184
248
|
}
|
|
185
249
|
|
|
186
250
|
fetchAsyncHasMany(
|
|
187
251
|
key: string,
|
|
188
252
|
relationship: ManyRelationship,
|
|
189
|
-
manyArray:
|
|
253
|
+
manyArray: RelatedCollection,
|
|
190
254
|
options?: FindOptions
|
|
191
|
-
): Promise<
|
|
255
|
+
): Promise<RelatedCollection> {
|
|
192
256
|
if (HAS_RECORD_DATA_PACKAGE) {
|
|
193
|
-
let loadingPromise = this._relationshipPromisesCache[key] as Promise<
|
|
257
|
+
let loadingPromise = this._relationshipPromisesCache[key] as Promise<RelatedCollection> | undefined;
|
|
194
258
|
if (loadingPromise) {
|
|
195
259
|
return loadingPromise;
|
|
196
260
|
}
|
|
197
261
|
|
|
198
262
|
const jsonApi = this.recordData.getRelationship(this.identifier, key) as CollectionResourceRelationship;
|
|
263
|
+
const promise = this._findHasManyByJsonApiResource(jsonApi, this.identifier, relationship, options);
|
|
264
|
+
|
|
265
|
+
if (!promise) {
|
|
266
|
+
manyArray.isLoaded = true;
|
|
267
|
+
return resolve(manyArray);
|
|
268
|
+
}
|
|
199
269
|
|
|
200
|
-
loadingPromise =
|
|
270
|
+
loadingPromise = promise.then(
|
|
201
271
|
() => handleCompletedRelationshipRequest(this, key, relationship, manyArray),
|
|
202
272
|
(e: Error) => handleCompletedRelationshipRequest(this, key, relationship, manyArray, e)
|
|
203
273
|
);
|
|
@@ -233,7 +303,7 @@ export class LegacySupport {
|
|
|
233
303
|
assert(`hasMany only works with the @ember-data/record-data package`);
|
|
234
304
|
}
|
|
235
305
|
|
|
236
|
-
getHasMany(key: string, options?: FindOptions): PromiseManyArray |
|
|
306
|
+
getHasMany(key: string, options?: FindOptions): PromiseManyArray | RelatedCollection {
|
|
237
307
|
if (HAS_RECORD_DATA_PACKAGE) {
|
|
238
308
|
const graphFor = (
|
|
239
309
|
importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
|
|
@@ -264,11 +334,6 @@ export class LegacySupport {
|
|
|
264
334
|
assert(`hasMany only works with the @ember-data/record-data package`);
|
|
265
335
|
}
|
|
266
336
|
|
|
267
|
-
setDirtyHasMany(key: string, records: RecordInstance[]) {
|
|
268
|
-
assertRecordsPassedToHasMany(records);
|
|
269
|
-
return this.recordData.setHasMany(this.identifier, key, extractIdentifiersFromRecords(records));
|
|
270
|
-
}
|
|
271
|
-
|
|
272
337
|
_updatePromiseProxyFor(kind: 'hasMany', key: string, args: HasManyProxyCreateArgs): PromiseManyArray;
|
|
273
338
|
_updatePromiseProxyFor(kind: 'belongsTo', key: string, args: BelongsToProxyCreateArgs): PromiseBelongsTo;
|
|
274
339
|
_updatePromiseProxyFor(
|
|
@@ -358,10 +423,10 @@ export class LegacySupport {
|
|
|
358
423
|
parentIdentifier: StableRecordIdentifier,
|
|
359
424
|
relationship: ManyRelationship,
|
|
360
425
|
options: FindOptions = {}
|
|
361
|
-
): Promise<void | unknown[]> {
|
|
426
|
+
): Promise<void | unknown[]> | void {
|
|
362
427
|
if (HAS_RECORD_DATA_PACKAGE) {
|
|
363
428
|
if (!resource) {
|
|
364
|
-
return
|
|
429
|
+
return;
|
|
365
430
|
}
|
|
366
431
|
const { definition, state } = relationship;
|
|
367
432
|
const adapter = this.store.adapterFor(definition.type);
|
|
@@ -411,11 +476,19 @@ export class LegacySupport {
|
|
|
411
476
|
|
|
412
477
|
// fetch using data, pulling from local cache if possible
|
|
413
478
|
if (!shouldForceReload && !isStale && (preferLocalCache || hasLocalPartialData)) {
|
|
479
|
+
if (allInverseRecordsAreLoaded) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
414
482
|
assert(`Expected collection to be an array`, Array.isArray(resource.data));
|
|
483
|
+
if (allInverseRecordsAreLoaded) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
415
486
|
let finds = new Array(resource.data.length);
|
|
487
|
+
let cache = this.store._instanceCache;
|
|
416
488
|
for (let i = 0; i < resource.data.length; i++) {
|
|
417
|
-
|
|
418
|
-
|
|
489
|
+
const identifier = resource.data[i];
|
|
490
|
+
assert(`expected a stable identifier`, isStableIdentifier(identifier));
|
|
491
|
+
finds[i] = cache._fetchDataIfNeededForIdentifier(identifier, options);
|
|
419
492
|
}
|
|
420
493
|
|
|
421
494
|
return all(finds);
|
|
@@ -425,8 +498,9 @@ export class LegacySupport {
|
|
|
425
498
|
|
|
426
499
|
// fetch by data
|
|
427
500
|
if (hasData || hasLocalPartialData) {
|
|
428
|
-
|
|
429
|
-
|
|
501
|
+
const identifiers = resource.data;
|
|
502
|
+
assert(`Expected collection to be an array`, Array.isArray(identifiers));
|
|
503
|
+
assert(`Expected stable identifiers`, identifiers.every(isStableIdentifier));
|
|
430
504
|
let fetches = new Array(identifiers.length);
|
|
431
505
|
const manager = this.store._fetchManager;
|
|
432
506
|
|
|
@@ -441,7 +515,7 @@ export class LegacySupport {
|
|
|
441
515
|
|
|
442
516
|
// we were explicitly told we have no data and no links.
|
|
443
517
|
// TODO if the relationshipIsStale, should we hit the adapter anyway?
|
|
444
|
-
return
|
|
518
|
+
return;
|
|
445
519
|
}
|
|
446
520
|
assert(`hasMany only works with the @ember-data/record-data package`);
|
|
447
521
|
}
|
|
@@ -456,7 +530,8 @@ export class LegacySupport {
|
|
|
456
530
|
return resolve(null);
|
|
457
531
|
}
|
|
458
532
|
|
|
459
|
-
const identifier = resource.data ?
|
|
533
|
+
const identifier = resource.data ? resource.data : null;
|
|
534
|
+
assert(`Expected a stable identifier`, !identifier || isStableIdentifier(identifier));
|
|
460
535
|
|
|
461
536
|
let { isStale, hasDematerializedInverse, hasReceivedData, isEmpty, shouldForceReload } = relationship.state;
|
|
462
537
|
|
|
@@ -557,8 +632,8 @@ function handleCompletedRelationshipRequest(
|
|
|
557
632
|
recordExt: LegacySupport,
|
|
558
633
|
key: string,
|
|
559
634
|
relationship: ManyRelationship,
|
|
560
|
-
value:
|
|
561
|
-
):
|
|
635
|
+
value: RelatedCollection
|
|
636
|
+
): RelatedCollection;
|
|
562
637
|
function handleCompletedRelationshipRequest(
|
|
563
638
|
recordExt: LegacySupport,
|
|
564
639
|
key: string,
|
|
@@ -570,16 +645,16 @@ function handleCompletedRelationshipRequest(
|
|
|
570
645
|
recordExt: LegacySupport,
|
|
571
646
|
key: string,
|
|
572
647
|
relationship: ManyRelationship,
|
|
573
|
-
value:
|
|
648
|
+
value: RelatedCollection,
|
|
574
649
|
error: Error
|
|
575
650
|
): never;
|
|
576
651
|
function handleCompletedRelationshipRequest(
|
|
577
652
|
recordExt: LegacySupport,
|
|
578
653
|
key: string,
|
|
579
654
|
relationship: BelongsToRelationship | ManyRelationship,
|
|
580
|
-
value:
|
|
655
|
+
value: RelatedCollection | StableRecordIdentifier | null,
|
|
581
656
|
error?: Error
|
|
582
|
-
):
|
|
657
|
+
): RelatedCollection | RecordInstance | null {
|
|
583
658
|
delete recordExt._relationshipPromisesCache[key];
|
|
584
659
|
relationship.state.shouldForceReload = false;
|
|
585
660
|
const isHasMany = relationship.definition.kind === 'hasMany';
|
|
@@ -587,7 +662,7 @@ function handleCompletedRelationshipRequest(
|
|
|
587
662
|
if (isHasMany) {
|
|
588
663
|
// we don't notify the record property here to avoid refetch
|
|
589
664
|
// only the many array
|
|
590
|
-
(value as
|
|
665
|
+
(value as RelatedCollection).notify();
|
|
591
666
|
}
|
|
592
667
|
|
|
593
668
|
if (error) {
|
|
@@ -611,7 +686,7 @@ function handleCompletedRelationshipRequest(
|
|
|
611
686
|
}
|
|
612
687
|
|
|
613
688
|
if (isHasMany) {
|
|
614
|
-
(value as
|
|
689
|
+
(value as RelatedCollection).isLoaded = true;
|
|
615
690
|
}
|
|
616
691
|
|
|
617
692
|
relationship.state.hasFailedLoadAttempt = false;
|
|
@@ -619,33 +694,10 @@ function handleCompletedRelationshipRequest(
|
|
|
619
694
|
relationship.state.isStale = false;
|
|
620
695
|
|
|
621
696
|
return isHasMany || !value
|
|
622
|
-
? (value as
|
|
697
|
+
? (value as RelatedCollection | null)
|
|
623
698
|
: recordExt.store.peekRecord(value as StableRecordIdentifier);
|
|
624
699
|
}
|
|
625
700
|
|
|
626
|
-
function assertRecordsPassedToHasMany(records: RecordInstance[]) {
|
|
627
|
-
assert(`You must pass an array of records to set a hasMany relationship`, Array.isArray(records));
|
|
628
|
-
assert(
|
|
629
|
-
`All elements of a hasMany relationship must be instances of Model, you passed ${records
|
|
630
|
-
.map((r) => `${typeof r}`)
|
|
631
|
-
.join(', ')}`,
|
|
632
|
-
(function () {
|
|
633
|
-
return records.every((record) => {
|
|
634
|
-
try {
|
|
635
|
-
recordIdentifierFor(record);
|
|
636
|
-
return true;
|
|
637
|
-
} catch {
|
|
638
|
-
return false;
|
|
639
|
-
}
|
|
640
|
-
});
|
|
641
|
-
})()
|
|
642
|
-
);
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
function extractIdentifiersFromRecords(records: RecordInstance[]): StableRecordIdentifier[] {
|
|
646
|
-
return records.map(extractIdentifierFromRecord) as StableRecordIdentifier[];
|
|
647
|
-
}
|
|
648
|
-
|
|
649
701
|
type PromiseProxyRecord = { then(): void; content: RecordInstance | null | undefined };
|
|
650
702
|
|
|
651
703
|
function extractIdentifierFromRecord(recordOrPromiseRecord: PromiseProxyRecord | RecordInstance | null) {
|
|
@@ -653,12 +705,25 @@ function extractIdentifierFromRecord(recordOrPromiseRecord: PromiseProxyRecord |
|
|
|
653
705
|
return null;
|
|
654
706
|
}
|
|
655
707
|
|
|
656
|
-
if (isPromiseRecord(recordOrPromiseRecord)) {
|
|
708
|
+
if (DEPRECATE_PROMISE_PROXIES && isPromiseRecord(recordOrPromiseRecord)) {
|
|
657
709
|
let content = recordOrPromiseRecord.content;
|
|
658
710
|
assert(
|
|
659
711
|
'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.',
|
|
660
712
|
content !== undefined
|
|
661
713
|
);
|
|
714
|
+
deprecate(
|
|
715
|
+
`You passed in a PromiseProxy to a Relationship API that now expects a resolved value. await the value before setting it.`,
|
|
716
|
+
false,
|
|
717
|
+
{
|
|
718
|
+
id: 'ember-data:deprecate-promise-proxies',
|
|
719
|
+
until: '5.0',
|
|
720
|
+
since: {
|
|
721
|
+
enabled: '4.8',
|
|
722
|
+
available: '4.8',
|
|
723
|
+
},
|
|
724
|
+
for: 'ember-data',
|
|
725
|
+
}
|
|
726
|
+
);
|
|
662
727
|
return content ? recordIdentifierFor(content) : null;
|
|
663
728
|
}
|
|
664
729
|
|
|
@@ -681,30 +746,21 @@ function anyUnloaded(store: Store, relationship: ManyRelationship) {
|
|
|
681
746
|
}
|
|
682
747
|
|
|
683
748
|
function areAllInverseRecordsLoaded(store: Store, resource: JsonApiRelationship): boolean {
|
|
684
|
-
const
|
|
749
|
+
const instanceCache = store._instanceCache;
|
|
750
|
+
const identifiers = resource.data;
|
|
685
751
|
|
|
686
|
-
if (Array.isArray(
|
|
752
|
+
if (Array.isArray(identifiers)) {
|
|
753
|
+
assert(`Expected stable identifiers`, identifiers.every(isStableIdentifier));
|
|
687
754
|
// treat as collection
|
|
688
755
|
// check for unloaded records
|
|
689
|
-
|
|
690
|
-
return hasEmptyModel || isEmpty(store, cache, resourceIdentifier);
|
|
691
|
-
}, false);
|
|
692
|
-
|
|
693
|
-
return !hasEmptyRecords;
|
|
694
|
-
} else {
|
|
695
|
-
// treat as single resource
|
|
696
|
-
if (!resource.data) {
|
|
697
|
-
return true;
|
|
698
|
-
} else {
|
|
699
|
-
return !isEmpty(store, cache, resource.data);
|
|
700
|
-
}
|
|
756
|
+
return identifiers.every((identifier: StableRecordIdentifier) => instanceCache.recordIsLoaded(identifier));
|
|
701
757
|
}
|
|
702
|
-
}
|
|
703
758
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
759
|
+
// treat as single resource
|
|
760
|
+
if (!identifiers) return true;
|
|
761
|
+
|
|
762
|
+
assert(`Expected stable identifiers`, isStableIdentifier(identifiers));
|
|
763
|
+
return instanceCache.recordIsLoaded(identifiers);
|
|
708
764
|
}
|
|
709
765
|
|
|
710
766
|
function isBelongsTo(
|