@ember-data/store 4.1.0 → 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 +186 -986
- 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 +7 -36
- 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 +16 -16
- 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,25 +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_DEFAULT_SERIALIZER,
|
|
34
|
-
DEPRECATE_LEGACY_TEST_REGISTRATIONS,
|
|
35
|
-
} from '@ember-data/private-build-infra/deprecations';
|
|
19
|
+
import { HAS_RECORD_DATA_PACKAGE } from '@ember-data/private-build-infra';
|
|
36
20
|
import type {
|
|
37
21
|
BelongsToRelationship,
|
|
38
22
|
ManyRelationship,
|
|
@@ -40,8 +24,7 @@ import type {
|
|
|
40
24
|
} from '@ember-data/record-data/-private';
|
|
41
25
|
import type { RelationshipState } from '@ember-data/record-data/-private/graph/-state';
|
|
42
26
|
|
|
43
|
-
import
|
|
44
|
-
import { identifierCacheFor } from '../identifiers/cache';
|
|
27
|
+
import { IdentifierCache } from '../identifiers/cache';
|
|
45
28
|
import type { DSModel } from '../ts-interfaces/ds-model';
|
|
46
29
|
import type {
|
|
47
30
|
CollectionResourceDocument,
|
|
@@ -69,7 +52,6 @@ import constructResource from '../utils/construct-resource';
|
|
|
69
52
|
import promiseRecord from '../utils/promise-record';
|
|
70
53
|
import edBackburner from './backburner';
|
|
71
54
|
import coerceId, { ensureStringId } from './coerce-id';
|
|
72
|
-
import { errorsArrayToHash } from './errors-utils';
|
|
73
55
|
import FetchManager, { SaveOp } from './fetch-manager';
|
|
74
56
|
import type InternalModel from './model/internal-model';
|
|
75
57
|
import {
|
|
@@ -87,9 +69,7 @@ import NotificationManager from './record-notification-manager';
|
|
|
87
69
|
import type { BelongsToReference, HasManyReference } from './references';
|
|
88
70
|
import { RecordReference } from './references';
|
|
89
71
|
import type RequestCache from './request-cache';
|
|
90
|
-
import
|
|
91
|
-
import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './store/common';
|
|
92
|
-
import { _find, _findAll, _findBelongsTo, _findHasMany, _findMany, _query, _queryRecord } from './store/finders';
|
|
72
|
+
import { _findAll, _findBelongsTo, _findHasMany, _query, _queryRecord } from './store/finders';
|
|
93
73
|
import {
|
|
94
74
|
internalModelFactoryFor,
|
|
95
75
|
peekRecordIdentifier,
|
|
@@ -97,7 +77,7 @@ import {
|
|
|
97
77
|
setRecordIdentifier,
|
|
98
78
|
} from './store/internal-model-factory';
|
|
99
79
|
import RecordDataStoreWrapper from './store/record-data-store-wrapper';
|
|
100
|
-
import
|
|
80
|
+
import WeakCache from './weak-cache';
|
|
101
81
|
|
|
102
82
|
type RecordDataConstruct = typeof RecordDataClass;
|
|
103
83
|
let _RecordData: RecordDataConstruct | undefined;
|
|
@@ -105,18 +85,8 @@ let _RecordData: RecordDataConstruct | undefined;
|
|
|
105
85
|
const { ENV } = Ember;
|
|
106
86
|
type AsyncTrackingToken = Readonly<{ label: string; trace: Error | string }>;
|
|
107
87
|
type PromiseArray<T> = Promise<T[]>;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
resolver: RSVP.Deferred<InternalModel>;
|
|
111
|
-
options: any;
|
|
112
|
-
trace?: Error;
|
|
113
|
-
};
|
|
114
|
-
type PendingSaveItem = {
|
|
115
|
-
snapshot: Snapshot;
|
|
116
|
-
resolver: RSVP.Deferred<void>;
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
const RECORD_REFERENCES = new WeakMap<StableRecordIdentifier, RecordReference>();
|
|
88
|
+
|
|
89
|
+
const RECORD_REFERENCES = new WeakCache<StableRecordIdentifier, RecordReference>(DEBUG ? 'reference' : '');
|
|
120
90
|
|
|
121
91
|
function freeze<T>(obj: T): T {
|
|
122
92
|
if (typeof Object.freeze === 'function') {
|
|
@@ -126,26 +96,6 @@ function freeze<T>(obj: T): T {
|
|
|
126
96
|
return obj;
|
|
127
97
|
}
|
|
128
98
|
|
|
129
|
-
function deprecateTestRegistration(factoryType: 'adapter', factoryName: '-json-api'): void;
|
|
130
|
-
function deprecateTestRegistration(factoryType: 'serializer', factoryName: '-json-api' | '-rest' | '-default'): void;
|
|
131
|
-
function deprecateTestRegistration(
|
|
132
|
-
factoryType: 'serializer' | 'adapter',
|
|
133
|
-
factoryName: '-json-api' | '-rest' | '-default'
|
|
134
|
-
): void {
|
|
135
|
-
deprecate(
|
|
136
|
-
`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.`,
|
|
137
|
-
false,
|
|
138
|
-
{
|
|
139
|
-
id: 'ember-data:-legacy-test-registrations',
|
|
140
|
-
until: '3.17',
|
|
141
|
-
for: '@ember-data/store',
|
|
142
|
-
since: {
|
|
143
|
-
available: '3.15',
|
|
144
|
-
enabled: '3.15',
|
|
145
|
-
},
|
|
146
|
-
}
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
99
|
/**
|
|
150
100
|
The store contains all of the data for records loaded from the server.
|
|
151
101
|
It is also responsible for creating instances of `Model` that wrap
|
|
@@ -219,9 +169,6 @@ function deprecateTestRegistration(
|
|
|
219
169
|
@public
|
|
220
170
|
@extends Ember.Service
|
|
221
171
|
*/
|
|
222
|
-
interface CoreStore {
|
|
223
|
-
adapter: string;
|
|
224
|
-
}
|
|
225
172
|
|
|
226
173
|
abstract class CoreStore extends Service {
|
|
227
174
|
/**
|
|
@@ -233,6 +180,7 @@ abstract class CoreStore extends Service {
|
|
|
233
180
|
public recordArrayManager: RecordArrayManager = new RecordArrayManager({ store: this });
|
|
234
181
|
|
|
235
182
|
declare _notificationManager: NotificationManager;
|
|
183
|
+
declare identifierCache: IdentifierCache;
|
|
236
184
|
private _adapterCache = Object.create(null);
|
|
237
185
|
private _serializerCache = Object.create(null);
|
|
238
186
|
public _storeWrapper = new RecordDataStoreWrapper(this);
|
|
@@ -244,20 +192,14 @@ abstract class CoreStore extends Service {
|
|
|
244
192
|
These queues are currently controlled by a flush scheduled into
|
|
245
193
|
ember-data's custom backburner instance.
|
|
246
194
|
*/
|
|
247
|
-
// used for coalescing record save requests
|
|
248
|
-
private _pendingSave: PendingSaveItem[] = [];
|
|
249
195
|
// used for coalescing internal model updates
|
|
250
196
|
private _updatedInternalModels: InternalModel[] = [];
|
|
251
197
|
|
|
252
|
-
// used to keep track of all the find requests that need to be coalesced
|
|
253
|
-
private _pendingFetch = new Map<string, PendingFetchItem[]>();
|
|
254
|
-
|
|
255
198
|
declare _fetchManager: FetchManager;
|
|
256
199
|
declare _schemaDefinitionService: SchemaDefinitionService;
|
|
257
200
|
|
|
258
201
|
// DEBUG-only properties
|
|
259
202
|
declare _trackedAsyncRequests: AsyncTrackingToken[];
|
|
260
|
-
shouldAssertMethodCallsOnDestroyedStore: boolean = true;
|
|
261
203
|
shouldTrackAsyncRequests: boolean = false;
|
|
262
204
|
generateStackTracesForTrackedRequests: boolean = false;
|
|
263
205
|
declare _trackAsyncRequestStart: (str: string) => void;
|
|
@@ -311,64 +253,27 @@ abstract class CoreStore extends Service {
|
|
|
311
253
|
constructor() {
|
|
312
254
|
super(...arguments);
|
|
313
255
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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();
|
|
321
275
|
|
|
322
276
|
if (DEBUG) {
|
|
323
|
-
if (HAS_EMBER_DATA_PACKAGE && HAS_SERIALIZER_PACKAGE) {
|
|
324
|
-
// support for legacy moduleFor style unit tests
|
|
325
|
-
// that did not include transforms in "needs"
|
|
326
|
-
// or which were not set to integration:true
|
|
327
|
-
// that were relying on ember-test-helpers
|
|
328
|
-
// doing an auto-registration of the transform
|
|
329
|
-
// or us doing one
|
|
330
|
-
const Mapping = {
|
|
331
|
-
date: 'DateTransform',
|
|
332
|
-
boolean: 'BooleanTransform',
|
|
333
|
-
number: 'NumberTransform',
|
|
334
|
-
string: 'StringTransform',
|
|
335
|
-
};
|
|
336
|
-
type MapKeys = keyof typeof Mapping;
|
|
337
|
-
const keys = Object.keys(Mapping) as MapKeys[];
|
|
338
|
-
let shouldWarn = false;
|
|
339
|
-
|
|
340
|
-
let owner = getOwner(this);
|
|
341
|
-
keys.forEach((attributeType) => {
|
|
342
|
-
const transformFactory = owner.factoryFor(`transform:${attributeType}`);
|
|
343
|
-
|
|
344
|
-
if (!transformFactory) {
|
|
345
|
-
// we don't deprecate this because the moduleFor style tests with the closed
|
|
346
|
-
// resolver will be deprecated on their own. When that deprecation completes
|
|
347
|
-
// we can drop this.
|
|
348
|
-
const Transform = require(`@ember-data/serializer/-private`)[Mapping[attributeType]];
|
|
349
|
-
owner.register(`transform:${attributeType}`, Transform);
|
|
350
|
-
shouldWarn = true;
|
|
351
|
-
}
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
if (shouldWarn) {
|
|
355
|
-
deprecate(
|
|
356
|
-
`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.`,
|
|
357
|
-
false,
|
|
358
|
-
{
|
|
359
|
-
id: 'ember-data:-legacy-test-registrations',
|
|
360
|
-
until: '3.17',
|
|
361
|
-
for: '@ember-data/store',
|
|
362
|
-
since: {
|
|
363
|
-
available: '3.15',
|
|
364
|
-
enabled: '3.15',
|
|
365
|
-
},
|
|
366
|
-
}
|
|
367
|
-
);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
this.shouldAssertMethodCallsOnDestroyedStore = this.shouldAssertMethodCallsOnDestroyedStore || false;
|
|
372
277
|
if (this.shouldTrackAsyncRequests === undefined) {
|
|
373
278
|
this.shouldTrackAsyncRequests = false;
|
|
374
279
|
}
|
|
@@ -378,14 +283,14 @@ abstract class CoreStore extends Service {
|
|
|
378
283
|
|
|
379
284
|
this._trackedAsyncRequests = [];
|
|
380
285
|
this._trackAsyncRequestStart = (label) => {
|
|
381
|
-
let trace =
|
|
286
|
+
let trace: string | Error =
|
|
382
287
|
'set `store.generateStackTracesForTrackedRequests = true;` to get a detailed trace for where this request originated';
|
|
383
288
|
|
|
384
289
|
if (this.generateStackTracesForTrackedRequests) {
|
|
385
290
|
try {
|
|
386
291
|
throw new Error(`EmberData TrackedRequest: ${label}`);
|
|
387
292
|
} catch (e) {
|
|
388
|
-
trace = e;
|
|
293
|
+
trace = e as Error;
|
|
389
294
|
}
|
|
390
295
|
}
|
|
391
296
|
|
|
@@ -422,24 +327,7 @@ abstract class CoreStore extends Service {
|
|
|
422
327
|
}
|
|
423
328
|
|
|
424
329
|
getRequestStateService(): RequestCache {
|
|
425
|
-
|
|
426
|
-
return this._fetchManager.requestCache;
|
|
427
|
-
}
|
|
428
|
-
assert('RequestService is not available unless the feature flag is on and running on a canary build', false);
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
/**
|
|
432
|
-
* Provides access to the IdentifierCache instance
|
|
433
|
-
* for this store.
|
|
434
|
-
*
|
|
435
|
-
* The IdentifierCache can be used to generate or
|
|
436
|
-
* retrieve a stable unique identifier for any resource.
|
|
437
|
-
*
|
|
438
|
-
* @property {IdentifierCache} identifierCache
|
|
439
|
-
* @public
|
|
440
|
-
*/
|
|
441
|
-
get identifierCache(): IdentifierCache {
|
|
442
|
-
return identifierCacheFor(this);
|
|
330
|
+
return this._fetchManager.requestCache;
|
|
443
331
|
}
|
|
444
332
|
|
|
445
333
|
_instantiateRecord(
|
|
@@ -449,55 +337,51 @@ abstract class CoreStore extends Service {
|
|
|
449
337
|
identifier: StableRecordIdentifier,
|
|
450
338
|
properties?: { [key: string]: any }
|
|
451
339
|
) {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
);
|
|
459
|
-
|
|
460
|
-
if ('id' in properties) {
|
|
461
|
-
internalModel.setId(properties.id);
|
|
462
|
-
}
|
|
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
|
+
);
|
|
463
346
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
if (def !== undefined) {
|
|
476
|
-
if (def.kind === 'hasMany') {
|
|
477
|
-
if (DEBUG) {
|
|
478
|
-
assertRecordsPassedToHasMany(properties[prop]);
|
|
479
|
-
}
|
|
480
|
-
relationshipValue = extractRecordDatasFromRecords(properties[prop]);
|
|
481
|
-
} else {
|
|
482
|
-
relationshipValue = extractRecordDataFromRecord(properties[prop]);
|
|
483
|
-
}
|
|
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;
|
|
484
357
|
|
|
485
|
-
|
|
358
|
+
for (let i = 0; i < keys.length; i++) {
|
|
359
|
+
let prop = keys[i];
|
|
360
|
+
let def = defs[prop];
|
|
361
|
+
|
|
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]);
|
|
486
370
|
}
|
|
371
|
+
|
|
372
|
+
properties[prop] = relationshipValue;
|
|
487
373
|
}
|
|
488
374
|
}
|
|
489
375
|
}
|
|
490
|
-
|
|
491
|
-
// TODO guard against initRecordOptions no being there
|
|
492
|
-
let createOptions = recordData._initRecordCreateOptions(properties);
|
|
493
|
-
//TODO Igor pass a wrapper instead of RD
|
|
494
|
-
let record = this.instantiateRecord(identifier, createOptions, this.__recordDataFor, this._notificationManager);
|
|
495
|
-
setRecordIdentifier(record, identifier);
|
|
496
|
-
//recordToInternalModelMap.set(record, internalModel);
|
|
497
|
-
return record;
|
|
498
376
|
}
|
|
499
377
|
|
|
500
|
-
|
|
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;
|
|
501
385
|
}
|
|
502
386
|
|
|
503
387
|
abstract instantiateRecord(
|
|
@@ -514,20 +398,12 @@ abstract class CoreStore extends Service {
|
|
|
514
398
|
}
|
|
515
399
|
|
|
516
400
|
// FeatureFlagged in the DSModelStore claas
|
|
517
|
-
_attributesDefinitionFor(
|
|
518
|
-
|
|
519
|
-
return this.getSchemaDefinitionService().attributesDefinitionFor(identifier);
|
|
520
|
-
} else {
|
|
521
|
-
return this.getSchemaDefinitionService().attributesDefinitionFor(modelName);
|
|
522
|
-
}
|
|
401
|
+
_attributesDefinitionFor(identifier: RecordIdentifier | { type: string }): AttributesSchema {
|
|
402
|
+
return this.getSchemaDefinitionService().attributesDefinitionFor(identifier);
|
|
523
403
|
}
|
|
524
404
|
|
|
525
|
-
_relationshipsDefinitionFor(
|
|
526
|
-
|
|
527
|
-
return this.getSchemaDefinitionService().relationshipsDefinitionFor(identifier);
|
|
528
|
-
} else {
|
|
529
|
-
return this.getSchemaDefinitionService().relationshipsDefinitionFor(modelName);
|
|
530
|
-
}
|
|
405
|
+
_relationshipsDefinitionFor(identifier: RecordIdentifier | { type: string }) {
|
|
406
|
+
return this.getSchemaDefinitionService().relationshipsDefinitionFor(identifier);
|
|
531
407
|
}
|
|
532
408
|
|
|
533
409
|
registerSchemaDefinitionService(schema: SchemaDefinitionService) {
|
|
@@ -535,15 +411,12 @@ abstract class CoreStore extends Service {
|
|
|
535
411
|
}
|
|
536
412
|
|
|
537
413
|
getSchemaDefinitionService(): SchemaDefinitionService {
|
|
538
|
-
|
|
539
|
-
return this._schemaDefinitionService;
|
|
540
|
-
}
|
|
541
|
-
assert('need to enable CUSTOM_MODEL_CLASS feature flag in order to access SchemaDefinitionService');
|
|
414
|
+
return this._schemaDefinitionService;
|
|
542
415
|
}
|
|
543
416
|
|
|
544
417
|
// TODO Double check this return value is correct
|
|
545
418
|
_relationshipMetaFor(modelName: string, id: string | null, key: string) {
|
|
546
|
-
return this._relationshipsDefinitionFor(modelName)[key];
|
|
419
|
+
return this._relationshipsDefinitionFor({ type: modelName })[key];
|
|
547
420
|
}
|
|
548
421
|
|
|
549
422
|
/**
|
|
@@ -716,31 +589,12 @@ abstract class CoreStore extends Service {
|
|
|
716
589
|
assertDestroyingStore(this, 'deleteRecord');
|
|
717
590
|
}
|
|
718
591
|
this._backburner.join(() => {
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
internalModel.deleteRecord();
|
|
725
|
-
}
|
|
726
|
-
} else {
|
|
727
|
-
deprecate(
|
|
728
|
-
`You passed a non ember-data managed record ${record} to store.deleteRecord. Ember Data store is not meant to manage non store records. This is not supported and will be removed`,
|
|
729
|
-
false,
|
|
730
|
-
{
|
|
731
|
-
id: 'ember-data:delete-record-non-store',
|
|
732
|
-
until: '4.0',
|
|
733
|
-
for: '@ember-data/store',
|
|
734
|
-
since: {
|
|
735
|
-
available: '3.28',
|
|
736
|
-
enabled: '3.28',
|
|
737
|
-
},
|
|
738
|
-
}
|
|
739
|
-
);
|
|
740
|
-
record.deleteRecord();
|
|
592
|
+
let identifier = peekRecordIdentifier(record);
|
|
593
|
+
if (identifier) {
|
|
594
|
+
let internalModel = internalModelFactoryFor(this).peek(identifier);
|
|
595
|
+
if (internalModel) {
|
|
596
|
+
internalModel.deleteRecord();
|
|
741
597
|
}
|
|
742
|
-
} else {
|
|
743
|
-
record.deleteRecord();
|
|
744
598
|
}
|
|
745
599
|
});
|
|
746
600
|
}
|
|
@@ -765,31 +619,12 @@ abstract class CoreStore extends Service {
|
|
|
765
619
|
if (DEBUG) {
|
|
766
620
|
assertDestroyingStore(this, 'unloadRecord');
|
|
767
621
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
internalModel.unloadRecord();
|
|
774
|
-
}
|
|
775
|
-
} else {
|
|
776
|
-
deprecate(
|
|
777
|
-
`You passed a non ember-data managed record ${record} to store.unloadRecord. Ember Data store is not meant to manage non store records. This is not supported and will be removed`,
|
|
778
|
-
false,
|
|
779
|
-
{
|
|
780
|
-
id: 'ember-data:unload-record-non-store',
|
|
781
|
-
until: '4.0',
|
|
782
|
-
for: '@ember-data/store',
|
|
783
|
-
since: {
|
|
784
|
-
available: '3.28',
|
|
785
|
-
enabled: '3.28',
|
|
786
|
-
},
|
|
787
|
-
}
|
|
788
|
-
);
|
|
789
|
-
record.unloadRecord();
|
|
622
|
+
let identifier = peekRecordIdentifier(record);
|
|
623
|
+
if (identifier) {
|
|
624
|
+
let internalModel = internalModelFactoryFor(this).peek(identifier);
|
|
625
|
+
if (internalModel) {
|
|
626
|
+
internalModel.unloadRecord();
|
|
790
627
|
}
|
|
791
|
-
} else {
|
|
792
|
-
record.unloadRecord();
|
|
793
628
|
}
|
|
794
629
|
}
|
|
795
630
|
|
|
@@ -1298,19 +1133,12 @@ abstract class CoreStore extends Service {
|
|
|
1298
1133
|
return this._scheduleFetch(internalModel, options);
|
|
1299
1134
|
}
|
|
1300
1135
|
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
if (
|
|
1304
|
-
return internalModel
|
|
1305
|
-
}
|
|
1306
|
-
} else {
|
|
1307
|
-
if (internalModel.currentState.isLoading) {
|
|
1308
|
-
let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier, options);
|
|
1309
|
-
if (pendingRequest) {
|
|
1310
|
-
return pendingRequest.then(() => Promise.resolve(internalModel));
|
|
1311
|
-
}
|
|
1312
|
-
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));
|
|
1313
1140
|
}
|
|
1141
|
+
return this._scheduleFetch(internalModel, options);
|
|
1314
1142
|
}
|
|
1315
1143
|
|
|
1316
1144
|
return Promise.resolve(internalModel);
|
|
@@ -1347,29 +1175,6 @@ abstract class CoreStore extends Service {
|
|
|
1347
1175
|
return promiseArray(all(promises).then(A, null, `DS: Store#findByIds of ${normalizedModelName} complete`));
|
|
1348
1176
|
}
|
|
1349
1177
|
|
|
1350
|
-
/**
|
|
1351
|
-
This method is called by `findRecord` if it discovers that a particular
|
|
1352
|
-
type/id pair hasn't been loaded yet to kick off a request to the
|
|
1353
|
-
adapter.
|
|
1354
|
-
|
|
1355
|
-
@method _fetchRecord
|
|
1356
|
-
@private
|
|
1357
|
-
@param {InternalModel} internalModel model
|
|
1358
|
-
@return {Promise} promise
|
|
1359
|
-
*/
|
|
1360
|
-
_fetchRecord(internalModel: InternalModel, options): Promise<InternalModel> {
|
|
1361
|
-
let modelName = internalModel.modelName;
|
|
1362
|
-
let adapter = this.adapterFor(modelName);
|
|
1363
|
-
|
|
1364
|
-
assert(`You tried to find a record but you have no adapter (for ${modelName})`, adapter);
|
|
1365
|
-
assert(
|
|
1366
|
-
`You tried to find a record but your adapter (for ${modelName}) does not implement 'findRecord'`,
|
|
1367
|
-
typeof adapter.findRecord === 'function'
|
|
1368
|
-
);
|
|
1369
|
-
|
|
1370
|
-
return _find(adapter, this, internalModel.modelClass, internalModel.id, internalModel, options);
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
1178
|
_scheduleFetchMany(internalModels, options) {
|
|
1374
1179
|
let fetches = new Array(internalModels.length);
|
|
1375
1180
|
|
|
@@ -1380,7 +1185,7 @@ abstract class CoreStore extends Service {
|
|
|
1380
1185
|
return Promise.all(fetches);
|
|
1381
1186
|
}
|
|
1382
1187
|
|
|
1383
|
-
|
|
1188
|
+
_scheduleFetch(internalModel: InternalModel, options = {}): RSVP.Promise<InternalModel> {
|
|
1384
1189
|
let generateStackTrace = this.generateStackTracesForTrackedRequests;
|
|
1385
1190
|
// TODO remove this once we don't rely on state machine
|
|
1386
1191
|
internalModel.send('loadingData');
|
|
@@ -1415,227 +1220,6 @@ abstract class CoreStore extends Service {
|
|
|
1415
1220
|
);
|
|
1416
1221
|
}
|
|
1417
1222
|
|
|
1418
|
-
_scheduleFetch(internalModel: InternalModel, options): RSVP.Promise<InternalModel> {
|
|
1419
|
-
if (REQUEST_SERVICE) {
|
|
1420
|
-
return this._scheduleFetchThroughFetchManager(internalModel, options);
|
|
1421
|
-
} else {
|
|
1422
|
-
if (internalModel._promiseProxy) {
|
|
1423
|
-
return internalModel._promiseProxy;
|
|
1424
|
-
}
|
|
1425
|
-
|
|
1426
|
-
assertIdentifierHasId(internalModel.identifier);
|
|
1427
|
-
|
|
1428
|
-
let { id, modelName } = internalModel;
|
|
1429
|
-
let resolver = defer<InternalModel>(`Fetching ${modelName}' with id: ${id}`);
|
|
1430
|
-
let pendingFetchItem: PendingFetchItem = {
|
|
1431
|
-
internalModel,
|
|
1432
|
-
resolver,
|
|
1433
|
-
options,
|
|
1434
|
-
};
|
|
1435
|
-
|
|
1436
|
-
if (DEBUG) {
|
|
1437
|
-
if (this.generateStackTracesForTrackedRequests === true) {
|
|
1438
|
-
let trace;
|
|
1439
|
-
|
|
1440
|
-
try {
|
|
1441
|
-
throw new Error(`Trace Origin for scheduled fetch for ${modelName}:${id}.`);
|
|
1442
|
-
} catch (e) {
|
|
1443
|
-
trace = e;
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
// enable folks to discover the origin of this findRecord call when
|
|
1447
|
-
// debugging. Ideally we would have a tracked queue for requests with
|
|
1448
|
-
// labels or local IDs that could be used to merge this trace with
|
|
1449
|
-
// the trace made available when we detect an async leak
|
|
1450
|
-
pendingFetchItem.trace = trace;
|
|
1451
|
-
}
|
|
1452
|
-
}
|
|
1453
|
-
|
|
1454
|
-
let promise = resolver.promise;
|
|
1455
|
-
|
|
1456
|
-
internalModel.send('loadingData', promise);
|
|
1457
|
-
if (this._pendingFetch.size === 0) {
|
|
1458
|
-
emberBackburner.schedule('actions', this, this.flushAllPendingFetches);
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
|
-
let fetches = this._pendingFetch;
|
|
1462
|
-
let pending = fetches.get(modelName);
|
|
1463
|
-
|
|
1464
|
-
if (pending === undefined) {
|
|
1465
|
-
pending = [];
|
|
1466
|
-
fetches.set(modelName, pending);
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1469
|
-
pending.push(pendingFetchItem);
|
|
1470
|
-
|
|
1471
|
-
return promise;
|
|
1472
|
-
}
|
|
1473
|
-
}
|
|
1474
|
-
|
|
1475
|
-
flushAllPendingFetches() {
|
|
1476
|
-
if (REQUEST_SERVICE) {
|
|
1477
|
-
return;
|
|
1478
|
-
//assert here
|
|
1479
|
-
} else {
|
|
1480
|
-
if (this.isDestroyed || this.isDestroying) {
|
|
1481
|
-
return;
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
this._pendingFetch.forEach(this._flushPendingFetchForType, this);
|
|
1485
|
-
this._pendingFetch.clear();
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
|
|
1489
|
-
_flushPendingFetchForType(pendingFetchItems: PendingFetchItem[], modelName: string) {
|
|
1490
|
-
let store = this;
|
|
1491
|
-
let adapter = store.adapterFor(modelName);
|
|
1492
|
-
let shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests;
|
|
1493
|
-
let totalItems = pendingFetchItems.length;
|
|
1494
|
-
let internalModels = new Array(totalItems);
|
|
1495
|
-
let seeking = Object.create(null);
|
|
1496
|
-
|
|
1497
|
-
let optionsMap = new WeakMap();
|
|
1498
|
-
|
|
1499
|
-
for (let i = 0; i < totalItems; i++) {
|
|
1500
|
-
let pendingItem = pendingFetchItems[i];
|
|
1501
|
-
let internalModel = pendingItem.internalModel;
|
|
1502
|
-
internalModels[i] = internalModel;
|
|
1503
|
-
optionsMap.set(internalModel, pendingItem.options);
|
|
1504
|
-
// We can remove this "not null" cast once we have enough typing
|
|
1505
|
-
// to know we are only dealing with ExistingResourceIdentifierObjects
|
|
1506
|
-
seeking[internalModel.id!] = pendingItem;
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
|
-
function _fetchRecord(recordResolverPair) {
|
|
1510
|
-
let recordFetch = store._fetchRecord(recordResolverPair.internalModel, recordResolverPair.options);
|
|
1511
|
-
|
|
1512
|
-
recordResolverPair.resolver.resolve(recordFetch);
|
|
1513
|
-
}
|
|
1514
|
-
|
|
1515
|
-
function handleFoundRecords(foundInternalModels: InternalModel[], expectedInternalModels: InternalModel[]) {
|
|
1516
|
-
// resolve found records
|
|
1517
|
-
let found = Object.create(null);
|
|
1518
|
-
for (let i = 0, l = foundInternalModels.length; i < l; i++) {
|
|
1519
|
-
let internalModel = foundInternalModels[i];
|
|
1520
|
-
|
|
1521
|
-
// We can remove this "not null" cast once we have enough typing
|
|
1522
|
-
// to know we are only dealing with ExistingResourceIdentifierObjects
|
|
1523
|
-
let pair = seeking[internalModel.id!];
|
|
1524
|
-
found[internalModel.id!] = internalModel;
|
|
1525
|
-
|
|
1526
|
-
if (pair) {
|
|
1527
|
-
let resolver = pair.resolver;
|
|
1528
|
-
resolver.resolve(internalModel);
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1531
|
-
|
|
1532
|
-
// reject missing records
|
|
1533
|
-
let missingInternalModels: InternalModel[] = [];
|
|
1534
|
-
|
|
1535
|
-
for (let i = 0, l = expectedInternalModels.length; i < l; i++) {
|
|
1536
|
-
let internalModel = expectedInternalModels[i];
|
|
1537
|
-
|
|
1538
|
-
// We can remove this "not null" cast once we have enough typing
|
|
1539
|
-
// to know we are only dealing with ExistingResourceIdentifierObjects
|
|
1540
|
-
if (!found[internalModel.id!]) {
|
|
1541
|
-
missingInternalModels.push(internalModel);
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
|
|
1545
|
-
if (missingInternalModels.length) {
|
|
1546
|
-
warn(
|
|
1547
|
-
'Ember Data expected to find records with the following ids in the adapter response but they were missing: [ "' +
|
|
1548
|
-
missingInternalModels.map((r) => r.id).join('", "') +
|
|
1549
|
-
'" ]',
|
|
1550
|
-
false,
|
|
1551
|
-
{
|
|
1552
|
-
id: 'ds.store.missing-records-from-adapter',
|
|
1553
|
-
}
|
|
1554
|
-
);
|
|
1555
|
-
rejectInternalModels(missingInternalModels);
|
|
1556
|
-
}
|
|
1557
|
-
}
|
|
1558
|
-
|
|
1559
|
-
function rejectInternalModels(internalModels: InternalModel[], error?: Error) {
|
|
1560
|
-
for (let i = 0, l = internalModels.length; i < l; i++) {
|
|
1561
|
-
let internalModel = internalModels[i];
|
|
1562
|
-
|
|
1563
|
-
// We can remove this "not null" cast once we have enough typing
|
|
1564
|
-
// to know we are only dealing with ExistingResourceIdentifierObjects
|
|
1565
|
-
let pair = seeking[internalModel.id!];
|
|
1566
|
-
|
|
1567
|
-
if (pair) {
|
|
1568
|
-
pair.resolver.reject(
|
|
1569
|
-
error ||
|
|
1570
|
-
new Error(
|
|
1571
|
-
`Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.`
|
|
1572
|
-
)
|
|
1573
|
-
);
|
|
1574
|
-
}
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
if (shouldCoalesce) {
|
|
1579
|
-
// TODO: Improve records => snapshots => records => snapshots
|
|
1580
|
-
//
|
|
1581
|
-
// We want to provide records to all store methods and snapshots to all
|
|
1582
|
-
// adapter methods. To make sure we're doing that we're providing an array
|
|
1583
|
-
// of snapshots to adapter.groupRecordsForFindMany(), which in turn will
|
|
1584
|
-
// return grouped snapshots instead of grouped records.
|
|
1585
|
-
//
|
|
1586
|
-
// But since the _findMany() finder is a store method we need to get the
|
|
1587
|
-
// records from the grouped snapshots even though the _findMany() finder
|
|
1588
|
-
// will once again convert the records to snapshots for adapter.findMany()
|
|
1589
|
-
let snapshots = new Array(totalItems);
|
|
1590
|
-
for (let i = 0; i < totalItems; i++) {
|
|
1591
|
-
let internalModel = internalModels[i];
|
|
1592
|
-
snapshots[i] = internalModel.createSnapshot(optionsMap.get(internalModel));
|
|
1593
|
-
}
|
|
1594
|
-
|
|
1595
|
-
let groups;
|
|
1596
|
-
if (adapter.groupRecordsForFindMany) {
|
|
1597
|
-
groups = adapter.groupRecordsForFindMany(this, snapshots);
|
|
1598
|
-
} else {
|
|
1599
|
-
groups = [snapshots];
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
for (let i = 0, l = groups.length; i < l; i++) {
|
|
1603
|
-
let group = groups[i];
|
|
1604
|
-
let totalInGroup = groups[i].length;
|
|
1605
|
-
let ids = new Array(totalInGroup);
|
|
1606
|
-
let groupedInternalModels = new Array(totalInGroup);
|
|
1607
|
-
|
|
1608
|
-
for (let j = 0; j < totalInGroup; j++) {
|
|
1609
|
-
let internalModel = group[j]._internalModel;
|
|
1610
|
-
|
|
1611
|
-
groupedInternalModels[j] = internalModel;
|
|
1612
|
-
ids[j] = internalModel.id;
|
|
1613
|
-
}
|
|
1614
|
-
|
|
1615
|
-
if (totalInGroup > 1) {
|
|
1616
|
-
(function (groupedInternalModels) {
|
|
1617
|
-
_findMany(adapter, store, modelName, ids, groupedInternalModels, optionsMap)
|
|
1618
|
-
.then(function (foundInternalModels) {
|
|
1619
|
-
handleFoundRecords(foundInternalModels, groupedInternalModels);
|
|
1620
|
-
})
|
|
1621
|
-
.catch(function (error) {
|
|
1622
|
-
rejectInternalModels(groupedInternalModels, error);
|
|
1623
|
-
});
|
|
1624
|
-
})(groupedInternalModels);
|
|
1625
|
-
} else if (ids.length === 1) {
|
|
1626
|
-
let pair = seeking[groupedInternalModels[0].id];
|
|
1627
|
-
_fetchRecord(pair);
|
|
1628
|
-
} else {
|
|
1629
|
-
assert("You cannot return an empty array from adapter's method groupRecordsForFindMany");
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
|
-
} else {
|
|
1633
|
-
for (let i = 0; i < totalItems; i++) {
|
|
1634
|
-
_fetchRecord(pendingFetchItems[i]);
|
|
1635
|
-
}
|
|
1636
|
-
}
|
|
1637
|
-
}
|
|
1638
|
-
|
|
1639
1223
|
/**
|
|
1640
1224
|
Get the reference for the specified record.
|
|
1641
1225
|
|
|
@@ -1693,15 +1277,9 @@ abstract class CoreStore extends Service {
|
|
|
1693
1277
|
isMaybeIdentifier(resourceIdentifier)
|
|
1694
1278
|
);
|
|
1695
1279
|
|
|
1696
|
-
let identifier: StableRecordIdentifier =
|
|
1280
|
+
let identifier: StableRecordIdentifier = this.identifierCache.getOrCreateRecordIdentifier(resourceIdentifier);
|
|
1697
1281
|
if (identifier) {
|
|
1698
|
-
|
|
1699
|
-
return RECORD_REFERENCES.get(identifier);
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1702
|
-
let reference = new RecordReference(this, identifier);
|
|
1703
|
-
RECORD_REFERENCES.set(identifier, reference);
|
|
1704
|
-
return reference;
|
|
1282
|
+
return RECORD_REFERENCES.lookup(identifier);
|
|
1705
1283
|
}
|
|
1706
1284
|
}
|
|
1707
1285
|
|
|
@@ -1757,7 +1335,7 @@ abstract class CoreStore extends Service {
|
|
|
1757
1335
|
peekRecord(identifier: ResourceIdentifierObject): RecordInstance | null;
|
|
1758
1336
|
peekRecord(identifier: ResourceIdentifierObject | string, id?: string | number): RecordInstance | null {
|
|
1759
1337
|
if (arguments.length === 1 && isMaybeIdentifier(identifier)) {
|
|
1760
|
-
let stableIdentifier =
|
|
1338
|
+
let stableIdentifier = this.identifierCache.peekRecordIdentifier(identifier);
|
|
1761
1339
|
if (stableIdentifier) {
|
|
1762
1340
|
return internalModelFactoryFor(this).peek(stableIdentifier)?.getRecord() || null;
|
|
1763
1341
|
}
|
|
@@ -1799,9 +1377,7 @@ abstract class CoreStore extends Service {
|
|
|
1799
1377
|
@return {Promise} promise
|
|
1800
1378
|
*/
|
|
1801
1379
|
_reloadRecord(internalModel, options): RSVP.Promise<InternalModel> {
|
|
1802
|
-
|
|
1803
|
-
options.isReloading = true;
|
|
1804
|
-
}
|
|
1380
|
+
options.isReloading = true;
|
|
1805
1381
|
let { id, modelName } = internalModel;
|
|
1806
1382
|
let adapter = this.adapterFor(modelName);
|
|
1807
1383
|
|
|
@@ -1849,7 +1425,7 @@ abstract class CoreStore extends Service {
|
|
|
1849
1425
|
const trueId = ensureStringId(id);
|
|
1850
1426
|
const resource = { type, id: trueId };
|
|
1851
1427
|
|
|
1852
|
-
const identifier =
|
|
1428
|
+
const identifier = this.identifierCache.peekRecordIdentifier(resource);
|
|
1853
1429
|
const internalModel = identifier && internalModelFactoryFor(this).peek(identifier);
|
|
1854
1430
|
|
|
1855
1431
|
return !!internalModel && internalModel.currentState.isLoaded;
|
|
@@ -2048,17 +1624,9 @@ abstract class CoreStore extends Service {
|
|
|
2048
1624
|
|
|
2049
1625
|
if (internalModel) {
|
|
2050
1626
|
// short circuit if we are already loading
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
return pendingRequest.then(() => internalModel.getRecord());
|
|
2055
|
-
}
|
|
2056
|
-
} else {
|
|
2057
|
-
if (internalModel.currentState.isLoading) {
|
|
2058
|
-
return internalModel._promiseProxy.then(() => {
|
|
2059
|
-
return internalModel.getRecord();
|
|
2060
|
-
});
|
|
2061
|
-
}
|
|
1627
|
+
let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier, options);
|
|
1628
|
+
if (pendingRequest) {
|
|
1629
|
+
return pendingRequest.then(() => internalModel.getRecord());
|
|
2062
1630
|
}
|
|
2063
1631
|
}
|
|
2064
1632
|
|
|
@@ -2691,33 +2259,32 @@ abstract class CoreStore extends Service {
|
|
|
2691
2259
|
@param {Object} options
|
|
2692
2260
|
*/
|
|
2693
2261
|
scheduleSave(internalModel: InternalModel, resolver: RSVP.Deferred<void>, options): void | RSVP.Promise<void> {
|
|
2694
|
-
if (
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
}
|
|
2262
|
+
if (internalModel._isRecordFullyDeleted()) {
|
|
2263
|
+
resolver.resolve();
|
|
2264
|
+
return resolver.promise;
|
|
2265
|
+
}
|
|
2699
2266
|
|
|
2700
|
-
|
|
2267
|
+
internalModel.adapterWillCommit();
|
|
2701
2268
|
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
// TODO handle missing isNew
|
|
2709
|
-
if (recordData.isNew && recordData.isNew()) {
|
|
2710
|
-
operation = 'createRecord';
|
|
2711
|
-
} else if (recordData.isDeleted && recordData.isDeleted()) {
|
|
2712
|
-
operation = 'deleteRecord';
|
|
2713
|
-
}
|
|
2269
|
+
if (!options) {
|
|
2270
|
+
options = {};
|
|
2271
|
+
}
|
|
2272
|
+
let recordData = internalModel._recordData;
|
|
2273
|
+
let operation: 'createRecord' | 'deleteRecord' | 'updateRecord' = 'updateRecord';
|
|
2714
2274
|
|
|
2715
|
-
|
|
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
|
+
}
|
|
2716
2281
|
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2282
|
+
options[SaveOp] = operation;
|
|
2283
|
+
|
|
2284
|
+
let fetchManagerPromise = this._fetchManager.scheduleSave(internalModel.identifier, options);
|
|
2285
|
+
let promise = fetchManagerPromise.then(
|
|
2286
|
+
(payload) => {
|
|
2287
|
+
/*
|
|
2721
2288
|
Note to future spelunkers hoping to optimize.
|
|
2722
2289
|
We rely on this `run` to create a run loop if needed
|
|
2723
2290
|
that `store._push` and `store.didSaveRecord` will both share.
|
|
@@ -2726,40 +2293,25 @@ abstract class CoreStore extends Service {
|
|
|
2726
2293
|
have an outer run loop available still from the first
|
|
2727
2294
|
call to `store._push`;
|
|
2728
2295
|
*/
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
}
|
|
2735
|
-
});
|
|
2736
|
-
},
|
|
2737
|
-
(e) => {
|
|
2738
|
-
if (typeof e === 'string') {
|
|
2739
|
-
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 });
|
|
2740
2301
|
}
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2302
|
+
});
|
|
2303
|
+
},
|
|
2304
|
+
(e) => {
|
|
2305
|
+
if (typeof e === 'string') {
|
|
2306
|
+
throw e;
|
|
2744
2307
|
}
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
} else {
|
|
2749
|
-
if (internalModel._isRecordFullyDeleted()) {
|
|
2750
|
-
resolver.resolve();
|
|
2751
|
-
return;
|
|
2308
|
+
const { error, parsedErrors } = e;
|
|
2309
|
+
this.recordWasInvalid(internalModel, parsedErrors, error);
|
|
2310
|
+
throw error;
|
|
2752
2311
|
}
|
|
2312
|
+
);
|
|
2753
2313
|
|
|
2754
|
-
|
|
2755
|
-
internalModel.adapterWillCommit();
|
|
2756
|
-
this._pendingSave.push({
|
|
2757
|
-
snapshot: snapshot,
|
|
2758
|
-
resolver: resolver,
|
|
2759
|
-
});
|
|
2760
|
-
|
|
2761
|
-
emberBackburner.scheduleOnce('actions', this, this.flushPendingSave);
|
|
2762
|
-
}
|
|
2314
|
+
return promise;
|
|
2763
2315
|
}
|
|
2764
2316
|
|
|
2765
2317
|
/**
|
|
@@ -2770,47 +2322,8 @@ abstract class CoreStore extends Service {
|
|
|
2770
2322
|
@private
|
|
2771
2323
|
*/
|
|
2772
2324
|
flushPendingSave() {
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
return;
|
|
2776
|
-
}
|
|
2777
|
-
let pending = this._pendingSave.slice();
|
|
2778
|
-
this._pendingSave = [];
|
|
2779
|
-
|
|
2780
|
-
for (let i = 0, j = pending.length; i < j; i++) {
|
|
2781
|
-
let pendingItem = pending[i];
|
|
2782
|
-
let snapshot = pendingItem.snapshot;
|
|
2783
|
-
let resolver = pendingItem.resolver;
|
|
2784
|
-
// TODO We have to cast due to our reliance on this private property
|
|
2785
|
-
// this will be refactored away once we change our pending API to be identifier based
|
|
2786
|
-
let internalModel = (snapshot as unknown as PrivateSnapshot)._internalModel;
|
|
2787
|
-
let adapter = this.adapterFor(internalModel.modelName);
|
|
2788
|
-
let operation;
|
|
2789
|
-
|
|
2790
|
-
if (RECORD_DATA_STATE) {
|
|
2791
|
-
// TODO move this out of internalModel
|
|
2792
|
-
if (internalModel.isNew()) {
|
|
2793
|
-
operation = 'createRecord';
|
|
2794
|
-
} else if (internalModel.isDeleted()) {
|
|
2795
|
-
operation = 'deleteRecord';
|
|
2796
|
-
} else {
|
|
2797
|
-
operation = 'updateRecord';
|
|
2798
|
-
}
|
|
2799
|
-
} else {
|
|
2800
|
-
if (internalModel.currentState.stateName === 'root.deleted.saved') {
|
|
2801
|
-
resolver.resolve();
|
|
2802
|
-
continue;
|
|
2803
|
-
} else if (internalModel.isNew()) {
|
|
2804
|
-
operation = 'createRecord';
|
|
2805
|
-
} else if (internalModel.isDeleted()) {
|
|
2806
|
-
operation = 'deleteRecord';
|
|
2807
|
-
} else {
|
|
2808
|
-
operation = 'updateRecord';
|
|
2809
|
-
}
|
|
2810
|
-
}
|
|
2811
|
-
|
|
2812
|
-
resolver.resolve(_commit(adapter, this, operation, snapshot));
|
|
2813
|
-
}
|
|
2325
|
+
// assert here
|
|
2326
|
+
return;
|
|
2814
2327
|
}
|
|
2815
2328
|
|
|
2816
2329
|
/**
|
|
@@ -2842,7 +2355,7 @@ abstract class CoreStore extends Service {
|
|
|
2842
2355
|
);
|
|
2843
2356
|
}
|
|
2844
2357
|
|
|
2845
|
-
const cache =
|
|
2358
|
+
const cache = this.identifierCache;
|
|
2846
2359
|
const identifier = internalModel.identifier;
|
|
2847
2360
|
|
|
2848
2361
|
if (op !== 'deleteRecord' && data) {
|
|
@@ -2868,11 +2381,7 @@ abstract class CoreStore extends Service {
|
|
|
2868
2381
|
if (DEBUG) {
|
|
2869
2382
|
assertDestroyingStore(this, 'recordWasInvalid');
|
|
2870
2383
|
}
|
|
2871
|
-
|
|
2872
|
-
internalModel.adapterDidInvalidate(parsedErrors, error);
|
|
2873
|
-
} else {
|
|
2874
|
-
internalModel.adapterDidInvalidate(parsedErrors);
|
|
2875
|
-
}
|
|
2384
|
+
internalModel.adapterDidInvalidate(parsedErrors, error);
|
|
2876
2385
|
}
|
|
2877
2386
|
|
|
2878
2387
|
/**
|
|
@@ -2934,7 +2443,7 @@ abstract class CoreStore extends Service {
|
|
|
2934
2443
|
// exclude store.push (root.empty) case
|
|
2935
2444
|
let identifier = internalModel.identifier;
|
|
2936
2445
|
if (isUpdate || isLoading) {
|
|
2937
|
-
let updatedIdentifier =
|
|
2446
|
+
let updatedIdentifier = this.identifierCache.updateRecordIdentifier(identifier, data);
|
|
2938
2447
|
|
|
2939
2448
|
if (updatedIdentifier !== identifier) {
|
|
2940
2449
|
// we encountered a merge of identifiers in which
|
|
@@ -3197,30 +2706,17 @@ abstract class CoreStore extends Service {
|
|
|
3197
2706
|
|
|
3198
2707
|
if (ENV.DS_WARN_ON_UNKNOWN_KEYS) {
|
|
3199
2708
|
let unknownAttributes, unknownRelationships;
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
});
|
|
3212
|
-
} else {
|
|
3213
|
-
let modelClass = this.modelFor(modelName);
|
|
3214
|
-
// Check unknown attributes
|
|
3215
|
-
unknownAttributes = Object.keys(data.attributes || {}).filter((key) => {
|
|
3216
|
-
return !get(modelClass, 'fields').has(key);
|
|
3217
|
-
});
|
|
3218
|
-
|
|
3219
|
-
// Check unknown relationships
|
|
3220
|
-
unknownRelationships = Object.keys(data.relationships || {}).filter((key) => {
|
|
3221
|
-
return !get(modelClass, 'fields').has(key);
|
|
3222
|
-
});
|
|
3223
|
-
}
|
|
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
|
+
});
|
|
3224
2720
|
let unknownAttributesMessage = `The payload for '${modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`;
|
|
3225
2721
|
warn(unknownAttributesMessage, unknownAttributes.length === 0, {
|
|
3226
2722
|
id: 'ds.store.unknown-keys-in-payload',
|
|
@@ -3350,38 +2846,26 @@ abstract class CoreStore extends Service {
|
|
|
3350
2846
|
}
|
|
3351
2847
|
|
|
3352
2848
|
serializeRecord(record: RecordInstance, options?: Dict<unknown>): unknown {
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
return internalModel!.createSnapshot(options).serialize(options);
|
|
3358
|
-
}
|
|
3359
|
-
|
|
3360
|
-
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);
|
|
3361
2853
|
}
|
|
3362
2854
|
|
|
3363
2855
|
saveRecord(record: RecordInstance, options?: Dict<unknown>): RSVP.Promise<RecordInstance> {
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
return (internalModel!.save(options) as RSVP.Promise<void>).then(() => record);
|
|
3371
|
-
}
|
|
3372
|
-
|
|
3373
|
-
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);
|
|
3374
2862
|
}
|
|
3375
2863
|
|
|
3376
2864
|
relationshipReferenceFor(identifier: RecordIdentifier, key: string): BelongsToReference | HasManyReference {
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
return internalModel!.referenceFor(null, key);
|
|
3382
|
-
}
|
|
3383
|
-
|
|
3384
|
-
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);
|
|
3385
2869
|
}
|
|
3386
2870
|
|
|
3387
2871
|
/**
|
|
@@ -3427,7 +2911,7 @@ abstract class CoreStore extends Service {
|
|
|
3427
2911
|
_RecordData = require('@ember-data/record-data/-private').RecordData as RecordDataConstruct;
|
|
3428
2912
|
}
|
|
3429
2913
|
|
|
3430
|
-
let identifier =
|
|
2914
|
+
let identifier = this.identifierCache.getOrCreateRecordIdentifier({
|
|
3431
2915
|
type: modelName,
|
|
3432
2916
|
id,
|
|
3433
2917
|
lid: clientId,
|
|
@@ -3442,7 +2926,7 @@ abstract class CoreStore extends Service {
|
|
|
3442
2926
|
* @internal
|
|
3443
2927
|
*/
|
|
3444
2928
|
__recordDataFor(resource: RecordIdentifier) {
|
|
3445
|
-
const identifier =
|
|
2929
|
+
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
|
|
3446
2930
|
return this.recordDataFor(identifier, false);
|
|
3447
2931
|
}
|
|
3448
2932
|
|
|
@@ -3560,25 +3044,15 @@ abstract class CoreStore extends Service {
|
|
|
3560
3044
|
|
|
3561
3045
|
let owner = getOwner(this);
|
|
3562
3046
|
|
|
3047
|
+
// name specific adapter
|
|
3563
3048
|
adapter = owner.lookup(`adapter:${normalizedModelName}`);
|
|
3564
|
-
|
|
3565
|
-
// in production this is handled by the re-export
|
|
3566
|
-
if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_ADAPTER_PACKAGE && adapter === undefined) {
|
|
3567
|
-
if (normalizedModelName === '-json-api') {
|
|
3568
|
-
const Adapter = require('@ember-data/adapter/json-api').default;
|
|
3569
|
-
owner.register(`adapter:-json-api`, Adapter);
|
|
3570
|
-
adapter = owner.lookup(`adapter:-json-api`);
|
|
3571
|
-
deprecateTestRegistration('adapter', '-json-api');
|
|
3572
|
-
}
|
|
3573
|
-
}
|
|
3574
|
-
|
|
3575
3049
|
if (adapter !== undefined) {
|
|
3576
3050
|
set(adapter, 'store', this);
|
|
3577
3051
|
_adapterCache[normalizedModelName] = adapter;
|
|
3578
3052
|
return adapter;
|
|
3579
3053
|
}
|
|
3580
3054
|
|
|
3581
|
-
// no adapter found for the specific
|
|
3055
|
+
// no adapter found for the specific name, fallback and check for application adapter
|
|
3582
3056
|
adapter = _adapterCache.application || owner.lookup('adapter:application');
|
|
3583
3057
|
if (adapter !== undefined) {
|
|
3584
3058
|
set(adapter, 'store', this);
|
|
@@ -3587,30 +3061,9 @@ abstract class CoreStore extends Service {
|
|
|
3587
3061
|
return adapter;
|
|
3588
3062
|
}
|
|
3589
3063
|
|
|
3590
|
-
// no model specific adapter or application adapter, check for an `adapter`
|
|
3591
|
-
// property defined on the store
|
|
3592
|
-
let adapterName = this.adapter || '-json-api';
|
|
3593
|
-
adapter = adapterName ? _adapterCache[adapterName] || owner.lookup(`adapter:${adapterName}`) : undefined;
|
|
3594
|
-
|
|
3595
|
-
// in production this is handled by the re-export
|
|
3596
|
-
if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_ADAPTER_PACKAGE && adapter === undefined) {
|
|
3597
|
-
if (adapterName === '-json-api') {
|
|
3598
|
-
const Adapter = require('@ember-data/adapter/json-api').default;
|
|
3599
|
-
owner.register(`adapter:-json-api`, Adapter);
|
|
3600
|
-
adapter = owner.lookup(`adapter:-json-api`);
|
|
3601
|
-
deprecateTestRegistration('adapter', '-json-api');
|
|
3602
|
-
}
|
|
3603
|
-
}
|
|
3604
|
-
|
|
3605
|
-
if (adapter !== undefined) {
|
|
3606
|
-
set(adapter, 'store', this);
|
|
3607
|
-
_adapterCache[normalizedModelName] = adapter;
|
|
3608
|
-
_adapterCache[adapterName] = adapter;
|
|
3609
|
-
return adapter;
|
|
3610
|
-
}
|
|
3611
|
-
|
|
3612
3064
|
// final fallback, no model specific adapter, no application adapter, no
|
|
3613
3065
|
// `adapter` property on store: use json-api adapter
|
|
3066
|
+
// TODO we should likely deprecate this?
|
|
3614
3067
|
adapter = _adapterCache['-json-api'] || owner.lookup('adapter:-json-api');
|
|
3615
3068
|
assert(
|
|
3616
3069
|
`No adapter was found for '${modelName}' and no 'application' adapter was found as a fallback.`,
|
|
@@ -3635,10 +3088,6 @@ abstract class CoreStore extends Service {
|
|
|
3635
3088
|
for an `App.ApplicationSerializer` (the default serializer for
|
|
3636
3089
|
your entire application).
|
|
3637
3090
|
|
|
3638
|
-
if no `App.ApplicationSerializer` is found, it will attempt
|
|
3639
|
-
to get the `defaultSerializer` from the `PersonAdapter`
|
|
3640
|
-
(`adapterFor('person')`).
|
|
3641
|
-
|
|
3642
3091
|
If a serializer cannot be found on the adapter, it will fall back
|
|
3643
3092
|
to an instance of `JSONSerializer`.
|
|
3644
3093
|
|
|
@@ -3666,30 +3115,8 @@ abstract class CoreStore extends Service {
|
|
|
3666
3115
|
|
|
3667
3116
|
let owner = getOwner(this);
|
|
3668
3117
|
|
|
3118
|
+
// by name
|
|
3669
3119
|
serializer = owner.lookup(`serializer:${normalizedModelName}`);
|
|
3670
|
-
|
|
3671
|
-
if (DEPRECATE_LEGACY_TEST_REGISTRATIONS) {
|
|
3672
|
-
// in production this is handled by the re-export
|
|
3673
|
-
if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_SERIALIZER_PACKAGE && serializer === undefined) {
|
|
3674
|
-
if (normalizedModelName === '-json-api') {
|
|
3675
|
-
const Serializer = require('@ember-data/serializer/json-api').default;
|
|
3676
|
-
owner.register(`serializer:-json-api`, Serializer);
|
|
3677
|
-
serializer = owner.lookup(`serializer:-json-api`);
|
|
3678
|
-
deprecateTestRegistration('serializer', '-json-api');
|
|
3679
|
-
} else if (normalizedModelName === '-rest') {
|
|
3680
|
-
const Serializer = require('@ember-data/serializer/rest').default;
|
|
3681
|
-
owner.register(`serializer:-rest`, Serializer);
|
|
3682
|
-
serializer = owner.lookup(`serializer:-rest`);
|
|
3683
|
-
deprecateTestRegistration('serializer', '-rest');
|
|
3684
|
-
} else if (normalizedModelName === '-default') {
|
|
3685
|
-
const Serializer = require('@ember-data/serializer/json').default;
|
|
3686
|
-
owner.register(`serializer:-default`, Serializer);
|
|
3687
|
-
serializer = owner.lookup(`serializer:-default`);
|
|
3688
|
-
serializer && deprecateTestRegistration('serializer', '-default');
|
|
3689
|
-
}
|
|
3690
|
-
}
|
|
3691
|
-
}
|
|
3692
|
-
|
|
3693
3120
|
if (serializer !== undefined) {
|
|
3694
3121
|
set(serializer, 'store', this);
|
|
3695
3122
|
_serializerCache[normalizedModelName] = serializer;
|
|
@@ -3705,105 +3132,10 @@ abstract class CoreStore extends Service {
|
|
|
3705
3132
|
return serializer;
|
|
3706
3133
|
}
|
|
3707
3134
|
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
let adapter = this.adapterFor(modelName);
|
|
3713
|
-
serializerName = get(adapter, 'defaultSerializer');
|
|
3714
|
-
|
|
3715
|
-
deprecate(
|
|
3716
|
-
`store.serializerFor("${modelName}") resolved the "${serializerName}" serializer via the deprecated \`adapter.defaultSerializer\` property.\n\n\tPreviously, if no application or type-specific serializer was specified, the store would attempt to lookup a serializer via the \`defaultSerializer\` property on the type's adapter. This behavior is deprecated in favor of explicitly defining a type-specific serializer or application serializer`,
|
|
3717
|
-
!serializerName,
|
|
3718
|
-
{
|
|
3719
|
-
id: 'ember-data:default-serializer',
|
|
3720
|
-
until: '4.0',
|
|
3721
|
-
url: 'https://deprecations.emberjs.com/ember-data/v3.x/#toc_ember-data-default-serializers',
|
|
3722
|
-
for: '@ember-data/store',
|
|
3723
|
-
since: {
|
|
3724
|
-
available: '3.15',
|
|
3725
|
-
enabled: '3.15',
|
|
3726
|
-
},
|
|
3727
|
-
}
|
|
3728
|
-
);
|
|
3729
|
-
|
|
3730
|
-
serializer = serializerName
|
|
3731
|
-
? _serializerCache[serializerName] || owner.lookup(`serializer:${serializerName}`)
|
|
3732
|
-
: undefined;
|
|
3733
|
-
}
|
|
3734
|
-
|
|
3735
|
-
if (DEPRECATE_LEGACY_TEST_REGISTRATIONS) {
|
|
3736
|
-
// in production this is handled by the re-export
|
|
3737
|
-
if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_SERIALIZER_PACKAGE && serializer === undefined) {
|
|
3738
|
-
if (serializerName === '-json-api') {
|
|
3739
|
-
const Serializer = require('@ember-data/serializer/json-api').default;
|
|
3740
|
-
owner.register(`serializer:-json-api`, Serializer);
|
|
3741
|
-
serializer = owner.lookup(`serializer:-json-api`);
|
|
3742
|
-
deprecateTestRegistration('serializer', '-json-api');
|
|
3743
|
-
} else if (serializerName === '-rest') {
|
|
3744
|
-
const Serializer = require('@ember-data/serializer/rest').default;
|
|
3745
|
-
owner.register(`serializer:-rest`, Serializer);
|
|
3746
|
-
serializer = owner.lookup(`serializer:-rest`);
|
|
3747
|
-
deprecateTestRegistration('serializer', '-rest');
|
|
3748
|
-
} else if (serializerName === '-default') {
|
|
3749
|
-
const Serializer = require('@ember-data/serializer/json').default;
|
|
3750
|
-
owner.register(`serializer:-default`, Serializer);
|
|
3751
|
-
serializer = owner.lookup(`serializer:-default`);
|
|
3752
|
-
serializer && deprecateTestRegistration('serializer', '-default');
|
|
3753
|
-
}
|
|
3754
|
-
}
|
|
3755
|
-
|
|
3756
|
-
if (serializer !== undefined) {
|
|
3757
|
-
set(serializer, 'store', this);
|
|
3758
|
-
_serializerCache[normalizedModelName] = serializer;
|
|
3759
|
-
_serializerCache[serializerName] = serializer;
|
|
3760
|
-
return serializer;
|
|
3761
|
-
}
|
|
3762
|
-
}
|
|
3763
|
-
|
|
3764
|
-
if (DEPRECATE_DEFAULT_SERIALIZER) {
|
|
3765
|
-
// final fallback, no model specific serializer, no application serializer, no
|
|
3766
|
-
// `serializer` property on store: use the convenience JSONSerializer
|
|
3767
|
-
serializer = _serializerCache['-default'] || owner.lookup('serializer:-default');
|
|
3768
|
-
if (DEBUG && HAS_EMBER_DATA_PACKAGE && HAS_SERIALIZER_PACKAGE && serializer === undefined) {
|
|
3769
|
-
const JSONSerializer = require('@ember-data/serializer/json').default;
|
|
3770
|
-
owner.register('serializer:-default', JSONSerializer);
|
|
3771
|
-
serializer = owner.lookup('serializer:-default');
|
|
3772
|
-
|
|
3773
|
-
serializer && deprecateTestRegistration('serializer', '-default');
|
|
3774
|
-
}
|
|
3775
|
-
|
|
3776
|
-
deprecate(
|
|
3777
|
-
`store.serializerFor("${modelName}") resolved the "-default" serializer via the deprecated "-default" lookup fallback.\n\n\tPreviously, when no type-specific serializer, application serializer, or adapter.defaultSerializer had been defined by the app, the "-default" serializer would be used which defaulted to the \`JSONSerializer\`. This behavior is deprecated in favor of explicitly defining an application or type-specific serializer`,
|
|
3778
|
-
!serializer,
|
|
3779
|
-
{
|
|
3780
|
-
id: 'ember-data:default-serializer',
|
|
3781
|
-
until: '4.0',
|
|
3782
|
-
url: 'https://deprecations.emberjs.com/ember-data/v3.x/#toc_ember-data-default-serializers',
|
|
3783
|
-
for: '@ember-data/store',
|
|
3784
|
-
since: {
|
|
3785
|
-
available: '3.15',
|
|
3786
|
-
enabled: '3.15',
|
|
3787
|
-
},
|
|
3788
|
-
}
|
|
3789
|
-
);
|
|
3790
|
-
|
|
3791
|
-
assert(
|
|
3792
|
-
`No serializer was found for '${modelName}' and no 'application' serializer was found as a fallback`,
|
|
3793
|
-
serializer !== undefined
|
|
3794
|
-
);
|
|
3795
|
-
|
|
3796
|
-
set(serializer, 'store', this);
|
|
3797
|
-
_serializerCache[normalizedModelName] = serializer;
|
|
3798
|
-
_serializerCache['-default'] = serializer;
|
|
3799
|
-
|
|
3800
|
-
return serializer;
|
|
3801
|
-
} else {
|
|
3802
|
-
assert(
|
|
3803
|
-
`No serializer was found for '${modelName}' and no 'application' serializer was found as a fallback`,
|
|
3804
|
-
serializer !== undefined
|
|
3805
|
-
);
|
|
3806
|
-
}
|
|
3135
|
+
assert(
|
|
3136
|
+
`No serializer was found for '${modelName}' and no 'application' serializer was found as a fallback`,
|
|
3137
|
+
serializer !== undefined
|
|
3138
|
+
);
|
|
3807
3139
|
}
|
|
3808
3140
|
|
|
3809
3141
|
destroy() {
|
|
@@ -3837,7 +3169,7 @@ abstract class CoreStore extends Service {
|
|
|
3837
3169
|
super.willDestroy();
|
|
3838
3170
|
this.recordArrayManager.destroy();
|
|
3839
3171
|
|
|
3840
|
-
|
|
3172
|
+
this.identifierCache.destroy();
|
|
3841
3173
|
|
|
3842
3174
|
// destroy the graph before unloadAll
|
|
3843
3175
|
// since then we avoid churning relationships
|
|
@@ -3897,155 +3229,23 @@ abstract class CoreStore extends Service {
|
|
|
3897
3229
|
}
|
|
3898
3230
|
}
|
|
3899
3231
|
|
|
3900
|
-
if (DEPRECATE_DEFAULT_ADAPTER) {
|
|
3901
|
-
defineProperty(
|
|
3902
|
-
CoreStore.prototype,
|
|
3903
|
-
'defaultAdapter',
|
|
3904
|
-
computed('adapter', function () {
|
|
3905
|
-
deprecate(
|
|
3906
|
-
`store.adapterFor(modelName) resolved the ("${
|
|
3907
|
-
this.adapter || '-json-api'
|
|
3908
|
-
}") 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.`,
|
|
3909
|
-
false,
|
|
3910
|
-
{
|
|
3911
|
-
id: 'ember-data:default-adapter',
|
|
3912
|
-
until: '4.0',
|
|
3913
|
-
url: 'https://deprecations.emberjs.com/ember-data/v3.x/#toc_ember-data-default-adapter',
|
|
3914
|
-
for: '@ember-data/store',
|
|
3915
|
-
since: {
|
|
3916
|
-
available: '3.15',
|
|
3917
|
-
enabled: '3.15',
|
|
3918
|
-
},
|
|
3919
|
-
}
|
|
3920
|
-
);
|
|
3921
|
-
let adapter = this.adapter || '-json-api';
|
|
3922
|
-
|
|
3923
|
-
assert(
|
|
3924
|
-
'You tried to set `adapter` property to an instance of `Adapter`, where it should be a name',
|
|
3925
|
-
typeof adapter === 'string'
|
|
3926
|
-
);
|
|
3927
|
-
|
|
3928
|
-
return this.adapterFor(adapter);
|
|
3929
|
-
})
|
|
3930
|
-
);
|
|
3931
|
-
}
|
|
3932
|
-
|
|
3933
3232
|
export default CoreStore;
|
|
3934
3233
|
|
|
3935
|
-
function _commit(adapter, store, operation, snapshot) {
|
|
3936
|
-
let internalModel = snapshot._internalModel;
|
|
3937
|
-
let modelName = snapshot.modelName;
|
|
3938
|
-
let modelClass = store.modelFor(modelName);
|
|
3939
|
-
assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter);
|
|
3940
|
-
assert(
|
|
3941
|
-
`You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`,
|
|
3942
|
-
typeof adapter[operation] === 'function'
|
|
3943
|
-
);
|
|
3944
|
-
|
|
3945
|
-
let promise = Promise.resolve().then(() => adapter[operation](store, modelClass, snapshot));
|
|
3946
|
-
let serializer = store.serializerFor(modelName);
|
|
3947
|
-
let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`;
|
|
3948
|
-
|
|
3949
|
-
promise = guardDestroyedStore(promise, store, label);
|
|
3950
|
-
promise = _guard(promise, _bind(_objectIsAlive, internalModel));
|
|
3951
|
-
|
|
3952
|
-
return promise.then(
|
|
3953
|
-
(adapterPayload) => {
|
|
3954
|
-
/*
|
|
3955
|
-
Note to future spelunkers hoping to optimize.
|
|
3956
|
-
We rely on this `run` to create a run loop if needed
|
|
3957
|
-
that `store._push` and `store.didSaveRecord` will both share.
|
|
3958
|
-
|
|
3959
|
-
We use `join` because it is often the case that we
|
|
3960
|
-
have an outer run loop available still from the first
|
|
3961
|
-
call to `store._push`;
|
|
3962
|
-
*/
|
|
3963
|
-
store._backburner.join(() => {
|
|
3964
|
-
let payload, data, sideloaded;
|
|
3965
|
-
if (adapterPayload) {
|
|
3966
|
-
payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, snapshot.id, operation);
|
|
3967
|
-
if (payload.included) {
|
|
3968
|
-
sideloaded = payload.included;
|
|
3969
|
-
}
|
|
3970
|
-
data = payload.data;
|
|
3971
|
-
}
|
|
3972
|
-
store.didSaveRecord(internalModel, { data }, operation);
|
|
3973
|
-
// seems risky, but if the tests pass might be fine?
|
|
3974
|
-
if (sideloaded) {
|
|
3975
|
-
store._push({ data: null, included: sideloaded });
|
|
3976
|
-
}
|
|
3977
|
-
});
|
|
3978
|
-
|
|
3979
|
-
return internalModel;
|
|
3980
|
-
},
|
|
3981
|
-
function (error) {
|
|
3982
|
-
if (error && error.isAdapterError === true && error.code === 'InvalidError') {
|
|
3983
|
-
let parsedErrors;
|
|
3984
|
-
|
|
3985
|
-
if (typeof serializer.extractErrors === 'function') {
|
|
3986
|
-
parsedErrors = serializer.extractErrors(store, modelClass, error, snapshot.id);
|
|
3987
|
-
} else {
|
|
3988
|
-
parsedErrors = errorsArrayToHash(error.errors);
|
|
3989
|
-
}
|
|
3990
|
-
|
|
3991
|
-
store.recordWasInvalid(internalModel, parsedErrors, error);
|
|
3992
|
-
} else {
|
|
3993
|
-
store.recordWasError(internalModel, error);
|
|
3994
|
-
}
|
|
3995
|
-
|
|
3996
|
-
throw error;
|
|
3997
|
-
},
|
|
3998
|
-
label
|
|
3999
|
-
);
|
|
4000
|
-
}
|
|
4001
|
-
|
|
4002
3234
|
let assertDestroyingStore: Function;
|
|
4003
3235
|
let assertDestroyedStoreOnly: Function;
|
|
4004
3236
|
|
|
4005
3237
|
if (DEBUG) {
|
|
4006
3238
|
assertDestroyingStore = function assertDestroyedStore(store, method) {
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
{
|
|
4012
|
-
id: 'ember-data:method-calls-on-destroyed-store',
|
|
4013
|
-
until: '3.8',
|
|
4014
|
-
for: '@ember-data/store',
|
|
4015
|
-
since: {
|
|
4016
|
-
available: '3.8',
|
|
4017
|
-
enabled: '3.8',
|
|
4018
|
-
},
|
|
4019
|
-
}
|
|
4020
|
-
);
|
|
4021
|
-
} else {
|
|
4022
|
-
assert(
|
|
4023
|
-
`Attempted to call store.${method}(), but the store instance has already been destroyed.`,
|
|
4024
|
-
!(store.isDestroying || store.isDestroyed)
|
|
4025
|
-
);
|
|
4026
|
-
}
|
|
3239
|
+
assert(
|
|
3240
|
+
`Attempted to call store.${method}(), but the store instance has already been destroyed.`,
|
|
3241
|
+
!(store.isDestroying || store.isDestroyed)
|
|
3242
|
+
);
|
|
4027
3243
|
};
|
|
4028
3244
|
assertDestroyedStoreOnly = function assertDestroyedStoreOnly(store, method) {
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
{
|
|
4034
|
-
id: 'ember-data:method-calls-on-destroyed-store',
|
|
4035
|
-
until: '3.8',
|
|
4036
|
-
for: '@ember-data/store',
|
|
4037
|
-
since: {
|
|
4038
|
-
available: '3.8',
|
|
4039
|
-
enabled: '3.8',
|
|
4040
|
-
},
|
|
4041
|
-
}
|
|
4042
|
-
);
|
|
4043
|
-
} else {
|
|
4044
|
-
assert(
|
|
4045
|
-
`Attempted to call store.${method}(), but the store instance has already been destroyed.`,
|
|
4046
|
-
!store.isDestroyed
|
|
4047
|
-
);
|
|
4048
|
-
}
|
|
3245
|
+
assert(
|
|
3246
|
+
`Attempted to call store.${method}(), but the store instance has already been destroyed.`,
|
|
3247
|
+
!store.isDestroyed
|
|
3248
|
+
);
|
|
4049
3249
|
};
|
|
4050
3250
|
}
|
|
4051
3251
|
|
|
@@ -4060,7 +3260,7 @@ if (DEBUG) {
|
|
|
4060
3260
|
* @return {boolean}
|
|
4061
3261
|
*/
|
|
4062
3262
|
function areAllInverseRecordsLoaded(store: CoreStore, resource: JsonApiRelationship): boolean {
|
|
4063
|
-
const cache =
|
|
3263
|
+
const cache = store.identifierCache;
|
|
4064
3264
|
|
|
4065
3265
|
if (Array.isArray(resource.data)) {
|
|
4066
3266
|
// treat as collection
|