@ember-data/store 4.4.0-beta.1 → 4.5.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/addon/-private/system/core-store.ts +136 -147
- package/addon/-private/system/ds-model-store.ts +1 -10
- package/addon/-private/system/fetch-manager.ts +48 -21
- package/addon/-private/system/model/internal-model.ts +263 -192
- package/addon/-private/system/model/states.js +5 -41
- package/addon/-private/system/{promise-proxies.js → promise-proxies.ts} +31 -21
- package/addon/-private/system/promise-proxy-base.js +7 -0
- package/addon/-private/system/{record-array-manager.js → record-array-manager.ts} +87 -60
- package/addon/-private/system/record-arrays/adapter-populated-record-array.ts +129 -0
- package/addon/-private/system/record-arrays/{record-array.js → record-array.ts} +96 -75
- package/addon/-private/system/record-data-for.ts +2 -0
- package/addon/-private/system/references/belongs-to.ts +3 -2
- package/addon/-private/system/references/has-many.ts +4 -2
- package/addon/-private/system/schema-definition-service.ts +2 -2
- package/addon/-private/system/snapshot-record-array.ts +12 -11
- package/addon/-private/system/snapshot.ts +24 -7
- package/addon/-private/system/store/common.js +24 -1
- package/addon/-private/system/store/finders.js +53 -5
- package/addon/-private/system/store/internal-model-factory.ts +8 -7
- package/addon/-private/system/store/record-data-store-wrapper.ts +7 -2
- package/addon/-private/system/store/serializer-response.ts +85 -0
- package/addon/-private/ts-interfaces/ds-model.ts +15 -7
- package/addon/-private/ts-interfaces/ember-data-json-api.ts +3 -0
- package/addon/-private/ts-interfaces/minimum-adapter-interface.ts +19 -20
- package/addon/-private/ts-interfaces/minimum-serializer-interface.ts +27 -6
- package/addon/-private/ts-interfaces/record-data.ts +4 -1
- package/addon/-private/ts-interfaces/record-instance.ts +3 -1
- package/addon/-private/ts-interfaces/store.ts +1 -0
- package/addon/-private/utils/promise-record.ts +3 -3
- package/index.js +3 -0
- package/package.json +8 -7
- package/addon/-private/system/record-arrays/adapter-populated-record-array.js +0 -95
- package/addon/-private/system/store/serializer-response.js +0 -71
|
@@ -13,19 +13,14 @@ import { isNone, isPresent, typeOf } from '@ember/utils';
|
|
|
13
13
|
import { DEBUG } from '@glimmer/env';
|
|
14
14
|
import Ember from 'ember';
|
|
15
15
|
|
|
16
|
-
import
|
|
17
|
-
import { all, default as RSVP,
|
|
16
|
+
import { importSync } from '@embroider/macros';
|
|
17
|
+
import { all, default as RSVP, resolve } from 'rsvp';
|
|
18
18
|
|
|
19
19
|
import { HAS_RECORD_DATA_PACKAGE } from '@ember-data/private-build-infra';
|
|
20
|
-
import type {
|
|
21
|
-
BelongsToRelationship,
|
|
22
|
-
ManyRelationship,
|
|
23
|
-
RecordData as RecordDataClass,
|
|
24
|
-
} from '@ember-data/record-data/-private';
|
|
20
|
+
import type { ManyRelationship, RecordData as RecordDataClass } from '@ember-data/record-data/-private';
|
|
25
21
|
import type { RelationshipState } from '@ember-data/record-data/-private/graph/-state';
|
|
26
22
|
|
|
27
23
|
import { IdentifierCache } from '../identifiers/cache';
|
|
28
|
-
import type { DSModel } from '../ts-interfaces/ds-model';
|
|
29
24
|
import type {
|
|
30
25
|
CollectionResourceDocument,
|
|
31
26
|
EmptyResourceDocument,
|
|
@@ -39,11 +34,12 @@ import type {
|
|
|
39
34
|
StableExistingRecordIdentifier,
|
|
40
35
|
StableRecordIdentifier,
|
|
41
36
|
} from '../ts-interfaces/identifier';
|
|
42
|
-
import
|
|
37
|
+
import { MinimumAdapterInterface } from '../ts-interfaces/minimum-adapter-interface';
|
|
38
|
+
import type { MinimumSerializerInterface } from '../ts-interfaces/minimum-serializer-interface';
|
|
43
39
|
import type { RecordData } from '../ts-interfaces/record-data';
|
|
44
40
|
import type { JsonApiRelationship } from '../ts-interfaces/record-data-json-api';
|
|
45
41
|
import type { RecordDataRecordWrapper } from '../ts-interfaces/record-data-record-wrapper';
|
|
46
|
-
import type { AttributesSchema } from '../ts-interfaces/record-data-schemas';
|
|
42
|
+
import type { AttributesSchema, RelationshipsSchema } from '../ts-interfaces/record-data-schemas';
|
|
47
43
|
import type { RecordInstance } from '../ts-interfaces/record-instance';
|
|
48
44
|
import type { SchemaDefinitionService } from '../ts-interfaces/schema-definition-service';
|
|
49
45
|
import type { FindOptions } from '../ts-interfaces/store';
|
|
@@ -62,8 +58,10 @@ import {
|
|
|
62
58
|
import type ShimModelClass from './model/shim-model-class';
|
|
63
59
|
import { getShimClass } from './model/shim-model-class';
|
|
64
60
|
import normalizeModelName from './normalize-model-name';
|
|
61
|
+
import type { PromiseArray, PromiseObject } from './promise-proxies';
|
|
65
62
|
import { promiseArray, promiseObject } from './promise-proxies';
|
|
66
63
|
import RecordArrayManager from './record-array-manager';
|
|
64
|
+
import { AdapterPopulatedRecordArray, RecordArray } from './record-arrays';
|
|
67
65
|
import { setRecordDataFor } from './record-data-for';
|
|
68
66
|
import NotificationManager from './record-notification-manager';
|
|
69
67
|
import type { BelongsToReference, HasManyReference } from './references';
|
|
@@ -84,7 +82,6 @@ let _RecordData: RecordDataConstruct | undefined;
|
|
|
84
82
|
|
|
85
83
|
const { ENV } = Ember;
|
|
86
84
|
type AsyncTrackingToken = Readonly<{ label: string; trace: Error | string }>;
|
|
87
|
-
type PromiseArray<T> = Promise<T[]>;
|
|
88
85
|
|
|
89
86
|
const RECORD_REFERENCES = new WeakCache<StableRecordIdentifier, RecordReference>(DEBUG ? 'reference' : '');
|
|
90
87
|
|
|
@@ -96,6 +93,11 @@ function freeze<T>(obj: T): T {
|
|
|
96
93
|
return obj;
|
|
97
94
|
}
|
|
98
95
|
|
|
96
|
+
export interface CreateRecordProperties {
|
|
97
|
+
id?: string | null;
|
|
98
|
+
[key: string]: unknown;
|
|
99
|
+
}
|
|
100
|
+
|
|
99
101
|
/**
|
|
100
102
|
The store contains all of the data for records loaded from the server.
|
|
101
103
|
It is also responsible for creating instances of `Model` that wrap
|
|
@@ -172,36 +174,31 @@ function freeze<T>(obj: T): T {
|
|
|
172
174
|
|
|
173
175
|
abstract class CoreStore extends Service {
|
|
174
176
|
/**
|
|
177
|
+
* Ember Data uses several specialized micro-queues for organizing
|
|
178
|
+
and coalescing similar async work.
|
|
179
|
+
|
|
180
|
+
These queues are currently controlled by a flush scheduled into
|
|
181
|
+
ember-data's custom backburner instance.
|
|
182
|
+
*
|
|
175
183
|
* EmberData specific backburner instance
|
|
176
184
|
* @property _backburner
|
|
177
185
|
* @private
|
|
178
186
|
*/
|
|
179
|
-
|
|
180
|
-
|
|
187
|
+
declare _backburner: Backburner;
|
|
188
|
+
declare recordArrayManager: RecordArrayManager;
|
|
181
189
|
|
|
182
190
|
declare _notificationManager: NotificationManager;
|
|
183
191
|
declare identifierCache: IdentifierCache;
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
/*
|
|
189
|
-
Ember Data uses several specialized micro-queues for organizing
|
|
190
|
-
and coalescing similar async work.
|
|
191
|
-
|
|
192
|
-
These queues are currently controlled by a flush scheduled into
|
|
193
|
-
ember-data's custom backburner instance.
|
|
194
|
-
*/
|
|
195
|
-
// used for coalescing internal model updates
|
|
196
|
-
private _updatedInternalModels: InternalModel[] = [];
|
|
197
|
-
|
|
192
|
+
declare _adapterCache: Dict<MinimumAdapterInterface & { store: CoreStore }>;
|
|
193
|
+
declare _serializerCache: Dict<MinimumSerializerInterface & { store: CoreStore }>;
|
|
194
|
+
declare _storeWrapper: RecordDataStoreWrapper;
|
|
198
195
|
declare _fetchManager: FetchManager;
|
|
199
196
|
declare _schemaDefinitionService: SchemaDefinitionService;
|
|
200
197
|
|
|
201
198
|
// DEBUG-only properties
|
|
202
199
|
declare _trackedAsyncRequests: AsyncTrackingToken[];
|
|
203
|
-
shouldTrackAsyncRequests: boolean
|
|
204
|
-
generateStackTracesForTrackedRequests: boolean
|
|
200
|
+
declare shouldTrackAsyncRequests: boolean;
|
|
201
|
+
declare generateStackTracesForTrackedRequests: boolean;
|
|
205
202
|
declare _trackAsyncRequestStart: (str: string) => void;
|
|
206
203
|
declare _trackAsyncRequestEnd: (token: AsyncTrackingToken) => void;
|
|
207
204
|
declare __asyncWaiter: () => boolean;
|
|
@@ -252,6 +249,11 @@ abstract class CoreStore extends Service {
|
|
|
252
249
|
*/
|
|
253
250
|
constructor() {
|
|
254
251
|
super(...arguments);
|
|
252
|
+
this._adapterCache = Object.create(null);
|
|
253
|
+
this._serializerCache = Object.create(null);
|
|
254
|
+
this._storeWrapper = new RecordDataStoreWrapper(this);
|
|
255
|
+
this._backburner = edBackburner;
|
|
256
|
+
this.recordArrayManager = new RecordArrayManager({ store: this });
|
|
255
257
|
|
|
256
258
|
RECORD_REFERENCES._generator = (identifier) => {
|
|
257
259
|
return new RecordReference(this, identifier);
|
|
@@ -390,19 +392,14 @@ abstract class CoreStore extends Service {
|
|
|
390
392
|
recordDataFor: (identifier: RecordIdentifier) => RecordDataRecordWrapper,
|
|
391
393
|
notificationManager: NotificationManager
|
|
392
394
|
): RecordInstance;
|
|
393
|
-
|
|
394
395
|
abstract teardownRecord(record: RecordInstance): void;
|
|
396
|
+
abstract getSchemaDefinitionService(): SchemaDefinitionService;
|
|
395
397
|
|
|
396
|
-
_internalDeleteRecord(internalModel: InternalModel) {
|
|
397
|
-
internalModel.deleteRecord();
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
// FeatureFlagged in the DSModelStore claas
|
|
401
398
|
_attributesDefinitionFor(identifier: RecordIdentifier | { type: string }): AttributesSchema {
|
|
402
399
|
return this.getSchemaDefinitionService().attributesDefinitionFor(identifier);
|
|
403
400
|
}
|
|
404
401
|
|
|
405
|
-
_relationshipsDefinitionFor(identifier: RecordIdentifier | { type: string }) {
|
|
402
|
+
_relationshipsDefinitionFor(identifier: RecordIdentifier | { type: string }): RelationshipsSchema {
|
|
406
403
|
return this.getSchemaDefinitionService().relationshipsDefinitionFor(identifier);
|
|
407
404
|
}
|
|
408
405
|
|
|
@@ -410,11 +407,6 @@ abstract class CoreStore extends Service {
|
|
|
410
407
|
this._schemaDefinitionService = schema;
|
|
411
408
|
}
|
|
412
409
|
|
|
413
|
-
getSchemaDefinitionService(): SchemaDefinitionService {
|
|
414
|
-
return this._schemaDefinitionService;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// TODO Double check this return value is correct
|
|
418
410
|
_relationshipMetaFor(modelName: string, id: string | null, key: string) {
|
|
419
411
|
return this._relationshipsDefinitionFor({ type: modelName })[key];
|
|
420
412
|
}
|
|
@@ -499,7 +491,7 @@ abstract class CoreStore extends Service {
|
|
|
499
491
|
newly created record.
|
|
500
492
|
@return {Model} record
|
|
501
493
|
*/
|
|
502
|
-
createRecord(modelName, inputProperties) {
|
|
494
|
+
createRecord(modelName: string, inputProperties: CreateRecordProperties): RecordInstance {
|
|
503
495
|
if (DEBUG) {
|
|
504
496
|
assertDestroyingStore(this, 'createRecord');
|
|
505
497
|
}
|
|
@@ -553,7 +545,7 @@ abstract class CoreStore extends Service {
|
|
|
553
545
|
@param {Object} properties from the new record
|
|
554
546
|
@return {String} if the adapter can generate one, an ID
|
|
555
547
|
*/
|
|
556
|
-
_generateId(modelName, properties) {
|
|
548
|
+
_generateId(modelName: string, properties: CreateRecordProperties): string | null {
|
|
557
549
|
let adapter = this.adapterFor(modelName);
|
|
558
550
|
|
|
559
551
|
if (adapter && adapter.generateIdForRecord) {
|
|
@@ -584,7 +576,7 @@ abstract class CoreStore extends Service {
|
|
|
584
576
|
@public
|
|
585
577
|
@param {Model} record
|
|
586
578
|
*/
|
|
587
|
-
deleteRecord(record) {
|
|
579
|
+
deleteRecord(record: RecordInstance): void {
|
|
588
580
|
if (DEBUG) {
|
|
589
581
|
assertDestroyingStore(this, 'deleteRecord');
|
|
590
582
|
}
|
|
@@ -615,7 +607,7 @@ abstract class CoreStore extends Service {
|
|
|
615
607
|
@public
|
|
616
608
|
@param {Model} record
|
|
617
609
|
*/
|
|
618
|
-
unloadRecord(record) {
|
|
610
|
+
unloadRecord(record: RecordInstance): void {
|
|
619
611
|
if (DEBUG) {
|
|
620
612
|
assertDestroyingStore(this, 'unloadRecord');
|
|
621
613
|
}
|
|
@@ -640,7 +632,7 @@ abstract class CoreStore extends Service {
|
|
|
640
632
|
@return {Promise} promise
|
|
641
633
|
@private
|
|
642
634
|
*/
|
|
643
|
-
find(modelName, id, options) {
|
|
635
|
+
find(modelName: string, id: string | number, options?): PromiseObject<RecordInstance> {
|
|
644
636
|
if (DEBUG) {
|
|
645
637
|
assertDestroyingStore(this, 'find');
|
|
646
638
|
}
|
|
@@ -1039,13 +1031,13 @@ abstract class CoreStore extends Service {
|
|
|
1039
1031
|
@param {Object} [options] - if the first param is a string this will be the optional options for the request. See examples for available options.
|
|
1040
1032
|
@return {Promise} promise
|
|
1041
1033
|
*/
|
|
1042
|
-
findRecord(resource: string, id: string | number, options?: FindOptions):
|
|
1043
|
-
findRecord(resource: ResourceIdentifierObject, id?: FindOptions):
|
|
1034
|
+
findRecord(resource: string, id: string | number, options?: FindOptions): PromiseObject<RecordInstance>;
|
|
1035
|
+
findRecord(resource: ResourceIdentifierObject, id?: FindOptions): PromiseObject<RecordInstance>;
|
|
1044
1036
|
findRecord(
|
|
1045
1037
|
resource: string | ResourceIdentifierObject,
|
|
1046
1038
|
id?: string | number | FindOptions,
|
|
1047
1039
|
options?: FindOptions
|
|
1048
|
-
):
|
|
1040
|
+
): PromiseObject<RecordInstance> {
|
|
1049
1041
|
if (DEBUG) {
|
|
1050
1042
|
assertDestroyingStore(this, 'findRecord');
|
|
1051
1043
|
}
|
|
@@ -1070,7 +1062,10 @@ abstract class CoreStore extends Service {
|
|
|
1070
1062
|
options = options || {};
|
|
1071
1063
|
|
|
1072
1064
|
if (!internalModel.currentState.isLoaded) {
|
|
1073
|
-
return
|
|
1065
|
+
return promiseRecord(
|
|
1066
|
+
this._findByInternalModel(internalModel, options),
|
|
1067
|
+
`DS: Store#findRecord ${internalModel.identifier}`
|
|
1068
|
+
);
|
|
1074
1069
|
}
|
|
1075
1070
|
|
|
1076
1071
|
let fetchedInternalModel = this._findRecord(internalModel, options);
|
|
@@ -1078,7 +1073,7 @@ abstract class CoreStore extends Service {
|
|
|
1078
1073
|
return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${internalModel.identifier}`);
|
|
1079
1074
|
}
|
|
1080
1075
|
|
|
1081
|
-
_findRecord(internalModel: InternalModel, options: FindOptions) {
|
|
1076
|
+
_findRecord(internalModel: InternalModel, options: FindOptions): Promise<InternalModel> {
|
|
1082
1077
|
// Refetch if the reload option is passed
|
|
1083
1078
|
if (options.reload) {
|
|
1084
1079
|
return this._scheduleFetch(internalModel, options);
|
|
@@ -1097,7 +1092,7 @@ abstract class CoreStore extends Service {
|
|
|
1097
1092
|
}
|
|
1098
1093
|
|
|
1099
1094
|
if (options.backgroundReload === false) {
|
|
1100
|
-
return
|
|
1095
|
+
return resolve(internalModel);
|
|
1101
1096
|
}
|
|
1102
1097
|
|
|
1103
1098
|
// Trigger the background refetch if backgroundReload option is passed
|
|
@@ -1110,25 +1105,20 @@ abstract class CoreStore extends Service {
|
|
|
1110
1105
|
}
|
|
1111
1106
|
|
|
1112
1107
|
// Return the cached record
|
|
1113
|
-
return
|
|
1108
|
+
return resolve(internalModel);
|
|
1114
1109
|
}
|
|
1115
1110
|
|
|
1116
|
-
_findByInternalModel(internalModel: InternalModel, options: FindOptions = {}) {
|
|
1111
|
+
_findByInternalModel(internalModel: InternalModel, options: FindOptions = {}): Promise<InternalModel> {
|
|
1117
1112
|
if (options.preload) {
|
|
1118
1113
|
this._backburner.join(() => {
|
|
1119
1114
|
internalModel.preloadData(options.preload);
|
|
1120
1115
|
});
|
|
1121
1116
|
}
|
|
1122
1117
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
return promiseRecord(
|
|
1126
|
-
fetchedInternalModel,
|
|
1127
|
-
`DS: Store#findRecord ${internalModel.modelName} with id: ${internalModel.id}`
|
|
1128
|
-
);
|
|
1118
|
+
return this._findEmptyInternalModel(internalModel, options);
|
|
1129
1119
|
}
|
|
1130
1120
|
|
|
1131
|
-
_findEmptyInternalModel(internalModel: InternalModel, options: FindOptions) {
|
|
1121
|
+
_findEmptyInternalModel(internalModel: InternalModel, options: FindOptions): Promise<InternalModel> {
|
|
1132
1122
|
if (internalModel.currentState.isEmpty) {
|
|
1133
1123
|
return this._scheduleFetch(internalModel, options);
|
|
1134
1124
|
}
|
|
@@ -1136,12 +1126,12 @@ abstract class CoreStore extends Service {
|
|
|
1136
1126
|
if (internalModel.currentState.isLoading) {
|
|
1137
1127
|
let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier, options);
|
|
1138
1128
|
if (pendingRequest) {
|
|
1139
|
-
return pendingRequest.then(() =>
|
|
1129
|
+
return pendingRequest.then(() => resolve(internalModel));
|
|
1140
1130
|
}
|
|
1141
1131
|
return this._scheduleFetch(internalModel, options);
|
|
1142
1132
|
}
|
|
1143
1133
|
|
|
1144
|
-
return
|
|
1134
|
+
return resolve(internalModel);
|
|
1145
1135
|
}
|
|
1146
1136
|
|
|
1147
1137
|
/**
|
|
@@ -1182,10 +1172,10 @@ abstract class CoreStore extends Service {
|
|
|
1182
1172
|
fetches[i] = this._scheduleFetch(internalModels[i], options);
|
|
1183
1173
|
}
|
|
1184
1174
|
|
|
1185
|
-
return
|
|
1175
|
+
return all(fetches);
|
|
1186
1176
|
}
|
|
1187
1177
|
|
|
1188
|
-
_scheduleFetch(internalModel: InternalModel, options = {}):
|
|
1178
|
+
_scheduleFetch(internalModel: InternalModel, options = {}): Promise<InternalModel> {
|
|
1189
1179
|
let generateStackTrace = this.generateStackTracesForTrackedRequests;
|
|
1190
1180
|
// TODO remove this once we don't rely on state machine
|
|
1191
1181
|
internalModel.send('loadingData');
|
|
@@ -1376,7 +1366,7 @@ abstract class CoreStore extends Service {
|
|
|
1376
1366
|
@param options optional to include adapterOptions
|
|
1377
1367
|
@return {Promise} promise
|
|
1378
1368
|
*/
|
|
1379
|
-
_reloadRecord(internalModel, options):
|
|
1369
|
+
_reloadRecord(internalModel: InternalModel, options: FindOptions): Promise<InternalModel> {
|
|
1380
1370
|
options.isReloading = true;
|
|
1381
1371
|
let { id, modelName } = internalModel;
|
|
1382
1372
|
let adapter = this.adapterFor(modelName);
|
|
@@ -1385,7 +1375,7 @@ abstract class CoreStore extends Service {
|
|
|
1385
1375
|
assert(`You tried to reload a record but you have no adapter (for ${modelName})`, adapter);
|
|
1386
1376
|
assert(
|
|
1387
1377
|
`You tried to reload a record but your adapter does not implement 'findRecord'`,
|
|
1388
|
-
typeof adapter.findRecord === 'function'
|
|
1378
|
+
typeof adapter.findRecord === 'function'
|
|
1389
1379
|
);
|
|
1390
1380
|
|
|
1391
1381
|
return this._scheduleFetch(internalModel, options);
|
|
@@ -1472,7 +1462,7 @@ abstract class CoreStore extends Service {
|
|
|
1472
1462
|
finds[i] = this._findEmptyInternalModel(internalModels[i], options);
|
|
1473
1463
|
}
|
|
1474
1464
|
|
|
1475
|
-
return
|
|
1465
|
+
return all(finds);
|
|
1476
1466
|
}
|
|
1477
1467
|
|
|
1478
1468
|
/**
|
|
@@ -1514,12 +1504,12 @@ abstract class CoreStore extends Service {
|
|
|
1514
1504
|
_findHasManyByJsonApiResource(
|
|
1515
1505
|
resource,
|
|
1516
1506
|
parentInternalModel: InternalModel,
|
|
1517
|
-
relationship: ManyRelationship
|
|
1518
|
-
options
|
|
1519
|
-
):
|
|
1507
|
+
relationship: ManyRelationship,
|
|
1508
|
+
options?: Dict<unknown>
|
|
1509
|
+
): Promise<void | unknown[]> {
|
|
1520
1510
|
if (HAS_RECORD_DATA_PACKAGE) {
|
|
1521
1511
|
if (!resource) {
|
|
1522
|
-
return resolve(
|
|
1512
|
+
return resolve();
|
|
1523
1513
|
}
|
|
1524
1514
|
const { definition, state } = relationship;
|
|
1525
1515
|
let adapter = this.adapterFor(definition.type);
|
|
@@ -1564,7 +1554,7 @@ abstract class CoreStore extends Service {
|
|
|
1564
1554
|
|
|
1565
1555
|
// we were explicitly told we have no data and no links.
|
|
1566
1556
|
// TODO if the relationshipIsStale, should we hit the adapter anyway?
|
|
1567
|
-
return resolve(
|
|
1557
|
+
return resolve();
|
|
1568
1558
|
}
|
|
1569
1559
|
assert(`hasMany only works with the @ember-data/record-data package`);
|
|
1570
1560
|
}
|
|
@@ -1577,7 +1567,7 @@ abstract class CoreStore extends Service {
|
|
|
1577
1567
|
@param {Relationship} relationship
|
|
1578
1568
|
@return {Promise} promise
|
|
1579
1569
|
*/
|
|
1580
|
-
findBelongsTo(internalModel, link, relationship, options) {
|
|
1570
|
+
findBelongsTo(internalModel, link, relationship, options): Promise<InternalModel> {
|
|
1581
1571
|
if (DEBUG) {
|
|
1582
1572
|
assertDestroyingStore(this, 'findBelongsTo');
|
|
1583
1573
|
}
|
|
@@ -1595,19 +1585,25 @@ abstract class CoreStore extends Service {
|
|
|
1595
1585
|
return _findBelongsTo(adapter, this, internalModel, link, relationship, options);
|
|
1596
1586
|
}
|
|
1597
1587
|
|
|
1598
|
-
_fetchBelongsToLinkFromResource(
|
|
1588
|
+
_fetchBelongsToLinkFromResource(
|
|
1589
|
+
resource,
|
|
1590
|
+
parentInternalModel: InternalModel,
|
|
1591
|
+
relationshipMeta,
|
|
1592
|
+
options
|
|
1593
|
+
): Promise<InternalModel | null> {
|
|
1599
1594
|
if (!resource || !resource.links || !resource.links.related) {
|
|
1600
1595
|
// should we warn here, not sure cause its an internal method
|
|
1601
1596
|
return resolve(null);
|
|
1602
1597
|
}
|
|
1603
|
-
return this.findBelongsTo(parentInternalModel, resource.links.related, relationshipMeta, options)
|
|
1604
|
-
(internalModel) => {
|
|
1605
|
-
return internalModel ? internalModel.getRecord() : null;
|
|
1606
|
-
}
|
|
1607
|
-
);
|
|
1598
|
+
return this.findBelongsTo(parentInternalModel, resource.links.related, relationshipMeta, options);
|
|
1608
1599
|
}
|
|
1609
1600
|
|
|
1610
|
-
_findBelongsToByJsonApiResource(
|
|
1601
|
+
_findBelongsToByJsonApiResource(
|
|
1602
|
+
resource,
|
|
1603
|
+
parentInternalModel: InternalModel,
|
|
1604
|
+
relationshipMeta,
|
|
1605
|
+
options
|
|
1606
|
+
): Promise<InternalModel | null> {
|
|
1611
1607
|
if (!resource) {
|
|
1612
1608
|
return resolve(null);
|
|
1613
1609
|
}
|
|
@@ -1626,7 +1622,7 @@ abstract class CoreStore extends Service {
|
|
|
1626
1622
|
// short circuit if we are already loading
|
|
1627
1623
|
let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier, options);
|
|
1628
1624
|
if (pendingRequest) {
|
|
1629
|
-
return pendingRequest.then(() => internalModel
|
|
1625
|
+
return pendingRequest.then(() => internalModel);
|
|
1630
1626
|
}
|
|
1631
1627
|
}
|
|
1632
1628
|
|
|
@@ -1659,14 +1655,12 @@ abstract class CoreStore extends Service {
|
|
|
1659
1655
|
let resourceIsLocal = !localDataIsEmpty && resource.data.id === null;
|
|
1660
1656
|
|
|
1661
1657
|
if (internalModel && resourceIsLocal) {
|
|
1662
|
-
return resolve(internalModel
|
|
1658
|
+
return resolve(internalModel);
|
|
1663
1659
|
}
|
|
1664
1660
|
|
|
1665
1661
|
// fetch by data
|
|
1666
1662
|
if (internalModel && !localDataIsEmpty) {
|
|
1667
|
-
return this._scheduleFetch(internalModel, options)
|
|
1668
|
-
return internalModel.getRecord();
|
|
1669
|
-
});
|
|
1663
|
+
return this._scheduleFetch(internalModel, options);
|
|
1670
1664
|
}
|
|
1671
1665
|
|
|
1672
1666
|
// we were explicitly told we have no data and no links.
|
|
@@ -1725,7 +1719,7 @@ abstract class CoreStore extends Service {
|
|
|
1725
1719
|
@param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.query
|
|
1726
1720
|
@return {Promise} promise
|
|
1727
1721
|
*/
|
|
1728
|
-
query(modelName: string, query, options): PromiseArray<
|
|
1722
|
+
query(modelName: string, query, options): PromiseArray<RecordInstance, AdapterPopulatedRecordArray> {
|
|
1729
1723
|
if (DEBUG) {
|
|
1730
1724
|
assertDestroyingStore(this, 'query');
|
|
1731
1725
|
}
|
|
@@ -1743,10 +1737,10 @@ abstract class CoreStore extends Service {
|
|
|
1743
1737
|
}
|
|
1744
1738
|
|
|
1745
1739
|
let normalizedModelName = normalizeModelName(modelName);
|
|
1746
|
-
return this._query(normalizedModelName, query, null, adapterOptionsWrapper);
|
|
1740
|
+
return promiseArray(this._query(normalizedModelName, query, null, adapterOptionsWrapper));
|
|
1747
1741
|
}
|
|
1748
1742
|
|
|
1749
|
-
_query(modelName: string, query, array, options):
|
|
1743
|
+
_query(modelName: string, query, array, options): Promise<AdapterPopulatedRecordArray> {
|
|
1750
1744
|
assert(`You need to pass a model name to the store's query method`, isPresent(modelName));
|
|
1751
1745
|
assert(`You need to pass a query hash to the store's query method`, query);
|
|
1752
1746
|
assert(
|
|
@@ -1762,7 +1756,7 @@ abstract class CoreStore extends Service {
|
|
|
1762
1756
|
typeof adapter.query === 'function'
|
|
1763
1757
|
);
|
|
1764
1758
|
|
|
1765
|
-
return
|
|
1759
|
+
return _query(adapter, this, modelName, query, array, options) as unknown as Promise<AdapterPopulatedRecordArray>;
|
|
1766
1760
|
}
|
|
1767
1761
|
|
|
1768
1762
|
/**
|
|
@@ -1863,7 +1857,7 @@ abstract class CoreStore extends Service {
|
|
|
1863
1857
|
@param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.queryRecord
|
|
1864
1858
|
@return {Promise} promise which resolves with the found record or `null`
|
|
1865
1859
|
*/
|
|
1866
|
-
queryRecord(modelName, query, options) {
|
|
1860
|
+
queryRecord(modelName: string, query, options): PromiseObject<RecordInstance | null> {
|
|
1867
1861
|
if (DEBUG) {
|
|
1868
1862
|
assertDestroyingStore(this, 'queryRecord');
|
|
1869
1863
|
}
|
|
@@ -1888,15 +1882,17 @@ abstract class CoreStore extends Service {
|
|
|
1888
1882
|
typeof adapter.queryRecord === 'function'
|
|
1889
1883
|
);
|
|
1890
1884
|
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1885
|
+
const promise: Promise<InternalModel | null> = _queryRecord(
|
|
1886
|
+
adapter,
|
|
1887
|
+
this,
|
|
1888
|
+
normalizedModelName,
|
|
1889
|
+
query,
|
|
1890
|
+
adapterOptionsWrapper
|
|
1891
|
+
) as Promise<InternalModel | null>;
|
|
1898
1892
|
|
|
1899
|
-
|
|
1893
|
+
return promiseObject(
|
|
1894
|
+
promise.then((internalModel: InternalModel | null) => {
|
|
1895
|
+
return internalModel ? internalModel.getRecord() : null;
|
|
1900
1896
|
})
|
|
1901
1897
|
);
|
|
1902
1898
|
}
|
|
@@ -2089,7 +2085,10 @@ abstract class CoreStore extends Service {
|
|
|
2089
2085
|
@param {Object} options
|
|
2090
2086
|
@return {Promise} promise
|
|
2091
2087
|
*/
|
|
2092
|
-
findAll(
|
|
2088
|
+
findAll(
|
|
2089
|
+
modelName: string,
|
|
2090
|
+
options: { reload?: boolean; backgroundReload?: boolean } = {}
|
|
2091
|
+
): PromiseArray<RecordInstance, RecordArray> {
|
|
2093
2092
|
if (DEBUG) {
|
|
2094
2093
|
assertDestroyingStore(this, 'findAll');
|
|
2095
2094
|
}
|
|
@@ -2102,7 +2101,7 @@ abstract class CoreStore extends Service {
|
|
|
2102
2101
|
let normalizedModelName = normalizeModelName(modelName);
|
|
2103
2102
|
let fetch = this._fetchAll(normalizedModelName, this.peekAll(normalizedModelName), options);
|
|
2104
2103
|
|
|
2105
|
-
return fetch;
|
|
2104
|
+
return promiseArray(fetch);
|
|
2106
2105
|
}
|
|
2107
2106
|
|
|
2108
2107
|
/**
|
|
@@ -2112,7 +2111,11 @@ abstract class CoreStore extends Service {
|
|
|
2112
2111
|
@param {RecordArray} array
|
|
2113
2112
|
@return {Promise} promise
|
|
2114
2113
|
*/
|
|
2115
|
-
_fetchAll(
|
|
2114
|
+
_fetchAll(
|
|
2115
|
+
modelName: string,
|
|
2116
|
+
array: RecordArray,
|
|
2117
|
+
options: { reload?: boolean; backgroundReload?: boolean }
|
|
2118
|
+
): Promise<RecordArray> {
|
|
2116
2119
|
let adapter = this.adapterFor(modelName);
|
|
2117
2120
|
|
|
2118
2121
|
assert(`You tried to load all records but you have no adapter (for ${modelName})`, adapter);
|
|
@@ -2123,7 +2126,7 @@ abstract class CoreStore extends Service {
|
|
|
2123
2126
|
|
|
2124
2127
|
if (options.reload) {
|
|
2125
2128
|
set(array, 'isUpdating', true);
|
|
2126
|
-
return
|
|
2129
|
+
return _findAll(adapter, this, modelName, options);
|
|
2127
2130
|
}
|
|
2128
2131
|
|
|
2129
2132
|
let snapshotArray = array._createSnapshot(options);
|
|
@@ -2134,12 +2137,12 @@ abstract class CoreStore extends Service {
|
|
|
2134
2137
|
(!adapter.shouldReloadAll && snapshotArray.length === 0)
|
|
2135
2138
|
) {
|
|
2136
2139
|
set(array, 'isUpdating', true);
|
|
2137
|
-
return
|
|
2140
|
+
return _findAll(adapter, this, modelName, options);
|
|
2138
2141
|
}
|
|
2139
2142
|
}
|
|
2140
2143
|
|
|
2141
2144
|
if (options.backgroundReload === false) {
|
|
2142
|
-
return
|
|
2145
|
+
return resolve(array);
|
|
2143
2146
|
}
|
|
2144
2147
|
|
|
2145
2148
|
if (
|
|
@@ -2151,7 +2154,7 @@ abstract class CoreStore extends Service {
|
|
|
2151
2154
|
_findAll(adapter, this, modelName, options);
|
|
2152
2155
|
}
|
|
2153
2156
|
|
|
2154
|
-
return
|
|
2157
|
+
return resolve(array);
|
|
2155
2158
|
}
|
|
2156
2159
|
|
|
2157
2160
|
/**
|
|
@@ -2159,7 +2162,7 @@ abstract class CoreStore extends Service {
|
|
|
2159
2162
|
@param {String} modelName
|
|
2160
2163
|
@private
|
|
2161
2164
|
*/
|
|
2162
|
-
_didUpdateAll(modelName) {
|
|
2165
|
+
_didUpdateAll(modelName: string): void {
|
|
2163
2166
|
this.recordArrayManager._didUpdateAll(modelName);
|
|
2164
2167
|
}
|
|
2165
2168
|
|
|
@@ -2258,7 +2261,11 @@ abstract class CoreStore extends Service {
|
|
|
2258
2261
|
@param {Resolver} resolver
|
|
2259
2262
|
@param {Object} options
|
|
2260
2263
|
*/
|
|
2261
|
-
scheduleSave(
|
|
2264
|
+
scheduleSave(
|
|
2265
|
+
internalModel: InternalModel,
|
|
2266
|
+
resolver: RSVP.Deferred<void>,
|
|
2267
|
+
options: FindOptions
|
|
2268
|
+
): void | Promise<void> {
|
|
2262
2269
|
if (internalModel._isRecordFullyDeleted()) {
|
|
2263
2270
|
resolver.resolve();
|
|
2264
2271
|
return resolver.promise;
|
|
@@ -2279,9 +2286,8 @@ abstract class CoreStore extends Service {
|
|
|
2279
2286
|
operation = 'deleteRecord';
|
|
2280
2287
|
}
|
|
2281
2288
|
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
let fetchManagerPromise = this._fetchManager.scheduleSave(internalModel.identifier, options);
|
|
2289
|
+
const saveOptions = Object.assign({ [SaveOp]: operation }, options);
|
|
2290
|
+
let fetchManagerPromise = this._fetchManager.scheduleSave(internalModel.identifier, saveOptions);
|
|
2285
2291
|
let promise = fetchManagerPromise.then(
|
|
2286
2292
|
(payload) => {
|
|
2287
2293
|
/*
|
|
@@ -2430,6 +2436,7 @@ abstract class CoreStore extends Service {
|
|
|
2430
2436
|
@param {Object} data
|
|
2431
2437
|
*/
|
|
2432
2438
|
_load(data: ExistingResourceObject) {
|
|
2439
|
+
// TODO this should determine identifier via the cache before making assumptions
|
|
2433
2440
|
const resource = constructResource(normalizeModelName(data.type), ensureStringId(data.id), coerceId(data.lid));
|
|
2434
2441
|
|
|
2435
2442
|
let internalModel = internalModelFactoryFor(this).lookup(resource, data);
|
|
@@ -2690,6 +2697,7 @@ abstract class CoreStore extends Service {
|
|
|
2690
2697
|
}
|
|
2691
2698
|
|
|
2692
2699
|
_pushInternalModel(data) {
|
|
2700
|
+
// TODO type should be pulled from the identifier for debug
|
|
2693
2701
|
let modelName = data.type;
|
|
2694
2702
|
assert(
|
|
2695
2703
|
`You must include an 'id' for ${modelName} in an object passed to 'push'`,
|
|
@@ -2822,10 +2830,6 @@ abstract class CoreStore extends Service {
|
|
|
2822
2830
|
serializer.pushPayload(this, payload);
|
|
2823
2831
|
}
|
|
2824
2832
|
|
|
2825
|
-
reloadManyArray(manyArray, internalModel, key, options) {
|
|
2826
|
-
return internalModel.reloadHasMany(key, options);
|
|
2827
|
-
}
|
|
2828
|
-
|
|
2829
2833
|
reloadBelongsTo(belongsToProxy, internalModel, key, options) {
|
|
2830
2834
|
return internalModel.reloadBelongsTo(key, options);
|
|
2831
2835
|
}
|
|
@@ -2852,13 +2856,13 @@ abstract class CoreStore extends Service {
|
|
|
2852
2856
|
return internalModel!.createSnapshot(options).serialize(options);
|
|
2853
2857
|
}
|
|
2854
2858
|
|
|
2855
|
-
saveRecord(record: RecordInstance, options?: Dict<unknown>):
|
|
2859
|
+
saveRecord(record: RecordInstance, options?: Dict<unknown>): Promise<RecordInstance> {
|
|
2856
2860
|
let identifier = recordIdentifierFor(record);
|
|
2857
2861
|
let internalModel = internalModelFactoryFor(this).peek(identifier);
|
|
2858
2862
|
// TODO we used to check if the record was destroyed here
|
|
2859
2863
|
// Casting can be removed once REQUEST_SERVICE ff is turned on
|
|
2860
2864
|
// because a `Record` is provided there will always be a matching internalModel
|
|
2861
|
-
return (internalModel!.save(options) as
|
|
2865
|
+
return (internalModel!.save(options) as Promise<void>).then(() => record);
|
|
2862
2866
|
}
|
|
2863
2867
|
|
|
2864
2868
|
relationshipReferenceFor(identifier: RecordIdentifier, key: string): BelongsToReference | HasManyReference {
|
|
@@ -2908,7 +2912,9 @@ abstract class CoreStore extends Service {
|
|
|
2908
2912
|
// it can be reproduced in partner tests by running
|
|
2909
2913
|
// node ./scripts/packages-for-commit.js && yarn test-external:ember-observer
|
|
2910
2914
|
if (_RecordData === undefined) {
|
|
2911
|
-
_RecordData =
|
|
2915
|
+
_RecordData = (
|
|
2916
|
+
importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
|
|
2917
|
+
).RecordData as RecordDataConstruct;
|
|
2912
2918
|
}
|
|
2913
2919
|
|
|
2914
2920
|
let identifier = this.identifierCache.getOrCreateRecordIdentifier({
|
|
@@ -2966,7 +2972,7 @@ abstract class CoreStore extends Service {
|
|
|
2966
2972
|
@param {Object} payload
|
|
2967
2973
|
@return {Object} The normalized payload
|
|
2968
2974
|
*/
|
|
2969
|
-
normalize(modelName, payload) {
|
|
2975
|
+
normalize(modelName: string, payload) {
|
|
2970
2976
|
if (DEBUG) {
|
|
2971
2977
|
assertDestroyingStore(this, 'normalize');
|
|
2972
2978
|
}
|
|
@@ -2982,7 +2988,7 @@ abstract class CoreStore extends Service {
|
|
|
2982
2988
|
let model = this.modelFor(normalizedModelName);
|
|
2983
2989
|
assert(
|
|
2984
2990
|
`You must define a normalize method in your serializer in order to call store.normalize`,
|
|
2985
|
-
serializer
|
|
2991
|
+
serializer?.normalize
|
|
2986
2992
|
);
|
|
2987
2993
|
return serializer.normalize(model, payload);
|
|
2988
2994
|
}
|
|
@@ -3096,7 +3102,7 @@ abstract class CoreStore extends Service {
|
|
|
3096
3102
|
@param {String} modelName the record to serialize
|
|
3097
3103
|
@return {Serializer}
|
|
3098
3104
|
*/
|
|
3099
|
-
serializerFor(modelName) {
|
|
3105
|
+
serializerFor(modelName: string): MinimumSerializerInterface | null {
|
|
3100
3106
|
if (DEBUG) {
|
|
3101
3107
|
assertDestroyingStore(this, 'serializerFor');
|
|
3102
3108
|
}
|
|
@@ -3132,30 +3138,29 @@ abstract class CoreStore extends Service {
|
|
|
3132
3138
|
return serializer;
|
|
3133
3139
|
}
|
|
3134
3140
|
|
|
3135
|
-
|
|
3136
|
-
`No serializer was found for '${modelName}' and no 'application' serializer was found as a fallback`,
|
|
3137
|
-
serializer !== undefined
|
|
3138
|
-
);
|
|
3141
|
+
return null;
|
|
3139
3142
|
}
|
|
3140
3143
|
|
|
3141
3144
|
destroy() {
|
|
3142
3145
|
// enqueue destruction of any adapters/serializers we have created
|
|
3143
3146
|
for (let adapterName in this._adapterCache) {
|
|
3144
|
-
let adapter = this._adapterCache[adapterName]
|
|
3147
|
+
let adapter = this._adapterCache[adapterName]!;
|
|
3145
3148
|
if (typeof adapter.destroy === 'function') {
|
|
3146
3149
|
adapter.destroy();
|
|
3147
3150
|
}
|
|
3148
3151
|
}
|
|
3149
3152
|
|
|
3150
3153
|
for (let serializerName in this._serializerCache) {
|
|
3151
|
-
let serializer = this._serializerCache[serializerName]
|
|
3154
|
+
let serializer = this._serializerCache[serializerName]!;
|
|
3152
3155
|
if (typeof serializer.destroy === 'function') {
|
|
3153
3156
|
serializer.destroy();
|
|
3154
3157
|
}
|
|
3155
3158
|
}
|
|
3156
3159
|
|
|
3157
3160
|
if (HAS_RECORD_DATA_PACKAGE) {
|
|
3158
|
-
const peekGraph =
|
|
3161
|
+
const peekGraph = (
|
|
3162
|
+
importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
|
|
3163
|
+
).peekGraph;
|
|
3159
3164
|
let graph = peekGraph(this);
|
|
3160
3165
|
if (graph) {
|
|
3161
3166
|
graph.destroy();
|
|
@@ -3175,7 +3180,9 @@ abstract class CoreStore extends Service {
|
|
|
3175
3180
|
// since then we avoid churning relationships
|
|
3176
3181
|
// during unload
|
|
3177
3182
|
if (HAS_RECORD_DATA_PACKAGE) {
|
|
3178
|
-
const peekGraph =
|
|
3183
|
+
const peekGraph = (
|
|
3184
|
+
importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
|
|
3185
|
+
).peekGraph;
|
|
3179
3186
|
let graph = peekGraph(this);
|
|
3180
3187
|
if (graph) {
|
|
3181
3188
|
graph.willDestroy();
|
|
@@ -3209,24 +3216,6 @@ abstract class CoreStore extends Service {
|
|
|
3209
3216
|
}
|
|
3210
3217
|
}
|
|
3211
3218
|
}
|
|
3212
|
-
|
|
3213
|
-
_updateInternalModel(internalModel: InternalModel) {
|
|
3214
|
-
if (this._updatedInternalModels.push(internalModel) !== 1) {
|
|
3215
|
-
return;
|
|
3216
|
-
}
|
|
3217
|
-
|
|
3218
|
-
emberBackburner.schedule('actions', this, this._flushUpdatedInternalModels);
|
|
3219
|
-
}
|
|
3220
|
-
|
|
3221
|
-
_flushUpdatedInternalModels() {
|
|
3222
|
-
let updated = this._updatedInternalModels;
|
|
3223
|
-
|
|
3224
|
-
for (let i = 0, l = updated.length; i < l; i++) {
|
|
3225
|
-
updated[i]._triggerDeferredTriggers();
|
|
3226
|
-
}
|
|
3227
|
-
|
|
3228
|
-
updated.length = 0;
|
|
3229
|
-
}
|
|
3230
3219
|
}
|
|
3231
3220
|
|
|
3232
3221
|
export default CoreStore;
|