@ember-data/store 4.5.0-beta.0 → 4.5.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/backburner.js → backburner.js} +0 -0
- package/addon/-private/{system/coerce-id.ts → coerce-id.ts} +0 -0
- package/addon/-private/{system/store/common.js → common.js} +0 -0
- package/addon/-private/{system/core-store.ts → core-store.ts} +467 -1253
- package/addon/-private/{system/errors-utils.js → errors-utils.js} +7 -6
- package/addon/-private/{system/fetch-manager.ts → fetch-manager.ts} +72 -42
- package/addon/-private/finders.js +107 -0
- package/addon/-private/identifer-debug-consts.ts +3 -0
- package/addon/-private/{identifiers/cache.ts → identifier-cache.ts} +26 -14
- package/addon/-private/{system/identity-map.ts → identity-map.ts} +2 -1
- package/addon/-private/index.ts +17 -17
- package/addon/-private/instance-cache.ts +387 -0
- package/addon/-private/{system/store/internal-model-factory.ts → internal-model-factory.ts} +25 -19
- package/addon/-private/{system/internal-model-map.ts → internal-model-map.ts} +9 -5
- package/addon/-private/model/internal-model.ts +602 -0
- package/addon/-private/{system/references/record.ts → model/record-reference.ts} +23 -36
- package/addon/-private/{system/model → model}/shim-model-class.ts +19 -14
- package/addon/-private/{system/normalize-model-name.ts → normalize-model-name.ts} +0 -0
- package/addon/-private/{system/promise-proxies.ts → promise-proxies.ts} +12 -5
- package/addon/-private/{system/promise-proxy-base.js → promise-proxy-base.js} +0 -0
- package/addon/-private/{system/record-array-manager.ts → record-array-manager.ts} +19 -18
- package/addon/-private/{system/record-arrays → record-arrays}/adapter-populated-record-array.ts +11 -10
- package/addon/-private/{system/record-arrays → record-arrays}/record-array.ts +37 -19
- package/addon/-private/record-data-for.ts +39 -0
- package/addon/-private/{system/store/record-data-store-wrapper.ts → record-data-store-wrapper.ts} +21 -26
- package/addon/-private/{system/record-notification-manager.ts → record-notification-manager.ts} +8 -3
- package/addon/-private/{system/request-cache.ts → request-cache.ts} +5 -6
- package/addon/-private/{system/schema-definition-service.ts → schema-definition-service.ts} +30 -14
- package/addon/-private/{system/store/serializer-response.ts → serializer-response.ts} +7 -6
- package/addon/-private/{system/snapshot-record-array.ts → snapshot-record-array.ts} +27 -8
- package/addon/-private/{system/snapshot.ts → snapshot.ts} +54 -39
- package/addon/-private/utils/construct-resource.ts +7 -3
- package/addon/-private/utils/promise-record.ts +9 -18
- package/addon/-private/{system/weak-cache.ts → weak-cache.ts} +2 -2
- package/addon/index.ts +1 -0
- package/package.json +21 -20
- package/addon/-private/identifiers/is-stable-identifier.ts +0 -18
- package/addon/-private/identifiers/utils/uuid-v4.ts +0 -80
- package/addon/-private/system/ds-model-store.ts +0 -136
- package/addon/-private/system/model/internal-model.ts +0 -1303
- package/addon/-private/system/model/states.js +0 -736
- package/addon/-private/system/record-arrays.ts +0 -8
- package/addon/-private/system/record-data-for.ts +0 -54
- package/addon/-private/system/references/belongs-to.ts +0 -406
- package/addon/-private/system/references/has-many.ts +0 -487
- package/addon/-private/system/references/reference.ts +0 -205
- package/addon/-private/system/references.js +0 -9
- package/addon/-private/system/store/finders.js +0 -412
- package/addon/-private/ts-interfaces/ds-model.ts +0 -50
- package/addon/-private/ts-interfaces/ember-data-json-api.ts +0 -145
- package/addon/-private/ts-interfaces/fetch-manager.ts +0 -44
- package/addon/-private/ts-interfaces/identifier.ts +0 -246
- package/addon/-private/ts-interfaces/minimum-adapter-interface.ts +0 -584
- package/addon/-private/ts-interfaces/minimum-serializer-interface.ts +0 -257
- package/addon/-private/ts-interfaces/promise-proxies.ts +0 -3
- package/addon/-private/ts-interfaces/record-data-json-api.ts +0 -29
- package/addon/-private/ts-interfaces/record-data-record-wrapper.ts +0 -46
- package/addon/-private/ts-interfaces/record-data-schemas.ts +0 -45
- package/addon/-private/ts-interfaces/record-data-store-wrapper.ts +0 -56
- package/addon/-private/ts-interfaces/record-data.ts +0 -72
- package/addon/-private/ts-interfaces/record-instance.ts +0 -18
- package/addon/-private/ts-interfaces/schema-definition-service.ts +0 -12
- package/addon/-private/ts-interfaces/store.ts +0 -10
- package/addon/-private/ts-interfaces/utils.ts +0 -6
|
@@ -1,1303 +0,0 @@
|
|
|
1
|
-
import { A, default as EmberArray } from '@ember/array';
|
|
2
|
-
import { assert, inspect } from '@ember/debug';
|
|
3
|
-
import EmberError from '@ember/error';
|
|
4
|
-
import { get } from '@ember/object';
|
|
5
|
-
import { _backburner as emberBackburner, cancel, run } from '@ember/runloop';
|
|
6
|
-
import { DEBUG } from '@glimmer/env';
|
|
7
|
-
|
|
8
|
-
import { importSync } from '@embroider/macros';
|
|
9
|
-
import RSVP, { resolve } from 'rsvp';
|
|
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';
|
|
21
|
-
import { HAS_MODEL_PACKAGE, HAS_RECORD_DATA_PACKAGE } from '@ember-data/private-build-infra';
|
|
22
|
-
import type {
|
|
23
|
-
BelongsToRelationship,
|
|
24
|
-
ManyRelationship,
|
|
25
|
-
RecordData as DefaultRecordData,
|
|
26
|
-
} from '@ember-data/record-data/-private';
|
|
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';
|
|
32
|
-
|
|
33
|
-
import type { DSModel } from '../../ts-interfaces/ds-model';
|
|
34
|
-
import type { StableRecordIdentifier } from '../../ts-interfaces/identifier';
|
|
35
|
-
import type { ChangedAttributesHash, RecordData } from '../../ts-interfaces/record-data';
|
|
36
|
-
import type { JsonApiResource, JsonApiValidationError } from '../../ts-interfaces/record-data-json-api';
|
|
37
|
-
import type { RelationshipSchema } from '../../ts-interfaces/record-data-schemas';
|
|
38
|
-
import type { RecordInstance } from '../../ts-interfaces/record-instance';
|
|
39
|
-
import type { FindOptions } from '../../ts-interfaces/store';
|
|
40
|
-
import type { Dict } from '../../ts-interfaces/utils';
|
|
41
|
-
import type CoreStore from '../core-store';
|
|
42
|
-
import type { CreateRecordProperties } from '../core-store';
|
|
43
|
-
import { errorsHashToArray } from '../errors-utils';
|
|
44
|
-
import recordDataFor from '../record-data-for';
|
|
45
|
-
import { BelongsToReference, HasManyReference, RecordReference } from '../references';
|
|
46
|
-
import Snapshot from '../snapshot';
|
|
47
|
-
import { internalModelFactoryFor } from '../store/internal-model-factory';
|
|
48
|
-
import RootState from './states';
|
|
49
|
-
|
|
50
|
-
type PrivateModelModule = {
|
|
51
|
-
ManyArray: { create(args: ManyArrayCreateArgs): ManyArray };
|
|
52
|
-
PromiseBelongsTo: { create(args: BelongsToProxyCreateArgs): PromiseBelongsTo };
|
|
53
|
-
PromiseManyArray: new (...args: unknown[]) => PromiseManyArray;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
@module @ember-data/store
|
|
58
|
-
*/
|
|
59
|
-
|
|
60
|
-
const { hasOwnProperty } = Object.prototype;
|
|
61
|
-
|
|
62
|
-
let _ManyArray: PrivateModelModule['ManyArray'];
|
|
63
|
-
let _PromiseBelongsTo: PrivateModelModule['PromiseBelongsTo'];
|
|
64
|
-
let _PromiseManyArray: PrivateModelModule['PromiseManyArray'];
|
|
65
|
-
|
|
66
|
-
let _found = false;
|
|
67
|
-
let _getModelPackage: () => boolean;
|
|
68
|
-
if (HAS_MODEL_PACKAGE) {
|
|
69
|
-
_getModelPackage = function () {
|
|
70
|
-
if (!_found) {
|
|
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) {
|
|
78
|
-
_found = true;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return _found;
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/*
|
|
86
|
-
The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached
|
|
87
|
-
when transitioning from one state to another, so that future transitions can replay the
|
|
88
|
-
transition without needing to walk the state tree, collect these hook calls and determine
|
|
89
|
-
the state to transition into.
|
|
90
|
-
|
|
91
|
-
A future optimization would be to build a single chained method out of the collected enters
|
|
92
|
-
and setups. It may also be faster to do a two level cache (from: { to }) instead of caching based
|
|
93
|
-
on a key that adds the two together.
|
|
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.
|
|
98
|
-
const TransitionChainMap = Object.create(null);
|
|
99
|
-
|
|
100
|
-
const _extractPivotNameCache = Object.create(null);
|
|
101
|
-
const _splitOnDotCache = Object.create(null);
|
|
102
|
-
|
|
103
|
-
function splitOnDot(name: string): string[] {
|
|
104
|
-
return _splitOnDotCache[name] || (_splitOnDotCache[name] = name.split('.'));
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function extractPivotName(name: string): string {
|
|
108
|
-
return _extractPivotNameCache[name] || (_extractPivotNameCache[name] = splitOnDot(name)[0]);
|
|
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
|
-
|
|
121
|
-
export default class InternalModel {
|
|
122
|
-
declare _id: string | null;
|
|
123
|
-
declare modelName: string;
|
|
124
|
-
declare clientId: string;
|
|
125
|
-
declare __recordData: RecordData | null;
|
|
126
|
-
declare _isDestroyed: boolean;
|
|
127
|
-
declare isError: boolean;
|
|
128
|
-
declare _pendingRecordArrayManagerFlush: boolean;
|
|
129
|
-
declare _isDematerializing: boolean;
|
|
130
|
-
declare _doNotDestroy: boolean;
|
|
131
|
-
declare isDestroying: boolean;
|
|
132
|
-
declare _isUpdatingId: boolean;
|
|
133
|
-
declare _deletedRecordWasNew: boolean;
|
|
134
|
-
|
|
135
|
-
// Not typed yet
|
|
136
|
-
declare _promiseProxy: any;
|
|
137
|
-
declare _record: RecordInstance | null;
|
|
138
|
-
declare _scheduledDestroy: any;
|
|
139
|
-
declare _modelClass: any;
|
|
140
|
-
declare __recordArrays: any;
|
|
141
|
-
declare references: any;
|
|
142
|
-
declare _recordReference: RecordReference;
|
|
143
|
-
declare _manyArrayCache: Dict<ManyArray>;
|
|
144
|
-
|
|
145
|
-
declare _relationshipPromisesCache: Dict<Promise<ManyArray | RecordInstance>>;
|
|
146
|
-
declare _relationshipProxyCache: Dict<PromiseManyArray | PromiseBelongsTo>;
|
|
147
|
-
declare error: any;
|
|
148
|
-
declare currentState: RecordState;
|
|
149
|
-
declare _previousState: any;
|
|
150
|
-
declare store: CoreStore;
|
|
151
|
-
declare identifier: StableRecordIdentifier;
|
|
152
|
-
|
|
153
|
-
constructor(store: CoreStore, identifier: StableRecordIdentifier) {
|
|
154
|
-
if (HAS_MODEL_PACKAGE) {
|
|
155
|
-
_getModelPackage();
|
|
156
|
-
}
|
|
157
|
-
this.store = store;
|
|
158
|
-
this.identifier = identifier;
|
|
159
|
-
this._id = identifier.id;
|
|
160
|
-
this._isUpdatingId = false;
|
|
161
|
-
this.modelName = identifier.type;
|
|
162
|
-
this.clientId = identifier.lid;
|
|
163
|
-
|
|
164
|
-
this.__recordData = null;
|
|
165
|
-
|
|
166
|
-
this._promiseProxy = null;
|
|
167
|
-
this._isDestroyed = false;
|
|
168
|
-
this._doNotDestroy = false;
|
|
169
|
-
this.isError = false;
|
|
170
|
-
this._pendingRecordArrayManagerFlush = false; // used by the recordArrayManager
|
|
171
|
-
|
|
172
|
-
// During dematerialization we don't want to rematerialize the record. The
|
|
173
|
-
// reason this might happen is that dematerialization removes records from
|
|
174
|
-
// record arrays, and Ember arrays will always `objectAt(0)` and
|
|
175
|
-
// `objectAt(len - 1)` to test whether or not `firstObject` or `lastObject`
|
|
176
|
-
// have changed.
|
|
177
|
-
this._isDematerializing = false;
|
|
178
|
-
this._scheduledDestroy = null;
|
|
179
|
-
|
|
180
|
-
this._record = null;
|
|
181
|
-
this.error = null;
|
|
182
|
-
|
|
183
|
-
// caches for lazy getters
|
|
184
|
-
this._modelClass = null;
|
|
185
|
-
this.__recordArrays = null;
|
|
186
|
-
this._recordReference = null;
|
|
187
|
-
this.__recordData = null;
|
|
188
|
-
|
|
189
|
-
this.error = null;
|
|
190
|
-
|
|
191
|
-
// other caches
|
|
192
|
-
// class fields have [[DEFINE]] semantics which are significantly slower than [[SET]] semantics here
|
|
193
|
-
this._manyArrayCache = Object.create(null);
|
|
194
|
-
this._relationshipPromisesCache = Object.create(null);
|
|
195
|
-
this._relationshipProxyCache = Object.create(null);
|
|
196
|
-
this.references = Object.create(null);
|
|
197
|
-
this.currentState = RootState.empty;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
get id(): string | null {
|
|
201
|
-
return this.identifier.id;
|
|
202
|
-
}
|
|
203
|
-
set id(value: string | null) {
|
|
204
|
-
if (value !== this._id) {
|
|
205
|
-
let newIdentifier = { type: this.identifier.type, lid: this.identifier.lid, id: value };
|
|
206
|
-
this.store.identifierCache.updateRecordIdentifier(this.identifier, newIdentifier);
|
|
207
|
-
this.notifyPropertyChange('id');
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
get modelClass() {
|
|
212
|
-
if (this.store.modelFor) {
|
|
213
|
-
return this._modelClass || (this._modelClass = this.store.modelFor(this.modelName));
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
get recordReference(): RecordReference {
|
|
218
|
-
if (this._recordReference === null) {
|
|
219
|
-
this._recordReference = new RecordReference(this.store, this.identifier);
|
|
220
|
-
}
|
|
221
|
-
return this._recordReference;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
get _recordData(): RecordData {
|
|
225
|
-
if (this.__recordData === null) {
|
|
226
|
-
let recordData = this.store._createRecordData(this.identifier);
|
|
227
|
-
this.__recordData = recordData;
|
|
228
|
-
return recordData;
|
|
229
|
-
}
|
|
230
|
-
return this.__recordData;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
set _recordData(newValue) {
|
|
234
|
-
this.__recordData = newValue;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
isHiddenFromRecordArrays() {
|
|
238
|
-
// During dematerialization we don't want to rematerialize the record.
|
|
239
|
-
// recordWasDeleted can cause other records to rematerialize because it
|
|
240
|
-
// removes the internal model from the array and Ember arrays will always
|
|
241
|
-
// `objectAt(0)` and `objectAt(len -1)` to check whether `firstObject` or
|
|
242
|
-
// `lastObject` have changed. When this happens we don't want those
|
|
243
|
-
// models to rematerialize their records.
|
|
244
|
-
|
|
245
|
-
// eager checks to avoid instantiating record data if we are empty or loading
|
|
246
|
-
if (this.currentState.isEmpty) {
|
|
247
|
-
return true;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (this.currentState.isLoading) {
|
|
251
|
-
return false;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
let isRecordFullyDeleted = this._isRecordFullyDeleted();
|
|
255
|
-
return this._isDematerializing || this.hasScheduledDestroy() || this.isDestroyed || isRecordFullyDeleted;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
_isRecordFullyDeleted(): boolean {
|
|
259
|
-
if (this._recordData.isDeletionCommitted && this._recordData.isDeletionCommitted()) {
|
|
260
|
-
return true;
|
|
261
|
-
} else if (
|
|
262
|
-
this._recordData.isNew &&
|
|
263
|
-
this._recordData.isDeleted &&
|
|
264
|
-
this._recordData.isNew() &&
|
|
265
|
-
this._recordData.isDeleted()
|
|
266
|
-
) {
|
|
267
|
-
return true;
|
|
268
|
-
} else {
|
|
269
|
-
return this.currentState.stateName === 'root.deleted.saved';
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
isDeleted() {
|
|
274
|
-
if (this._recordData.isDeleted) {
|
|
275
|
-
return this._recordData.isDeleted();
|
|
276
|
-
} else {
|
|
277
|
-
return this.currentState.isDeleted;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
isNew() {
|
|
282
|
-
if (this._recordData.isNew) {
|
|
283
|
-
return this._recordData.isNew();
|
|
284
|
-
} else {
|
|
285
|
-
return this.currentState.isNew;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
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) {
|
|
298
|
-
let { store } = this;
|
|
299
|
-
|
|
300
|
-
record = this._record = store._instantiateRecord(
|
|
301
|
-
this,
|
|
302
|
-
this.modelName,
|
|
303
|
-
this._recordData,
|
|
304
|
-
this.identifier,
|
|
305
|
-
properties
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
return record;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
dematerializeRecord() {
|
|
313
|
-
this._isDematerializing = true;
|
|
314
|
-
|
|
315
|
-
// TODO IGOR add a test that fails when this is missing, something that involves canceling a destroy
|
|
316
|
-
// and the destroy not happening, and then later on trying to destroy
|
|
317
|
-
this._doNotDestroy = false;
|
|
318
|
-
// this has to occur before the internal model is removed
|
|
319
|
-
// for legacy compat.
|
|
320
|
-
if (this._record) {
|
|
321
|
-
this.store.teardownRecord(this._record);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// move to an empty never-loaded state
|
|
325
|
-
// ensure any record notifications happen prior to us
|
|
326
|
-
// unseting the record but after we've triggered
|
|
327
|
-
// destroy
|
|
328
|
-
this.store._backburner.join(() => {
|
|
329
|
-
this._recordData.unloadRecord();
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
if (this._record) {
|
|
333
|
-
let keys = Object.keys(this._relationshipProxyCache);
|
|
334
|
-
keys.forEach((key) => {
|
|
335
|
-
let proxy = this._relationshipProxyCache[key]!;
|
|
336
|
-
if (proxy.destroy) {
|
|
337
|
-
proxy.destroy();
|
|
338
|
-
}
|
|
339
|
-
delete this._relationshipProxyCache[key];
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
this._record = null;
|
|
344
|
-
this.error = null;
|
|
345
|
-
this._previousState = this.currentState;
|
|
346
|
-
this.currentState = RootState.empty;
|
|
347
|
-
this.store.recordArrayManager.recordDidChange(this.identifier);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
deleteRecord() {
|
|
351
|
-
run(() => {
|
|
352
|
-
const backburner = this.store._backburner;
|
|
353
|
-
backburner.run(() => {
|
|
354
|
-
if (this._recordData.setIsDeleted) {
|
|
355
|
-
this._recordData.setIsDeleted(true);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
if (this.isNew()) {
|
|
359
|
-
// destroyRecord follows up deleteRecord with save(). This prevents an unecessary save for a new record
|
|
360
|
-
this._deletedRecordWasNew = true;
|
|
361
|
-
this.send('deleteRecord');
|
|
362
|
-
this.unloadRecord();
|
|
363
|
-
} else {
|
|
364
|
-
this.send('deleteRecord');
|
|
365
|
-
}
|
|
366
|
-
});
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
save(options: FindOptions = {}): Promise<void> {
|
|
371
|
-
if (this._deletedRecordWasNew) {
|
|
372
|
-
return resolve();
|
|
373
|
-
}
|
|
374
|
-
let promiseLabel = 'DS: Model#save ' + this;
|
|
375
|
-
let resolver = RSVP.defer<void>(promiseLabel);
|
|
376
|
-
|
|
377
|
-
// Casting to promise to narrow due to the feature flag paths inside scheduleSave
|
|
378
|
-
return this.store.scheduleSave(this, resolver, options) as Promise<void>;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
reload(options: Dict<unknown> = {}): Promise<InternalModel> {
|
|
382
|
-
return this.store._reloadRecord(this, options);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
/*
|
|
386
|
-
Unload the record for this internal model. This will cause the record to be
|
|
387
|
-
destroyed and freed up for garbage collection. It will also do a check
|
|
388
|
-
for cleaning up internal models.
|
|
389
|
-
|
|
390
|
-
This check is performed by first computing the set of related internal
|
|
391
|
-
models. If all records in this set are unloaded, then the entire set is
|
|
392
|
-
destroyed. Otherwise, nothing in the set is destroyed.
|
|
393
|
-
|
|
394
|
-
This means that this internal model will be freed up for garbage collection
|
|
395
|
-
once all models that refer to it via some relationship are also unloaded.
|
|
396
|
-
*/
|
|
397
|
-
unloadRecord() {
|
|
398
|
-
if (this.isDestroyed) {
|
|
399
|
-
return;
|
|
400
|
-
}
|
|
401
|
-
this.send('unloadRecord');
|
|
402
|
-
this.dematerializeRecord();
|
|
403
|
-
if (this._scheduledDestroy === null) {
|
|
404
|
-
this._scheduledDestroy = emberBackburner.schedule('destroy', this, '_checkForOrphanedInternalModels');
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
hasScheduledDestroy() {
|
|
409
|
-
return !!this._scheduledDestroy;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
cancelDestroy() {
|
|
413
|
-
assert(
|
|
414
|
-
`You cannot cancel the destruction of an InternalModel once it has already been destroyed`,
|
|
415
|
-
!this.isDestroyed
|
|
416
|
-
);
|
|
417
|
-
|
|
418
|
-
this._doNotDestroy = true;
|
|
419
|
-
this._isDematerializing = false;
|
|
420
|
-
cancel(this._scheduledDestroy);
|
|
421
|
-
this._scheduledDestroy = null;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// typically, we prefer to async destroy this lets us batch cleanup work.
|
|
425
|
-
// Unfortunately, some scenarios where that is not possible. Such as:
|
|
426
|
-
//
|
|
427
|
-
// ```js
|
|
428
|
-
// const record = store.findRecord(‘record’, 1);
|
|
429
|
-
// record.unloadRecord();
|
|
430
|
-
// store.createRecord(‘record’, 1);
|
|
431
|
-
// ```
|
|
432
|
-
//
|
|
433
|
-
// In those scenarios, we make that model's cleanup work, sync.
|
|
434
|
-
//
|
|
435
|
-
destroySync() {
|
|
436
|
-
if (this._isDematerializing) {
|
|
437
|
-
this.cancelDestroy();
|
|
438
|
-
}
|
|
439
|
-
this._checkForOrphanedInternalModels();
|
|
440
|
-
if (this.isDestroyed || this.isDestroying) {
|
|
441
|
-
return;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// just in-case we are not one of the orphaned, we should still
|
|
445
|
-
// still destroy ourselves
|
|
446
|
-
this.destroy();
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
_checkForOrphanedInternalModels() {
|
|
450
|
-
this._isDematerializing = false;
|
|
451
|
-
this._scheduledDestroy = null;
|
|
452
|
-
if (this.isDestroyed) {
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
_findBelongsTo(
|
|
458
|
-
key: string,
|
|
459
|
-
resource: DefaultSingleResourceRelationship,
|
|
460
|
-
relationshipMeta: RelationshipSchema,
|
|
461
|
-
options?: Dict<unknown>
|
|
462
|
-
): Promise<RecordInstance | null> {
|
|
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
|
|
465
|
-
return this.store._findBelongsToByJsonApiResource(resource, this, relationshipMeta, options).then(
|
|
466
|
-
(internalModel) => handleCompletedRelationshipRequest(this, key, resource._relationship, internalModel),
|
|
467
|
-
(e) => handleCompletedRelationshipRequest(this, key, resource._relationship, null, e)
|
|
468
|
-
);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
getBelongsTo(key: string, options?: Dict<unknown>): PromiseBelongsTo | RecordInstance | null {
|
|
472
|
-
let resource = (this._recordData as DefaultRecordData).getBelongsTo(key);
|
|
473
|
-
let identifier =
|
|
474
|
-
resource && resource.data ? this.store.identifierCache.getOrCreateRecordIdentifier(resource.data) : null;
|
|
475
|
-
let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key);
|
|
476
|
-
assert(`Attempted to access a belongsTo relationship but no definition exists for it`, relationshipMeta);
|
|
477
|
-
|
|
478
|
-
let store = this.store;
|
|
479
|
-
let parentInternalModel = this;
|
|
480
|
-
let async = relationshipMeta.options.async;
|
|
481
|
-
let isAsync = typeof async === 'undefined' ? true : async;
|
|
482
|
-
let _belongsToState: BelongsToProxyMeta = {
|
|
483
|
-
key,
|
|
484
|
-
store,
|
|
485
|
-
originatingInternalModel: this,
|
|
486
|
-
modelName: relationshipMeta.type,
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
if (isAsync) {
|
|
490
|
-
let internalModel = identifier !== null ? store._internalModelForResource(identifier) : null;
|
|
491
|
-
|
|
492
|
-
if (resource._relationship.state.hasFailedLoadAttempt) {
|
|
493
|
-
return this._relationshipProxyCache[key] as PromiseBelongsTo;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
let promise = this._findBelongsTo(key, resource, relationshipMeta, options);
|
|
497
|
-
|
|
498
|
-
return this._updatePromiseProxyFor('belongsTo', key, {
|
|
499
|
-
promise,
|
|
500
|
-
content: internalModel ? internalModel.getRecord() : null,
|
|
501
|
-
_belongsToState,
|
|
502
|
-
});
|
|
503
|
-
} else {
|
|
504
|
-
if (identifier === null) {
|
|
505
|
-
return null;
|
|
506
|
-
} else {
|
|
507
|
-
let internalModel = store._internalModelForResource(identifier);
|
|
508
|
-
let toReturn = internalModel.getRecord();
|
|
509
|
-
assert(
|
|
510
|
-
"You looked up the '" +
|
|
511
|
-
key +
|
|
512
|
-
"' relationship on a '" +
|
|
513
|
-
parentInternalModel.modelName +
|
|
514
|
-
"' with id " +
|
|
515
|
-
parentInternalModel.id +
|
|
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 })`)',
|
|
517
|
-
toReturn === null || !internalModel.currentState.isEmpty
|
|
518
|
-
);
|
|
519
|
-
return toReturn;
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
|
|
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;
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
return manyArray;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
fetchAsyncHasMany(
|
|
553
|
-
key: string,
|
|
554
|
-
relationship: ManyRelationship,
|
|
555
|
-
manyArray: ManyArray,
|
|
556
|
-
options?: Dict<unknown>
|
|
557
|
-
): Promise<ManyArray> {
|
|
558
|
-
if (HAS_RECORD_DATA_PACKAGE) {
|
|
559
|
-
let loadingPromise = this._relationshipPromisesCache[key] as Promise<ManyArray> | undefined;
|
|
560
|
-
if (loadingPromise) {
|
|
561
|
-
return loadingPromise;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
const jsonApi = this._recordData.getHasMany(key);
|
|
565
|
-
|
|
566
|
-
loadingPromise = this.store._findHasManyByJsonApiResource(jsonApi, this, relationship, options).then(
|
|
567
|
-
() => handleCompletedRelationshipRequest(this, key, relationship, manyArray),
|
|
568
|
-
(e) => handleCompletedRelationshipRequest(this, key, relationship, manyArray, e)
|
|
569
|
-
);
|
|
570
|
-
this._relationshipPromisesCache[key] = loadingPromise;
|
|
571
|
-
return loadingPromise;
|
|
572
|
-
}
|
|
573
|
-
assert('hasMany only works with the @ember-data/record-data package');
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
getHasMany(key: string, options?): PromiseManyArray | ManyArray {
|
|
577
|
-
if (HAS_RECORD_DATA_PACKAGE) {
|
|
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;
|
|
582
|
-
const { definition, state } = relationship;
|
|
583
|
-
let manyArray = this.getManyArray(key, definition);
|
|
584
|
-
|
|
585
|
-
if (definition.isAsync) {
|
|
586
|
-
if (state.hasFailedLoadAttempt) {
|
|
587
|
-
return this._relationshipProxyCache[key] as PromiseManyArray;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
let promise = this.fetchAsyncHasMany(key, relationship, manyArray, options);
|
|
591
|
-
|
|
592
|
-
return this._updatePromiseProxyFor('hasMany', key, { promise, content: manyArray });
|
|
593
|
-
} else {
|
|
594
|
-
assert(
|
|
595
|
-
`You looked up the '${key}' relationship on a '${this.modelName}' with id ${this.id} 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 ('hasMany({ async: true })')`,
|
|
596
|
-
!anyUnloaded(this.store, relationship)
|
|
597
|
-
);
|
|
598
|
-
|
|
599
|
-
return manyArray;
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
assert(`hasMany only works with the @ember-data/record-data package`);
|
|
603
|
-
}
|
|
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;
|
|
612
|
-
_updatePromiseProxyFor(
|
|
613
|
-
kind: 'hasMany' | 'belongsTo',
|
|
614
|
-
key: string,
|
|
615
|
-
args: BelongsToProxyCreateArgs | HasManyProxyCreateArgs | { promise: Promise<RecordInstance | null> }
|
|
616
|
-
): PromiseBelongsTo | PromiseManyArray {
|
|
617
|
-
let promiseProxy = this._relationshipProxyCache[key];
|
|
618
|
-
if (kind === 'hasMany') {
|
|
619
|
-
const { promise, content } = args as HasManyProxyCreateArgs;
|
|
620
|
-
if (promiseProxy) {
|
|
621
|
-
assert(`Expected a PromiseManyArray`, '_update' in promiseProxy);
|
|
622
|
-
promiseProxy._update(promise, content);
|
|
623
|
-
} else {
|
|
624
|
-
promiseProxy = this._relationshipProxyCache[key] = new _PromiseManyArray(promise, content);
|
|
625
|
-
}
|
|
626
|
-
return promiseProxy;
|
|
627
|
-
}
|
|
628
|
-
if (promiseProxy) {
|
|
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);
|
|
634
|
-
}
|
|
635
|
-
promiseProxy.set('promise', promise);
|
|
636
|
-
} else {
|
|
637
|
-
// this usage of `any` can be removed when `@types/ember_object` proxy allows `null` for content
|
|
638
|
-
this._relationshipProxyCache[key] = promiseProxy = _PromiseBelongsTo.create(args as any);
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
return promiseProxy;
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
reloadHasMany(key: string, options) {
|
|
645
|
-
if (HAS_RECORD_DATA_PACKAGE) {
|
|
646
|
-
let loadingPromise = this._relationshipPromisesCache[key];
|
|
647
|
-
if (loadingPromise) {
|
|
648
|
-
return loadingPromise;
|
|
649
|
-
}
|
|
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;
|
|
654
|
-
const { definition, state } = relationship;
|
|
655
|
-
|
|
656
|
-
state.hasFailedLoadAttempt = false;
|
|
657
|
-
state.shouldForceReload = true;
|
|
658
|
-
let manyArray = this.getManyArray(key, definition);
|
|
659
|
-
let promise = this.fetchAsyncHasMany(key, relationship, manyArray, options);
|
|
660
|
-
|
|
661
|
-
if (this._relationshipProxyCache[key]) {
|
|
662
|
-
return this._updatePromiseProxyFor('hasMany', key, { promise });
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
return promise;
|
|
666
|
-
}
|
|
667
|
-
assert(`hasMany only works with the @ember-data/record-data package`);
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
reloadBelongsTo(key: string, options?: Dict<unknown>): Promise<RecordInstance | null> {
|
|
671
|
-
let loadingPromise = this._relationshipPromisesCache[key] as Promise<RecordInstance | null> | undefined;
|
|
672
|
-
if (loadingPromise) {
|
|
673
|
-
return loadingPromise;
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
let resource = (this._recordData as DefaultRecordData).getBelongsTo(key);
|
|
677
|
-
// TODO move this to a public api
|
|
678
|
-
if (resource._relationship) {
|
|
679
|
-
resource._relationship.state.hasFailedLoadAttempt = false;
|
|
680
|
-
resource._relationship.state.shouldForceReload = true;
|
|
681
|
-
}
|
|
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);
|
|
684
|
-
let promise = this._findBelongsTo(key, resource, relationshipMeta, options);
|
|
685
|
-
if (this._relationshipProxyCache[key]) {
|
|
686
|
-
return this._updatePromiseProxyFor('belongsTo', key, { promise });
|
|
687
|
-
}
|
|
688
|
-
return promise;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
destroyFromRecordData() {
|
|
692
|
-
if (this._doNotDestroy) {
|
|
693
|
-
this._doNotDestroy = false;
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
|
-
this.destroy();
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
destroy() {
|
|
700
|
-
assert(
|
|
701
|
-
'Cannot destroy an internalModel while its record is materialized',
|
|
702
|
-
!this._record || this._record.isDestroyed || this._record.isDestroying
|
|
703
|
-
);
|
|
704
|
-
this.isDestroying = true;
|
|
705
|
-
if (this._recordReference) {
|
|
706
|
-
this._recordReference.destroy();
|
|
707
|
-
}
|
|
708
|
-
this._recordReference = null;
|
|
709
|
-
let cache = this._manyArrayCache;
|
|
710
|
-
Object.keys(cache).forEach((key) => {
|
|
711
|
-
cache[key]!.destroy();
|
|
712
|
-
delete cache[key];
|
|
713
|
-
});
|
|
714
|
-
if (this.references) {
|
|
715
|
-
cache = this.references;
|
|
716
|
-
Object.keys(cache).forEach((key) => {
|
|
717
|
-
cache[key]!.destroy();
|
|
718
|
-
delete cache[key];
|
|
719
|
-
});
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
internalModelFactoryFor(this.store).remove(this);
|
|
723
|
-
this._isDestroyed = true;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
setupData(data) {
|
|
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);
|
|
733
|
-
}
|
|
734
|
-
this.send('pushedData');
|
|
735
|
-
}
|
|
736
|
-
|
|
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) {
|
|
747
|
-
assertRecordsPassedToHasMany(records);
|
|
748
|
-
return this._recordData.setDirtyHasMany(key, extractRecordDatasFromRecords(records));
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
setDirtyBelongsTo(key: string, value) {
|
|
752
|
-
return this._recordData.setDirtyBelongsTo(key, extractRecordDataFromRecord(value));
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
setDirtyAttribute<T>(key: string, value: T): T {
|
|
756
|
-
if (this.isDeleted()) {
|
|
757
|
-
if (DEBUG) {
|
|
758
|
-
throw new EmberError(`Attempted to set '${key}' to '${value}' on the deleted record ${this}`);
|
|
759
|
-
} else {
|
|
760
|
-
throw new EmberError(`Attempted to set '${key}' on the deleted record ${this}`);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
let currentValue = this._recordData.getAttr(key);
|
|
765
|
-
if (currentValue !== value) {
|
|
766
|
-
this._recordData.setDirtyAttribute(key, value);
|
|
767
|
-
let isDirty = this._recordData.isAttrDirty(key);
|
|
768
|
-
this.send('didSetProperty', {
|
|
769
|
-
name: key,
|
|
770
|
-
isDirty: isDirty,
|
|
771
|
-
});
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
return value;
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
get isDestroyed(): boolean {
|
|
778
|
-
return this._isDestroyed;
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
get hasRecord(): boolean {
|
|
782
|
-
return !!this._record;
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
createSnapshot(options: FindOptions = {}): Snapshot {
|
|
786
|
-
return new Snapshot(options, this.identifier, this.store);
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
hasChangedAttributes(): boolean {
|
|
790
|
-
if (!this.__recordData) {
|
|
791
|
-
// no need to calculate changed attributes when calling `findRecord`
|
|
792
|
-
return false;
|
|
793
|
-
}
|
|
794
|
-
return this._recordData.hasChangedAttributes();
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
changedAttributes(): ChangedAttributesHash {
|
|
798
|
-
if (!this.__recordData) {
|
|
799
|
-
// no need to calculate changed attributes when calling `findRecord`
|
|
800
|
-
return {};
|
|
801
|
-
}
|
|
802
|
-
return this._recordData.changedAttributes();
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
adapterWillCommit(): void {
|
|
806
|
-
this._recordData.willCommit();
|
|
807
|
-
this.send('willCommit');
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
adapterDidDirty(): void {
|
|
811
|
-
this.send('becomeDirty');
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
send(name: string, context?) {
|
|
815
|
-
let currentState = this.currentState;
|
|
816
|
-
|
|
817
|
-
if (!currentState[name]) {
|
|
818
|
-
this._unhandledEvent(currentState, name, context);
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
return currentState[name](this, context);
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
notifyHasManyChange(key: string) {
|
|
825
|
-
if (this.hasRecord) {
|
|
826
|
-
let manyArray = this._manyArrayCache[key];
|
|
827
|
-
let hasPromise = !!this._relationshipPromisesCache[key];
|
|
828
|
-
|
|
829
|
-
if (manyArray && hasPromise) {
|
|
830
|
-
// do nothing, we will notify the ManyArray directly
|
|
831
|
-
// once the fetch has completed.
|
|
832
|
-
return;
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
this.store._notificationManager.notify(this.identifier, 'relationships', key);
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
notifyBelongsToChange(key: string) {
|
|
840
|
-
if (this.hasRecord) {
|
|
841
|
-
this.store._notificationManager.notify(this.identifier, 'relationships', key);
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
notifyPropertyChange(key: string) {
|
|
846
|
-
if (this.hasRecord) {
|
|
847
|
-
// TODO this should likely *mostly* be the `attributes` bucket
|
|
848
|
-
// but it seems for local mutations we rely on computed updating
|
|
849
|
-
// iteself when set. As we design our own thing we may need to change
|
|
850
|
-
// that.
|
|
851
|
-
this.store._notificationManager.notify(this.identifier, 'property', key);
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
notifyStateChange(key?: string) {
|
|
856
|
-
if (this.hasRecord) {
|
|
857
|
-
this.store._notificationManager.notify(this.identifier, 'state');
|
|
858
|
-
}
|
|
859
|
-
if (!key || key === 'isDeletionCommitted') {
|
|
860
|
-
this.store.recordArrayManager.recordDidChange(this.identifier);
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
didCreateRecord() {
|
|
865
|
-
this._recordData.clientDidCreate();
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
rollbackAttributes() {
|
|
869
|
-
this.store._backburner.join(() => {
|
|
870
|
-
let dirtyKeys = this._recordData.rollbackAttributes();
|
|
871
|
-
if (this.isError) {
|
|
872
|
-
this.didCleanError();
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
this.send('rolledBack');
|
|
876
|
-
|
|
877
|
-
if (this.hasRecord && dirtyKeys && dirtyKeys.length > 0) {
|
|
878
|
-
this.notifyAttributes(dirtyKeys);
|
|
879
|
-
}
|
|
880
|
-
});
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
transitionTo(name: string) {
|
|
884
|
-
// POSSIBLE TODO: Remove this code and replace with
|
|
885
|
-
// always having direct reference to state objects
|
|
886
|
-
|
|
887
|
-
let pivotName = extractPivotName(name);
|
|
888
|
-
let state: any = this.currentState;
|
|
889
|
-
let transitionMapId = `${state.stateName}->${name}`;
|
|
890
|
-
|
|
891
|
-
do {
|
|
892
|
-
if (state.exit) {
|
|
893
|
-
state.exit(this);
|
|
894
|
-
}
|
|
895
|
-
state = state.parentState;
|
|
896
|
-
} while (!state[pivotName]);
|
|
897
|
-
|
|
898
|
-
let setups;
|
|
899
|
-
let enters;
|
|
900
|
-
let i;
|
|
901
|
-
let l;
|
|
902
|
-
let map = TransitionChainMap[transitionMapId];
|
|
903
|
-
|
|
904
|
-
if (map) {
|
|
905
|
-
setups = map.setups;
|
|
906
|
-
enters = map.enters;
|
|
907
|
-
state = map.state;
|
|
908
|
-
} else {
|
|
909
|
-
setups = [];
|
|
910
|
-
enters = [];
|
|
911
|
-
|
|
912
|
-
let path = splitOnDot(name);
|
|
913
|
-
|
|
914
|
-
for (i = 0, l = path.length; i < l; i++) {
|
|
915
|
-
state = state[path[i]];
|
|
916
|
-
|
|
917
|
-
if (state.enter) {
|
|
918
|
-
enters.push(state);
|
|
919
|
-
}
|
|
920
|
-
if (state.setup) {
|
|
921
|
-
setups.push(state);
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
TransitionChainMap[transitionMapId] = { setups, enters, state };
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
for (i = 0, l = enters.length; i < l; i++) {
|
|
929
|
-
enters[i].enter(this);
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
this.currentState = state;
|
|
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.
|
|
938
|
-
this.notifyStateChange('currentState');
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
for (i = 0, l = setups.length; i < l; i++) {
|
|
942
|
-
setups[i].setup(this);
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
_unhandledEvent(state, name: string, context) {
|
|
947
|
-
let errorMessage = 'Attempted to handle event `' + name + '` ';
|
|
948
|
-
errorMessage += 'on ' + String(this) + ' while in state ';
|
|
949
|
-
errorMessage += state.stateName + '. ';
|
|
950
|
-
|
|
951
|
-
if (context !== undefined) {
|
|
952
|
-
errorMessage += 'Called with ' + inspect(context) + '.';
|
|
953
|
-
}
|
|
954
|
-
|
|
955
|
-
throw new EmberError(errorMessage);
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
removeFromInverseRelationships() {
|
|
959
|
-
if (this.__recordData) {
|
|
960
|
-
this.store._backburner.join(() => {
|
|
961
|
-
this._recordData.removeFromInverseRelationships();
|
|
962
|
-
});
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
/*
|
|
967
|
-
When a find request is triggered on the store, the user can optionally pass in
|
|
968
|
-
attributes and relationships to be preloaded. These are meant to behave as if they
|
|
969
|
-
came back from the server, except the user obtained them out of band and is informing
|
|
970
|
-
the store of their existence. The most common use case is for supporting client side
|
|
971
|
-
nested URLs, such as `/posts/1/comments/2` so the user can do
|
|
972
|
-
`store.findRecord('comment', 2, { preload: { post: 1 } })` without having to fetch the post.
|
|
973
|
-
|
|
974
|
-
Preloaded data can be attributes and relationships passed in either as IDs or as actual
|
|
975
|
-
models.
|
|
976
|
-
*/
|
|
977
|
-
preloadData(preload) {
|
|
978
|
-
let jsonPayload: JsonApiResource = {};
|
|
979
|
-
//TODO(Igor) consider the polymorphic case
|
|
980
|
-
Object.keys(preload).forEach((key) => {
|
|
981
|
-
let preloadValue = get(preload, key);
|
|
982
|
-
let relationshipMeta = this.modelClass.metaForProperty(key);
|
|
983
|
-
if (relationshipMeta.isRelationship) {
|
|
984
|
-
if (!jsonPayload.relationships) {
|
|
985
|
-
jsonPayload.relationships = {};
|
|
986
|
-
}
|
|
987
|
-
jsonPayload.relationships[key] = this._preloadRelationship(key, preloadValue);
|
|
988
|
-
} else {
|
|
989
|
-
if (!jsonPayload.attributes) {
|
|
990
|
-
jsonPayload.attributes = {};
|
|
991
|
-
}
|
|
992
|
-
jsonPayload.attributes[key] = preloadValue;
|
|
993
|
-
}
|
|
994
|
-
});
|
|
995
|
-
this._recordData.pushData(jsonPayload);
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
_preloadRelationship(key, preloadValue) {
|
|
999
|
-
let relationshipMeta = this.modelClass.metaForProperty(key);
|
|
1000
|
-
let modelClass = relationshipMeta.type;
|
|
1001
|
-
let data;
|
|
1002
|
-
if (relationshipMeta.kind === 'hasMany') {
|
|
1003
|
-
assert('You need to pass in an array to set a hasMany property on a record', Array.isArray(preloadValue));
|
|
1004
|
-
data = preloadValue.map((value) => this._convertPreloadRelationshipToJSON(value, modelClass));
|
|
1005
|
-
} else {
|
|
1006
|
-
data = this._convertPreloadRelationshipToJSON(preloadValue, modelClass);
|
|
1007
|
-
}
|
|
1008
|
-
return { data };
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
_convertPreloadRelationshipToJSON(value, modelClass) {
|
|
1012
|
-
if (typeof value === 'string' || typeof value === 'number') {
|
|
1013
|
-
return { type: modelClass, id: value };
|
|
1014
|
-
}
|
|
1015
|
-
let internalModel;
|
|
1016
|
-
if (value._internalModel) {
|
|
1017
|
-
internalModel = value._internalModel;
|
|
1018
|
-
} else {
|
|
1019
|
-
internalModel = value;
|
|
1020
|
-
}
|
|
1021
|
-
// TODO IGOR DAVID assert if no id is present
|
|
1022
|
-
return { type: internalModel.modelName, id: internalModel.id };
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
/*
|
|
1026
|
-
* calling `store.setRecordId` is necessary to update
|
|
1027
|
-
* the cache index for this record if we have changed.
|
|
1028
|
-
*
|
|
1029
|
-
* However, since the store is not aware of whether the update
|
|
1030
|
-
* is from us (via user set) or from a push of new data
|
|
1031
|
-
* it will also call us so that we can notify and update state.
|
|
1032
|
-
*
|
|
1033
|
-
* When it does so it calls with `fromCache` so that we can
|
|
1034
|
-
* short-circuit instead of cycling back.
|
|
1035
|
-
*
|
|
1036
|
-
* This differs from the short-circuit in the `_isUpdatingId`
|
|
1037
|
-
* case in that the the cache can originate the call to setId,
|
|
1038
|
-
* so on first entry we will still need to do our own update.
|
|
1039
|
-
*/
|
|
1040
|
-
setId(id: string, fromCache: boolean = false) {
|
|
1041
|
-
if (this._isUpdatingId === true) {
|
|
1042
|
-
return;
|
|
1043
|
-
}
|
|
1044
|
-
this._isUpdatingId = true;
|
|
1045
|
-
let didChange = id !== this._id;
|
|
1046
|
-
this._id = id;
|
|
1047
|
-
|
|
1048
|
-
if (didChange && id !== null) {
|
|
1049
|
-
if (!fromCache) {
|
|
1050
|
-
this.store.setRecordId(this.modelName, id, this.clientId);
|
|
1051
|
-
}
|
|
1052
|
-
// internal set of ID to get it to RecordData from DS.Model
|
|
1053
|
-
// if we are within create we may not have a recordData yet.
|
|
1054
|
-
if (this.__recordData && this._recordData.__setId) {
|
|
1055
|
-
this._recordData.__setId(id);
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
if (didChange && this.hasRecord) {
|
|
1060
|
-
this.store._notificationManager.notify(this.identifier, 'identity');
|
|
1061
|
-
}
|
|
1062
|
-
this._isUpdatingId = false;
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
didError() {}
|
|
1066
|
-
|
|
1067
|
-
didCleanError() {}
|
|
1068
|
-
|
|
1069
|
-
/*
|
|
1070
|
-
If the adapter did not return a hash in response to a commit,
|
|
1071
|
-
merge the changed attributes and relationships into the existing
|
|
1072
|
-
saved data.
|
|
1073
|
-
*/
|
|
1074
|
-
adapterDidCommit(data) {
|
|
1075
|
-
this.didCleanError();
|
|
1076
|
-
|
|
1077
|
-
this._recordData.didCommit(data);
|
|
1078
|
-
this.send('didCommit');
|
|
1079
|
-
this.store.recordArrayManager.recordDidChange(this.identifier);
|
|
1080
|
-
|
|
1081
|
-
if (!data) {
|
|
1082
|
-
return;
|
|
1083
|
-
}
|
|
1084
|
-
this.store._notificationManager.notify(this.identifier, 'attributes');
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
hasErrors(): boolean {
|
|
1088
|
-
// TODO add assertion forcing consuming RecordData's to implement getErrors
|
|
1089
|
-
if (this._recordData.getErrors) {
|
|
1090
|
-
return this._recordData.getErrors(this.identifier).length > 0;
|
|
1091
|
-
} else {
|
|
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;
|
|
1097
|
-
return errors.length > 0;
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
// FOR USE DURING COMMIT PROCESS
|
|
1102
|
-
adapterDidInvalidate(parsedErrors, error?) {
|
|
1103
|
-
// TODO @runspired this should be handled by RecordState
|
|
1104
|
-
// and errors should be dirtied but lazily fetch if at
|
|
1105
|
-
// all possible. We should only notify errors here.
|
|
1106
|
-
let attribute;
|
|
1107
|
-
if (error && parsedErrors) {
|
|
1108
|
-
// TODO add assertion forcing consuming RecordData's to implement getErrors
|
|
1109
|
-
if (!this._recordData.getErrors) {
|
|
1110
|
-
let record = this.getRecord() as DSModel;
|
|
1111
|
-
let errors = record.errors;
|
|
1112
|
-
for (attribute in parsedErrors) {
|
|
1113
|
-
if (hasOwnProperty.call(parsedErrors, attribute)) {
|
|
1114
|
-
errors._add(attribute, parsedErrors[attribute]);
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
let jsonApiErrors: JsonApiValidationError[] = errorsHashToArray(parsedErrors);
|
|
1120
|
-
this.send('becameInvalid');
|
|
1121
|
-
if (jsonApiErrors.length === 0) {
|
|
1122
|
-
jsonApiErrors = [{ title: 'Invalid Error', detail: '', source: { pointer: '/data' } }];
|
|
1123
|
-
}
|
|
1124
|
-
this._recordData.commitWasRejected(this.identifier, jsonApiErrors);
|
|
1125
|
-
} else {
|
|
1126
|
-
this.send('becameError');
|
|
1127
|
-
this._recordData.commitWasRejected(this.identifier);
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
notifyErrorsChange() {
|
|
1132
|
-
this.store._notificationManager.notify(this.identifier, 'errors');
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
adapterDidError() {
|
|
1136
|
-
this.send('becameError');
|
|
1137
|
-
|
|
1138
|
-
this._recordData.commitWasRejected();
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
toString() {
|
|
1142
|
-
return `<${this.modelName}:${this.id}>`;
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
referenceFor(kind: string | null, name: string) {
|
|
1146
|
-
let reference = this.references[name];
|
|
1147
|
-
|
|
1148
|
-
if (!reference) {
|
|
1149
|
-
if (!HAS_RECORD_DATA_PACKAGE) {
|
|
1150
|
-
// TODO @runspired while this feels odd, it is not a regression in capability because we do
|
|
1151
|
-
// not today support references pulling from RecordDatas other than our own
|
|
1152
|
-
// because of the intimate API access involved. This is something we will need to redesign.
|
|
1153
|
-
assert(`snapshot.belongsTo only supported for @ember-data/record-data`);
|
|
1154
|
-
}
|
|
1155
|
-
const graphFor = (
|
|
1156
|
-
importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
|
|
1157
|
-
).graphFor;
|
|
1158
|
-
const relationship = graphFor(this.store._storeWrapper).get(this.identifier, name);
|
|
1159
|
-
|
|
1160
|
-
if (DEBUG && kind) {
|
|
1161
|
-
let modelName = this.modelName;
|
|
1162
|
-
let actualRelationshipKind = relationship.definition.kind;
|
|
1163
|
-
assert(
|
|
1164
|
-
`You tried to get the '${name}' relationship on a '${modelName}' via record.${kind}('${name}'), but the relationship is of kind '${actualRelationshipKind}'. Use record.${actualRelationshipKind}('${name}') instead.`,
|
|
1165
|
-
actualRelationshipKind === kind
|
|
1166
|
-
);
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
let relationshipKind = relationship.definition.kind;
|
|
1170
|
-
let identifierOrInternalModel = this.identifier;
|
|
1171
|
-
|
|
1172
|
-
if (relationshipKind === 'belongsTo') {
|
|
1173
|
-
reference = new BelongsToReference(this.store, identifierOrInternalModel, relationship, name);
|
|
1174
|
-
} else if (relationshipKind === 'hasMany') {
|
|
1175
|
-
reference = new HasManyReference(this.store, identifierOrInternalModel, relationship, name);
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
this.references[name] = reference;
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
return reference;
|
|
1182
|
-
}
|
|
1183
|
-
}
|
|
1184
|
-
|
|
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 {
|
|
1218
|
-
delete internalModel._relationshipPromisesCache[key];
|
|
1219
|
-
relationship.state.shouldForceReload = false;
|
|
1220
|
-
const isHasMany = relationship.definition.kind === 'hasMany';
|
|
1221
|
-
|
|
1222
|
-
if (isHasMany) {
|
|
1223
|
-
// we don't notify the record property here to avoid refetch
|
|
1224
|
-
// only the many array
|
|
1225
|
-
(value as ManyArray).notify();
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
if (error) {
|
|
1229
|
-
relationship.state.hasFailedLoadAttempt = true;
|
|
1230
|
-
let proxy = internalModel._relationshipProxyCache[key];
|
|
1231
|
-
// belongsTo relationships are sometimes unloaded
|
|
1232
|
-
// when a load fails, in this case we need
|
|
1233
|
-
// to make sure that we aren't proxying
|
|
1234
|
-
// to destroyed content
|
|
1235
|
-
// for the sync belongsTo reload case there will be no proxy
|
|
1236
|
-
// for the async reload case there will be no proxy if the ui
|
|
1237
|
-
// has never been accessed
|
|
1238
|
-
if (proxy && !isHasMany) {
|
|
1239
|
-
if (proxy.content && proxy.content.isDestroying) {
|
|
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);
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
throw error;
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
if (isHasMany) {
|
|
1250
|
-
(value as ManyArray).set('isLoaded', true);
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
relationship.state.hasFailedLoadAttempt = false;
|
|
1254
|
-
// only set to not stale if no error is thrown
|
|
1255
|
-
relationship.state.isStale = false;
|
|
1256
|
-
|
|
1257
|
-
return isHasMany || !value ? (value as ManyArray | null) : (value as InternalModel).getRecord();
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
export function assertRecordsPassedToHasMany(records) {
|
|
1261
|
-
// TODO only allow native arrays
|
|
1262
|
-
assert(
|
|
1263
|
-
`You must pass an array of records to set a hasMany relationship`,
|
|
1264
|
-
Array.isArray(records) || EmberArray.detect(records)
|
|
1265
|
-
);
|
|
1266
|
-
assert(
|
|
1267
|
-
`All elements of a hasMany relationship must be instances of Model, you passed ${inspect(records)}`,
|
|
1268
|
-
(function () {
|
|
1269
|
-
return A(records).every((record) => hasOwnProperty.call(record, '_internalModel') === true);
|
|
1270
|
-
})()
|
|
1271
|
-
);
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
export function extractRecordDatasFromRecords(records) {
|
|
1275
|
-
return records.map(extractRecordDataFromRecord);
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
|
-
export function extractRecordDataFromRecord(recordOrPromiseRecord) {
|
|
1279
|
-
if (!recordOrPromiseRecord) {
|
|
1280
|
-
return null;
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
if (recordOrPromiseRecord.then) {
|
|
1284
|
-
let content = recordOrPromiseRecord.get && recordOrPromiseRecord.get('content');
|
|
1285
|
-
assert(
|
|
1286
|
-
'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.',
|
|
1287
|
-
content !== undefined
|
|
1288
|
-
);
|
|
1289
|
-
return content ? recordDataFor(content) : null;
|
|
1290
|
-
}
|
|
1291
|
-
|
|
1292
|
-
return recordDataFor(recordOrPromiseRecord);
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
function anyUnloaded(store: CoreStore, relationship: ManyRelationship) {
|
|
1296
|
-
let state = relationship.currentState;
|
|
1297
|
-
const unloaded = state.find((s) => {
|
|
1298
|
-
let im = store._internalModelForResource(s);
|
|
1299
|
-
return im._isDematerializing || !im.currentState.isLoaded;
|
|
1300
|
-
});
|
|
1301
|
-
|
|
1302
|
-
return unloaded || false;
|
|
1303
|
-
}
|