@ember-data/store 4.4.0 → 4.5.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/system/core-store.ts +136 -147
- package/addon/-private/system/ds-model-store.ts +1 -10
- package/addon/-private/system/fetch-manager.ts +48 -21
- package/addon/-private/system/model/internal-model.ts +263 -192
- package/addon/-private/system/model/states.js +5 -41
- package/addon/-private/system/{promise-proxies.js → promise-proxies.ts} +31 -21
- package/addon/-private/system/promise-proxy-base.js +7 -0
- package/addon/-private/system/{record-array-manager.js → record-array-manager.ts} +87 -60
- package/addon/-private/system/record-arrays/adapter-populated-record-array.ts +129 -0
- package/addon/-private/system/record-arrays/{record-array.js → record-array.ts} +96 -75
- package/addon/-private/system/record-data-for.ts +2 -0
- package/addon/-private/system/references/belongs-to.ts +3 -2
- package/addon/-private/system/references/has-many.ts +4 -2
- package/addon/-private/system/schema-definition-service.ts +2 -2
- package/addon/-private/system/snapshot-record-array.ts +12 -11
- package/addon/-private/system/snapshot.ts +24 -7
- package/addon/-private/system/store/common.js +24 -1
- package/addon/-private/system/store/finders.js +53 -5
- package/addon/-private/system/store/internal-model-factory.ts +8 -7
- package/addon/-private/system/store/record-data-store-wrapper.ts +7 -2
- package/addon/-private/system/store/serializer-response.ts +85 -0
- package/addon/-private/ts-interfaces/ds-model.ts +15 -7
- package/addon/-private/ts-interfaces/ember-data-json-api.ts +3 -0
- package/addon/-private/ts-interfaces/minimum-adapter-interface.ts +19 -20
- package/addon/-private/ts-interfaces/minimum-serializer-interface.ts +27 -6
- package/addon/-private/ts-interfaces/record-data.ts +4 -1
- package/addon/-private/ts-interfaces/record-instance.ts +3 -1
- package/addon/-private/ts-interfaces/store.ts +1 -0
- package/addon/-private/utils/promise-record.ts +3 -3
- package/index.js +3 -0
- package/package.json +7 -6
- package/addon/-private/system/record-arrays/adapter-populated-record-array.js +0 -95
- package/addon/-private/system/store/serializer-response.js +0 -71
|
@@ -5,8 +5,19 @@ import { get } from '@ember/object';
|
|
|
5
5
|
import { _backburner as emberBackburner, cancel, run } from '@ember/runloop';
|
|
6
6
|
import { DEBUG } from '@glimmer/env';
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import { importSync } from '@embroider/macros';
|
|
9
|
+
import RSVP, { resolve } from 'rsvp';
|
|
9
10
|
|
|
11
|
+
import type { ManyArray } from '@ember-data/model/-private';
|
|
12
|
+
import RecordState from '@ember-data/model/-private/record-state';
|
|
13
|
+
import type { ManyArrayCreateArgs } from '@ember-data/model/-private/system/many-array';
|
|
14
|
+
import type {
|
|
15
|
+
BelongsToProxyCreateArgs,
|
|
16
|
+
BelongsToProxyMeta,
|
|
17
|
+
} from '@ember-data/model/-private/system/promise-belongs-to';
|
|
18
|
+
import type PromiseBelongsTo from '@ember-data/model/-private/system/promise-belongs-to';
|
|
19
|
+
import type { HasManyProxyCreateArgs } from '@ember-data/model/-private/system/promise-many-array';
|
|
20
|
+
import type PromiseManyArray from '@ember-data/model/-private/system/promise-many-array';
|
|
10
21
|
import { HAS_MODEL_PACKAGE, HAS_RECORD_DATA_PACKAGE } from '@ember-data/private-build-infra';
|
|
11
22
|
import type {
|
|
12
23
|
BelongsToRelationship,
|
|
@@ -14,16 +25,21 @@ import type {
|
|
|
14
25
|
RecordData as DefaultRecordData,
|
|
15
26
|
} from '@ember-data/record-data/-private';
|
|
16
27
|
import type { UpgradedMeta } from '@ember-data/record-data/-private/graph/-edge-definition';
|
|
28
|
+
import type {
|
|
29
|
+
DefaultSingleResourceRelationship,
|
|
30
|
+
RelationshipRecordData,
|
|
31
|
+
} from '@ember-data/record-data/-private/ts-interfaces/relationship-record-data';
|
|
17
32
|
|
|
18
|
-
import { DSModel } from '../../ts-interfaces/ds-model';
|
|
33
|
+
import type { DSModel } from '../../ts-interfaces/ds-model';
|
|
19
34
|
import type { StableRecordIdentifier } from '../../ts-interfaces/identifier';
|
|
20
|
-
import type { RecordData } from '../../ts-interfaces/record-data';
|
|
35
|
+
import type { ChangedAttributesHash, RecordData } from '../../ts-interfaces/record-data';
|
|
21
36
|
import type { JsonApiResource, JsonApiValidationError } from '../../ts-interfaces/record-data-json-api';
|
|
37
|
+
import type { RelationshipSchema } from '../../ts-interfaces/record-data-schemas';
|
|
22
38
|
import type { RecordInstance } from '../../ts-interfaces/record-instance';
|
|
23
39
|
import type { FindOptions } from '../../ts-interfaces/store';
|
|
24
|
-
import type {
|
|
40
|
+
import type { Dict } from '../../ts-interfaces/utils';
|
|
25
41
|
import type CoreStore from '../core-store';
|
|
26
|
-
import type
|
|
42
|
+
import type { CreateRecordProperties } from '../core-store';
|
|
27
43
|
import { errorsHashToArray } from '../errors-utils';
|
|
28
44
|
import recordDataFor from '../record-data-for';
|
|
29
45
|
import { BelongsToReference, HasManyReference, RecordReference } from '../references';
|
|
@@ -31,10 +47,11 @@ import Snapshot from '../snapshot';
|
|
|
31
47
|
import { internalModelFactoryFor } from '../store/internal-model-factory';
|
|
32
48
|
import RootState from './states';
|
|
33
49
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
50
|
+
type PrivateModelModule = {
|
|
51
|
+
ManyArray: { create(args: ManyArrayCreateArgs): ManyArray };
|
|
52
|
+
PromiseBelongsTo: { create(args: BelongsToProxyCreateArgs): PromiseBelongsTo };
|
|
53
|
+
PromiseManyArray: new (...args: unknown[]) => PromiseManyArray;
|
|
54
|
+
};
|
|
38
55
|
|
|
39
56
|
/**
|
|
40
57
|
@module @ember-data/store
|
|
@@ -42,18 +59,22 @@ type PromiseManyArray = InstanceType<typeof import('@ember-data/model/-private')
|
|
|
42
59
|
|
|
43
60
|
const { hasOwnProperty } = Object.prototype;
|
|
44
61
|
|
|
45
|
-
let
|
|
46
|
-
let
|
|
47
|
-
let _PromiseManyArray:
|
|
62
|
+
let _ManyArray: PrivateModelModule['ManyArray'];
|
|
63
|
+
let _PromiseBelongsTo: PrivateModelModule['PromiseBelongsTo'];
|
|
64
|
+
let _PromiseManyArray: PrivateModelModule['PromiseManyArray'];
|
|
48
65
|
|
|
49
66
|
let _found = false;
|
|
50
67
|
let _getModelPackage: () => boolean;
|
|
51
68
|
if (HAS_MODEL_PACKAGE) {
|
|
52
69
|
_getModelPackage = function () {
|
|
53
70
|
if (!_found) {
|
|
54
|
-
let modelPackage =
|
|
55
|
-
({
|
|
56
|
-
|
|
71
|
+
let modelPackage = importSync('@ember-data/model/-private') as PrivateModelModule;
|
|
72
|
+
({
|
|
73
|
+
ManyArray: _ManyArray,
|
|
74
|
+
PromiseBelongsTo: _PromiseBelongsTo,
|
|
75
|
+
PromiseManyArray: _PromiseManyArray,
|
|
76
|
+
} = modelPackage);
|
|
77
|
+
if (_ManyArray && _PromiseBelongsTo && _PromiseManyArray) {
|
|
57
78
|
_found = true;
|
|
58
79
|
}
|
|
59
80
|
}
|
|
@@ -61,13 +82,6 @@ if (HAS_MODEL_PACKAGE) {
|
|
|
61
82
|
};
|
|
62
83
|
}
|
|
63
84
|
|
|
64
|
-
interface BelongsToMetaWrapper {
|
|
65
|
-
key: string;
|
|
66
|
-
store: CoreStore;
|
|
67
|
-
originatingInternalModel: InternalModel;
|
|
68
|
-
modelName: string;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
85
|
/*
|
|
72
86
|
The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached
|
|
73
87
|
when transitioning from one state to another, so that future transitions can replay the
|
|
@@ -78,18 +92,32 @@ interface BelongsToMetaWrapper {
|
|
|
78
92
|
and setups. It may also be faster to do a two level cache (from: { to }) instead of caching based
|
|
79
93
|
on a key that adds the two together.
|
|
80
94
|
*/
|
|
95
|
+
// TODO before deleting the state machine we should
|
|
96
|
+
// ensure all things in this map were properly accounted for.
|
|
97
|
+
// in the RecordState class.
|
|
81
98
|
const TransitionChainMap = Object.create(null);
|
|
82
99
|
|
|
83
100
|
const _extractPivotNameCache = Object.create(null);
|
|
84
101
|
const _splitOnDotCache = Object.create(null);
|
|
85
102
|
|
|
86
|
-
function splitOnDot(name) {
|
|
103
|
+
function splitOnDot(name: string): string[] {
|
|
87
104
|
return _splitOnDotCache[name] || (_splitOnDotCache[name] = name.split('.'));
|
|
88
105
|
}
|
|
89
106
|
|
|
90
|
-
function extractPivotName(name) {
|
|
107
|
+
function extractPivotName(name: string): string {
|
|
91
108
|
return _extractPivotNameCache[name] || (_extractPivotNameCache[name] = splitOnDot(name)[0]);
|
|
92
109
|
}
|
|
110
|
+
|
|
111
|
+
function isDSModel(record: RecordInstance | null): record is DSModel {
|
|
112
|
+
return (
|
|
113
|
+
HAS_MODEL_PACKAGE &&
|
|
114
|
+
!!record &&
|
|
115
|
+
'constructor' in record &&
|
|
116
|
+
'isModel' in record.constructor &&
|
|
117
|
+
record.constructor.isModel === true
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
93
121
|
export default class InternalModel {
|
|
94
122
|
declare _id: string | null;
|
|
95
123
|
declare modelName: string;
|
|
@@ -106,25 +134,28 @@ export default class InternalModel {
|
|
|
106
134
|
|
|
107
135
|
// Not typed yet
|
|
108
136
|
declare _promiseProxy: any;
|
|
109
|
-
declare _record:
|
|
137
|
+
declare _record: RecordInstance | null;
|
|
110
138
|
declare _scheduledDestroy: any;
|
|
111
139
|
declare _modelClass: any;
|
|
112
|
-
declare _deferredTriggers: any;
|
|
113
140
|
declare __recordArrays: any;
|
|
114
141
|
declare references: any;
|
|
115
142
|
declare _recordReference: RecordReference;
|
|
116
|
-
declare _manyArrayCache:
|
|
143
|
+
declare _manyArrayCache: Dict<ManyArray>;
|
|
117
144
|
|
|
118
|
-
declare _relationshipPromisesCache:
|
|
119
|
-
declare _relationshipProxyCache:
|
|
145
|
+
declare _relationshipPromisesCache: Dict<Promise<ManyArray | RecordInstance>>;
|
|
146
|
+
declare _relationshipProxyCache: Dict<PromiseManyArray | PromiseBelongsTo>;
|
|
120
147
|
declare error: any;
|
|
121
|
-
declare currentState:
|
|
148
|
+
declare currentState: RecordState;
|
|
122
149
|
declare _previousState: any;
|
|
150
|
+
declare store: CoreStore;
|
|
151
|
+
declare identifier: StableRecordIdentifier;
|
|
123
152
|
|
|
124
|
-
constructor(
|
|
153
|
+
constructor(store: CoreStore, identifier: StableRecordIdentifier) {
|
|
125
154
|
if (HAS_MODEL_PACKAGE) {
|
|
126
155
|
_getModelPackage();
|
|
127
156
|
}
|
|
157
|
+
this.store = store;
|
|
158
|
+
this.identifier = identifier;
|
|
128
159
|
this._id = identifier.id;
|
|
129
160
|
this._isUpdatingId = false;
|
|
130
161
|
this.modelName = identifier.type;
|
|
@@ -163,7 +194,6 @@ export default class InternalModel {
|
|
|
163
194
|
this._relationshipPromisesCache = Object.create(null);
|
|
164
195
|
this._relationshipProxyCache = Object.create(null);
|
|
165
196
|
this.references = Object.create(null);
|
|
166
|
-
this._deferredTriggers = [];
|
|
167
197
|
this.currentState = RootState.empty;
|
|
168
198
|
}
|
|
169
199
|
|
|
@@ -256,15 +286,27 @@ export default class InternalModel {
|
|
|
256
286
|
}
|
|
257
287
|
}
|
|
258
288
|
|
|
259
|
-
getRecord(properties
|
|
260
|
-
|
|
289
|
+
getRecord(properties?: CreateRecordProperties): RecordInstance {
|
|
290
|
+
let record = this._record;
|
|
291
|
+
|
|
292
|
+
if (this._isDematerializing) {
|
|
293
|
+
// TODO we should assert here instead of this return.
|
|
294
|
+
return null as unknown as RecordInstance;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (!record) {
|
|
261
298
|
let { store } = this;
|
|
262
299
|
|
|
263
|
-
this._record = store._instantiateRecord(
|
|
264
|
-
|
|
300
|
+
record = this._record = store._instantiateRecord(
|
|
301
|
+
this,
|
|
302
|
+
this.modelName,
|
|
303
|
+
this._recordData,
|
|
304
|
+
this.identifier,
|
|
305
|
+
properties
|
|
306
|
+
);
|
|
265
307
|
}
|
|
266
308
|
|
|
267
|
-
return
|
|
309
|
+
return record;
|
|
268
310
|
}
|
|
269
311
|
|
|
270
312
|
dematerializeRecord() {
|
|
@@ -288,9 +330,11 @@ export default class InternalModel {
|
|
|
288
330
|
});
|
|
289
331
|
|
|
290
332
|
if (this._record) {
|
|
291
|
-
Object.keys(this._relationshipProxyCache)
|
|
292
|
-
|
|
293
|
-
|
|
333
|
+
let keys = Object.keys(this._relationshipProxyCache);
|
|
334
|
+
keys.forEach((key) => {
|
|
335
|
+
let proxy = this._relationshipProxyCache[key]!;
|
|
336
|
+
if (proxy.destroy) {
|
|
337
|
+
proxy.destroy();
|
|
294
338
|
}
|
|
295
339
|
delete this._relationshipProxyCache[key];
|
|
296
340
|
});
|
|
@@ -315,7 +359,6 @@ export default class InternalModel {
|
|
|
315
359
|
// destroyRecord follows up deleteRecord with save(). This prevents an unecessary save for a new record
|
|
316
360
|
this._deletedRecordWasNew = true;
|
|
317
361
|
this.send('deleteRecord');
|
|
318
|
-
this._triggerDeferredTriggers();
|
|
319
362
|
this.unloadRecord();
|
|
320
363
|
} else {
|
|
321
364
|
this.send('deleteRecord');
|
|
@@ -324,9 +367,9 @@ export default class InternalModel {
|
|
|
324
367
|
});
|
|
325
368
|
}
|
|
326
369
|
|
|
327
|
-
save(options): Promise<void> {
|
|
370
|
+
save(options: FindOptions = {}): Promise<void> {
|
|
328
371
|
if (this._deletedRecordWasNew) {
|
|
329
|
-
return
|
|
372
|
+
return resolve();
|
|
330
373
|
}
|
|
331
374
|
let promiseLabel = 'DS: Model#save ' + this;
|
|
332
375
|
let resolver = RSVP.defer<void>(promiseLabel);
|
|
@@ -335,22 +378,8 @@ export default class InternalModel {
|
|
|
335
378
|
return this.store.scheduleSave(this, resolver, options) as Promise<void>;
|
|
336
379
|
}
|
|
337
380
|
|
|
338
|
-
reload(options) {
|
|
339
|
-
|
|
340
|
-
options = {};
|
|
341
|
-
}
|
|
342
|
-
let internalModel = this;
|
|
343
|
-
|
|
344
|
-
return internalModel.store._reloadRecord(internalModel, options).then(
|
|
345
|
-
function () {
|
|
346
|
-
//TODO NOW seems like we shouldn't need to do this
|
|
347
|
-
return internalModel;
|
|
348
|
-
},
|
|
349
|
-
function (error) {
|
|
350
|
-
throw error;
|
|
351
|
-
},
|
|
352
|
-
'DS: Model#reload complete, update flags'
|
|
353
|
-
);
|
|
381
|
+
reload(options: Dict<unknown> = {}): Promise<InternalModel> {
|
|
382
|
+
return this.store._reloadRecord(this, options);
|
|
354
383
|
}
|
|
355
384
|
|
|
356
385
|
/*
|
|
@@ -425,26 +454,32 @@ export default class InternalModel {
|
|
|
425
454
|
}
|
|
426
455
|
}
|
|
427
456
|
|
|
428
|
-
_findBelongsTo(
|
|
457
|
+
_findBelongsTo(
|
|
458
|
+
key: string,
|
|
459
|
+
resource: DefaultSingleResourceRelationship,
|
|
460
|
+
relationshipMeta: RelationshipSchema,
|
|
461
|
+
options?: Dict<unknown>
|
|
462
|
+
): Promise<RecordInstance | null> {
|
|
429
463
|
// TODO @runspired follow up if parent isNew then we should not be attempting load here
|
|
464
|
+
// TODO @runspired follow up on whether this should be in the relationship requests cache
|
|
430
465
|
return this.store._findBelongsToByJsonApiResource(resource, this, relationshipMeta, options).then(
|
|
431
|
-
(internalModel) => handleCompletedRelationshipRequest(this, key, resource._relationship, internalModel
|
|
466
|
+
(internalModel) => handleCompletedRelationshipRequest(this, key, resource._relationship, internalModel),
|
|
432
467
|
(e) => handleCompletedRelationshipRequest(this, key, resource._relationship, null, e)
|
|
433
468
|
);
|
|
434
469
|
}
|
|
435
470
|
|
|
436
|
-
getBelongsTo(key, options) {
|
|
471
|
+
getBelongsTo(key: string, options?: Dict<unknown>): PromiseBelongsTo | RecordInstance | null {
|
|
437
472
|
let resource = (this._recordData as DefaultRecordData).getBelongsTo(key);
|
|
438
473
|
let identifier =
|
|
439
474
|
resource && resource.data ? this.store.identifierCache.getOrCreateRecordIdentifier(resource.data) : null;
|
|
440
475
|
let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key);
|
|
441
|
-
|
|
476
|
+
assert(`Attempted to access a belongsTo relationship but no definition exists for it`, relationshipMeta);
|
|
442
477
|
|
|
443
478
|
let store = this.store;
|
|
444
479
|
let parentInternalModel = this;
|
|
445
480
|
let async = relationshipMeta.options.async;
|
|
446
481
|
let isAsync = typeof async === 'undefined' ? true : async;
|
|
447
|
-
let _belongsToState:
|
|
482
|
+
let _belongsToState: BelongsToProxyMeta = {
|
|
448
483
|
key,
|
|
449
484
|
store,
|
|
450
485
|
originatingInternalModel: this,
|
|
@@ -455,7 +490,7 @@ export default class InternalModel {
|
|
|
455
490
|
let internalModel = identifier !== null ? store._internalModelForResource(identifier) : null;
|
|
456
491
|
|
|
457
492
|
if (resource._relationship.state.hasFailedLoadAttempt) {
|
|
458
|
-
return this._relationshipProxyCache[key];
|
|
493
|
+
return this._relationshipProxyCache[key] as PromiseBelongsTo;
|
|
459
494
|
}
|
|
460
495
|
|
|
461
496
|
let promise = this._findBelongsTo(key, resource, relationshipMeta, options);
|
|
@@ -479,49 +514,49 @@ export default class InternalModel {
|
|
|
479
514
|
"' with id " +
|
|
480
515
|
parentInternalModel.id +
|
|
481
516
|
' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`belongsTo({ async: true })`)',
|
|
482
|
-
toReturn === null || !
|
|
517
|
+
toReturn === null || !internalModel.currentState.isEmpty
|
|
483
518
|
);
|
|
484
519
|
return toReturn;
|
|
485
520
|
}
|
|
486
521
|
}
|
|
487
522
|
}
|
|
488
523
|
|
|
489
|
-
getManyArray(key: string, definition?: UpgradedMeta) {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
return manyArray;
|
|
524
|
+
getManyArray(key: string, definition?: UpgradedMeta): ManyArray {
|
|
525
|
+
assert('hasMany only works with the @ember-data/record-data package', HAS_RECORD_DATA_PACKAGE);
|
|
526
|
+
let manyArray: ManyArray | undefined = this._manyArrayCache[key];
|
|
527
|
+
if (!definition) {
|
|
528
|
+
const graphFor = (
|
|
529
|
+
importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
|
|
530
|
+
).graphFor;
|
|
531
|
+
definition = graphFor(this.store).get(this.identifier, key).definition as UpgradedMeta;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (!manyArray) {
|
|
535
|
+
manyArray = _ManyArray.create({
|
|
536
|
+
store: this.store,
|
|
537
|
+
type: this.store.modelFor(definition.type),
|
|
538
|
+
recordData: this._recordData as RelationshipRecordData,
|
|
539
|
+
key,
|
|
540
|
+
isPolymorphic: definition.isPolymorphic,
|
|
541
|
+
isAsync: definition.isAsync,
|
|
542
|
+
_inverseIsAsync: definition.inverseIsAsync,
|
|
543
|
+
internalModel: this,
|
|
544
|
+
isLoaded: !definition.isAsync,
|
|
545
|
+
});
|
|
546
|
+
this._manyArrayCache[key] = manyArray;
|
|
513
547
|
}
|
|
514
|
-
|
|
548
|
+
|
|
549
|
+
return manyArray;
|
|
515
550
|
}
|
|
516
551
|
|
|
517
552
|
fetchAsyncHasMany(
|
|
518
553
|
key: string,
|
|
519
|
-
relationship: ManyRelationship
|
|
520
|
-
manyArray,
|
|
521
|
-
options
|
|
522
|
-
):
|
|
554
|
+
relationship: ManyRelationship,
|
|
555
|
+
manyArray: ManyArray,
|
|
556
|
+
options?: Dict<unknown>
|
|
557
|
+
): Promise<ManyArray> {
|
|
523
558
|
if (HAS_RECORD_DATA_PACKAGE) {
|
|
524
|
-
let loadingPromise = this._relationshipPromisesCache[key];
|
|
559
|
+
let loadingPromise = this._relationshipPromisesCache[key] as Promise<ManyArray> | undefined;
|
|
525
560
|
if (loadingPromise) {
|
|
526
561
|
return loadingPromise;
|
|
527
562
|
}
|
|
@@ -529,25 +564,27 @@ export default class InternalModel {
|
|
|
529
564
|
const jsonApi = this._recordData.getHasMany(key);
|
|
530
565
|
|
|
531
566
|
loadingPromise = this.store._findHasManyByJsonApiResource(jsonApi, this, relationship, options).then(
|
|
532
|
-
() => handleCompletedRelationshipRequest(this, key, relationship, manyArray
|
|
567
|
+
() => handleCompletedRelationshipRequest(this, key, relationship, manyArray),
|
|
533
568
|
(e) => handleCompletedRelationshipRequest(this, key, relationship, manyArray, e)
|
|
534
569
|
);
|
|
535
570
|
this._relationshipPromisesCache[key] = loadingPromise;
|
|
536
571
|
return loadingPromise;
|
|
537
572
|
}
|
|
538
|
-
assert(
|
|
573
|
+
assert('hasMany only works with the @ember-data/record-data package');
|
|
539
574
|
}
|
|
540
575
|
|
|
541
|
-
getHasMany(key: string, options?) {
|
|
576
|
+
getHasMany(key: string, options?): PromiseManyArray | ManyArray {
|
|
542
577
|
if (HAS_RECORD_DATA_PACKAGE) {
|
|
543
|
-
const graphFor =
|
|
544
|
-
|
|
578
|
+
const graphFor = (
|
|
579
|
+
importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
|
|
580
|
+
).graphFor;
|
|
581
|
+
const relationship = graphFor(this.store).get(this.identifier, key) as ManyRelationship;
|
|
545
582
|
const { definition, state } = relationship;
|
|
546
583
|
let manyArray = this.getManyArray(key, definition);
|
|
547
584
|
|
|
548
585
|
if (definition.isAsync) {
|
|
549
586
|
if (state.hasFailedLoadAttempt) {
|
|
550
|
-
return this._relationshipProxyCache[key];
|
|
587
|
+
return this._relationshipProxyCache[key] as PromiseManyArray;
|
|
551
588
|
}
|
|
552
589
|
|
|
553
590
|
let promise = this.fetchAsyncHasMany(key, relationship, manyArray, options);
|
|
@@ -565,47 +602,55 @@ export default class InternalModel {
|
|
|
565
602
|
assert(`hasMany only works with the @ember-data/record-data package`);
|
|
566
603
|
}
|
|
567
604
|
|
|
605
|
+
_updatePromiseProxyFor(kind: 'hasMany', key: string, args: HasManyProxyCreateArgs): PromiseManyArray;
|
|
606
|
+
_updatePromiseProxyFor(kind: 'belongsTo', key: string, args: BelongsToProxyCreateArgs): PromiseBelongsTo;
|
|
607
|
+
_updatePromiseProxyFor(
|
|
608
|
+
kind: 'belongsTo',
|
|
609
|
+
key: string,
|
|
610
|
+
args: { promise: Promise<RecordInstance | null> }
|
|
611
|
+
): PromiseBelongsTo;
|
|
568
612
|
_updatePromiseProxyFor(
|
|
569
613
|
kind: 'hasMany' | 'belongsTo',
|
|
570
614
|
key: string,
|
|
571
|
-
args: {
|
|
572
|
-
|
|
573
|
-
content?: RecordInstance | ManyArray | null;
|
|
574
|
-
_belongsToState?: BelongsToMetaWrapper;
|
|
575
|
-
}
|
|
576
|
-
) {
|
|
615
|
+
args: BelongsToProxyCreateArgs | HasManyProxyCreateArgs | { promise: Promise<RecordInstance | null> }
|
|
616
|
+
): PromiseBelongsTo | PromiseManyArray {
|
|
577
617
|
let promiseProxy = this._relationshipProxyCache[key];
|
|
578
618
|
if (kind === 'hasMany') {
|
|
619
|
+
const { promise, content } = args as HasManyProxyCreateArgs;
|
|
579
620
|
if (promiseProxy) {
|
|
580
|
-
|
|
621
|
+
assert(`Expected a PromiseManyArray`, '_update' in promiseProxy);
|
|
622
|
+
promiseProxy._update(promise, content);
|
|
581
623
|
} else {
|
|
582
|
-
promiseProxy = this._relationshipProxyCache[key] = new _PromiseManyArray(
|
|
624
|
+
promiseProxy = this._relationshipProxyCache[key] = new _PromiseManyArray(promise, content);
|
|
583
625
|
}
|
|
584
626
|
return promiseProxy;
|
|
585
627
|
}
|
|
586
628
|
if (promiseProxy) {
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
629
|
+
const { promise, content } = args as BelongsToProxyCreateArgs;
|
|
630
|
+
assert(`Expected a PromiseBelongsTo`, '_belongsToState' in promiseProxy);
|
|
631
|
+
|
|
632
|
+
if (content !== undefined) {
|
|
633
|
+
promiseProxy.set('content', content);
|
|
590
634
|
}
|
|
591
|
-
promiseProxy.set('promise',
|
|
635
|
+
promiseProxy.set('promise', promise);
|
|
592
636
|
} else {
|
|
593
|
-
const klass = PromiseBelongsTo;
|
|
594
637
|
// this usage of `any` can be removed when `@types/ember_object` proxy allows `null` for content
|
|
595
|
-
this._relationshipProxyCache[key] =
|
|
638
|
+
this._relationshipProxyCache[key] = promiseProxy = _PromiseBelongsTo.create(args as any);
|
|
596
639
|
}
|
|
597
640
|
|
|
598
|
-
return
|
|
641
|
+
return promiseProxy;
|
|
599
642
|
}
|
|
600
643
|
|
|
601
|
-
reloadHasMany(key, options) {
|
|
644
|
+
reloadHasMany(key: string, options) {
|
|
602
645
|
if (HAS_RECORD_DATA_PACKAGE) {
|
|
603
646
|
let loadingPromise = this._relationshipPromisesCache[key];
|
|
604
647
|
if (loadingPromise) {
|
|
605
648
|
return loadingPromise;
|
|
606
649
|
}
|
|
607
|
-
const graphFor =
|
|
608
|
-
|
|
650
|
+
const graphFor = (
|
|
651
|
+
importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
|
|
652
|
+
).graphFor;
|
|
653
|
+
const relationship = graphFor(this.store).get(this.identifier, key) as ManyRelationship;
|
|
609
654
|
const { definition, state } = relationship;
|
|
610
655
|
|
|
611
656
|
state.hasFailedLoadAttempt = false;
|
|
@@ -622,8 +667,8 @@ export default class InternalModel {
|
|
|
622
667
|
assert(`hasMany only works with the @ember-data/record-data package`);
|
|
623
668
|
}
|
|
624
669
|
|
|
625
|
-
reloadBelongsTo(key, options) {
|
|
626
|
-
let loadingPromise = this._relationshipPromisesCache[key];
|
|
670
|
+
reloadBelongsTo(key: string, options?: Dict<unknown>): Promise<RecordInstance | null> {
|
|
671
|
+
let loadingPromise = this._relationshipPromisesCache[key] as Promise<RecordInstance | null> | undefined;
|
|
627
672
|
if (loadingPromise) {
|
|
628
673
|
return loadingPromise;
|
|
629
674
|
}
|
|
@@ -635,6 +680,7 @@ export default class InternalModel {
|
|
|
635
680
|
resource._relationship.state.shouldForceReload = true;
|
|
636
681
|
}
|
|
637
682
|
let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key);
|
|
683
|
+
assert(`Attempted to reload a belongsTo relationship but no definition exists for it`, relationshipMeta);
|
|
638
684
|
let promise = this._findBelongsTo(key, resource, relationshipMeta, options);
|
|
639
685
|
if (this._relationshipProxyCache[key]) {
|
|
640
686
|
return this._updatePromiseProxyFor('belongsTo', key, { promise });
|
|
@@ -653,7 +699,7 @@ export default class InternalModel {
|
|
|
653
699
|
destroy() {
|
|
654
700
|
assert(
|
|
655
701
|
'Cannot destroy an internalModel while its record is materialized',
|
|
656
|
-
!this._record || this._record.
|
|
702
|
+
!this._record || this._record.isDestroyed || this._record.isDestroying
|
|
657
703
|
);
|
|
658
704
|
this.isDestroying = true;
|
|
659
705
|
if (this._recordReference) {
|
|
@@ -662,13 +708,13 @@ export default class InternalModel {
|
|
|
662
708
|
this._recordReference = null;
|
|
663
709
|
let cache = this._manyArrayCache;
|
|
664
710
|
Object.keys(cache).forEach((key) => {
|
|
665
|
-
cache[key]
|
|
711
|
+
cache[key]!.destroy();
|
|
666
712
|
delete cache[key];
|
|
667
713
|
});
|
|
668
714
|
if (this.references) {
|
|
669
715
|
cache = this.references;
|
|
670
716
|
Object.keys(cache).forEach((key) => {
|
|
671
|
-
cache[key]
|
|
717
|
+
cache[key]!.destroy();
|
|
672
718
|
delete cache[key];
|
|
673
719
|
});
|
|
674
720
|
}
|
|
@@ -678,24 +724,35 @@ export default class InternalModel {
|
|
|
678
724
|
}
|
|
679
725
|
|
|
680
726
|
setupData(data) {
|
|
681
|
-
|
|
682
|
-
if (
|
|
683
|
-
|
|
684
|
-
this.
|
|
727
|
+
const hasRecord = this.hasRecord;
|
|
728
|
+
if (hasRecord) {
|
|
729
|
+
let changedKeys = this._recordData.pushData(data, true);
|
|
730
|
+
this.notifyAttributes(changedKeys);
|
|
731
|
+
} else {
|
|
732
|
+
this._recordData.pushData(data);
|
|
685
733
|
}
|
|
686
734
|
this.send('pushedData');
|
|
687
735
|
}
|
|
688
736
|
|
|
689
|
-
|
|
737
|
+
notifyAttributes(keys: string[]): void {
|
|
738
|
+
let manager = this.store._notificationManager;
|
|
739
|
+
let { identifier } = this;
|
|
740
|
+
|
|
741
|
+
for (let i = 0; i < keys.length; i++) {
|
|
742
|
+
manager.notify(identifier, 'attributes', keys[i]);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
setDirtyHasMany(key: string, records) {
|
|
690
747
|
assertRecordsPassedToHasMany(records);
|
|
691
748
|
return this._recordData.setDirtyHasMany(key, extractRecordDatasFromRecords(records));
|
|
692
749
|
}
|
|
693
750
|
|
|
694
|
-
setDirtyBelongsTo(key, value) {
|
|
751
|
+
setDirtyBelongsTo(key: string, value) {
|
|
695
752
|
return this._recordData.setDirtyBelongsTo(key, extractRecordDataFromRecord(value));
|
|
696
753
|
}
|
|
697
754
|
|
|
698
|
-
setDirtyAttribute(key, value) {
|
|
755
|
+
setDirtyAttribute<T>(key: string, value: T): T {
|
|
699
756
|
if (this.isDeleted()) {
|
|
700
757
|
if (DEBUG) {
|
|
701
758
|
throw new EmberError(`Attempted to set '${key}' to '${value}' on the deleted record ${this}`);
|
|
@@ -717,11 +774,11 @@ export default class InternalModel {
|
|
|
717
774
|
return value;
|
|
718
775
|
}
|
|
719
776
|
|
|
720
|
-
get isDestroyed() {
|
|
777
|
+
get isDestroyed(): boolean {
|
|
721
778
|
return this._isDestroyed;
|
|
722
779
|
}
|
|
723
780
|
|
|
724
|
-
get hasRecord() {
|
|
781
|
+
get hasRecord(): boolean {
|
|
725
782
|
return !!this._record;
|
|
726
783
|
}
|
|
727
784
|
|
|
@@ -729,7 +786,7 @@ export default class InternalModel {
|
|
|
729
786
|
return new Snapshot(options, this.identifier, this.store);
|
|
730
787
|
}
|
|
731
788
|
|
|
732
|
-
hasChangedAttributes() {
|
|
789
|
+
hasChangedAttributes(): boolean {
|
|
733
790
|
if (!this.__recordData) {
|
|
734
791
|
// no need to calculate changed attributes when calling `findRecord`
|
|
735
792
|
return false;
|
|
@@ -737,7 +794,7 @@ export default class InternalModel {
|
|
|
737
794
|
return this._recordData.hasChangedAttributes();
|
|
738
795
|
}
|
|
739
796
|
|
|
740
|
-
changedAttributes() {
|
|
797
|
+
changedAttributes(): ChangedAttributesHash {
|
|
741
798
|
if (!this.__recordData) {
|
|
742
799
|
// no need to calculate changed attributes when calling `findRecord`
|
|
743
800
|
return {};
|
|
@@ -745,16 +802,16 @@ export default class InternalModel {
|
|
|
745
802
|
return this._recordData.changedAttributes();
|
|
746
803
|
}
|
|
747
804
|
|
|
748
|
-
adapterWillCommit() {
|
|
805
|
+
adapterWillCommit(): void {
|
|
749
806
|
this._recordData.willCommit();
|
|
750
807
|
this.send('willCommit');
|
|
751
808
|
}
|
|
752
809
|
|
|
753
|
-
adapterDidDirty() {
|
|
810
|
+
adapterDidDirty(): void {
|
|
754
811
|
this.send('becomeDirty');
|
|
755
812
|
}
|
|
756
813
|
|
|
757
|
-
send(name, context?) {
|
|
814
|
+
send(name: string, context?) {
|
|
758
815
|
let currentState = this.currentState;
|
|
759
816
|
|
|
760
817
|
if (!currentState[name]) {
|
|
@@ -785,7 +842,7 @@ export default class InternalModel {
|
|
|
785
842
|
}
|
|
786
843
|
}
|
|
787
844
|
|
|
788
|
-
notifyPropertyChange(key) {
|
|
845
|
+
notifyPropertyChange(key: string) {
|
|
789
846
|
if (this.hasRecord) {
|
|
790
847
|
// TODO this should likely *mostly* be the `attributes` bucket
|
|
791
848
|
// but it seems for local mutations we rely on computed updating
|
|
@@ -795,7 +852,7 @@ export default class InternalModel {
|
|
|
795
852
|
}
|
|
796
853
|
}
|
|
797
854
|
|
|
798
|
-
notifyStateChange(key
|
|
855
|
+
notifyStateChange(key?: string) {
|
|
799
856
|
if (this.hasRecord) {
|
|
800
857
|
this.store._notificationManager.notify(this.identifier, 'state');
|
|
801
858
|
}
|
|
@@ -811,24 +868,24 @@ export default class InternalModel {
|
|
|
811
868
|
rollbackAttributes() {
|
|
812
869
|
this.store._backburner.join(() => {
|
|
813
870
|
let dirtyKeys = this._recordData.rollbackAttributes();
|
|
814
|
-
if (
|
|
871
|
+
if (this.isError) {
|
|
815
872
|
this.didCleanError();
|
|
816
873
|
}
|
|
817
874
|
|
|
818
875
|
this.send('rolledBack');
|
|
819
876
|
|
|
820
|
-
if (this.
|
|
821
|
-
this.
|
|
877
|
+
if (this.hasRecord && dirtyKeys && dirtyKeys.length > 0) {
|
|
878
|
+
this.notifyAttributes(dirtyKeys);
|
|
822
879
|
}
|
|
823
880
|
});
|
|
824
881
|
}
|
|
825
882
|
|
|
826
|
-
transitionTo(name) {
|
|
883
|
+
transitionTo(name: string) {
|
|
827
884
|
// POSSIBLE TODO: Remove this code and replace with
|
|
828
885
|
// always having direct reference to state objects
|
|
829
886
|
|
|
830
887
|
let pivotName = extractPivotName(name);
|
|
831
|
-
let state = this.currentState;
|
|
888
|
+
let state: any = this.currentState;
|
|
832
889
|
let transitionMapId = `${state.stateName}->${name}`;
|
|
833
890
|
|
|
834
891
|
do {
|
|
@@ -873,13 +930,12 @@ export default class InternalModel {
|
|
|
873
930
|
}
|
|
874
931
|
|
|
875
932
|
this.currentState = state;
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
//
|
|
933
|
+
|
|
934
|
+
// isDSModel is the guard we want, but may be too restrictive if
|
|
935
|
+
// ember-m3 / ember-data-model-fragments were relying on this still.
|
|
936
|
+
if (this.hasRecord && isDSModel(this._record)) {
|
|
937
|
+
// TODO eliminate this.
|
|
881
938
|
this.notifyStateChange('currentState');
|
|
882
|
-
// this._record.notifyPropertyChange('currentState');
|
|
883
939
|
}
|
|
884
940
|
|
|
885
941
|
for (i = 0, l = setups.length; i < l; i++) {
|
|
@@ -887,7 +943,7 @@ export default class InternalModel {
|
|
|
887
943
|
}
|
|
888
944
|
}
|
|
889
945
|
|
|
890
|
-
_unhandledEvent(state, name, context) {
|
|
946
|
+
_unhandledEvent(state, name: string, context) {
|
|
891
947
|
let errorMessage = 'Attempted to handle event `' + name + '` ';
|
|
892
948
|
errorMessage += 'on ' + String(this) + ' while in state ';
|
|
893
949
|
errorMessage += state.stateName + '. ';
|
|
@@ -899,35 +955,6 @@ export default class InternalModel {
|
|
|
899
955
|
throw new EmberError(errorMessage);
|
|
900
956
|
}
|
|
901
957
|
|
|
902
|
-
triggerLater(...args) {
|
|
903
|
-
if (this._deferredTriggers.push(args) !== 1) {
|
|
904
|
-
return;
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
this.store._updateInternalModel(this);
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
_triggerDeferredTriggers() {
|
|
911
|
-
//TODO: Before 1.0 we want to remove all the events that happen on the pre materialized record,
|
|
912
|
-
//but for now, we queue up all the events triggered before the record was materialized, and flush
|
|
913
|
-
//them once we have the record
|
|
914
|
-
if (!this.hasRecord) {
|
|
915
|
-
return;
|
|
916
|
-
}
|
|
917
|
-
let triggers = this._deferredTriggers;
|
|
918
|
-
let record = this._record;
|
|
919
|
-
let trigger = record.trigger;
|
|
920
|
-
// TODO Igor make nicer check
|
|
921
|
-
if (trigger && typeof trigger === 'function') {
|
|
922
|
-
for (let i = 0, l = triggers.length; i < l; i++) {
|
|
923
|
-
let eventName = triggers[i];
|
|
924
|
-
trigger.apply(record, eventName);
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
triggers.length = 0;
|
|
929
|
-
}
|
|
930
|
-
|
|
931
958
|
removeFromInverseRelationships() {
|
|
932
959
|
if (this.__recordData) {
|
|
933
960
|
this.store._backburner.join(() => {
|
|
@@ -1057,26 +1084,34 @@ export default class InternalModel {
|
|
|
1057
1084
|
this.store._notificationManager.notify(this.identifier, 'attributes');
|
|
1058
1085
|
}
|
|
1059
1086
|
|
|
1060
|
-
hasErrors() {
|
|
1087
|
+
hasErrors(): boolean {
|
|
1088
|
+
// TODO add assertion forcing consuming RecordData's to implement getErrors
|
|
1061
1089
|
if (this._recordData.getErrors) {
|
|
1062
1090
|
return this._recordData.getErrors(this.identifier).length > 0;
|
|
1063
1091
|
} else {
|
|
1064
|
-
|
|
1092
|
+
// we can't have errors if we never tried loading
|
|
1093
|
+
if (!this._record) {
|
|
1094
|
+
return false;
|
|
1095
|
+
}
|
|
1096
|
+
let errors = (this._record as DSModel).errors;
|
|
1065
1097
|
return errors.length > 0;
|
|
1066
1098
|
}
|
|
1067
1099
|
}
|
|
1068
1100
|
|
|
1069
1101
|
// FOR USE DURING COMMIT PROCESS
|
|
1070
|
-
adapterDidInvalidate(parsedErrors, error) {
|
|
1102
|
+
adapterDidInvalidate(parsedErrors, error?) {
|
|
1071
1103
|
// TODO @runspired this should be handled by RecordState
|
|
1072
1104
|
// and errors should be dirtied but lazily fetch if at
|
|
1073
1105
|
// all possible. We should only notify errors here.
|
|
1074
1106
|
let attribute;
|
|
1075
1107
|
if (error && parsedErrors) {
|
|
1108
|
+
// TODO add assertion forcing consuming RecordData's to implement getErrors
|
|
1076
1109
|
if (!this._recordData.getErrors) {
|
|
1110
|
+
let record = this.getRecord() as DSModel;
|
|
1111
|
+
let errors = record.errors;
|
|
1077
1112
|
for (attribute in parsedErrors) {
|
|
1078
1113
|
if (hasOwnProperty.call(parsedErrors, attribute)) {
|
|
1079
|
-
|
|
1114
|
+
errors._add(attribute, parsedErrors[attribute]);
|
|
1080
1115
|
}
|
|
1081
1116
|
}
|
|
1082
1117
|
}
|
|
@@ -1117,7 +1152,9 @@ export default class InternalModel {
|
|
|
1117
1152
|
// because of the intimate API access involved. This is something we will need to redesign.
|
|
1118
1153
|
assert(`snapshot.belongsTo only supported for @ember-data/record-data`);
|
|
1119
1154
|
}
|
|
1120
|
-
const graphFor =
|
|
1155
|
+
const graphFor = (
|
|
1156
|
+
importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
|
|
1157
|
+
).graphFor;
|
|
1121
1158
|
const relationship = graphFor(this.store._storeWrapper).get(this.identifier, name);
|
|
1122
1159
|
|
|
1123
1160
|
if (DEBUG && kind) {
|
|
@@ -1145,7 +1182,39 @@ export default class InternalModel {
|
|
|
1145
1182
|
}
|
|
1146
1183
|
}
|
|
1147
1184
|
|
|
1148
|
-
function handleCompletedRelationshipRequest(
|
|
1185
|
+
function handleCompletedRelationshipRequest(
|
|
1186
|
+
internalModel: InternalModel,
|
|
1187
|
+
key: string,
|
|
1188
|
+
relationship: BelongsToRelationship,
|
|
1189
|
+
value: InternalModel | null
|
|
1190
|
+
): RecordInstance | null;
|
|
1191
|
+
function handleCompletedRelationshipRequest(
|
|
1192
|
+
internalModel: InternalModel,
|
|
1193
|
+
key: string,
|
|
1194
|
+
relationship: ManyRelationship,
|
|
1195
|
+
value: ManyArray
|
|
1196
|
+
): ManyArray;
|
|
1197
|
+
function handleCompletedRelationshipRequest(
|
|
1198
|
+
internalModel: InternalModel,
|
|
1199
|
+
key: string,
|
|
1200
|
+
relationship: BelongsToRelationship,
|
|
1201
|
+
value: null,
|
|
1202
|
+
error: Error
|
|
1203
|
+
): never;
|
|
1204
|
+
function handleCompletedRelationshipRequest(
|
|
1205
|
+
internalModel: InternalModel,
|
|
1206
|
+
key: string,
|
|
1207
|
+
relationship: ManyRelationship,
|
|
1208
|
+
value: ManyArray,
|
|
1209
|
+
error: Error
|
|
1210
|
+
): never;
|
|
1211
|
+
function handleCompletedRelationshipRequest(
|
|
1212
|
+
internalModel: InternalModel,
|
|
1213
|
+
key: string,
|
|
1214
|
+
relationship: BelongsToRelationship | ManyRelationship,
|
|
1215
|
+
value: ManyArray | InternalModel | null,
|
|
1216
|
+
error?: Error
|
|
1217
|
+
): ManyArray | RecordInstance | null {
|
|
1149
1218
|
delete internalModel._relationshipPromisesCache[key];
|
|
1150
1219
|
relationship.state.shouldForceReload = false;
|
|
1151
1220
|
const isHasMany = relationship.definition.kind === 'hasMany';
|
|
@@ -1153,7 +1222,7 @@ function handleCompletedRelationshipRequest(internalModel, key, relationship, va
|
|
|
1153
1222
|
if (isHasMany) {
|
|
1154
1223
|
// we don't notify the record property here to avoid refetch
|
|
1155
1224
|
// only the many array
|
|
1156
|
-
value.notify();
|
|
1225
|
+
(value as ManyArray).notify();
|
|
1157
1226
|
}
|
|
1158
1227
|
|
|
1159
1228
|
if (error) {
|
|
@@ -1168,7 +1237,9 @@ function handleCompletedRelationshipRequest(internalModel, key, relationship, va
|
|
|
1168
1237
|
// has never been accessed
|
|
1169
1238
|
if (proxy && !isHasMany) {
|
|
1170
1239
|
if (proxy.content && proxy.content.isDestroying) {
|
|
1171
|
-
|
|
1240
|
+
// TODO @types/ember__object incorrectly disallows `null`, we should either
|
|
1241
|
+
// override or fix upstream
|
|
1242
|
+
(proxy as PromiseBelongsTo).set('content', null as unknown as undefined);
|
|
1172
1243
|
}
|
|
1173
1244
|
}
|
|
1174
1245
|
|
|
@@ -1176,14 +1247,14 @@ function handleCompletedRelationshipRequest(internalModel, key, relationship, va
|
|
|
1176
1247
|
}
|
|
1177
1248
|
|
|
1178
1249
|
if (isHasMany) {
|
|
1179
|
-
value.set('isLoaded', true);
|
|
1250
|
+
(value as ManyArray).set('isLoaded', true);
|
|
1180
1251
|
}
|
|
1181
1252
|
|
|
1182
1253
|
relationship.state.hasFailedLoadAttempt = false;
|
|
1183
1254
|
// only set to not stale if no error is thrown
|
|
1184
1255
|
relationship.state.isStale = false;
|
|
1185
1256
|
|
|
1186
|
-
return value;
|
|
1257
|
+
return isHasMany || !value ? (value as ManyArray | null) : (value as InternalModel).getRecord();
|
|
1187
1258
|
}
|
|
1188
1259
|
|
|
1189
1260
|
export function assertRecordsPassedToHasMany(records) {
|