@ember-data/store 4.2.0-alpha.1 → 4.2.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/addon/-private/identifiers/cache.ts +3 -16
- package/addon/-private/identifiers/is-stable-identifier.ts +2 -2
- package/addon/-private/index.ts +1 -3
- package/addon/-private/system/core-store.ts +182 -883
- package/addon/-private/system/ds-model-store.ts +20 -111
- package/addon/-private/system/fetch-manager.ts +2 -1
- package/addon/-private/system/model/internal-model.ts +92 -345
- package/addon/-private/system/model/shim-model-class.ts +15 -16
- package/addon/-private/system/model/states.js +2 -14
- package/addon/-private/system/record-array-manager.js +21 -70
- package/addon/-private/system/record-arrays/adapter-populated-record-array.js +1 -20
- package/addon/-private/system/record-arrays/record-array.js +1 -8
- package/addon/-private/system/record-data-for.ts +10 -8
- package/addon/-private/system/record-notification-manager.ts +11 -10
- package/addon/-private/system/references/belongs-to.ts +32 -67
- package/addon/-private/system/references/has-many.ts +21 -41
- package/addon/-private/system/references/record.ts +15 -27
- package/addon/-private/system/references/reference.ts +4 -11
- package/addon/-private/system/schema-definition-service.ts +2 -2
- package/addon/-private/system/snapshot.ts +28 -48
- package/addon/-private/system/store/finders.js +2 -96
- package/addon/-private/system/store/internal-model-factory.ts +34 -28
- package/addon/-private/system/store/record-data-store-wrapper.ts +28 -36
- package/addon/-private/system/weak-cache.ts +125 -0
- package/addon/-private/ts-interfaces/identifier.ts +2 -2
- package/addon/-private/ts-interfaces/minimum-adapter-interface.ts +0 -1
- package/addon/-private/ts-interfaces/schema-definition-service.ts +2 -2
- package/package.json +15 -15
- package/addon/-private/system/deprecated-evented.js +0 -92
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { getOwner } from '@ember/application';
|
|
5
5
|
import { A } from '@ember/array';
|
|
6
|
-
import { assert,
|
|
7
|
-
import {
|
|
6
|
+
import { assert, inspect, warn } from '@ember/debug';
|
|
7
|
+
import { set } from '@ember/object';
|
|
8
8
|
import { _backburner as emberBackburner } from '@ember/runloop';
|
|
9
9
|
import type { Backburner } from '@ember/runloop/-private/backburner';
|
|
10
10
|
import Service from '@ember/service';
|
|
@@ -14,24 +14,9 @@ import { DEBUG } from '@glimmer/env';
|
|
|
14
14
|
import Ember from 'ember';
|
|
15
15
|
|
|
16
16
|
import require from 'require';
|
|
17
|
-
import { all, default as RSVP,
|
|
17
|
+
import { all, default as RSVP, Promise, resolve } from 'rsvp';
|
|
18
18
|
|
|
19
|
-
import {
|
|
20
|
-
CUSTOM_MODEL_CLASS,
|
|
21
|
-
RECORD_DATA_ERRORS,
|
|
22
|
-
RECORD_DATA_STATE,
|
|
23
|
-
REQUEST_SERVICE,
|
|
24
|
-
} from '@ember-data/canary-features';
|
|
25
|
-
import {
|
|
26
|
-
HAS_ADAPTER_PACKAGE,
|
|
27
|
-
HAS_EMBER_DATA_PACKAGE,
|
|
28
|
-
HAS_RECORD_DATA_PACKAGE,
|
|
29
|
-
HAS_SERIALIZER_PACKAGE,
|
|
30
|
-
} from '@ember-data/private-build-infra';
|
|
31
|
-
import {
|
|
32
|
-
DEPRECATE_DEFAULT_ADAPTER,
|
|
33
|
-
DEPRECATE_LEGACY_TEST_REGISTRATIONS,
|
|
34
|
-
} from '@ember-data/private-build-infra/deprecations';
|
|
19
|
+
import { HAS_RECORD_DATA_PACKAGE } from '@ember-data/private-build-infra';
|
|
35
20
|
import type {
|
|
36
21
|
BelongsToRelationship,
|
|
37
22
|
ManyRelationship,
|
|
@@ -39,8 +24,7 @@ import type {
|
|
|
39
24
|
} from '@ember-data/record-data/-private';
|
|
40
25
|
import type { RelationshipState } from '@ember-data/record-data/-private/graph/-state';
|
|
41
26
|
|
|
42
|
-
import
|
|
43
|
-
import { identifierCacheFor } from '../identifiers/cache';
|
|
27
|
+
import { IdentifierCache } from '../identifiers/cache';
|
|
44
28
|
import type { DSModel } from '../ts-interfaces/ds-model';
|
|
45
29
|
import type {
|
|
46
30
|
CollectionResourceDocument,
|
|
@@ -68,7 +52,6 @@ import constructResource from '../utils/construct-resource';
|
|
|
68
52
|
import promiseRecord from '../utils/promise-record';
|
|
69
53
|
import edBackburner from './backburner';
|
|
70
54
|
import coerceId, { ensureStringId } from './coerce-id';
|
|
71
|
-
import { errorsArrayToHash } from './errors-utils';
|
|
72
55
|
import FetchManager, { SaveOp } from './fetch-manager';
|
|
73
56
|
import type InternalModel from './model/internal-model';
|
|
74
57
|
import {
|
|
@@ -86,9 +69,7 @@ import NotificationManager from './record-notification-manager';
|
|
|
86
69
|
import type { BelongsToReference, HasManyReference } from './references';
|
|
87
70
|
import { RecordReference } from './references';
|
|
88
71
|
import type RequestCache from './request-cache';
|
|
89
|
-
import
|
|
90
|
-
import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './store/common';
|
|
91
|
-
import { _find, _findAll, _findBelongsTo, _findHasMany, _findMany, _query, _queryRecord } from './store/finders';
|
|
72
|
+
import { _findAll, _findBelongsTo, _findHasMany, _query, _queryRecord } from './store/finders';
|
|
92
73
|
import {
|
|
93
74
|
internalModelFactoryFor,
|
|
94
75
|
peekRecordIdentifier,
|
|
@@ -96,7 +77,7 @@ import {
|
|
|
96
77
|
setRecordIdentifier,
|
|
97
78
|
} from './store/internal-model-factory';
|
|
98
79
|
import RecordDataStoreWrapper from './store/record-data-store-wrapper';
|
|
99
|
-
import
|
|
80
|
+
import WeakCache from './weak-cache';
|
|
100
81
|
|
|
101
82
|
type RecordDataConstruct = typeof RecordDataClass;
|
|
102
83
|
let _RecordData: RecordDataConstruct | undefined;
|
|
@@ -104,18 +85,8 @@ let _RecordData: RecordDataConstruct | undefined;
|
|
|
104
85
|
const { ENV } = Ember;
|
|
105
86
|
type AsyncTrackingToken = Readonly<{ label: string; trace: Error | string }>;
|
|
106
87
|
type PromiseArray<T> = Promise<T[]>;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
resolver: RSVP.Deferred<InternalModel>;
|
|
110
|
-
options: any;
|
|
111
|
-
trace?: Error;
|
|
112
|
-
};
|
|
113
|
-
type PendingSaveItem = {
|
|
114
|
-
snapshot: Snapshot;
|
|
115
|
-
resolver: RSVP.Deferred<void>;
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
const RECORD_REFERENCES = new WeakMap<StableRecordIdentifier, RecordReference>();
|
|
88
|
+
|
|
89
|
+
const RECORD_REFERENCES = new WeakCache<StableRecordIdentifier, RecordReference>(DEBUG ? 'reference' : '');
|
|
119
90
|
|
|
120
91
|
function freeze<T>(obj: T): T {
|
|
121
92
|
if (typeof Object.freeze === 'function') {
|
|
@@ -125,26 +96,6 @@ function freeze<T>(obj: T): T {
|
|
|
125
96
|
return obj;
|
|
126
97
|
}
|
|
127
98
|
|
|
128
|
-
function deprecateTestRegistration(factoryType: 'adapter', factoryName: '-json-api'): void;
|
|
129
|
-
function deprecateTestRegistration(factoryType: 'serializer', factoryName: '-json-api' | '-rest' | '-default'): void;
|
|
130
|
-
function deprecateTestRegistration(
|
|
131
|
-
factoryType: 'serializer' | 'adapter',
|
|
132
|
-
factoryName: '-json-api' | '-rest' | '-default'
|
|
133
|
-
): void {
|
|
134
|
-
deprecate(
|
|
135
|
-
`You looked up the ${factoryType} "${factoryName}" but it was not found. Likely this means you are using a legacy ember-qunit moduleFor helper. Add "needs: ['${factoryType}:${factoryName}']", "integration: true", or refactor to modern syntax to resolve this deprecation.`,
|
|
136
|
-
false,
|
|
137
|
-
{
|
|
138
|
-
id: 'ember-data:-legacy-test-registrations',
|
|
139
|
-
until: '3.17',
|
|
140
|
-
for: '@ember-data/store',
|
|
141
|
-
since: {
|
|
142
|
-
available: '3.15',
|
|
143
|
-
enabled: '3.15',
|
|
144
|
-
},
|
|
145
|
-
}
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
99
|
/**
|
|
149
100
|
The store contains all of the data for records loaded from the server.
|
|
150
101
|
It is also responsible for creating instances of `Model` that wrap
|
|
@@ -218,9 +169,6 @@ function deprecateTestRegistration(
|
|
|
218
169
|
@public
|
|
219
170
|
@extends Ember.Service
|
|
220
171
|
*/
|
|
221
|
-
interface CoreStore {
|
|
222
|
-
adapter: string;
|
|
223
|
-
}
|
|
224
172
|
|
|
225
173
|
abstract class CoreStore extends Service {
|
|
226
174
|
/**
|
|
@@ -232,6 +180,7 @@ abstract class CoreStore extends Service {
|
|
|
232
180
|
public recordArrayManager: RecordArrayManager = new RecordArrayManager({ store: this });
|
|
233
181
|
|
|
234
182
|
declare _notificationManager: NotificationManager;
|
|
183
|
+
declare identifierCache: IdentifierCache;
|
|
235
184
|
private _adapterCache = Object.create(null);
|
|
236
185
|
private _serializerCache = Object.create(null);
|
|
237
186
|
public _storeWrapper = new RecordDataStoreWrapper(this);
|
|
@@ -243,20 +192,14 @@ abstract class CoreStore extends Service {
|
|
|
243
192
|
These queues are currently controlled by a flush scheduled into
|
|
244
193
|
ember-data's custom backburner instance.
|
|
245
194
|
*/
|
|
246
|
-
// used for coalescing record save requests
|
|
247
|
-
private _pendingSave: PendingSaveItem[] = [];
|
|
248
195
|
// used for coalescing internal model updates
|
|
249
196
|
private _updatedInternalModels: InternalModel[] = [];
|
|
250
197
|
|
|
251
|
-
// used to keep track of all the find requests that need to be coalesced
|
|
252
|
-
private _pendingFetch = new Map<string, PendingFetchItem[]>();
|
|
253
|
-
|
|
254
198
|
declare _fetchManager: FetchManager;
|
|
255
199
|
declare _schemaDefinitionService: SchemaDefinitionService;
|
|
256
200
|
|
|
257
201
|
// DEBUG-only properties
|
|
258
202
|
declare _trackedAsyncRequests: AsyncTrackingToken[];
|
|
259
|
-
shouldAssertMethodCallsOnDestroyedStore: boolean = true;
|
|
260
203
|
shouldTrackAsyncRequests: boolean = false;
|
|
261
204
|
generateStackTracesForTrackedRequests: boolean = false;
|
|
262
205
|
declare _trackAsyncRequestStart: (str: string) => void;
|
|
@@ -310,64 +253,27 @@ abstract class CoreStore extends Service {
|
|
|
310
253
|
constructor() {
|
|
311
254
|
super(...arguments);
|
|
312
255
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
256
|
+
RECORD_REFERENCES._generator = (identifier) => {
|
|
257
|
+
return new RecordReference(this, identifier);
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
this._fetchManager = new FetchManager(this);
|
|
261
|
+
this._notificationManager = new NotificationManager(this);
|
|
262
|
+
this.__recordDataFor = this.__recordDataFor.bind(this);
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Provides access to the IdentifierCache instance
|
|
266
|
+
* for this store.
|
|
267
|
+
*
|
|
268
|
+
* The IdentifierCache can be used to generate or
|
|
269
|
+
* retrieve a stable unique identifier for any resource.
|
|
270
|
+
*
|
|
271
|
+
* @property {IdentifierCache} identifierCache
|
|
272
|
+
* @public
|
|
273
|
+
*/
|
|
274
|
+
this.identifierCache = new IdentifierCache();
|
|
320
275
|
|
|
321
276
|
if (DEBUG) {
|
|
322
|
-
if (HAS_EMBER_DATA_PACKAGE && HAS_SERIALIZER_PACKAGE) {
|
|
323
|
-
// support for legacy moduleFor style unit tests
|
|
324
|
-
// that did not include transforms in "needs"
|
|
325
|
-
// or which were not set to integration:true
|
|
326
|
-
// that were relying on ember-test-helpers
|
|
327
|
-
// doing an auto-registration of the transform
|
|
328
|
-
// or us doing one
|
|
329
|
-
const Mapping = {
|
|
330
|
-
date: 'DateTransform',
|
|
331
|
-
boolean: 'BooleanTransform',
|
|
332
|
-
number: 'NumberTransform',
|
|
333
|
-
string: 'StringTransform',
|
|
334
|
-
};
|
|
335
|
-
type MapKeys = keyof typeof Mapping;
|
|
336
|
-
const keys = Object.keys(Mapping) as MapKeys[];
|
|
337
|
-
let shouldWarn = false;
|
|
338
|
-
|
|
339
|
-
let owner = getOwner(this);
|
|
340
|
-
keys.forEach((attributeType) => {
|
|
341
|
-
const transformFactory = owner.factoryFor(`transform:${attributeType}`);
|
|
342
|
-
|
|
343
|
-
if (!transformFactory) {
|
|
344
|
-
// we don't deprecate this because the moduleFor style tests with the closed
|
|
345
|
-
// resolver will be deprecated on their own. When that deprecation completes
|
|
346
|
-
// we can drop this.
|
|
347
|
-
const Transform = require(`@ember-data/serializer/-private`)[Mapping[attributeType]];
|
|
348
|
-
owner.register(`transform:${attributeType}`, Transform);
|
|
349
|
-
shouldWarn = true;
|
|
350
|
-
}
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
if (shouldWarn) {
|
|
354
|
-
deprecate(
|
|
355
|
-
`You are relying on the automatic registration of the transforms "date", "number", "boolean", and "string". Likely this means you are using a legacy ember-qunit moduleFor helper. Add "needs: ['transform:date', 'transform:boolean', 'transform:number', 'transform:string']", "integration: true", or refactor to modern syntax to resolve this deprecation.`,
|
|
356
|
-
false,
|
|
357
|
-
{
|
|
358
|
-
id: 'ember-data:-legacy-test-registrations',
|
|
359
|
-
until: '3.17',
|
|
360
|
-
for: '@ember-data/store',
|
|
361
|
-
since: {
|
|
362
|
-
available: '3.15',
|
|
363
|
-
enabled: '3.15',
|
|
364
|
-
},
|
|
365
|
-
}
|
|
366
|
-
);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
this.shouldAssertMethodCallsOnDestroyedStore = this.shouldAssertMethodCallsOnDestroyedStore || false;
|
|
371
277
|
if (this.shouldTrackAsyncRequests === undefined) {
|
|
372
278
|
this.shouldTrackAsyncRequests = false;
|
|
373
279
|
}
|
|
@@ -377,14 +283,14 @@ abstract class CoreStore extends Service {
|
|
|
377
283
|
|
|
378
284
|
this._trackedAsyncRequests = [];
|
|
379
285
|
this._trackAsyncRequestStart = (label) => {
|
|
380
|
-
let trace =
|
|
286
|
+
let trace: string | Error =
|
|
381
287
|
'set `store.generateStackTracesForTrackedRequests = true;` to get a detailed trace for where this request originated';
|
|
382
288
|
|
|
383
289
|
if (this.generateStackTracesForTrackedRequests) {
|
|
384
290
|
try {
|
|
385
291
|
throw new Error(`EmberData TrackedRequest: ${label}`);
|
|
386
292
|
} catch (e) {
|
|
387
|
-
trace = e;
|
|
293
|
+
trace = e as Error;
|
|
388
294
|
}
|
|
389
295
|
}
|
|
390
296
|
|
|
@@ -421,24 +327,7 @@ abstract class CoreStore extends Service {
|
|
|
421
327
|
}
|
|
422
328
|
|
|
423
329
|
getRequestStateService(): RequestCache {
|
|
424
|
-
|
|
425
|
-
return this._fetchManager.requestCache;
|
|
426
|
-
}
|
|
427
|
-
assert('RequestService is not available unless the feature flag is on and running on a canary build', false);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Provides access to the IdentifierCache instance
|
|
432
|
-
* for this store.
|
|
433
|
-
*
|
|
434
|
-
* The IdentifierCache can be used to generate or
|
|
435
|
-
* retrieve a stable unique identifier for any resource.
|
|
436
|
-
*
|
|
437
|
-
* @property {IdentifierCache} identifierCache
|
|
438
|
-
* @public
|
|
439
|
-
*/
|
|
440
|
-
get identifierCache(): IdentifierCache {
|
|
441
|
-
return identifierCacheFor(this);
|
|
330
|
+
return this._fetchManager.requestCache;
|
|
442
331
|
}
|
|
443
332
|
|
|
444
333
|
_instantiateRecord(
|
|
@@ -448,55 +337,51 @@ abstract class CoreStore extends Service {
|
|
|
448
337
|
identifier: StableRecordIdentifier,
|
|
449
338
|
properties?: { [key: string]: any }
|
|
450
339
|
) {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
);
|
|
458
|
-
|
|
459
|
-
if ('id' in properties) {
|
|
460
|
-
internalModel.setId(properties.id);
|
|
461
|
-
}
|
|
340
|
+
// assert here
|
|
341
|
+
if (properties !== undefined) {
|
|
342
|
+
assert(
|
|
343
|
+
`You passed '${properties}' as properties for record creation instead of an object.`,
|
|
344
|
+
typeof properties === 'object' && properties !== null
|
|
345
|
+
);
|
|
462
346
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
assertRecordsPassedToHasMany(properties[prop]);
|
|
478
|
-
}
|
|
479
|
-
relationshipValue = extractRecordDatasFromRecords(properties[prop]);
|
|
480
|
-
} else {
|
|
481
|
-
relationshipValue = extractRecordDataFromRecord(properties[prop]);
|
|
482
|
-
}
|
|
347
|
+
if ('id' in properties) {
|
|
348
|
+
internalModel.setId(properties.id);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// convert relationship Records to RecordDatas before passing to RecordData
|
|
352
|
+
let defs = this._relationshipsDefinitionFor({ type: modelName });
|
|
353
|
+
|
|
354
|
+
if (defs !== null) {
|
|
355
|
+
let keys = Object.keys(properties);
|
|
356
|
+
let relationshipValue;
|
|
357
|
+
|
|
358
|
+
for (let i = 0; i < keys.length; i++) {
|
|
359
|
+
let prop = keys[i];
|
|
360
|
+
let def = defs[prop];
|
|
483
361
|
|
|
484
|
-
|
|
362
|
+
if (def !== undefined) {
|
|
363
|
+
if (def.kind === 'hasMany') {
|
|
364
|
+
if (DEBUG) {
|
|
365
|
+
assertRecordsPassedToHasMany(properties[prop]);
|
|
366
|
+
}
|
|
367
|
+
relationshipValue = extractRecordDatasFromRecords(properties[prop]);
|
|
368
|
+
} else {
|
|
369
|
+
relationshipValue = extractRecordDataFromRecord(properties[prop]);
|
|
485
370
|
}
|
|
371
|
+
|
|
372
|
+
properties[prop] = relationshipValue;
|
|
486
373
|
}
|
|
487
374
|
}
|
|
488
375
|
}
|
|
489
|
-
|
|
490
|
-
// TODO guard against initRecordOptions no being there
|
|
491
|
-
let createOptions = recordData._initRecordCreateOptions(properties);
|
|
492
|
-
//TODO Igor pass a wrapper instead of RD
|
|
493
|
-
let record = this.instantiateRecord(identifier, createOptions, this.__recordDataFor, this._notificationManager);
|
|
494
|
-
setRecordIdentifier(record, identifier);
|
|
495
|
-
//recordToInternalModelMap.set(record, internalModel);
|
|
496
|
-
return record;
|
|
497
376
|
}
|
|
498
377
|
|
|
499
|
-
|
|
378
|
+
// TODO guard against initRecordOptions no being there
|
|
379
|
+
let createOptions = recordData._initRecordCreateOptions(properties);
|
|
380
|
+
//TODO Igor pass a wrapper instead of RD
|
|
381
|
+
let record = this.instantiateRecord(identifier, createOptions, this.__recordDataFor, this._notificationManager);
|
|
382
|
+
setRecordIdentifier(record, identifier);
|
|
383
|
+
//recordToInternalModelMap.set(record, internalModel);
|
|
384
|
+
return record;
|
|
500
385
|
}
|
|
501
386
|
|
|
502
387
|
abstract instantiateRecord(
|
|
@@ -513,20 +398,12 @@ abstract class CoreStore extends Service {
|
|
|
513
398
|
}
|
|
514
399
|
|
|
515
400
|
// FeatureFlagged in the DSModelStore claas
|
|
516
|
-
_attributesDefinitionFor(
|
|
517
|
-
|
|
518
|
-
return this.getSchemaDefinitionService().attributesDefinitionFor(identifier);
|
|
519
|
-
} else {
|
|
520
|
-
return this.getSchemaDefinitionService().attributesDefinitionFor(modelName);
|
|
521
|
-
}
|
|
401
|
+
_attributesDefinitionFor(identifier: RecordIdentifier | { type: string }): AttributesSchema {
|
|
402
|
+
return this.getSchemaDefinitionService().attributesDefinitionFor(identifier);
|
|
522
403
|
}
|
|
523
404
|
|
|
524
|
-
_relationshipsDefinitionFor(
|
|
525
|
-
|
|
526
|
-
return this.getSchemaDefinitionService().relationshipsDefinitionFor(identifier);
|
|
527
|
-
} else {
|
|
528
|
-
return this.getSchemaDefinitionService().relationshipsDefinitionFor(modelName);
|
|
529
|
-
}
|
|
405
|
+
_relationshipsDefinitionFor(identifier: RecordIdentifier | { type: string }) {
|
|
406
|
+
return this.getSchemaDefinitionService().relationshipsDefinitionFor(identifier);
|
|
530
407
|
}
|
|
531
408
|
|
|
532
409
|
registerSchemaDefinitionService(schema: SchemaDefinitionService) {
|
|
@@ -534,15 +411,12 @@ abstract class CoreStore extends Service {
|
|
|
534
411
|
}
|
|
535
412
|
|
|
536
413
|
getSchemaDefinitionService(): SchemaDefinitionService {
|
|
537
|
-
|
|
538
|
-
return this._schemaDefinitionService;
|
|
539
|
-
}
|
|
540
|
-
assert('need to enable CUSTOM_MODEL_CLASS feature flag in order to access SchemaDefinitionService');
|
|
414
|
+
return this._schemaDefinitionService;
|
|
541
415
|
}
|
|
542
416
|
|
|
543
417
|
// TODO Double check this return value is correct
|
|
544
418
|
_relationshipMetaFor(modelName: string, id: string | null, key: string) {
|
|
545
|
-
return this._relationshipsDefinitionFor(modelName)[key];
|
|
419
|
+
return this._relationshipsDefinitionFor({ type: modelName })[key];
|
|
546
420
|
}
|
|
547
421
|
|
|
548
422
|
/**
|
|
@@ -715,16 +589,12 @@ abstract class CoreStore extends Service {
|
|
|
715
589
|
assertDestroyingStore(this, 'deleteRecord');
|
|
716
590
|
}
|
|
717
591
|
this._backburner.join(() => {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
internalModel.deleteRecord();
|
|
724
|
-
}
|
|
592
|
+
let identifier = peekRecordIdentifier(record);
|
|
593
|
+
if (identifier) {
|
|
594
|
+
let internalModel = internalModelFactoryFor(this).peek(identifier);
|
|
595
|
+
if (internalModel) {
|
|
596
|
+
internalModel.deleteRecord();
|
|
725
597
|
}
|
|
726
|
-
} else {
|
|
727
|
-
record.deleteRecord();
|
|
728
598
|
}
|
|
729
599
|
});
|
|
730
600
|
}
|
|
@@ -749,16 +619,12 @@ abstract class CoreStore extends Service {
|
|
|
749
619
|
if (DEBUG) {
|
|
750
620
|
assertDestroyingStore(this, 'unloadRecord');
|
|
751
621
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
internalModel.unloadRecord();
|
|
758
|
-
}
|
|
622
|
+
let identifier = peekRecordIdentifier(record);
|
|
623
|
+
if (identifier) {
|
|
624
|
+
let internalModel = internalModelFactoryFor(this).peek(identifier);
|
|
625
|
+
if (internalModel) {
|
|
626
|
+
internalModel.unloadRecord();
|
|
759
627
|
}
|
|
760
|
-
} else {
|
|
761
|
-
record.unloadRecord();
|
|
762
628
|
}
|
|
763
629
|
}
|
|
764
630
|
|
|
@@ -1267,19 +1133,12 @@ abstract class CoreStore extends Service {
|
|
|
1267
1133
|
return this._scheduleFetch(internalModel, options);
|
|
1268
1134
|
}
|
|
1269
1135
|
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
if (
|
|
1273
|
-
return internalModel
|
|
1274
|
-
}
|
|
1275
|
-
} else {
|
|
1276
|
-
if (internalModel.currentState.isLoading) {
|
|
1277
|
-
let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier, options);
|
|
1278
|
-
if (pendingRequest) {
|
|
1279
|
-
return pendingRequest.then(() => Promise.resolve(internalModel));
|
|
1280
|
-
}
|
|
1281
|
-
return this._scheduleFetch(internalModel, options);
|
|
1136
|
+
if (internalModel.currentState.isLoading) {
|
|
1137
|
+
let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier, options);
|
|
1138
|
+
if (pendingRequest) {
|
|
1139
|
+
return pendingRequest.then(() => Promise.resolve(internalModel));
|
|
1282
1140
|
}
|
|
1141
|
+
return this._scheduleFetch(internalModel, options);
|
|
1283
1142
|
}
|
|
1284
1143
|
|
|
1285
1144
|
return Promise.resolve(internalModel);
|
|
@@ -1316,29 +1175,6 @@ abstract class CoreStore extends Service {
|
|
|
1316
1175
|
return promiseArray(all(promises).then(A, null, `DS: Store#findByIds of ${normalizedModelName} complete`));
|
|
1317
1176
|
}
|
|
1318
1177
|
|
|
1319
|
-
/**
|
|
1320
|
-
This method is called by `findRecord` if it discovers that a particular
|
|
1321
|
-
type/id pair hasn't been loaded yet to kick off a request to the
|
|
1322
|
-
adapter.
|
|
1323
|
-
|
|
1324
|
-
@method _fetchRecord
|
|
1325
|
-
@private
|
|
1326
|
-
@param {InternalModel} internalModel model
|
|
1327
|
-
@return {Promise} promise
|
|
1328
|
-
*/
|
|
1329
|
-
_fetchRecord(internalModel: InternalModel, options): Promise<InternalModel> {
|
|
1330
|
-
let modelName = internalModel.modelName;
|
|
1331
|
-
let adapter = this.adapterFor(modelName);
|
|
1332
|
-
|
|
1333
|
-
assert(`You tried to find a record but you have no adapter (for ${modelName})`, adapter);
|
|
1334
|
-
assert(
|
|
1335
|
-
`You tried to find a record but your adapter (for ${modelName}) does not implement 'findRecord'`,
|
|
1336
|
-
typeof adapter.findRecord === 'function'
|
|
1337
|
-
);
|
|
1338
|
-
|
|
1339
|
-
return _find(adapter, this, internalModel.modelClass, internalModel.id, internalModel, options);
|
|
1340
|
-
}
|
|
1341
|
-
|
|
1342
1178
|
_scheduleFetchMany(internalModels, options) {
|
|
1343
1179
|
let fetches = new Array(internalModels.length);
|
|
1344
1180
|
|
|
@@ -1349,7 +1185,7 @@ abstract class CoreStore extends Service {
|
|
|
1349
1185
|
return Promise.all(fetches);
|
|
1350
1186
|
}
|
|
1351
1187
|
|
|
1352
|
-
|
|
1188
|
+
_scheduleFetch(internalModel: InternalModel, options = {}): RSVP.Promise<InternalModel> {
|
|
1353
1189
|
let generateStackTrace = this.generateStackTracesForTrackedRequests;
|
|
1354
1190
|
// TODO remove this once we don't rely on state machine
|
|
1355
1191
|
internalModel.send('loadingData');
|
|
@@ -1384,227 +1220,6 @@ abstract class CoreStore extends Service {
|
|
|
1384
1220
|
);
|
|
1385
1221
|
}
|
|
1386
1222
|
|
|
1387
|
-
_scheduleFetch(internalModel: InternalModel, options): RSVP.Promise<InternalModel> {
|
|
1388
|
-
if (REQUEST_SERVICE) {
|
|
1389
|
-
return this._scheduleFetchThroughFetchManager(internalModel, options);
|
|
1390
|
-
} else {
|
|
1391
|
-
if (internalModel._promiseProxy) {
|
|
1392
|
-
return internalModel._promiseProxy;
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
assertIdentifierHasId(internalModel.identifier);
|
|
1396
|
-
|
|
1397
|
-
let { id, modelName } = internalModel;
|
|
1398
|
-
let resolver = defer<InternalModel>(`Fetching ${modelName}' with id: ${id}`);
|
|
1399
|
-
let pendingFetchItem: PendingFetchItem = {
|
|
1400
|
-
internalModel,
|
|
1401
|
-
resolver,
|
|
1402
|
-
options,
|
|
1403
|
-
};
|
|
1404
|
-
|
|
1405
|
-
if (DEBUG) {
|
|
1406
|
-
if (this.generateStackTracesForTrackedRequests === true) {
|
|
1407
|
-
let trace;
|
|
1408
|
-
|
|
1409
|
-
try {
|
|
1410
|
-
throw new Error(`Trace Origin for scheduled fetch for ${modelName}:${id}.`);
|
|
1411
|
-
} catch (e) {
|
|
1412
|
-
trace = e;
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
|
-
// enable folks to discover the origin of this findRecord call when
|
|
1416
|
-
// debugging. Ideally we would have a tracked queue for requests with
|
|
1417
|
-
// labels or local IDs that could be used to merge this trace with
|
|
1418
|
-
// the trace made available when we detect an async leak
|
|
1419
|
-
pendingFetchItem.trace = trace;
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
|
-
|
|
1423
|
-
let promise = resolver.promise;
|
|
1424
|
-
|
|
1425
|
-
internalModel.send('loadingData', promise);
|
|
1426
|
-
if (this._pendingFetch.size === 0) {
|
|
1427
|
-
emberBackburner.schedule('actions', this, this.flushAllPendingFetches);
|
|
1428
|
-
}
|
|
1429
|
-
|
|
1430
|
-
let fetches = this._pendingFetch;
|
|
1431
|
-
let pending = fetches.get(modelName);
|
|
1432
|
-
|
|
1433
|
-
if (pending === undefined) {
|
|
1434
|
-
pending = [];
|
|
1435
|
-
fetches.set(modelName, pending);
|
|
1436
|
-
}
|
|
1437
|
-
|
|
1438
|
-
pending.push(pendingFetchItem);
|
|
1439
|
-
|
|
1440
|
-
return promise;
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
|
-
flushAllPendingFetches() {
|
|
1445
|
-
if (REQUEST_SERVICE) {
|
|
1446
|
-
return;
|
|
1447
|
-
//assert here
|
|
1448
|
-
} else {
|
|
1449
|
-
if (this.isDestroyed || this.isDestroying) {
|
|
1450
|
-
return;
|
|
1451
|
-
}
|
|
1452
|
-
|
|
1453
|
-
this._pendingFetch.forEach(this._flushPendingFetchForType, this);
|
|
1454
|
-
this._pendingFetch.clear();
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
_flushPendingFetchForType(pendingFetchItems: PendingFetchItem[], modelName: string) {
|
|
1459
|
-
let store = this;
|
|
1460
|
-
let adapter = store.adapterFor(modelName);
|
|
1461
|
-
let shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests;
|
|
1462
|
-
let totalItems = pendingFetchItems.length;
|
|
1463
|
-
let internalModels = new Array(totalItems);
|
|
1464
|
-
let seeking = Object.create(null);
|
|
1465
|
-
|
|
1466
|
-
let optionsMap = new WeakMap();
|
|
1467
|
-
|
|
1468
|
-
for (let i = 0; i < totalItems; i++) {
|
|
1469
|
-
let pendingItem = pendingFetchItems[i];
|
|
1470
|
-
let internalModel = pendingItem.internalModel;
|
|
1471
|
-
internalModels[i] = internalModel;
|
|
1472
|
-
optionsMap.set(internalModel, pendingItem.options);
|
|
1473
|
-
// We can remove this "not null" cast once we have enough typing
|
|
1474
|
-
// to know we are only dealing with ExistingResourceIdentifierObjects
|
|
1475
|
-
seeking[internalModel.id!] = pendingItem;
|
|
1476
|
-
}
|
|
1477
|
-
|
|
1478
|
-
function _fetchRecord(recordResolverPair) {
|
|
1479
|
-
let recordFetch = store._fetchRecord(recordResolverPair.internalModel, recordResolverPair.options);
|
|
1480
|
-
|
|
1481
|
-
recordResolverPair.resolver.resolve(recordFetch);
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
function handleFoundRecords(foundInternalModels: InternalModel[], expectedInternalModels: InternalModel[]) {
|
|
1485
|
-
// resolve found records
|
|
1486
|
-
let found = Object.create(null);
|
|
1487
|
-
for (let i = 0, l = foundInternalModels.length; i < l; i++) {
|
|
1488
|
-
let internalModel = foundInternalModels[i];
|
|
1489
|
-
|
|
1490
|
-
// We can remove this "not null" cast once we have enough typing
|
|
1491
|
-
// to know we are only dealing with ExistingResourceIdentifierObjects
|
|
1492
|
-
let pair = seeking[internalModel.id!];
|
|
1493
|
-
found[internalModel.id!] = internalModel;
|
|
1494
|
-
|
|
1495
|
-
if (pair) {
|
|
1496
|
-
let resolver = pair.resolver;
|
|
1497
|
-
resolver.resolve(internalModel);
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
|
|
1501
|
-
// reject missing records
|
|
1502
|
-
let missingInternalModels: InternalModel[] = [];
|
|
1503
|
-
|
|
1504
|
-
for (let i = 0, l = expectedInternalModels.length; i < l; i++) {
|
|
1505
|
-
let internalModel = expectedInternalModels[i];
|
|
1506
|
-
|
|
1507
|
-
// We can remove this "not null" cast once we have enough typing
|
|
1508
|
-
// to know we are only dealing with ExistingResourceIdentifierObjects
|
|
1509
|
-
if (!found[internalModel.id!]) {
|
|
1510
|
-
missingInternalModels.push(internalModel);
|
|
1511
|
-
}
|
|
1512
|
-
}
|
|
1513
|
-
|
|
1514
|
-
if (missingInternalModels.length) {
|
|
1515
|
-
warn(
|
|
1516
|
-
'Ember Data expected to find records with the following ids in the adapter response but they were missing: [ "' +
|
|
1517
|
-
missingInternalModels.map((r) => r.id).join('", "') +
|
|
1518
|
-
'" ]',
|
|
1519
|
-
false,
|
|
1520
|
-
{
|
|
1521
|
-
id: 'ds.store.missing-records-from-adapter',
|
|
1522
|
-
}
|
|
1523
|
-
);
|
|
1524
|
-
rejectInternalModels(missingInternalModels);
|
|
1525
|
-
}
|
|
1526
|
-
}
|
|
1527
|
-
|
|
1528
|
-
function rejectInternalModels(internalModels: InternalModel[], error?: Error) {
|
|
1529
|
-
for (let i = 0, l = internalModels.length; i < l; i++) {
|
|
1530
|
-
let internalModel = internalModels[i];
|
|
1531
|
-
|
|
1532
|
-
// We can remove this "not null" cast once we have enough typing
|
|
1533
|
-
// to know we are only dealing with ExistingResourceIdentifierObjects
|
|
1534
|
-
let pair = seeking[internalModel.id!];
|
|
1535
|
-
|
|
1536
|
-
if (pair) {
|
|
1537
|
-
pair.resolver.reject(
|
|
1538
|
-
error ||
|
|
1539
|
-
new Error(
|
|
1540
|
-
`Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.`
|
|
1541
|
-
)
|
|
1542
|
-
);
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
if (shouldCoalesce) {
|
|
1548
|
-
// TODO: Improve records => snapshots => records => snapshots
|
|
1549
|
-
//
|
|
1550
|
-
// We want to provide records to all store methods and snapshots to all
|
|
1551
|
-
// adapter methods. To make sure we're doing that we're providing an array
|
|
1552
|
-
// of snapshots to adapter.groupRecordsForFindMany(), which in turn will
|
|
1553
|
-
// return grouped snapshots instead of grouped records.
|
|
1554
|
-
//
|
|
1555
|
-
// But since the _findMany() finder is a store method we need to get the
|
|
1556
|
-
// records from the grouped snapshots even though the _findMany() finder
|
|
1557
|
-
// will once again convert the records to snapshots for adapter.findMany()
|
|
1558
|
-
let snapshots = new Array(totalItems);
|
|
1559
|
-
for (let i = 0; i < totalItems; i++) {
|
|
1560
|
-
let internalModel = internalModels[i];
|
|
1561
|
-
snapshots[i] = internalModel.createSnapshot(optionsMap.get(internalModel));
|
|
1562
|
-
}
|
|
1563
|
-
|
|
1564
|
-
let groups;
|
|
1565
|
-
if (adapter.groupRecordsForFindMany) {
|
|
1566
|
-
groups = adapter.groupRecordsForFindMany(this, snapshots);
|
|
1567
|
-
} else {
|
|
1568
|
-
groups = [snapshots];
|
|
1569
|
-
}
|
|
1570
|
-
|
|
1571
|
-
for (let i = 0, l = groups.length; i < l; i++) {
|
|
1572
|
-
let group = groups[i];
|
|
1573
|
-
let totalInGroup = groups[i].length;
|
|
1574
|
-
let ids = new Array(totalInGroup);
|
|
1575
|
-
let groupedInternalModels = new Array(totalInGroup);
|
|
1576
|
-
|
|
1577
|
-
for (let j = 0; j < totalInGroup; j++) {
|
|
1578
|
-
let internalModel = group[j]._internalModel;
|
|
1579
|
-
|
|
1580
|
-
groupedInternalModels[j] = internalModel;
|
|
1581
|
-
ids[j] = internalModel.id;
|
|
1582
|
-
}
|
|
1583
|
-
|
|
1584
|
-
if (totalInGroup > 1) {
|
|
1585
|
-
(function (groupedInternalModels) {
|
|
1586
|
-
_findMany(adapter, store, modelName, ids, groupedInternalModels, optionsMap)
|
|
1587
|
-
.then(function (foundInternalModels) {
|
|
1588
|
-
handleFoundRecords(foundInternalModels, groupedInternalModels);
|
|
1589
|
-
})
|
|
1590
|
-
.catch(function (error) {
|
|
1591
|
-
rejectInternalModels(groupedInternalModels, error);
|
|
1592
|
-
});
|
|
1593
|
-
})(groupedInternalModels);
|
|
1594
|
-
} else if (ids.length === 1) {
|
|
1595
|
-
let pair = seeking[groupedInternalModels[0].id];
|
|
1596
|
-
_fetchRecord(pair);
|
|
1597
|
-
} else {
|
|
1598
|
-
assert("You cannot return an empty array from adapter's method groupRecordsForFindMany");
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1601
|
-
} else {
|
|
1602
|
-
for (let i = 0; i < totalItems; i++) {
|
|
1603
|
-
_fetchRecord(pendingFetchItems[i]);
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
}
|
|
1607
|
-
|
|
1608
1223
|
/**
|
|
1609
1224
|
Get the reference for the specified record.
|
|
1610
1225
|
|
|
@@ -1662,15 +1277,9 @@ abstract class CoreStore extends Service {
|
|
|
1662
1277
|
isMaybeIdentifier(resourceIdentifier)
|
|
1663
1278
|
);
|
|
1664
1279
|
|
|
1665
|
-
let identifier: StableRecordIdentifier =
|
|
1280
|
+
let identifier: StableRecordIdentifier = this.identifierCache.getOrCreateRecordIdentifier(resourceIdentifier);
|
|
1666
1281
|
if (identifier) {
|
|
1667
|
-
|
|
1668
|
-
return RECORD_REFERENCES.get(identifier);
|
|
1669
|
-
}
|
|
1670
|
-
|
|
1671
|
-
let reference = new RecordReference(this, identifier);
|
|
1672
|
-
RECORD_REFERENCES.set(identifier, reference);
|
|
1673
|
-
return reference;
|
|
1282
|
+
return RECORD_REFERENCES.lookup(identifier);
|
|
1674
1283
|
}
|
|
1675
1284
|
}
|
|
1676
1285
|
|
|
@@ -1726,7 +1335,7 @@ abstract class CoreStore extends Service {
|
|
|
1726
1335
|
peekRecord(identifier: ResourceIdentifierObject): RecordInstance | null;
|
|
1727
1336
|
peekRecord(identifier: ResourceIdentifierObject | string, id?: string | number): RecordInstance | null {
|
|
1728
1337
|
if (arguments.length === 1 && isMaybeIdentifier(identifier)) {
|
|
1729
|
-
let stableIdentifier =
|
|
1338
|
+
let stableIdentifier = this.identifierCache.peekRecordIdentifier(identifier);
|
|
1730
1339
|
if (stableIdentifier) {
|
|
1731
1340
|
return internalModelFactoryFor(this).peek(stableIdentifier)?.getRecord() || null;
|
|
1732
1341
|
}
|
|
@@ -1768,9 +1377,7 @@ abstract class CoreStore extends Service {
|
|
|
1768
1377
|
@return {Promise} promise
|
|
1769
1378
|
*/
|
|
1770
1379
|
_reloadRecord(internalModel, options): RSVP.Promise<InternalModel> {
|
|
1771
|
-
|
|
1772
|
-
options.isReloading = true;
|
|
1773
|
-
}
|
|
1380
|
+
options.isReloading = true;
|
|
1774
1381
|
let { id, modelName } = internalModel;
|
|
1775
1382
|
let adapter = this.adapterFor(modelName);
|
|
1776
1383
|
|
|
@@ -1818,7 +1425,7 @@ abstract class CoreStore extends Service {
|
|
|
1818
1425
|
const trueId = ensureStringId(id);
|
|
1819
1426
|
const resource = { type, id: trueId };
|
|
1820
1427
|
|
|
1821
|
-
const identifier =
|
|
1428
|
+
const identifier = this.identifierCache.peekRecordIdentifier(resource);
|
|
1822
1429
|
const internalModel = identifier && internalModelFactoryFor(this).peek(identifier);
|
|
1823
1430
|
|
|
1824
1431
|
return !!internalModel && internalModel.currentState.isLoaded;
|
|
@@ -2017,17 +1624,9 @@ abstract class CoreStore extends Service {
|
|
|
2017
1624
|
|
|
2018
1625
|
if (internalModel) {
|
|
2019
1626
|
// short circuit if we are already loading
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
return pendingRequest.then(() => internalModel.getRecord());
|
|
2024
|
-
}
|
|
2025
|
-
} else {
|
|
2026
|
-
if (internalModel.currentState.isLoading) {
|
|
2027
|
-
return internalModel._promiseProxy.then(() => {
|
|
2028
|
-
return internalModel.getRecord();
|
|
2029
|
-
});
|
|
2030
|
-
}
|
|
1627
|
+
let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier, options);
|
|
1628
|
+
if (pendingRequest) {
|
|
1629
|
+
return pendingRequest.then(() => internalModel.getRecord());
|
|
2031
1630
|
}
|
|
2032
1631
|
}
|
|
2033
1632
|
|
|
@@ -2660,33 +2259,32 @@ abstract class CoreStore extends Service {
|
|
|
2660
2259
|
@param {Object} options
|
|
2661
2260
|
*/
|
|
2662
2261
|
scheduleSave(internalModel: InternalModel, resolver: RSVP.Deferred<void>, options): void | RSVP.Promise<void> {
|
|
2663
|
-
if (
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
}
|
|
2262
|
+
if (internalModel._isRecordFullyDeleted()) {
|
|
2263
|
+
resolver.resolve();
|
|
2264
|
+
return resolver.promise;
|
|
2265
|
+
}
|
|
2668
2266
|
|
|
2669
|
-
|
|
2267
|
+
internalModel.adapterWillCommit();
|
|
2670
2268
|
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2269
|
+
if (!options) {
|
|
2270
|
+
options = {};
|
|
2271
|
+
}
|
|
2272
|
+
let recordData = internalModel._recordData;
|
|
2273
|
+
let operation: 'createRecord' | 'deleteRecord' | 'updateRecord' = 'updateRecord';
|
|
2274
|
+
|
|
2275
|
+
// TODO handle missing isNew
|
|
2276
|
+
if (recordData.isNew && recordData.isNew()) {
|
|
2277
|
+
operation = 'createRecord';
|
|
2278
|
+
} else if (recordData.isDeleted && recordData.isDeleted()) {
|
|
2279
|
+
operation = 'deleteRecord';
|
|
2280
|
+
}
|
|
2683
2281
|
|
|
2684
|
-
|
|
2282
|
+
options[SaveOp] = operation;
|
|
2685
2283
|
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2284
|
+
let fetchManagerPromise = this._fetchManager.scheduleSave(internalModel.identifier, options);
|
|
2285
|
+
let promise = fetchManagerPromise.then(
|
|
2286
|
+
(payload) => {
|
|
2287
|
+
/*
|
|
2690
2288
|
Note to future spelunkers hoping to optimize.
|
|
2691
2289
|
We rely on this `run` to create a run loop if needed
|
|
2692
2290
|
that `store._push` and `store.didSaveRecord` will both share.
|
|
@@ -2695,40 +2293,25 @@ abstract class CoreStore extends Service {
|
|
|
2695
2293
|
have an outer run loop available still from the first
|
|
2696
2294
|
call to `store._push`;
|
|
2697
2295
|
*/
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
}
|
|
2704
|
-
});
|
|
2705
|
-
},
|
|
2706
|
-
(e) => {
|
|
2707
|
-
if (typeof e === 'string') {
|
|
2708
|
-
throw e;
|
|
2296
|
+
this._backburner.join(() => {
|
|
2297
|
+
let data = payload && payload.data;
|
|
2298
|
+
this.didSaveRecord(internalModel, { data }, operation);
|
|
2299
|
+
if (payload && payload.included) {
|
|
2300
|
+
this._push({ data: null, included: payload.included });
|
|
2709
2301
|
}
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2302
|
+
});
|
|
2303
|
+
},
|
|
2304
|
+
(e) => {
|
|
2305
|
+
if (typeof e === 'string') {
|
|
2306
|
+
throw e;
|
|
2713
2307
|
}
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
} else {
|
|
2718
|
-
if (internalModel._isRecordFullyDeleted()) {
|
|
2719
|
-
resolver.resolve();
|
|
2720
|
-
return;
|
|
2308
|
+
const { error, parsedErrors } = e;
|
|
2309
|
+
this.recordWasInvalid(internalModel, parsedErrors, error);
|
|
2310
|
+
throw error;
|
|
2721
2311
|
}
|
|
2312
|
+
);
|
|
2722
2313
|
|
|
2723
|
-
|
|
2724
|
-
internalModel.adapterWillCommit();
|
|
2725
|
-
this._pendingSave.push({
|
|
2726
|
-
snapshot: snapshot,
|
|
2727
|
-
resolver: resolver,
|
|
2728
|
-
});
|
|
2729
|
-
|
|
2730
|
-
emberBackburner.scheduleOnce('actions', this, this.flushPendingSave);
|
|
2731
|
-
}
|
|
2314
|
+
return promise;
|
|
2732
2315
|
}
|
|
2733
2316
|
|
|
2734
2317
|
/**
|
|
@@ -2739,47 +2322,8 @@ abstract class CoreStore extends Service {
|
|
|
2739
2322
|
@private
|
|
2740
2323
|
*/
|
|
2741
2324
|
flushPendingSave() {
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
return;
|
|
2745
|
-
}
|
|
2746
|
-
let pending = this._pendingSave.slice();
|
|
2747
|
-
this._pendingSave = [];
|
|
2748
|
-
|
|
2749
|
-
for (let i = 0, j = pending.length; i < j; i++) {
|
|
2750
|
-
let pendingItem = pending[i];
|
|
2751
|
-
let snapshot = pendingItem.snapshot;
|
|
2752
|
-
let resolver = pendingItem.resolver;
|
|
2753
|
-
// TODO We have to cast due to our reliance on this private property
|
|
2754
|
-
// this will be refactored away once we change our pending API to be identifier based
|
|
2755
|
-
let internalModel = (snapshot as unknown as PrivateSnapshot)._internalModel;
|
|
2756
|
-
let adapter = this.adapterFor(internalModel.modelName);
|
|
2757
|
-
let operation;
|
|
2758
|
-
|
|
2759
|
-
if (RECORD_DATA_STATE) {
|
|
2760
|
-
// TODO move this out of internalModel
|
|
2761
|
-
if (internalModel.isNew()) {
|
|
2762
|
-
operation = 'createRecord';
|
|
2763
|
-
} else if (internalModel.isDeleted()) {
|
|
2764
|
-
operation = 'deleteRecord';
|
|
2765
|
-
} else {
|
|
2766
|
-
operation = 'updateRecord';
|
|
2767
|
-
}
|
|
2768
|
-
} else {
|
|
2769
|
-
if (internalModel.currentState.stateName === 'root.deleted.saved') {
|
|
2770
|
-
resolver.resolve();
|
|
2771
|
-
continue;
|
|
2772
|
-
} else if (internalModel.isNew()) {
|
|
2773
|
-
operation = 'createRecord';
|
|
2774
|
-
} else if (internalModel.isDeleted()) {
|
|
2775
|
-
operation = 'deleteRecord';
|
|
2776
|
-
} else {
|
|
2777
|
-
operation = 'updateRecord';
|
|
2778
|
-
}
|
|
2779
|
-
}
|
|
2780
|
-
|
|
2781
|
-
resolver.resolve(_commit(adapter, this, operation, snapshot));
|
|
2782
|
-
}
|
|
2325
|
+
// assert here
|
|
2326
|
+
return;
|
|
2783
2327
|
}
|
|
2784
2328
|
|
|
2785
2329
|
/**
|
|
@@ -2811,7 +2355,7 @@ abstract class CoreStore extends Service {
|
|
|
2811
2355
|
);
|
|
2812
2356
|
}
|
|
2813
2357
|
|
|
2814
|
-
const cache =
|
|
2358
|
+
const cache = this.identifierCache;
|
|
2815
2359
|
const identifier = internalModel.identifier;
|
|
2816
2360
|
|
|
2817
2361
|
if (op !== 'deleteRecord' && data) {
|
|
@@ -2837,11 +2381,7 @@ abstract class CoreStore extends Service {
|
|
|
2837
2381
|
if (DEBUG) {
|
|
2838
2382
|
assertDestroyingStore(this, 'recordWasInvalid');
|
|
2839
2383
|
}
|
|
2840
|
-
|
|
2841
|
-
internalModel.adapterDidInvalidate(parsedErrors, error);
|
|
2842
|
-
} else {
|
|
2843
|
-
internalModel.adapterDidInvalidate(parsedErrors);
|
|
2844
|
-
}
|
|
2384
|
+
internalModel.adapterDidInvalidate(parsedErrors, error);
|
|
2845
2385
|
}
|
|
2846
2386
|
|
|
2847
2387
|
/**
|
|
@@ -2903,7 +2443,7 @@ abstract class CoreStore extends Service {
|
|
|
2903
2443
|
// exclude store.push (root.empty) case
|
|
2904
2444
|
let identifier = internalModel.identifier;
|
|
2905
2445
|
if (isUpdate || isLoading) {
|
|
2906
|
-
let updatedIdentifier =
|
|
2446
|
+
let updatedIdentifier = this.identifierCache.updateRecordIdentifier(identifier, data);
|
|
2907
2447
|
|
|
2908
2448
|
if (updatedIdentifier !== identifier) {
|
|
2909
2449
|
// we encountered a merge of identifiers in which
|
|
@@ -3166,30 +2706,17 @@ abstract class CoreStore extends Service {
|
|
|
3166
2706
|
|
|
3167
2707
|
if (ENV.DS_WARN_ON_UNKNOWN_KEYS) {
|
|
3168
2708
|
let unknownAttributes, unknownRelationships;
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
});
|
|
3181
|
-
} else {
|
|
3182
|
-
let modelClass = this.modelFor(modelName);
|
|
3183
|
-
// Check unknown attributes
|
|
3184
|
-
unknownAttributes = Object.keys(data.attributes || {}).filter((key) => {
|
|
3185
|
-
return !get(modelClass, 'fields').has(key);
|
|
3186
|
-
});
|
|
3187
|
-
|
|
3188
|
-
// Check unknown relationships
|
|
3189
|
-
unknownRelationships = Object.keys(data.relationships || {}).filter((key) => {
|
|
3190
|
-
return !get(modelClass, 'fields').has(key);
|
|
3191
|
-
});
|
|
3192
|
-
}
|
|
2709
|
+
let relationships = this.getSchemaDefinitionService().relationshipsDefinitionFor(modelName);
|
|
2710
|
+
let attributes = this.getSchemaDefinitionService().attributesDefinitionFor(modelName);
|
|
2711
|
+
// Check unknown attributes
|
|
2712
|
+
unknownAttributes = Object.keys(data.attributes || {}).filter((key) => {
|
|
2713
|
+
return !attributes[key];
|
|
2714
|
+
});
|
|
2715
|
+
|
|
2716
|
+
// Check unknown relationships
|
|
2717
|
+
unknownRelationships = Object.keys(data.relationships || {}).filter((key) => {
|
|
2718
|
+
return !relationships[key];
|
|
2719
|
+
});
|
|
3193
2720
|
let unknownAttributesMessage = `The payload for '${modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`;
|
|
3194
2721
|
warn(unknownAttributesMessage, unknownAttributes.length === 0, {
|
|
3195
2722
|
id: 'ds.store.unknown-keys-in-payload',
|
|
@@ -3319,38 +2846,26 @@ abstract class CoreStore extends Service {
|
|
|
3319
2846
|
}
|
|
3320
2847
|
|
|
3321
2848
|
serializeRecord(record: RecordInstance, options?: Dict<unknown>): unknown {
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
return internalModel!.createSnapshot(options).serialize(options);
|
|
3327
|
-
}
|
|
3328
|
-
|
|
3329
|
-
assert('serializeRecord is only available when CUSTOM_MODEL_CLASS ff is on', false);
|
|
2849
|
+
let identifier = recordIdentifierFor(record);
|
|
2850
|
+
let internalModel = internalModelFactoryFor(this).peek(identifier);
|
|
2851
|
+
// TODO we used to check if the record was destroyed here
|
|
2852
|
+
return internalModel!.createSnapshot(options).serialize(options);
|
|
3330
2853
|
}
|
|
3331
2854
|
|
|
3332
2855
|
saveRecord(record: RecordInstance, options?: Dict<unknown>): RSVP.Promise<RecordInstance> {
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
return (internalModel!.save(options) as RSVP.Promise<void>).then(() => record);
|
|
3340
|
-
}
|
|
3341
|
-
|
|
3342
|
-
assert('saveRecord is only available when CUSTOM_MODEL_CLASS ff is on');
|
|
2856
|
+
let identifier = recordIdentifierFor(record);
|
|
2857
|
+
let internalModel = internalModelFactoryFor(this).peek(identifier);
|
|
2858
|
+
// TODO we used to check if the record was destroyed here
|
|
2859
|
+
// Casting can be removed once REQUEST_SERVICE ff is turned on
|
|
2860
|
+
// because a `Record` is provided there will always be a matching internalModel
|
|
2861
|
+
return (internalModel!.save(options) as RSVP.Promise<void>).then(() => record);
|
|
3343
2862
|
}
|
|
3344
2863
|
|
|
3345
2864
|
relationshipReferenceFor(identifier: RecordIdentifier, key: string): BelongsToReference | HasManyReference {
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
return internalModel!.referenceFor(null, key);
|
|
3351
|
-
}
|
|
3352
|
-
|
|
3353
|
-
assert('relationshipReferenceFor is only available when CUSTOM_MODEL_CLASS ff is on', false);
|
|
2865
|
+
let stableIdentifier = this.identifierCache.getOrCreateRecordIdentifier(identifier);
|
|
2866
|
+
let internalModel = internalModelFactoryFor(this).peek(stableIdentifier);
|
|
2867
|
+
// TODO we used to check if the record was destroyed here
|
|
2868
|
+
return internalModel!.referenceFor(null, key);
|
|
3354
2869
|
}
|
|
3355
2870
|
|
|
3356
2871
|
/**
|
|
@@ -3396,7 +2911,7 @@ abstract class CoreStore extends Service {
|
|
|
3396
2911
|
_RecordData = require('@ember-data/record-data/-private').RecordData as RecordDataConstruct;
|
|
3397
2912
|
}
|
|
3398
2913
|
|
|
3399
|
-
let identifier =
|
|
2914
|
+
let identifier = this.identifierCache.getOrCreateRecordIdentifier({
|
|
3400
2915
|
type: modelName,
|
|
3401
2916
|
id,
|
|
3402
2917
|
lid: clientId,
|
|
@@ -3411,7 +2926,7 @@ abstract class CoreStore extends Service {
|
|
|
3411
2926
|
* @internal
|
|
3412
2927
|
*/
|
|
3413
2928
|
__recordDataFor(resource: RecordIdentifier) {
|
|
3414
|
-
const identifier =
|
|
2929
|
+
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
|
|
3415
2930
|
return this.recordDataFor(identifier, false);
|
|
3416
2931
|
}
|
|
3417
2932
|
|
|
@@ -3529,25 +3044,15 @@ abstract class CoreStore extends Service {
|
|
|
3529
3044
|
|
|
3530
3045
|
let owner = getOwner(this);
|
|
3531
3046
|
|
|
3047
|
+
// name specific adapter
|
|
3532
3048
|
adapter = owner.lookup(`adapter:${normalizedModelName}`);
|
|
3533
|
-
|
|
3534
|
-
// in production this is handled by the re-export
|
|
3535
|
-
if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_ADAPTER_PACKAGE && adapter === undefined) {
|
|
3536
|
-
if (normalizedModelName === '-json-api') {
|
|
3537
|
-
const Adapter = require('@ember-data/adapter/json-api').default;
|
|
3538
|
-
owner.register(`adapter:-json-api`, Adapter);
|
|
3539
|
-
adapter = owner.lookup(`adapter:-json-api`);
|
|
3540
|
-
deprecateTestRegistration('adapter', '-json-api');
|
|
3541
|
-
}
|
|
3542
|
-
}
|
|
3543
|
-
|
|
3544
3049
|
if (adapter !== undefined) {
|
|
3545
3050
|
set(adapter, 'store', this);
|
|
3546
3051
|
_adapterCache[normalizedModelName] = adapter;
|
|
3547
3052
|
return adapter;
|
|
3548
3053
|
}
|
|
3549
3054
|
|
|
3550
|
-
// no adapter found for the specific
|
|
3055
|
+
// no adapter found for the specific name, fallback and check for application adapter
|
|
3551
3056
|
adapter = _adapterCache.application || owner.lookup('adapter:application');
|
|
3552
3057
|
if (adapter !== undefined) {
|
|
3553
3058
|
set(adapter, 'store', this);
|
|
@@ -3556,30 +3061,9 @@ abstract class CoreStore extends Service {
|
|
|
3556
3061
|
return adapter;
|
|
3557
3062
|
}
|
|
3558
3063
|
|
|
3559
|
-
// no model specific adapter or application adapter, check for an `adapter`
|
|
3560
|
-
// property defined on the store
|
|
3561
|
-
let adapterName = this.adapter || '-json-api';
|
|
3562
|
-
adapter = adapterName ? _adapterCache[adapterName] || owner.lookup(`adapter:${adapterName}`) : undefined;
|
|
3563
|
-
|
|
3564
|
-
// in production this is handled by the re-export
|
|
3565
|
-
if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_ADAPTER_PACKAGE && adapter === undefined) {
|
|
3566
|
-
if (adapterName === '-json-api') {
|
|
3567
|
-
const Adapter = require('@ember-data/adapter/json-api').default;
|
|
3568
|
-
owner.register(`adapter:-json-api`, Adapter);
|
|
3569
|
-
adapter = owner.lookup(`adapter:-json-api`);
|
|
3570
|
-
deprecateTestRegistration('adapter', '-json-api');
|
|
3571
|
-
}
|
|
3572
|
-
}
|
|
3573
|
-
|
|
3574
|
-
if (adapter !== undefined) {
|
|
3575
|
-
set(adapter, 'store', this);
|
|
3576
|
-
_adapterCache[normalizedModelName] = adapter;
|
|
3577
|
-
_adapterCache[adapterName] = adapter;
|
|
3578
|
-
return adapter;
|
|
3579
|
-
}
|
|
3580
|
-
|
|
3581
3064
|
// final fallback, no model specific adapter, no application adapter, no
|
|
3582
3065
|
// `adapter` property on store: use json-api adapter
|
|
3066
|
+
// TODO we should likely deprecate this?
|
|
3583
3067
|
adapter = _adapterCache['-json-api'] || owner.lookup('adapter:-json-api');
|
|
3584
3068
|
assert(
|
|
3585
3069
|
`No adapter was found for '${modelName}' and no 'application' adapter was found as a fallback.`,
|
|
@@ -3631,30 +3115,8 @@ abstract class CoreStore extends Service {
|
|
|
3631
3115
|
|
|
3632
3116
|
let owner = getOwner(this);
|
|
3633
3117
|
|
|
3118
|
+
// by name
|
|
3634
3119
|
serializer = owner.lookup(`serializer:${normalizedModelName}`);
|
|
3635
|
-
|
|
3636
|
-
if (DEPRECATE_LEGACY_TEST_REGISTRATIONS) {
|
|
3637
|
-
// in production this is handled by the re-export
|
|
3638
|
-
if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_SERIALIZER_PACKAGE && serializer === undefined) {
|
|
3639
|
-
if (normalizedModelName === '-json-api') {
|
|
3640
|
-
const Serializer = require('@ember-data/serializer/json-api').default;
|
|
3641
|
-
owner.register(`serializer:-json-api`, Serializer);
|
|
3642
|
-
serializer = owner.lookup(`serializer:-json-api`);
|
|
3643
|
-
deprecateTestRegistration('serializer', '-json-api');
|
|
3644
|
-
} else if (normalizedModelName === '-rest') {
|
|
3645
|
-
const Serializer = require('@ember-data/serializer/rest').default;
|
|
3646
|
-
owner.register(`serializer:-rest`, Serializer);
|
|
3647
|
-
serializer = owner.lookup(`serializer:-rest`);
|
|
3648
|
-
deprecateTestRegistration('serializer', '-rest');
|
|
3649
|
-
} else if (normalizedModelName === '-default') {
|
|
3650
|
-
const Serializer = require('@ember-data/serializer/json').default;
|
|
3651
|
-
owner.register(`serializer:-default`, Serializer);
|
|
3652
|
-
serializer = owner.lookup(`serializer:-default`);
|
|
3653
|
-
serializer && deprecateTestRegistration('serializer', '-default');
|
|
3654
|
-
}
|
|
3655
|
-
}
|
|
3656
|
-
}
|
|
3657
|
-
|
|
3658
3120
|
if (serializer !== undefined) {
|
|
3659
3121
|
set(serializer, 'store', this);
|
|
3660
3122
|
_serializerCache[normalizedModelName] = serializer;
|
|
@@ -3670,37 +3132,6 @@ abstract class CoreStore extends Service {
|
|
|
3670
3132
|
return serializer;
|
|
3671
3133
|
}
|
|
3672
3134
|
|
|
3673
|
-
let serializerName;
|
|
3674
|
-
|
|
3675
|
-
if (DEPRECATE_LEGACY_TEST_REGISTRATIONS) {
|
|
3676
|
-
// in production this is handled by the re-export
|
|
3677
|
-
if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_SERIALIZER_PACKAGE && serializer === undefined) {
|
|
3678
|
-
if (serializerName === '-json-api') {
|
|
3679
|
-
const Serializer = require('@ember-data/serializer/json-api').default;
|
|
3680
|
-
owner.register(`serializer:-json-api`, Serializer);
|
|
3681
|
-
serializer = owner.lookup(`serializer:-json-api`);
|
|
3682
|
-
deprecateTestRegistration('serializer', '-json-api');
|
|
3683
|
-
} else if (serializerName === '-rest') {
|
|
3684
|
-
const Serializer = require('@ember-data/serializer/rest').default;
|
|
3685
|
-
owner.register(`serializer:-rest`, Serializer);
|
|
3686
|
-
serializer = owner.lookup(`serializer:-rest`);
|
|
3687
|
-
deprecateTestRegistration('serializer', '-rest');
|
|
3688
|
-
} else if (serializerName === '-default') {
|
|
3689
|
-
const Serializer = require('@ember-data/serializer/json').default;
|
|
3690
|
-
owner.register(`serializer:-default`, Serializer);
|
|
3691
|
-
serializer = owner.lookup(`serializer:-default`);
|
|
3692
|
-
serializer && deprecateTestRegistration('serializer', '-default');
|
|
3693
|
-
}
|
|
3694
|
-
}
|
|
3695
|
-
|
|
3696
|
-
if (serializer !== undefined) {
|
|
3697
|
-
set(serializer, 'store', this);
|
|
3698
|
-
_serializerCache[normalizedModelName] = serializer;
|
|
3699
|
-
_serializerCache[serializerName] = serializer;
|
|
3700
|
-
return serializer;
|
|
3701
|
-
}
|
|
3702
|
-
}
|
|
3703
|
-
|
|
3704
3135
|
assert(
|
|
3705
3136
|
`No serializer was found for '${modelName}' and no 'application' serializer was found as a fallback`,
|
|
3706
3137
|
serializer !== undefined
|
|
@@ -3738,7 +3169,7 @@ abstract class CoreStore extends Service {
|
|
|
3738
3169
|
super.willDestroy();
|
|
3739
3170
|
this.recordArrayManager.destroy();
|
|
3740
3171
|
|
|
3741
|
-
|
|
3172
|
+
this.identifierCache.destroy();
|
|
3742
3173
|
|
|
3743
3174
|
// destroy the graph before unloadAll
|
|
3744
3175
|
// since then we avoid churning relationships
|
|
@@ -3798,155 +3229,23 @@ abstract class CoreStore extends Service {
|
|
|
3798
3229
|
}
|
|
3799
3230
|
}
|
|
3800
3231
|
|
|
3801
|
-
if (DEPRECATE_DEFAULT_ADAPTER) {
|
|
3802
|
-
defineProperty(
|
|
3803
|
-
CoreStore.prototype,
|
|
3804
|
-
'defaultAdapter',
|
|
3805
|
-
computed('adapter', function () {
|
|
3806
|
-
deprecate(
|
|
3807
|
-
`store.adapterFor(modelName) resolved the ("${
|
|
3808
|
-
this.adapter || '-json-api'
|
|
3809
|
-
}") adapter via the deprecated \`store.defaultAdapter\` property.\n\n\tPreviously, applications could define the store's \`adapter\` property which would be used by \`defaultAdapter\` and \`adapterFor\` as a fallback for when an adapter was not found by an exact name match. This behavior is deprecated in favor of explicitly defining an application or type-specific adapter.`,
|
|
3810
|
-
false,
|
|
3811
|
-
{
|
|
3812
|
-
id: 'ember-data:default-adapter',
|
|
3813
|
-
until: '4.0',
|
|
3814
|
-
url: 'https://deprecations.emberjs.com/ember-data/v3.x/#toc_ember-data-default-adapter',
|
|
3815
|
-
for: '@ember-data/store',
|
|
3816
|
-
since: {
|
|
3817
|
-
available: '3.15',
|
|
3818
|
-
enabled: '3.15',
|
|
3819
|
-
},
|
|
3820
|
-
}
|
|
3821
|
-
);
|
|
3822
|
-
let adapter = this.adapter || '-json-api';
|
|
3823
|
-
|
|
3824
|
-
assert(
|
|
3825
|
-
'You tried to set `adapter` property to an instance of `Adapter`, where it should be a name',
|
|
3826
|
-
typeof adapter === 'string'
|
|
3827
|
-
);
|
|
3828
|
-
|
|
3829
|
-
return this.adapterFor(adapter);
|
|
3830
|
-
})
|
|
3831
|
-
);
|
|
3832
|
-
}
|
|
3833
|
-
|
|
3834
3232
|
export default CoreStore;
|
|
3835
3233
|
|
|
3836
|
-
function _commit(adapter, store, operation, snapshot) {
|
|
3837
|
-
let internalModel = snapshot._internalModel;
|
|
3838
|
-
let modelName = snapshot.modelName;
|
|
3839
|
-
let modelClass = store.modelFor(modelName);
|
|
3840
|
-
assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter);
|
|
3841
|
-
assert(
|
|
3842
|
-
`You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`,
|
|
3843
|
-
typeof adapter[operation] === 'function'
|
|
3844
|
-
);
|
|
3845
|
-
|
|
3846
|
-
let promise = Promise.resolve().then(() => adapter[operation](store, modelClass, snapshot));
|
|
3847
|
-
let serializer = store.serializerFor(modelName);
|
|
3848
|
-
let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`;
|
|
3849
|
-
|
|
3850
|
-
promise = guardDestroyedStore(promise, store, label);
|
|
3851
|
-
promise = _guard(promise, _bind(_objectIsAlive, internalModel));
|
|
3852
|
-
|
|
3853
|
-
return promise.then(
|
|
3854
|
-
(adapterPayload) => {
|
|
3855
|
-
/*
|
|
3856
|
-
Note to future spelunkers hoping to optimize.
|
|
3857
|
-
We rely on this `run` to create a run loop if needed
|
|
3858
|
-
that `store._push` and `store.didSaveRecord` will both share.
|
|
3859
|
-
|
|
3860
|
-
We use `join` because it is often the case that we
|
|
3861
|
-
have an outer run loop available still from the first
|
|
3862
|
-
call to `store._push`;
|
|
3863
|
-
*/
|
|
3864
|
-
store._backburner.join(() => {
|
|
3865
|
-
let payload, data, sideloaded;
|
|
3866
|
-
if (adapterPayload) {
|
|
3867
|
-
payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, snapshot.id, operation);
|
|
3868
|
-
if (payload.included) {
|
|
3869
|
-
sideloaded = payload.included;
|
|
3870
|
-
}
|
|
3871
|
-
data = payload.data;
|
|
3872
|
-
}
|
|
3873
|
-
store.didSaveRecord(internalModel, { data }, operation);
|
|
3874
|
-
// seems risky, but if the tests pass might be fine?
|
|
3875
|
-
if (sideloaded) {
|
|
3876
|
-
store._push({ data: null, included: sideloaded });
|
|
3877
|
-
}
|
|
3878
|
-
});
|
|
3879
|
-
|
|
3880
|
-
return internalModel;
|
|
3881
|
-
},
|
|
3882
|
-
function (error) {
|
|
3883
|
-
if (error && error.isAdapterError === true && error.code === 'InvalidError') {
|
|
3884
|
-
let parsedErrors;
|
|
3885
|
-
|
|
3886
|
-
if (typeof serializer.extractErrors === 'function') {
|
|
3887
|
-
parsedErrors = serializer.extractErrors(store, modelClass, error, snapshot.id);
|
|
3888
|
-
} else {
|
|
3889
|
-
parsedErrors = errorsArrayToHash(error.errors);
|
|
3890
|
-
}
|
|
3891
|
-
|
|
3892
|
-
store.recordWasInvalid(internalModel, parsedErrors, error);
|
|
3893
|
-
} else {
|
|
3894
|
-
store.recordWasError(internalModel, error);
|
|
3895
|
-
}
|
|
3896
|
-
|
|
3897
|
-
throw error;
|
|
3898
|
-
},
|
|
3899
|
-
label
|
|
3900
|
-
);
|
|
3901
|
-
}
|
|
3902
|
-
|
|
3903
3234
|
let assertDestroyingStore: Function;
|
|
3904
3235
|
let assertDestroyedStoreOnly: Function;
|
|
3905
3236
|
|
|
3906
3237
|
if (DEBUG) {
|
|
3907
3238
|
assertDestroyingStore = function assertDestroyedStore(store, method) {
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
{
|
|
3913
|
-
id: 'ember-data:method-calls-on-destroyed-store',
|
|
3914
|
-
until: '3.8',
|
|
3915
|
-
for: '@ember-data/store',
|
|
3916
|
-
since: {
|
|
3917
|
-
available: '3.8',
|
|
3918
|
-
enabled: '3.8',
|
|
3919
|
-
},
|
|
3920
|
-
}
|
|
3921
|
-
);
|
|
3922
|
-
} else {
|
|
3923
|
-
assert(
|
|
3924
|
-
`Attempted to call store.${method}(), but the store instance has already been destroyed.`,
|
|
3925
|
-
!(store.isDestroying || store.isDestroyed)
|
|
3926
|
-
);
|
|
3927
|
-
}
|
|
3239
|
+
assert(
|
|
3240
|
+
`Attempted to call store.${method}(), but the store instance has already been destroyed.`,
|
|
3241
|
+
!(store.isDestroying || store.isDestroyed)
|
|
3242
|
+
);
|
|
3928
3243
|
};
|
|
3929
3244
|
assertDestroyedStoreOnly = function assertDestroyedStoreOnly(store, method) {
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
{
|
|
3935
|
-
id: 'ember-data:method-calls-on-destroyed-store',
|
|
3936
|
-
until: '3.8',
|
|
3937
|
-
for: '@ember-data/store',
|
|
3938
|
-
since: {
|
|
3939
|
-
available: '3.8',
|
|
3940
|
-
enabled: '3.8',
|
|
3941
|
-
},
|
|
3942
|
-
}
|
|
3943
|
-
);
|
|
3944
|
-
} else {
|
|
3945
|
-
assert(
|
|
3946
|
-
`Attempted to call store.${method}(), but the store instance has already been destroyed.`,
|
|
3947
|
-
!store.isDestroyed
|
|
3948
|
-
);
|
|
3949
|
-
}
|
|
3245
|
+
assert(
|
|
3246
|
+
`Attempted to call store.${method}(), but the store instance has already been destroyed.`,
|
|
3247
|
+
!store.isDestroyed
|
|
3248
|
+
);
|
|
3950
3249
|
};
|
|
3951
3250
|
}
|
|
3952
3251
|
|
|
@@ -3961,7 +3260,7 @@ if (DEBUG) {
|
|
|
3961
3260
|
* @return {boolean}
|
|
3962
3261
|
*/
|
|
3963
3262
|
function areAllInverseRecordsLoaded(store: CoreStore, resource: JsonApiRelationship): boolean {
|
|
3964
|
-
const cache =
|
|
3263
|
+
const cache = store.identifierCache;
|
|
3965
3264
|
|
|
3966
3265
|
if (Array.isArray(resource.data)) {
|
|
3967
3266
|
// treat as collection
|