@ember-data/store 4.4.0-alpha.8 → 4.4.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/system/core-store.ts +119 -130
- package/addon/-private/system/ds-model-store.ts +10 -1
- package/addon/-private/system/fetch-manager.ts +21 -48
- package/addon/-private/system/model/internal-model.ts +160 -264
- package/addon/-private/system/{promise-proxies.ts → promise-proxies.js} +21 -31
- package/addon/-private/system/{record-array-manager.ts → record-array-manager.js} +60 -87
- package/addon/-private/system/record-arrays/adapter-populated-record-array.js +95 -0
- package/addon/-private/system/record-arrays/{record-array.ts → record-array.js} +75 -96
- package/addon/-private/system/record-data-for.ts +0 -2
- package/addon/-private/system/references/belongs-to.ts +2 -3
- package/addon/-private/system/references/has-many.ts +2 -4
- package/addon/-private/system/schema-definition-service.ts +2 -2
- package/addon/-private/system/snapshot-record-array.ts +11 -12
- package/addon/-private/system/snapshot.ts +7 -24
- package/addon/-private/system/store/common.js +1 -24
- package/addon/-private/system/store/finders.js +5 -53
- package/addon/-private/system/store/internal-model-factory.ts +7 -8
- package/addon/-private/system/store/record-data-store-wrapper.ts +2 -7
- package/addon/-private/system/store/serializer-response.js +71 -0
- package/addon/-private/ts-interfaces/ds-model.ts +7 -15
- package/addon/-private/ts-interfaces/ember-data-json-api.ts +0 -3
- package/addon/-private/ts-interfaces/minimum-adapter-interface.ts +20 -19
- package/addon/-private/ts-interfaces/minimum-serializer-interface.ts +6 -27
- package/addon/-private/ts-interfaces/record-data.ts +1 -4
- package/addon/-private/ts-interfaces/record-instance.ts +1 -3
- package/addon/-private/ts-interfaces/store.ts +0 -1
- package/addon/-private/utils/promise-record.ts +3 -3
- package/index.js +0 -3
- package/package.json +6 -7
- package/addon/-private/system/promise-proxy-base.js +0 -7
- package/addon/-private/system/record-arrays/adapter-populated-record-array.ts +0 -129
- package/addon/-private/system/store/serializer-response.ts +0 -85
|
@@ -5,19 +5,8 @@ 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 {
|
|
9
|
-
import RSVP, { resolve } from 'rsvp';
|
|
8
|
+
import RSVP, { Promise } from 'rsvp';
|
|
10
9
|
|
|
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';
|
|
21
10
|
import { HAS_MODEL_PACKAGE, HAS_RECORD_DATA_PACKAGE } from '@ember-data/private-build-infra';
|
|
22
11
|
import type {
|
|
23
12
|
BelongsToRelationship,
|
|
@@ -25,21 +14,16 @@ import type {
|
|
|
25
14
|
RecordData as DefaultRecordData,
|
|
26
15
|
} from '@ember-data/record-data/-private';
|
|
27
16
|
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';
|
|
32
17
|
|
|
33
|
-
import
|
|
18
|
+
import { DSModel } from '../../ts-interfaces/ds-model';
|
|
34
19
|
import type { StableRecordIdentifier } from '../../ts-interfaces/identifier';
|
|
35
|
-
import type {
|
|
20
|
+
import type { RecordData } from '../../ts-interfaces/record-data';
|
|
36
21
|
import type { JsonApiResource, JsonApiValidationError } from '../../ts-interfaces/record-data-json-api';
|
|
37
|
-
import type { RelationshipSchema } from '../../ts-interfaces/record-data-schemas';
|
|
38
22
|
import type { RecordInstance } from '../../ts-interfaces/record-instance';
|
|
39
23
|
import type { FindOptions } from '../../ts-interfaces/store';
|
|
40
|
-
import type {
|
|
24
|
+
import type { ConfidentDict } from '../../ts-interfaces/utils';
|
|
41
25
|
import type CoreStore from '../core-store';
|
|
42
|
-
import type
|
|
26
|
+
import type Store from '../ds-model-store';
|
|
43
27
|
import { errorsHashToArray } from '../errors-utils';
|
|
44
28
|
import recordDataFor from '../record-data-for';
|
|
45
29
|
import { BelongsToReference, HasManyReference, RecordReference } from '../references';
|
|
@@ -47,11 +31,10 @@ import Snapshot from '../snapshot';
|
|
|
47
31
|
import { internalModelFactoryFor } from '../store/internal-model-factory';
|
|
48
32
|
import RootState from './states';
|
|
49
33
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
};
|
|
34
|
+
// move to TS hacks module that we can delete when this is no longer a necessary recast
|
|
35
|
+
type ManyArray = InstanceType<typeof import('@ember-data/model/-private').ManyArray>;
|
|
36
|
+
type PromiseBelongsTo = InstanceType<typeof import('@ember-data/model/-private').PromiseBelongsTo>;
|
|
37
|
+
type PromiseManyArray = InstanceType<typeof import('@ember-data/model/-private').PromiseManyArray>;
|
|
55
38
|
|
|
56
39
|
/**
|
|
57
40
|
@module @ember-data/store
|
|
@@ -59,22 +42,18 @@ type PrivateModelModule = {
|
|
|
59
42
|
|
|
60
43
|
const { hasOwnProperty } = Object.prototype;
|
|
61
44
|
|
|
62
|
-
let
|
|
63
|
-
let
|
|
64
|
-
let _PromiseManyArray:
|
|
45
|
+
let ManyArray: ManyArray;
|
|
46
|
+
let PromiseBelongsTo: PromiseBelongsTo;
|
|
47
|
+
let _PromiseManyArray: any; // TODO find a way to get the klass type here
|
|
65
48
|
|
|
66
49
|
let _found = false;
|
|
67
50
|
let _getModelPackage: () => boolean;
|
|
68
51
|
if (HAS_MODEL_PACKAGE) {
|
|
69
52
|
_getModelPackage = function () {
|
|
70
53
|
if (!_found) {
|
|
71
|
-
let modelPackage =
|
|
72
|
-
({
|
|
73
|
-
|
|
74
|
-
PromiseBelongsTo: _PromiseBelongsTo,
|
|
75
|
-
PromiseManyArray: _PromiseManyArray,
|
|
76
|
-
} = modelPackage);
|
|
77
|
-
if (_ManyArray && _PromiseBelongsTo && _PromiseManyArray) {
|
|
54
|
+
let modelPackage = require('@ember-data/model/-private');
|
|
55
|
+
({ ManyArray, PromiseBelongsTo, PromiseManyArray: _PromiseManyArray } = modelPackage);
|
|
56
|
+
if (ManyArray && PromiseBelongsTo && _PromiseManyArray) {
|
|
78
57
|
_found = true;
|
|
79
58
|
}
|
|
80
59
|
}
|
|
@@ -82,6 +61,13 @@ if (HAS_MODEL_PACKAGE) {
|
|
|
82
61
|
};
|
|
83
62
|
}
|
|
84
63
|
|
|
64
|
+
interface BelongsToMetaWrapper {
|
|
65
|
+
key: string;
|
|
66
|
+
store: CoreStore;
|
|
67
|
+
originatingInternalModel: InternalModel;
|
|
68
|
+
modelName: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
85
71
|
/*
|
|
86
72
|
The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached
|
|
87
73
|
when transitioning from one state to another, so that future transitions can replay the
|
|
@@ -92,32 +78,18 @@ if (HAS_MODEL_PACKAGE) {
|
|
|
92
78
|
and setups. It may also be faster to do a two level cache (from: { to }) instead of caching based
|
|
93
79
|
on a key that adds the two together.
|
|
94
80
|
*/
|
|
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.
|
|
98
81
|
const TransitionChainMap = Object.create(null);
|
|
99
82
|
|
|
100
83
|
const _extractPivotNameCache = Object.create(null);
|
|
101
84
|
const _splitOnDotCache = Object.create(null);
|
|
102
85
|
|
|
103
|
-
function splitOnDot(name
|
|
86
|
+
function splitOnDot(name) {
|
|
104
87
|
return _splitOnDotCache[name] || (_splitOnDotCache[name] = name.split('.'));
|
|
105
88
|
}
|
|
106
89
|
|
|
107
|
-
function extractPivotName(name
|
|
90
|
+
function extractPivotName(name) {
|
|
108
91
|
return _extractPivotNameCache[name] || (_extractPivotNameCache[name] = splitOnDot(name)[0]);
|
|
109
92
|
}
|
|
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
|
-
|
|
121
93
|
export default class InternalModel {
|
|
122
94
|
declare _id: string | null;
|
|
123
95
|
declare modelName: string;
|
|
@@ -134,29 +106,25 @@ export default class InternalModel {
|
|
|
134
106
|
|
|
135
107
|
// Not typed yet
|
|
136
108
|
declare _promiseProxy: any;
|
|
137
|
-
declare _record:
|
|
109
|
+
declare _record: any;
|
|
138
110
|
declare _scheduledDestroy: any;
|
|
139
111
|
declare _modelClass: any;
|
|
140
112
|
declare _deferredTriggers: any;
|
|
141
113
|
declare __recordArrays: any;
|
|
142
114
|
declare references: any;
|
|
143
115
|
declare _recordReference: RecordReference;
|
|
144
|
-
declare _manyArrayCache:
|
|
116
|
+
declare _manyArrayCache: ConfidentDict<ManyArray>;
|
|
145
117
|
|
|
146
|
-
declare _relationshipPromisesCache:
|
|
147
|
-
declare _relationshipProxyCache:
|
|
118
|
+
declare _relationshipPromisesCache: ConfidentDict<RSVP.Promise<any>>;
|
|
119
|
+
declare _relationshipProxyCache: ConfidentDict<PromiseManyArray | PromiseBelongsTo>;
|
|
148
120
|
declare error: any;
|
|
149
|
-
declare currentState:
|
|
121
|
+
declare currentState: any;
|
|
150
122
|
declare _previousState: any;
|
|
151
|
-
declare store: CoreStore;
|
|
152
|
-
declare identifier: StableRecordIdentifier;
|
|
153
123
|
|
|
154
|
-
constructor(store: CoreStore, identifier: StableRecordIdentifier) {
|
|
124
|
+
constructor(public store: CoreStore | Store, public identifier: StableRecordIdentifier) {
|
|
155
125
|
if (HAS_MODEL_PACKAGE) {
|
|
156
126
|
_getModelPackage();
|
|
157
127
|
}
|
|
158
|
-
this.store = store;
|
|
159
|
-
this.identifier = identifier;
|
|
160
128
|
this._id = identifier.id;
|
|
161
129
|
this._isUpdatingId = false;
|
|
162
130
|
this.modelName = identifier.type;
|
|
@@ -288,28 +256,15 @@ export default class InternalModel {
|
|
|
288
256
|
}
|
|
289
257
|
}
|
|
290
258
|
|
|
291
|
-
getRecord(properties
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
if (this._isDematerializing) {
|
|
295
|
-
// TODO we should assert here instead of this return.
|
|
296
|
-
return null as unknown as RecordInstance;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (!record) {
|
|
259
|
+
getRecord(properties?): Object {
|
|
260
|
+
if (!this._record && !this._isDematerializing) {
|
|
300
261
|
let { store } = this;
|
|
301
262
|
|
|
302
|
-
|
|
303
|
-
this,
|
|
304
|
-
this.modelName,
|
|
305
|
-
this._recordData,
|
|
306
|
-
this.identifier,
|
|
307
|
-
properties
|
|
308
|
-
);
|
|
263
|
+
this._record = store._instantiateRecord(this, this.modelName, this._recordData, this.identifier, properties);
|
|
309
264
|
this._triggerDeferredTriggers();
|
|
310
265
|
}
|
|
311
266
|
|
|
312
|
-
return
|
|
267
|
+
return this._record;
|
|
313
268
|
}
|
|
314
269
|
|
|
315
270
|
dematerializeRecord() {
|
|
@@ -333,11 +288,9 @@ export default class InternalModel {
|
|
|
333
288
|
});
|
|
334
289
|
|
|
335
290
|
if (this._record) {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
if (proxy.destroy) {
|
|
340
|
-
proxy.destroy();
|
|
291
|
+
Object.keys(this._relationshipProxyCache).forEach((key) => {
|
|
292
|
+
if (this._relationshipProxyCache[key].destroy) {
|
|
293
|
+
this._relationshipProxyCache[key].destroy();
|
|
341
294
|
}
|
|
342
295
|
delete this._relationshipProxyCache[key];
|
|
343
296
|
});
|
|
@@ -371,9 +324,9 @@ export default class InternalModel {
|
|
|
371
324
|
});
|
|
372
325
|
}
|
|
373
326
|
|
|
374
|
-
save(options
|
|
327
|
+
save(options): Promise<void> {
|
|
375
328
|
if (this._deletedRecordWasNew) {
|
|
376
|
-
return resolve();
|
|
329
|
+
return Promise.resolve();
|
|
377
330
|
}
|
|
378
331
|
let promiseLabel = 'DS: Model#save ' + this;
|
|
379
332
|
let resolver = RSVP.defer<void>(promiseLabel);
|
|
@@ -382,8 +335,22 @@ export default class InternalModel {
|
|
|
382
335
|
return this.store.scheduleSave(this, resolver, options) as Promise<void>;
|
|
383
336
|
}
|
|
384
337
|
|
|
385
|
-
reload(options
|
|
386
|
-
|
|
338
|
+
reload(options) {
|
|
339
|
+
if (!options) {
|
|
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
|
+
);
|
|
387
354
|
}
|
|
388
355
|
|
|
389
356
|
/*
|
|
@@ -458,32 +425,26 @@ export default class InternalModel {
|
|
|
458
425
|
}
|
|
459
426
|
}
|
|
460
427
|
|
|
461
|
-
_findBelongsTo(
|
|
462
|
-
key: string,
|
|
463
|
-
resource: DefaultSingleResourceRelationship,
|
|
464
|
-
relationshipMeta: RelationshipSchema,
|
|
465
|
-
options?: Dict<unknown>
|
|
466
|
-
): Promise<RecordInstance | null> {
|
|
428
|
+
_findBelongsTo(key, resource, relationshipMeta, options) {
|
|
467
429
|
// TODO @runspired follow up if parent isNew then we should not be attempting load here
|
|
468
|
-
// TODO @runspired follow up on whether this should be in the relationship requests cache
|
|
469
430
|
return this.store._findBelongsToByJsonApiResource(resource, this, relationshipMeta, options).then(
|
|
470
|
-
(internalModel) => handleCompletedRelationshipRequest(this, key, resource._relationship, internalModel),
|
|
431
|
+
(internalModel) => handleCompletedRelationshipRequest(this, key, resource._relationship, internalModel, null),
|
|
471
432
|
(e) => handleCompletedRelationshipRequest(this, key, resource._relationship, null, e)
|
|
472
433
|
);
|
|
473
434
|
}
|
|
474
435
|
|
|
475
|
-
getBelongsTo(key
|
|
436
|
+
getBelongsTo(key, options) {
|
|
476
437
|
let resource = (this._recordData as DefaultRecordData).getBelongsTo(key);
|
|
477
438
|
let identifier =
|
|
478
439
|
resource && resource.data ? this.store.identifierCache.getOrCreateRecordIdentifier(resource.data) : null;
|
|
479
440
|
let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key);
|
|
480
|
-
|
|
441
|
+
if (!relationshipMeta) return;
|
|
481
442
|
|
|
482
443
|
let store = this.store;
|
|
483
444
|
let parentInternalModel = this;
|
|
484
445
|
let async = relationshipMeta.options.async;
|
|
485
446
|
let isAsync = typeof async === 'undefined' ? true : async;
|
|
486
|
-
let _belongsToState:
|
|
447
|
+
let _belongsToState: BelongsToMetaWrapper = {
|
|
487
448
|
key,
|
|
488
449
|
store,
|
|
489
450
|
originatingInternalModel: this,
|
|
@@ -494,7 +455,7 @@ export default class InternalModel {
|
|
|
494
455
|
let internalModel = identifier !== null ? store._internalModelForResource(identifier) : null;
|
|
495
456
|
|
|
496
457
|
if (resource._relationship.state.hasFailedLoadAttempt) {
|
|
497
|
-
return this._relationshipProxyCache[key]
|
|
458
|
+
return this._relationshipProxyCache[key];
|
|
498
459
|
}
|
|
499
460
|
|
|
500
461
|
let promise = this._findBelongsTo(key, resource, relationshipMeta, options);
|
|
@@ -518,49 +479,49 @@ export default class InternalModel {
|
|
|
518
479
|
"' with id " +
|
|
519
480
|
parentInternalModel.id +
|
|
520
481
|
' 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 })`)',
|
|
521
|
-
toReturn === null || !
|
|
482
|
+
toReturn === null || !(toReturn as DSModel).isEmpty
|
|
522
483
|
);
|
|
523
484
|
return toReturn;
|
|
524
485
|
}
|
|
525
486
|
}
|
|
526
487
|
}
|
|
527
488
|
|
|
528
|
-
getManyArray(key: string, definition?: UpgradedMeta)
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
definition = graphFor(this.store).get(this.identifier, key).definition as UpgradedMeta;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
if (!manyArray) {
|
|
539
|
-
manyArray = _ManyArray.create({
|
|
540
|
-
store: this.store,
|
|
541
|
-
type: this.store.modelFor(definition.type),
|
|
542
|
-
recordData: this._recordData as RelationshipRecordData,
|
|
543
|
-
key,
|
|
544
|
-
isPolymorphic: definition.isPolymorphic,
|
|
545
|
-
isAsync: definition.isAsync,
|
|
546
|
-
_inverseIsAsync: definition.inverseIsAsync,
|
|
547
|
-
internalModel: this,
|
|
548
|
-
isLoaded: !definition.isAsync,
|
|
549
|
-
});
|
|
550
|
-
this._manyArrayCache[key] = manyArray;
|
|
551
|
-
}
|
|
489
|
+
getManyArray(key: string, definition?: UpgradedMeta) {
|
|
490
|
+
if (HAS_RECORD_DATA_PACKAGE) {
|
|
491
|
+
let manyArray = this._manyArrayCache[key];
|
|
492
|
+
if (!definition) {
|
|
493
|
+
const graphFor = require('@ember-data/record-data/-private').graphFor;
|
|
494
|
+
definition = graphFor(this.store).get(this.identifier, key).definition as UpgradedMeta;
|
|
495
|
+
}
|
|
552
496
|
|
|
553
|
-
|
|
497
|
+
if (!manyArray) {
|
|
498
|
+
manyArray = ManyArray.create({
|
|
499
|
+
store: this.store,
|
|
500
|
+
type: this.store.modelFor(definition.type),
|
|
501
|
+
recordData: this._recordData,
|
|
502
|
+
key,
|
|
503
|
+
isPolymorphic: definition.isPolymorphic,
|
|
504
|
+
isAsync: definition.isAsync,
|
|
505
|
+
_inverseIsAsync: definition.inverseIsAsync,
|
|
506
|
+
internalModel: this,
|
|
507
|
+
isLoaded: !definition.isAsync,
|
|
508
|
+
});
|
|
509
|
+
this._manyArrayCache[key] = manyArray;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return manyArray;
|
|
513
|
+
}
|
|
514
|
+
assert(`hasMany only works with the @ember-data/record-data package`, HAS_RECORD_DATA_PACKAGE);
|
|
554
515
|
}
|
|
555
516
|
|
|
556
517
|
fetchAsyncHasMany(
|
|
557
518
|
key: string,
|
|
558
|
-
relationship: ManyRelationship,
|
|
559
|
-
manyArray
|
|
560
|
-
options
|
|
561
|
-
): Promise<
|
|
519
|
+
relationship: ManyRelationship | BelongsToRelationship,
|
|
520
|
+
manyArray,
|
|
521
|
+
options
|
|
522
|
+
): RSVP.Promise<unknown> {
|
|
562
523
|
if (HAS_RECORD_DATA_PACKAGE) {
|
|
563
|
-
let loadingPromise = this._relationshipPromisesCache[key]
|
|
524
|
+
let loadingPromise = this._relationshipPromisesCache[key];
|
|
564
525
|
if (loadingPromise) {
|
|
565
526
|
return loadingPromise;
|
|
566
527
|
}
|
|
@@ -568,27 +529,25 @@ export default class InternalModel {
|
|
|
568
529
|
const jsonApi = this._recordData.getHasMany(key);
|
|
569
530
|
|
|
570
531
|
loadingPromise = this.store._findHasManyByJsonApiResource(jsonApi, this, relationship, options).then(
|
|
571
|
-
() => handleCompletedRelationshipRequest(this, key, relationship, manyArray),
|
|
532
|
+
() => handleCompletedRelationshipRequest(this, key, relationship, manyArray, null),
|
|
572
533
|
(e) => handleCompletedRelationshipRequest(this, key, relationship, manyArray, e)
|
|
573
534
|
);
|
|
574
535
|
this._relationshipPromisesCache[key] = loadingPromise;
|
|
575
536
|
return loadingPromise;
|
|
576
537
|
}
|
|
577
|
-
assert(
|
|
538
|
+
assert(`hasMany only works with the @ember-data/record-data package`);
|
|
578
539
|
}
|
|
579
540
|
|
|
580
|
-
getHasMany(key: string, options?)
|
|
541
|
+
getHasMany(key: string, options?) {
|
|
581
542
|
if (HAS_RECORD_DATA_PACKAGE) {
|
|
582
|
-
const graphFor = (
|
|
583
|
-
|
|
584
|
-
).graphFor;
|
|
585
|
-
const relationship = graphFor(this.store).get(this.identifier, key) as ManyRelationship;
|
|
543
|
+
const graphFor = require('@ember-data/record-data/-private').graphFor;
|
|
544
|
+
const relationship = graphFor(this.store).get(this.identifier, key);
|
|
586
545
|
const { definition, state } = relationship;
|
|
587
546
|
let manyArray = this.getManyArray(key, definition);
|
|
588
547
|
|
|
589
548
|
if (definition.isAsync) {
|
|
590
549
|
if (state.hasFailedLoadAttempt) {
|
|
591
|
-
return this._relationshipProxyCache[key]
|
|
550
|
+
return this._relationshipProxyCache[key];
|
|
592
551
|
}
|
|
593
552
|
|
|
594
553
|
let promise = this.fetchAsyncHasMany(key, relationship, manyArray, options);
|
|
@@ -606,55 +565,47 @@ export default class InternalModel {
|
|
|
606
565
|
assert(`hasMany only works with the @ember-data/record-data package`);
|
|
607
566
|
}
|
|
608
567
|
|
|
609
|
-
_updatePromiseProxyFor(kind: 'hasMany', key: string, args: HasManyProxyCreateArgs): PromiseManyArray;
|
|
610
|
-
_updatePromiseProxyFor(kind: 'belongsTo', key: string, args: BelongsToProxyCreateArgs): PromiseBelongsTo;
|
|
611
|
-
_updatePromiseProxyFor(
|
|
612
|
-
kind: 'belongsTo',
|
|
613
|
-
key: string,
|
|
614
|
-
args: { promise: Promise<RecordInstance | null> }
|
|
615
|
-
): PromiseBelongsTo;
|
|
616
568
|
_updatePromiseProxyFor(
|
|
617
569
|
kind: 'hasMany' | 'belongsTo',
|
|
618
570
|
key: string,
|
|
619
|
-
args:
|
|
620
|
-
|
|
571
|
+
args: {
|
|
572
|
+
promise: RSVP.Promise<any>;
|
|
573
|
+
content?: RecordInstance | ManyArray | null;
|
|
574
|
+
_belongsToState?: BelongsToMetaWrapper;
|
|
575
|
+
}
|
|
576
|
+
) {
|
|
621
577
|
let promiseProxy = this._relationshipProxyCache[key];
|
|
622
578
|
if (kind === 'hasMany') {
|
|
623
|
-
const { promise, content } = args as HasManyProxyCreateArgs;
|
|
624
579
|
if (promiseProxy) {
|
|
625
|
-
|
|
626
|
-
promiseProxy._update(promise, content);
|
|
580
|
+
promiseProxy._update(args.promise, args.content);
|
|
627
581
|
} else {
|
|
628
|
-
promiseProxy = this._relationshipProxyCache[key] = new _PromiseManyArray(promise, content);
|
|
582
|
+
promiseProxy = this._relationshipProxyCache[key] = new _PromiseManyArray(args.promise, args.content);
|
|
629
583
|
}
|
|
630
584
|
return promiseProxy;
|
|
631
585
|
}
|
|
632
586
|
if (promiseProxy) {
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
if (content !== undefined) {
|
|
637
|
-
promiseProxy.set('content', content);
|
|
587
|
+
if (args.content !== undefined) {
|
|
588
|
+
// this usage of `any` can be removed when `@types/ember_object` proxy allows `null` for content
|
|
589
|
+
promiseProxy.set('content', args.content as any);
|
|
638
590
|
}
|
|
639
|
-
promiseProxy.set('promise', promise);
|
|
591
|
+
promiseProxy.set('promise', args.promise);
|
|
640
592
|
} else {
|
|
593
|
+
const klass = PromiseBelongsTo;
|
|
641
594
|
// this usage of `any` can be removed when `@types/ember_object` proxy allows `null` for content
|
|
642
|
-
this._relationshipProxyCache[key] =
|
|
595
|
+
this._relationshipProxyCache[key] = klass.create(args as any);
|
|
643
596
|
}
|
|
644
597
|
|
|
645
|
-
return
|
|
598
|
+
return this._relationshipProxyCache[key];
|
|
646
599
|
}
|
|
647
600
|
|
|
648
|
-
reloadHasMany(key
|
|
601
|
+
reloadHasMany(key, options) {
|
|
649
602
|
if (HAS_RECORD_DATA_PACKAGE) {
|
|
650
603
|
let loadingPromise = this._relationshipPromisesCache[key];
|
|
651
604
|
if (loadingPromise) {
|
|
652
605
|
return loadingPromise;
|
|
653
606
|
}
|
|
654
|
-
const graphFor = (
|
|
655
|
-
|
|
656
|
-
).graphFor;
|
|
657
|
-
const relationship = graphFor(this.store).get(this.identifier, key) as ManyRelationship;
|
|
607
|
+
const graphFor = require('@ember-data/record-data/-private').graphFor;
|
|
608
|
+
const relationship = graphFor(this.store).get(this.identifier, key);
|
|
658
609
|
const { definition, state } = relationship;
|
|
659
610
|
|
|
660
611
|
state.hasFailedLoadAttempt = false;
|
|
@@ -671,8 +622,8 @@ export default class InternalModel {
|
|
|
671
622
|
assert(`hasMany only works with the @ember-data/record-data package`);
|
|
672
623
|
}
|
|
673
624
|
|
|
674
|
-
reloadBelongsTo(key
|
|
675
|
-
let loadingPromise = this._relationshipPromisesCache[key]
|
|
625
|
+
reloadBelongsTo(key, options) {
|
|
626
|
+
let loadingPromise = this._relationshipPromisesCache[key];
|
|
676
627
|
if (loadingPromise) {
|
|
677
628
|
return loadingPromise;
|
|
678
629
|
}
|
|
@@ -684,7 +635,6 @@ export default class InternalModel {
|
|
|
684
635
|
resource._relationship.state.shouldForceReload = true;
|
|
685
636
|
}
|
|
686
637
|
let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key);
|
|
687
|
-
assert(`Attempted to reload a belongsTo relationship but no definition exists for it`, relationshipMeta);
|
|
688
638
|
let promise = this._findBelongsTo(key, resource, relationshipMeta, options);
|
|
689
639
|
if (this._relationshipProxyCache[key]) {
|
|
690
640
|
return this._updatePromiseProxyFor('belongsTo', key, { promise });
|
|
@@ -703,7 +653,7 @@ export default class InternalModel {
|
|
|
703
653
|
destroy() {
|
|
704
654
|
assert(
|
|
705
655
|
'Cannot destroy an internalModel while its record is materialized',
|
|
706
|
-
!this._record || this._record.isDestroyed || this._record.isDestroying
|
|
656
|
+
!this._record || this._record.get('isDestroyed') || this._record.get('isDestroying')
|
|
707
657
|
);
|
|
708
658
|
this.isDestroying = true;
|
|
709
659
|
if (this._recordReference) {
|
|
@@ -712,13 +662,13 @@ export default class InternalModel {
|
|
|
712
662
|
this._recordReference = null;
|
|
713
663
|
let cache = this._manyArrayCache;
|
|
714
664
|
Object.keys(cache).forEach((key) => {
|
|
715
|
-
cache[key]
|
|
665
|
+
cache[key].destroy();
|
|
716
666
|
delete cache[key];
|
|
717
667
|
});
|
|
718
668
|
if (this.references) {
|
|
719
669
|
cache = this.references;
|
|
720
670
|
Object.keys(cache).forEach((key) => {
|
|
721
|
-
cache[key]
|
|
671
|
+
cache[key].destroy();
|
|
722
672
|
delete cache[key];
|
|
723
673
|
});
|
|
724
674
|
}
|
|
@@ -728,35 +678,24 @@ export default class InternalModel {
|
|
|
728
678
|
}
|
|
729
679
|
|
|
730
680
|
setupData(data) {
|
|
731
|
-
|
|
732
|
-
if (hasRecord) {
|
|
733
|
-
|
|
734
|
-
this.
|
|
735
|
-
} else {
|
|
736
|
-
this._recordData.pushData(data);
|
|
681
|
+
let changedKeys = this._recordData.pushData(data, this.hasRecord);
|
|
682
|
+
if (this.hasRecord) {
|
|
683
|
+
// TODO @runspired should this be going through the notification manager?
|
|
684
|
+
this._record._notifyProperties(changedKeys);
|
|
737
685
|
}
|
|
738
686
|
this.send('pushedData');
|
|
739
687
|
}
|
|
740
688
|
|
|
741
|
-
|
|
742
|
-
let manager = this.store._notificationManager;
|
|
743
|
-
let { identifier } = this;
|
|
744
|
-
|
|
745
|
-
for (let i = 0; i < keys.length; i++) {
|
|
746
|
-
manager.notify(identifier, 'attributes', keys[i]);
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
setDirtyHasMany(key: string, records) {
|
|
689
|
+
setDirtyHasMany(key, records) {
|
|
751
690
|
assertRecordsPassedToHasMany(records);
|
|
752
691
|
return this._recordData.setDirtyHasMany(key, extractRecordDatasFromRecords(records));
|
|
753
692
|
}
|
|
754
693
|
|
|
755
|
-
setDirtyBelongsTo(key
|
|
694
|
+
setDirtyBelongsTo(key, value) {
|
|
756
695
|
return this._recordData.setDirtyBelongsTo(key, extractRecordDataFromRecord(value));
|
|
757
696
|
}
|
|
758
697
|
|
|
759
|
-
setDirtyAttribute
|
|
698
|
+
setDirtyAttribute(key, value) {
|
|
760
699
|
if (this.isDeleted()) {
|
|
761
700
|
if (DEBUG) {
|
|
762
701
|
throw new EmberError(`Attempted to set '${key}' to '${value}' on the deleted record ${this}`);
|
|
@@ -778,11 +717,11 @@ export default class InternalModel {
|
|
|
778
717
|
return value;
|
|
779
718
|
}
|
|
780
719
|
|
|
781
|
-
get isDestroyed()
|
|
720
|
+
get isDestroyed() {
|
|
782
721
|
return this._isDestroyed;
|
|
783
722
|
}
|
|
784
723
|
|
|
785
|
-
get hasRecord()
|
|
724
|
+
get hasRecord() {
|
|
786
725
|
return !!this._record;
|
|
787
726
|
}
|
|
788
727
|
|
|
@@ -790,7 +729,7 @@ export default class InternalModel {
|
|
|
790
729
|
return new Snapshot(options, this.identifier, this.store);
|
|
791
730
|
}
|
|
792
731
|
|
|
793
|
-
hasChangedAttributes()
|
|
732
|
+
hasChangedAttributes() {
|
|
794
733
|
if (!this.__recordData) {
|
|
795
734
|
// no need to calculate changed attributes when calling `findRecord`
|
|
796
735
|
return false;
|
|
@@ -798,7 +737,7 @@ export default class InternalModel {
|
|
|
798
737
|
return this._recordData.hasChangedAttributes();
|
|
799
738
|
}
|
|
800
739
|
|
|
801
|
-
changedAttributes()
|
|
740
|
+
changedAttributes() {
|
|
802
741
|
if (!this.__recordData) {
|
|
803
742
|
// no need to calculate changed attributes when calling `findRecord`
|
|
804
743
|
return {};
|
|
@@ -806,16 +745,16 @@ export default class InternalModel {
|
|
|
806
745
|
return this._recordData.changedAttributes();
|
|
807
746
|
}
|
|
808
747
|
|
|
809
|
-
adapterWillCommit()
|
|
748
|
+
adapterWillCommit() {
|
|
810
749
|
this._recordData.willCommit();
|
|
811
750
|
this.send('willCommit');
|
|
812
751
|
}
|
|
813
752
|
|
|
814
|
-
adapterDidDirty()
|
|
753
|
+
adapterDidDirty() {
|
|
815
754
|
this.send('becomeDirty');
|
|
816
755
|
}
|
|
817
756
|
|
|
818
|
-
send(name
|
|
757
|
+
send(name, context?) {
|
|
819
758
|
let currentState = this.currentState;
|
|
820
759
|
|
|
821
760
|
if (!currentState[name]) {
|
|
@@ -846,7 +785,7 @@ export default class InternalModel {
|
|
|
846
785
|
}
|
|
847
786
|
}
|
|
848
787
|
|
|
849
|
-
notifyPropertyChange(key
|
|
788
|
+
notifyPropertyChange(key) {
|
|
850
789
|
if (this.hasRecord) {
|
|
851
790
|
// TODO this should likely *mostly* be the `attributes` bucket
|
|
852
791
|
// but it seems for local mutations we rely on computed updating
|
|
@@ -856,7 +795,7 @@ export default class InternalModel {
|
|
|
856
795
|
}
|
|
857
796
|
}
|
|
858
797
|
|
|
859
|
-
notifyStateChange(key
|
|
798
|
+
notifyStateChange(key?) {
|
|
860
799
|
if (this.hasRecord) {
|
|
861
800
|
this.store._notificationManager.notify(this.identifier, 'state');
|
|
862
801
|
}
|
|
@@ -872,24 +811,24 @@ export default class InternalModel {
|
|
|
872
811
|
rollbackAttributes() {
|
|
873
812
|
this.store._backburner.join(() => {
|
|
874
813
|
let dirtyKeys = this._recordData.rollbackAttributes();
|
|
875
|
-
if (this
|
|
814
|
+
if (get(this, 'isError')) {
|
|
876
815
|
this.didCleanError();
|
|
877
816
|
}
|
|
878
817
|
|
|
879
818
|
this.send('rolledBack');
|
|
880
819
|
|
|
881
|
-
if (this.
|
|
882
|
-
this.
|
|
820
|
+
if (this._record && dirtyKeys && dirtyKeys.length > 0) {
|
|
821
|
+
this._record._notifyProperties(dirtyKeys);
|
|
883
822
|
}
|
|
884
823
|
});
|
|
885
824
|
}
|
|
886
825
|
|
|
887
|
-
transitionTo(name
|
|
826
|
+
transitionTo(name) {
|
|
888
827
|
// POSSIBLE TODO: Remove this code and replace with
|
|
889
828
|
// always having direct reference to state objects
|
|
890
829
|
|
|
891
830
|
let pivotName = extractPivotName(name);
|
|
892
|
-
let state
|
|
831
|
+
let state = this.currentState;
|
|
893
832
|
let transitionMapId = `${state.stateName}->${name}`;
|
|
894
833
|
|
|
895
834
|
do {
|
|
@@ -934,12 +873,13 @@ export default class InternalModel {
|
|
|
934
873
|
}
|
|
935
874
|
|
|
936
875
|
this.currentState = state;
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
//
|
|
876
|
+
if (this.hasRecord && typeof this._record.notifyPropertyChange === 'function') {
|
|
877
|
+
// TODO refactor Model to have all flags pull from the notification manager
|
|
878
|
+
// and for currentState.stateName to be constructed from flag state.
|
|
879
|
+
// Probably just port this work from ember-m3
|
|
880
|
+
// After that we can eliminate this.
|
|
942
881
|
this.notifyStateChange('currentState');
|
|
882
|
+
// this._record.notifyPropertyChange('currentState');
|
|
943
883
|
}
|
|
944
884
|
|
|
945
885
|
for (i = 0, l = setups.length; i < l; i++) {
|
|
@@ -947,7 +887,7 @@ export default class InternalModel {
|
|
|
947
887
|
}
|
|
948
888
|
}
|
|
949
889
|
|
|
950
|
-
_unhandledEvent(state, name
|
|
890
|
+
_unhandledEvent(state, name, context) {
|
|
951
891
|
let errorMessage = 'Attempted to handle event `' + name + '` ';
|
|
952
892
|
errorMessage += 'on ' + String(this) + ' while in state ';
|
|
953
893
|
errorMessage += state.stateName + '. ';
|
|
@@ -975,7 +915,7 @@ export default class InternalModel {
|
|
|
975
915
|
return;
|
|
976
916
|
}
|
|
977
917
|
let triggers = this._deferredTriggers;
|
|
978
|
-
let record = this._record
|
|
918
|
+
let record = this._record;
|
|
979
919
|
let trigger = record.trigger;
|
|
980
920
|
// TODO Igor make nicer check
|
|
981
921
|
if (trigger && typeof trigger === 'function') {
|
|
@@ -1117,34 +1057,26 @@ export default class InternalModel {
|
|
|
1117
1057
|
this.store._notificationManager.notify(this.identifier, 'attributes');
|
|
1118
1058
|
}
|
|
1119
1059
|
|
|
1120
|
-
hasErrors()
|
|
1121
|
-
// TODO add assertion forcing consuming RecordData's to implement getErrors
|
|
1060
|
+
hasErrors() {
|
|
1122
1061
|
if (this._recordData.getErrors) {
|
|
1123
1062
|
return this._recordData.getErrors(this.identifier).length > 0;
|
|
1124
1063
|
} else {
|
|
1125
|
-
|
|
1126
|
-
if (!this._record) {
|
|
1127
|
-
return false;
|
|
1128
|
-
}
|
|
1129
|
-
let errors = (this._record as DSModel).errors;
|
|
1064
|
+
let errors = (this.getRecord() as DSModel).errors;
|
|
1130
1065
|
return errors.length > 0;
|
|
1131
1066
|
}
|
|
1132
1067
|
}
|
|
1133
1068
|
|
|
1134
1069
|
// FOR USE DURING COMMIT PROCESS
|
|
1135
|
-
adapterDidInvalidate(parsedErrors, error
|
|
1070
|
+
adapterDidInvalidate(parsedErrors, error) {
|
|
1136
1071
|
// TODO @runspired this should be handled by RecordState
|
|
1137
1072
|
// and errors should be dirtied but lazily fetch if at
|
|
1138
1073
|
// all possible. We should only notify errors here.
|
|
1139
1074
|
let attribute;
|
|
1140
1075
|
if (error && parsedErrors) {
|
|
1141
|
-
// TODO add assertion forcing consuming RecordData's to implement getErrors
|
|
1142
1076
|
if (!this._recordData.getErrors) {
|
|
1143
|
-
let record = this.getRecord() as DSModel;
|
|
1144
|
-
let errors = record.errors;
|
|
1145
1077
|
for (attribute in parsedErrors) {
|
|
1146
1078
|
if (hasOwnProperty.call(parsedErrors, attribute)) {
|
|
1147
|
-
errors._add(attribute, parsedErrors[attribute]);
|
|
1079
|
+
(this.getRecord() as DSModel).errors._add(attribute, parsedErrors[attribute]);
|
|
1148
1080
|
}
|
|
1149
1081
|
}
|
|
1150
1082
|
}
|
|
@@ -1185,9 +1117,7 @@ export default class InternalModel {
|
|
|
1185
1117
|
// because of the intimate API access involved. This is something we will need to redesign.
|
|
1186
1118
|
assert(`snapshot.belongsTo only supported for @ember-data/record-data`);
|
|
1187
1119
|
}
|
|
1188
|
-
const graphFor = (
|
|
1189
|
-
importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
|
|
1190
|
-
).graphFor;
|
|
1120
|
+
const graphFor = require('@ember-data/record-data/-private').graphFor;
|
|
1191
1121
|
const relationship = graphFor(this.store._storeWrapper).get(this.identifier, name);
|
|
1192
1122
|
|
|
1193
1123
|
if (DEBUG && kind) {
|
|
@@ -1215,39 +1145,7 @@ export default class InternalModel {
|
|
|
1215
1145
|
}
|
|
1216
1146
|
}
|
|
1217
1147
|
|
|
1218
|
-
function handleCompletedRelationshipRequest(
|
|
1219
|
-
internalModel: InternalModel,
|
|
1220
|
-
key: string,
|
|
1221
|
-
relationship: BelongsToRelationship,
|
|
1222
|
-
value: InternalModel | null
|
|
1223
|
-
): RecordInstance | null;
|
|
1224
|
-
function handleCompletedRelationshipRequest(
|
|
1225
|
-
internalModel: InternalModel,
|
|
1226
|
-
key: string,
|
|
1227
|
-
relationship: ManyRelationship,
|
|
1228
|
-
value: ManyArray
|
|
1229
|
-
): ManyArray;
|
|
1230
|
-
function handleCompletedRelationshipRequest(
|
|
1231
|
-
internalModel: InternalModel,
|
|
1232
|
-
key: string,
|
|
1233
|
-
relationship: BelongsToRelationship,
|
|
1234
|
-
value: null,
|
|
1235
|
-
error: Error
|
|
1236
|
-
): never;
|
|
1237
|
-
function handleCompletedRelationshipRequest(
|
|
1238
|
-
internalModel: InternalModel,
|
|
1239
|
-
key: string,
|
|
1240
|
-
relationship: ManyRelationship,
|
|
1241
|
-
value: ManyArray,
|
|
1242
|
-
error: Error
|
|
1243
|
-
): never;
|
|
1244
|
-
function handleCompletedRelationshipRequest(
|
|
1245
|
-
internalModel: InternalModel,
|
|
1246
|
-
key: string,
|
|
1247
|
-
relationship: BelongsToRelationship | ManyRelationship,
|
|
1248
|
-
value: ManyArray | InternalModel | null,
|
|
1249
|
-
error?: Error
|
|
1250
|
-
): ManyArray | RecordInstance | null {
|
|
1148
|
+
function handleCompletedRelationshipRequest(internalModel, key, relationship, value, error) {
|
|
1251
1149
|
delete internalModel._relationshipPromisesCache[key];
|
|
1252
1150
|
relationship.state.shouldForceReload = false;
|
|
1253
1151
|
const isHasMany = relationship.definition.kind === 'hasMany';
|
|
@@ -1255,7 +1153,7 @@ function handleCompletedRelationshipRequest(
|
|
|
1255
1153
|
if (isHasMany) {
|
|
1256
1154
|
// we don't notify the record property here to avoid refetch
|
|
1257
1155
|
// only the many array
|
|
1258
|
-
|
|
1156
|
+
value.notify();
|
|
1259
1157
|
}
|
|
1260
1158
|
|
|
1261
1159
|
if (error) {
|
|
@@ -1270,9 +1168,7 @@ function handleCompletedRelationshipRequest(
|
|
|
1270
1168
|
// has never been accessed
|
|
1271
1169
|
if (proxy && !isHasMany) {
|
|
1272
1170
|
if (proxy.content && proxy.content.isDestroying) {
|
|
1273
|
-
|
|
1274
|
-
// override or fix upstream
|
|
1275
|
-
(proxy as PromiseBelongsTo).set('content', null as unknown as undefined);
|
|
1171
|
+
proxy.set('content', null);
|
|
1276
1172
|
}
|
|
1277
1173
|
}
|
|
1278
1174
|
|
|
@@ -1280,14 +1176,14 @@ function handleCompletedRelationshipRequest(
|
|
|
1280
1176
|
}
|
|
1281
1177
|
|
|
1282
1178
|
if (isHasMany) {
|
|
1283
|
-
|
|
1179
|
+
value.set('isLoaded', true);
|
|
1284
1180
|
}
|
|
1285
1181
|
|
|
1286
1182
|
relationship.state.hasFailedLoadAttempt = false;
|
|
1287
1183
|
// only set to not stale if no error is thrown
|
|
1288
1184
|
relationship.state.isStale = false;
|
|
1289
1185
|
|
|
1290
|
-
return
|
|
1186
|
+
return value;
|
|
1291
1187
|
}
|
|
1292
1188
|
|
|
1293
1189
|
export function assertRecordsPassedToHasMany(records) {
|