@ember-data/store 4.5.0-beta.0 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/addon/-private/{system/backburner.js → backburner.js} +0 -0
- package/addon/-private/{system/coerce-id.ts → coerce-id.ts} +0 -0
- package/addon/-private/{system/store/common.js → common.js} +0 -0
- package/addon/-private/{system/core-store.ts → core-store.ts} +467 -1253
- package/addon/-private/{system/errors-utils.js → errors-utils.js} +7 -6
- package/addon/-private/{system/fetch-manager.ts → fetch-manager.ts} +72 -42
- package/addon/-private/finders.js +107 -0
- package/addon/-private/identifer-debug-consts.ts +3 -0
- package/addon/-private/{identifiers/cache.ts → identifier-cache.ts} +26 -14
- package/addon/-private/{system/identity-map.ts → identity-map.ts} +2 -1
- package/addon/-private/index.ts +17 -17
- package/addon/-private/instance-cache.ts +387 -0
- package/addon/-private/{system/store/internal-model-factory.ts → internal-model-factory.ts} +25 -19
- package/addon/-private/{system/internal-model-map.ts → internal-model-map.ts} +9 -5
- package/addon/-private/model/internal-model.ts +602 -0
- package/addon/-private/{system/references/record.ts → model/record-reference.ts} +23 -36
- package/addon/-private/{system/model → model}/shim-model-class.ts +19 -14
- package/addon/-private/{system/normalize-model-name.ts → normalize-model-name.ts} +0 -0
- package/addon/-private/{system/promise-proxies.ts → promise-proxies.ts} +12 -5
- package/addon/-private/{system/promise-proxy-base.js → promise-proxy-base.js} +0 -0
- package/addon/-private/{system/record-array-manager.ts → record-array-manager.ts} +19 -18
- package/addon/-private/{system/record-arrays → record-arrays}/adapter-populated-record-array.ts +11 -10
- package/addon/-private/{system/record-arrays → record-arrays}/record-array.ts +37 -19
- package/addon/-private/record-data-for.ts +39 -0
- package/addon/-private/{system/store/record-data-store-wrapper.ts → record-data-store-wrapper.ts} +21 -26
- package/addon/-private/{system/record-notification-manager.ts → record-notification-manager.ts} +8 -3
- package/addon/-private/{system/request-cache.ts → request-cache.ts} +5 -6
- package/addon/-private/{system/schema-definition-service.ts → schema-definition-service.ts} +30 -14
- package/addon/-private/{system/store/serializer-response.ts → serializer-response.ts} +7 -6
- package/addon/-private/{system/snapshot-record-array.ts → snapshot-record-array.ts} +27 -8
- package/addon/-private/{system/snapshot.ts → snapshot.ts} +54 -39
- package/addon/-private/utils/construct-resource.ts +7 -3
- package/addon/-private/utils/promise-record.ts +9 -18
- package/addon/-private/{system/weak-cache.ts → weak-cache.ts} +2 -2
- package/addon/index.ts +1 -0
- package/package.json +21 -20
- package/addon/-private/identifiers/is-stable-identifier.ts +0 -18
- package/addon/-private/identifiers/utils/uuid-v4.ts +0 -80
- package/addon/-private/system/ds-model-store.ts +0 -136
- package/addon/-private/system/model/internal-model.ts +0 -1303
- package/addon/-private/system/model/states.js +0 -736
- package/addon/-private/system/record-arrays.ts +0 -8
- package/addon/-private/system/record-data-for.ts +0 -54
- package/addon/-private/system/references/belongs-to.ts +0 -406
- package/addon/-private/system/references/has-many.ts +0 -487
- package/addon/-private/system/references/reference.ts +0 -205
- package/addon/-private/system/references.js +0 -9
- package/addon/-private/system/store/finders.js +0 -412
- package/addon/-private/ts-interfaces/ds-model.ts +0 -50
- package/addon/-private/ts-interfaces/ember-data-json-api.ts +0 -145
- package/addon/-private/ts-interfaces/fetch-manager.ts +0 -44
- package/addon/-private/ts-interfaces/identifier.ts +0 -246
- package/addon/-private/ts-interfaces/minimum-adapter-interface.ts +0 -584
- package/addon/-private/ts-interfaces/minimum-serializer-interface.ts +0 -257
- package/addon/-private/ts-interfaces/promise-proxies.ts +0 -3
- package/addon/-private/ts-interfaces/record-data-json-api.ts +0 -29
- package/addon/-private/ts-interfaces/record-data-record-wrapper.ts +0 -46
- package/addon/-private/ts-interfaces/record-data-schemas.ts +0 -45
- package/addon/-private/ts-interfaces/record-data-store-wrapper.ts +0 -56
- package/addon/-private/ts-interfaces/record-data.ts +0 -72
- package/addon/-private/ts-interfaces/record-instance.ts +0 -18
- package/addon/-private/ts-interfaces/schema-definition-service.ts +0 -12
- package/addon/-private/ts-interfaces/store.ts +0 -10
- package/addon/-private/ts-interfaces/utils.ts +0 -6
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { makeArray } from '@ember/array';
|
|
2
|
-
import { isPresent } from '@ember/utils';
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
2
|
@module @ember-data/adapter/error
|
|
6
3
|
*/
|
|
@@ -9,13 +6,17 @@ const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/;
|
|
|
9
6
|
const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/;
|
|
10
7
|
const PRIMARY_ATTRIBUTE_KEY = 'base';
|
|
11
8
|
|
|
9
|
+
function makeArray(value) {
|
|
10
|
+
return Array.isArray(value) ? value : [value];
|
|
11
|
+
}
|
|
12
|
+
|
|
12
13
|
/**
|
|
13
14
|
Convert an hash of errors into an array with errors in JSON-API format.
|
|
14
15
|
```javascript
|
|
15
16
|
import DS from 'ember-data';
|
|
16
17
|
|
|
17
18
|
const { errorsHashToArray } = DS;
|
|
18
|
-
|
|
19
|
+
|
|
19
20
|
let errors = {
|
|
20
21
|
base: 'Invalid attributes on saving this record',
|
|
21
22
|
name: 'Must be present',
|
|
@@ -55,7 +56,7 @@ const PRIMARY_ATTRIBUTE_KEY = 'base';
|
|
|
55
56
|
export function errorsHashToArray(errors) {
|
|
56
57
|
let out = [];
|
|
57
58
|
|
|
58
|
-
if (
|
|
59
|
+
if (errors) {
|
|
59
60
|
Object.keys(errors).forEach((key) => {
|
|
60
61
|
let messages = makeArray(errors[key]);
|
|
61
62
|
for (let i = 0; i < messages.length; i++) {
|
|
@@ -122,7 +123,7 @@ export function errorsHashToArray(errors) {
|
|
|
122
123
|
export function errorsArrayToHash(errors) {
|
|
123
124
|
let out = {};
|
|
124
125
|
|
|
125
|
-
if (
|
|
126
|
+
if (errors) {
|
|
126
127
|
errors.forEach((error) => {
|
|
127
128
|
if (error.source && error.source.pointer) {
|
|
128
129
|
let key = error.source.pointer.match(SOURCE_POINTER_REGEXP);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module @ember-data/store
|
|
3
3
|
*/
|
|
4
|
-
import { A } from '@ember/array';
|
|
5
4
|
import { assert, deprecate, warn } from '@ember/debug';
|
|
6
5
|
import { _backburner as emberBackburner } from '@ember/runloop';
|
|
7
6
|
import { DEBUG } from '@glimmer/env';
|
|
@@ -9,22 +8,25 @@ import { DEBUG } from '@glimmer/env';
|
|
|
9
8
|
import { default as RSVP, resolve } from 'rsvp';
|
|
10
9
|
|
|
11
10
|
import { DEPRECATE_RSVP_PROMISE } from '@ember-data/private-build-infra/deprecations';
|
|
11
|
+
import type { CollectionResourceDocument, SingleResourceDocument } from '@ember-data/types/q/ember-data-json-api';
|
|
12
|
+
import type { FindRecordQuery, Request, SaveRecordMutation } from '@ember-data/types/q/fetch-manager';
|
|
13
|
+
import type {
|
|
14
|
+
RecordIdentifier,
|
|
15
|
+
StableExistingRecordIdentifier,
|
|
16
|
+
StableRecordIdentifier,
|
|
17
|
+
} from '@ember-data/types/q/identifier';
|
|
18
|
+
import type { MinimumSerializerInterface } from '@ember-data/types/q/minimum-serializer-interface';
|
|
19
|
+
import type { FindOptions } from '@ember-data/types/q/store';
|
|
20
|
+
import type { Dict } from '@ember-data/types/q/utils';
|
|
12
21
|
|
|
13
|
-
import type { CollectionResourceDocument, SingleResourceDocument } from '../ts-interfaces/ember-data-json-api';
|
|
14
|
-
import type { FindRecordQuery, Request, SaveRecordMutation } from '../ts-interfaces/fetch-manager';
|
|
15
|
-
import type { ExistingRecordIdentifier, RecordIdentifier, StableRecordIdentifier } from '../ts-interfaces/identifier';
|
|
16
|
-
import type { MinimumSerializerInterface } from '../ts-interfaces/minimum-serializer-interface';
|
|
17
|
-
import { FindOptions } from '../ts-interfaces/store';
|
|
18
|
-
import type { Dict } from '../ts-interfaces/utils';
|
|
19
22
|
import coerceId from './coerce-id';
|
|
20
|
-
import
|
|
23
|
+
import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './common';
|
|
24
|
+
import type Store from './core-store';
|
|
21
25
|
import { errorsArrayToHash } from './errors-utils';
|
|
22
26
|
import ShimModelClass from './model/shim-model-class';
|
|
23
|
-
import RequestCache
|
|
24
|
-
import
|
|
27
|
+
import RequestCache from './request-cache';
|
|
28
|
+
import { normalizeResponseHelper } from './serializer-response';
|
|
25
29
|
import Snapshot from './snapshot';
|
|
26
|
-
import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './store/common';
|
|
27
|
-
import { normalizeResponseHelper } from './store/serializer-response';
|
|
28
30
|
import WeakCache from './weak-cache';
|
|
29
31
|
|
|
30
32
|
function payloadIsNotBlank(adapterPayload): boolean {
|
|
@@ -37,7 +39,7 @@ function payloadIsNotBlank(adapterPayload): boolean {
|
|
|
37
39
|
|
|
38
40
|
type AdapterErrors = Error & { errors?: string[]; isAdapterError?: true };
|
|
39
41
|
type SerializerWithParseErrors = MinimumSerializerInterface & {
|
|
40
|
-
extractErrors?(store:
|
|
42
|
+
extractErrors?(store: Store, modelClass: ShimModelClass, error: AdapterErrors, recordId: string | null): any;
|
|
41
43
|
};
|
|
42
44
|
|
|
43
45
|
export const SaveOp: unique symbol = Symbol('SaveOp');
|
|
@@ -45,11 +47,12 @@ export const SaveOp: unique symbol = Symbol('SaveOp');
|
|
|
45
47
|
export type FetchMutationOptions = FindOptions & { [SaveOp]: 'createRecord' | 'deleteRecord' | 'updateRecord' };
|
|
46
48
|
|
|
47
49
|
interface PendingFetchItem {
|
|
48
|
-
identifier:
|
|
50
|
+
identifier: StableExistingRecordIdentifier;
|
|
49
51
|
queryRequest: Request;
|
|
50
52
|
resolver: RSVP.Deferred<any>;
|
|
51
|
-
options:
|
|
53
|
+
options: FindOptions;
|
|
52
54
|
trace?: any;
|
|
55
|
+
promise: Promise<StableRecordIdentifier>;
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
interface PendingSaveItem {
|
|
@@ -74,7 +77,7 @@ export default class FetchManager {
|
|
|
74
77
|
// fetches pending in the runloop, waiting to be coalesced
|
|
75
78
|
declare _pendingFetch: Map<string, PendingFetchItem[]>;
|
|
76
79
|
|
|
77
|
-
constructor(private _store:
|
|
80
|
+
constructor(private _store: Store) {
|
|
78
81
|
// used to keep track of all the find requests that need to be coalesced
|
|
79
82
|
this._pendingFetch = new Map();
|
|
80
83
|
this._pendingSave = [];
|
|
@@ -124,9 +127,7 @@ export default class FetchManager {
|
|
|
124
127
|
let adapter = this._store.adapterFor(identifier.type);
|
|
125
128
|
let operation = options[SaveOp];
|
|
126
129
|
|
|
127
|
-
|
|
128
|
-
// this will be refactored away once we change our pending API to be identifier based
|
|
129
|
-
let internalModel = (snapshot as unknown as PrivateSnapshot)._internalModel;
|
|
130
|
+
let internalModel = snapshot._internalModel;
|
|
130
131
|
let modelName = snapshot.modelName;
|
|
131
132
|
let store = this._store;
|
|
132
133
|
let modelClass = store.modelFor(modelName);
|
|
@@ -207,8 +208,9 @@ export default class FetchManager {
|
|
|
207
208
|
}
|
|
208
209
|
}
|
|
209
210
|
|
|
210
|
-
scheduleFetch(identifier:
|
|
211
|
+
scheduleFetch(identifier: StableExistingRecordIdentifier, options: FindOptions): Promise<StableRecordIdentifier> {
|
|
211
212
|
// TODO Probably the store should pass in the query object
|
|
213
|
+
let shouldTrace = DEBUG && this._store.generateStackTracesForTrackedRequests;
|
|
212
214
|
|
|
213
215
|
let query: FindRecordQuery = {
|
|
214
216
|
op: 'findRecord',
|
|
@@ -220,26 +222,21 @@ export default class FetchManager {
|
|
|
220
222
|
data: [query],
|
|
221
223
|
};
|
|
222
224
|
|
|
223
|
-
let
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if (pendingFetches) {
|
|
227
|
-
let matchingPendingFetch = pendingFetches.filter((fetch) => fetch.identifier.id === identifier.id)[0];
|
|
228
|
-
if (matchingPendingFetch) {
|
|
229
|
-
return matchingPendingFetch.resolver.promise;
|
|
230
|
-
}
|
|
225
|
+
let pendingFetch = this.getPendingFetch(identifier, options);
|
|
226
|
+
if (pendingFetch) {
|
|
227
|
+
return pendingFetch;
|
|
231
228
|
}
|
|
232
229
|
|
|
233
230
|
let id = identifier.id;
|
|
234
231
|
let modelName = identifier.type;
|
|
235
232
|
|
|
236
|
-
let resolver = RSVP.defer(`Fetching ${modelName}' with id: ${id}`);
|
|
233
|
+
let resolver = RSVP.defer<SingleResourceDocument>(`Fetching ${modelName}' with id: ${id}`);
|
|
237
234
|
let pendingFetchItem: PendingFetchItem = {
|
|
238
235
|
identifier,
|
|
239
236
|
resolver,
|
|
240
237
|
options,
|
|
241
238
|
queryRequest,
|
|
242
|
-
};
|
|
239
|
+
} as PendingFetchItem;
|
|
243
240
|
|
|
244
241
|
if (DEBUG) {
|
|
245
242
|
if (shouldTrace) {
|
|
@@ -259,7 +256,36 @@ export default class FetchManager {
|
|
|
259
256
|
}
|
|
260
257
|
}
|
|
261
258
|
|
|
262
|
-
let
|
|
259
|
+
let resolverPromise = resolver.promise;
|
|
260
|
+
|
|
261
|
+
// TODO replace with some form of record state cache
|
|
262
|
+
const store = this._store;
|
|
263
|
+
const internalModel = store._instanceCache.getInternalModel(identifier);
|
|
264
|
+
const isLoading = !internalModel.isLoaded; // we don't use isLoading directly because we are the request
|
|
265
|
+
|
|
266
|
+
const promise = resolverPromise.then(
|
|
267
|
+
(payload) => {
|
|
268
|
+
// ensure that regardless of id returned we assign to the correct record
|
|
269
|
+
if (payload.data && !Array.isArray(payload.data)) {
|
|
270
|
+
payload.data.lid = identifier.lid;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// additional data received in the payload
|
|
274
|
+
// may result in the merging of identifiers (and thus records)
|
|
275
|
+
let potentiallyNewIm = store._push(payload);
|
|
276
|
+
if (potentiallyNewIm && !Array.isArray(potentiallyNewIm)) {
|
|
277
|
+
return potentiallyNewIm;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return identifier;
|
|
281
|
+
},
|
|
282
|
+
(error) => {
|
|
283
|
+
if (internalModel.isEmpty || isLoading) {
|
|
284
|
+
internalModel.unloadRecord();
|
|
285
|
+
}
|
|
286
|
+
throw error;
|
|
287
|
+
}
|
|
288
|
+
);
|
|
263
289
|
|
|
264
290
|
if (this._pendingFetch.size === 0) {
|
|
265
291
|
emberBackburner.schedule('actions', this, this.flushAllPendingFetches);
|
|
@@ -273,7 +299,8 @@ export default class FetchManager {
|
|
|
273
299
|
|
|
274
300
|
(fetches.get(modelName) as PendingFetchItem[]).push(pendingFetchItem);
|
|
275
301
|
|
|
276
|
-
|
|
302
|
+
pendingFetchItem.promise = promise;
|
|
303
|
+
this.requestCache.enqueue(resolverPromise, pendingFetchItem.queryRequest);
|
|
277
304
|
return promise;
|
|
278
305
|
}
|
|
279
306
|
|
|
@@ -410,7 +437,7 @@ export default class FetchManager {
|
|
|
410
437
|
|
|
411
438
|
_findMany(
|
|
412
439
|
adapter: any,
|
|
413
|
-
store:
|
|
440
|
+
store: Store,
|
|
414
441
|
modelName: string,
|
|
415
442
|
snapshots: Snapshot[],
|
|
416
443
|
identifiers: RecordIdentifier[],
|
|
@@ -418,7 +445,7 @@ export default class FetchManager {
|
|
|
418
445
|
) {
|
|
419
446
|
let modelClass = store.modelFor(modelName); // `adapter.findMany` gets the modelClass still
|
|
420
447
|
let ids = snapshots.map((s) => s.id);
|
|
421
|
-
let promise = adapter.findMany(store, modelClass, ids,
|
|
448
|
+
let promise = adapter.findMany(store, modelClass, ids, snapshots);
|
|
422
449
|
let label = `DS: Handle Adapter#findMany of '${modelName}'`;
|
|
423
450
|
|
|
424
451
|
if (promise === undefined) {
|
|
@@ -483,7 +510,7 @@ export default class FetchManager {
|
|
|
483
510
|
let identifiers = new Array(totalItems);
|
|
484
511
|
let seeking: { [id: string]: PendingFetchItem } = Object.create(null);
|
|
485
512
|
|
|
486
|
-
let optionsMap = new WeakCache<RecordIdentifier,
|
|
513
|
+
let optionsMap = new WeakCache<RecordIdentifier, FindOptions>(DEBUG ? 'fetch-options' : '');
|
|
487
514
|
|
|
488
515
|
for (let i = 0; i < totalItems; i++) {
|
|
489
516
|
let pendingItem = pendingFetchItems[i];
|
|
@@ -529,13 +556,15 @@ export default class FetchManager {
|
|
|
529
556
|
}
|
|
530
557
|
}
|
|
531
558
|
|
|
532
|
-
getPendingFetch(identifier: StableRecordIdentifier, options) {
|
|
533
|
-
let
|
|
534
|
-
return req.type === 'query' && isSameRequest(options, req.request.data[0].options);
|
|
535
|
-
});
|
|
559
|
+
getPendingFetch(identifier: StableRecordIdentifier, options: FindOptions) {
|
|
560
|
+
let pendingFetches = this._pendingFetch.get(identifier.type);
|
|
536
561
|
|
|
537
|
-
|
|
538
|
-
|
|
562
|
+
// We already have a pending fetch for this
|
|
563
|
+
if (pendingFetches) {
|
|
564
|
+
let matchingPendingFetch = pendingFetches.find((fetch) => fetch.identifier === identifier);
|
|
565
|
+
if (matchingPendingFetch && isSameRequest(options, matchingPendingFetch.options)) {
|
|
566
|
+
return matchingPendingFetch.promise;
|
|
567
|
+
}
|
|
539
568
|
}
|
|
540
569
|
}
|
|
541
570
|
|
|
@@ -562,6 +591,7 @@ function assertIsString(id: string | null): asserts id is string {
|
|
|
562
591
|
}
|
|
563
592
|
|
|
564
593
|
// this function helps resolve whether we have a pending request that we should use instead
|
|
565
|
-
|
|
594
|
+
// TODO @runspired @needsTest removing this did not cause any test failures
|
|
595
|
+
function isSameRequest(options: FindOptions = {}, reqOptions: FindOptions = {}) {
|
|
566
596
|
return options.include === reqOptions.include;
|
|
567
597
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { assert } from '@ember/debug';
|
|
2
|
+
|
|
3
|
+
import { Promise } from 'rsvp';
|
|
4
|
+
|
|
5
|
+
import { guardDestroyedStore } from './common';
|
|
6
|
+
import { normalizeResponseHelper } from './serializer-response';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
@module @ember-data/store
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
function payloadIsNotBlank(adapterPayload) {
|
|
13
|
+
if (Array.isArray(adapterPayload)) {
|
|
14
|
+
return true;
|
|
15
|
+
} else {
|
|
16
|
+
return Object.keys(adapterPayload || {}).length;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function _findAll(adapter, store, modelName, options) {
|
|
21
|
+
let modelClass = store.modelFor(modelName); // adapter.findAll depends on the class
|
|
22
|
+
let recordArray = store.peekAll(modelName);
|
|
23
|
+
let snapshotArray = recordArray._createSnapshot(options);
|
|
24
|
+
let promise = Promise.resolve().then(() => adapter.findAll(store, modelClass, null, snapshotArray));
|
|
25
|
+
let label = 'DS: Handle Adapter#findAll of ' + modelClass;
|
|
26
|
+
|
|
27
|
+
promise = guardDestroyedStore(promise, store, label);
|
|
28
|
+
|
|
29
|
+
return promise.then(
|
|
30
|
+
(adapterPayload) => {
|
|
31
|
+
assert(
|
|
32
|
+
`You made a 'findAll' request for '${modelName}' records, but the adapter's response did not have any data`,
|
|
33
|
+
payloadIsNotBlank(adapterPayload)
|
|
34
|
+
);
|
|
35
|
+
let serializer = store.serializerFor(modelName);
|
|
36
|
+
let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findAll');
|
|
37
|
+
|
|
38
|
+
store._push(payload);
|
|
39
|
+
store.recordArrayManager._didUpdateAll(modelName);
|
|
40
|
+
|
|
41
|
+
return recordArray;
|
|
42
|
+
},
|
|
43
|
+
null,
|
|
44
|
+
'DS: Extract payload of findAll ${modelName}'
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function _query(adapter, store, modelName, query, recordArray, options) {
|
|
49
|
+
let modelClass = store.modelFor(modelName); // adapter.query needs the class
|
|
50
|
+
|
|
51
|
+
recordArray = recordArray || store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query);
|
|
52
|
+
let promise = Promise.resolve().then(() => adapter.query(store, modelClass, query, recordArray, options));
|
|
53
|
+
|
|
54
|
+
let label = `DS: Handle Adapter#query of ${modelName}`;
|
|
55
|
+
promise = guardDestroyedStore(promise, store, label);
|
|
56
|
+
|
|
57
|
+
return promise.then(
|
|
58
|
+
(adapterPayload) => {
|
|
59
|
+
let serializer = store.serializerFor(modelName);
|
|
60
|
+
let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'query');
|
|
61
|
+
let identifiers = store._push(payload);
|
|
62
|
+
|
|
63
|
+
assert(
|
|
64
|
+
'The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.',
|
|
65
|
+
Array.isArray(identifiers)
|
|
66
|
+
);
|
|
67
|
+
if (recordArray) {
|
|
68
|
+
recordArray._setIdentifiers(identifiers, payload);
|
|
69
|
+
} else {
|
|
70
|
+
recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray(
|
|
71
|
+
modelName,
|
|
72
|
+
query,
|
|
73
|
+
identifiers,
|
|
74
|
+
payload
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return recordArray;
|
|
79
|
+
},
|
|
80
|
+
null,
|
|
81
|
+
`DS: Extract payload of query ${modelName}`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function _queryRecord(adapter, store, modelName, query, options) {
|
|
86
|
+
let modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class
|
|
87
|
+
let promise = Promise.resolve().then(() => adapter.queryRecord(store, modelClass, query, options));
|
|
88
|
+
|
|
89
|
+
let label = `DS: Handle Adapter#queryRecord of ${modelName}`;
|
|
90
|
+
promise = guardDestroyedStore(promise, store, label);
|
|
91
|
+
|
|
92
|
+
return promise.then(
|
|
93
|
+
(adapterPayload) => {
|
|
94
|
+
let serializer = store.serializerFor(modelName);
|
|
95
|
+
let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'queryRecord');
|
|
96
|
+
|
|
97
|
+
assert(
|
|
98
|
+
`Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array.`,
|
|
99
|
+
!Array.isArray(payload.data)
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
return store._push(payload);
|
|
103
|
+
},
|
|
104
|
+
null,
|
|
105
|
+
`DS: Extract payload of queryRecord ${modelName}`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
@@ -4,10 +4,7 @@
|
|
|
4
4
|
import { assert, warn } from '@ember/debug';
|
|
5
5
|
import { DEBUG } from '@glimmer/env';
|
|
6
6
|
|
|
7
|
-
import
|
|
8
|
-
import normalizeModelName from '../system/normalize-model-name';
|
|
9
|
-
import WeakCache from '../system/weak-cache';
|
|
10
|
-
import type { ExistingResourceObject, ResourceIdentifierObject } from '../ts-interfaces/ember-data-json-api';
|
|
7
|
+
import type { ExistingResourceObject, ResourceIdentifierObject } from '@ember-data/types/q/ember-data-json-api';
|
|
11
8
|
import type {
|
|
12
9
|
ForgetMethod,
|
|
13
10
|
GenerationMethod,
|
|
@@ -18,12 +15,27 @@ import type {
|
|
|
18
15
|
ResourceData,
|
|
19
16
|
StableRecordIdentifier,
|
|
20
17
|
UpdateMethod,
|
|
21
|
-
} from '
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
import
|
|
25
|
-
import
|
|
26
|
-
import
|
|
18
|
+
} from '@ember-data/types/q/identifier';
|
|
19
|
+
import type { ConfidentDict } from '@ember-data/types/q/utils';
|
|
20
|
+
|
|
21
|
+
import coerceId from './coerce-id';
|
|
22
|
+
import { DEBUG_CLIENT_ORIGINATED, DEBUG_IDENTIFIER_BUCKET } from './identifer-debug-consts';
|
|
23
|
+
import normalizeModelName from './normalize-model-name';
|
|
24
|
+
import isNonEmptyString from './utils/is-non-empty-string';
|
|
25
|
+
import WeakCache from './weak-cache';
|
|
26
|
+
|
|
27
|
+
const IDENTIFIERS = new WeakSet();
|
|
28
|
+
|
|
29
|
+
export function isStableIdentifier(identifier: Object): identifier is StableRecordIdentifier {
|
|
30
|
+
return IDENTIFIERS.has(identifier);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const isFastBoot = typeof FastBoot !== 'undefined';
|
|
34
|
+
const _crypto: Crypto = isFastBoot ? (FastBoot.require('crypto') as Crypto) : window.crypto;
|
|
35
|
+
|
|
36
|
+
function uuidv4(): string {
|
|
37
|
+
return _crypto.randomUUID();
|
|
38
|
+
}
|
|
27
39
|
|
|
28
40
|
function freeze<T>(obj: T): T {
|
|
29
41
|
if (typeof Object.freeze === 'function') {
|
|
@@ -75,7 +87,7 @@ function defaultGenerationMethod(data: ResourceData | { type: string }, bucket:
|
|
|
75
87
|
let { type, id } = data;
|
|
76
88
|
// TODO: add test for id not a string
|
|
77
89
|
if (isNonEmptyString(coerceId(id))) {
|
|
78
|
-
return `@
|
|
90
|
+
return `@lid:${normalizeModelName(type)}-${id}`;
|
|
79
91
|
}
|
|
80
92
|
}
|
|
81
93
|
return uuidv4();
|
|
@@ -440,7 +452,7 @@ export class IdentifierCache {
|
|
|
440
452
|
let index = keyOptions._allIdentifiers.indexOf(identifier);
|
|
441
453
|
keyOptions._allIdentifiers.splice(index, 1);
|
|
442
454
|
|
|
443
|
-
|
|
455
|
+
IDENTIFIERS.delete(identifierObject);
|
|
444
456
|
this._forget(identifier, 'record');
|
|
445
457
|
}
|
|
446
458
|
|
|
@@ -476,7 +488,7 @@ function makeStableRecordIdentifier(
|
|
|
476
488
|
id,
|
|
477
489
|
type,
|
|
478
490
|
};
|
|
479
|
-
|
|
491
|
+
IDENTIFIERS.add(recordIdentifier);
|
|
480
492
|
|
|
481
493
|
if (DEBUG) {
|
|
482
494
|
// we enforce immutability in dev
|
|
@@ -498,7 +510,7 @@ function makeStableRecordIdentifier(
|
|
|
498
510
|
};
|
|
499
511
|
wrapper[DEBUG_CLIENT_ORIGINATED] = clientOriginated;
|
|
500
512
|
wrapper[DEBUG_IDENTIFIER_BUCKET] = bucket;
|
|
501
|
-
|
|
513
|
+
IDENTIFIERS.add(wrapper);
|
|
502
514
|
DEBUG_MAP.set(wrapper, recordIdentifier);
|
|
503
515
|
wrapper = freeze(wrapper);
|
|
504
516
|
return wrapper;
|
package/addon/-private/index.ts
CHANGED
|
@@ -2,38 +2,38 @@
|
|
|
2
2
|
@module @ember-data/store
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
export { default as Store } from './
|
|
5
|
+
export { default as Store, storeFor } from './core-store';
|
|
6
6
|
|
|
7
|
-
export { recordIdentifierFor } from './
|
|
7
|
+
export { recordIdentifierFor } from './internal-model-factory';
|
|
8
8
|
|
|
9
|
-
export { default as Snapshot } from './
|
|
9
|
+
export { default as Snapshot } from './snapshot';
|
|
10
10
|
export {
|
|
11
11
|
setIdentifierGenerationMethod,
|
|
12
12
|
setIdentifierUpdateMethod,
|
|
13
13
|
setIdentifierForgetMethod,
|
|
14
14
|
setIdentifierResetMethod,
|
|
15
|
-
} from './
|
|
15
|
+
} from './identifier-cache';
|
|
16
16
|
|
|
17
|
-
export { default as normalizeModelName } from './
|
|
18
|
-
export { default as coerceId } from './
|
|
17
|
+
export { default as normalizeModelName } from './normalize-model-name';
|
|
18
|
+
export { default as coerceId } from './coerce-id';
|
|
19
19
|
|
|
20
|
-
export { errorsHashToArray, errorsArrayToHash } from './
|
|
20
|
+
export { errorsHashToArray, errorsArrayToHash } from './errors-utils';
|
|
21
21
|
|
|
22
|
-
// `ember-data-model-fragments` relies on `
|
|
23
|
-
export { default as
|
|
24
|
-
export { default as InternalModel } from './system/model/internal-model';
|
|
22
|
+
// `ember-data-model-fragments` relies on `InternalModel`
|
|
23
|
+
export { default as InternalModel } from './model/internal-model';
|
|
25
24
|
|
|
26
|
-
export { PromiseArray, PromiseObject, deprecatedPromiseObject } from './
|
|
25
|
+
export { PromiseArray, PromiseObject, deprecatedPromiseObject } from './promise-proxies';
|
|
27
26
|
|
|
28
|
-
export { RecordArray
|
|
27
|
+
export { default as RecordArray } from './record-arrays/record-array';
|
|
28
|
+
export { default as AdapterPopulatedRecordArray } from './record-arrays/adapter-populated-record-array';
|
|
29
29
|
|
|
30
|
-
export { default as RecordArrayManager } from './
|
|
30
|
+
export { default as RecordArrayManager } from './record-array-manager';
|
|
31
31
|
|
|
32
32
|
// // Used by tests
|
|
33
|
-
export { default as SnapshotRecordArray } from './
|
|
33
|
+
export { default as SnapshotRecordArray } from './snapshot-record-array';
|
|
34
34
|
|
|
35
35
|
// New
|
|
36
|
-
export { default as recordDataFor, removeRecordDataFor } from './
|
|
37
|
-
export { default as RecordDataStoreWrapper } from './
|
|
36
|
+
export { default as recordDataFor, removeRecordDataFor } from './record-data-for';
|
|
37
|
+
export { default as RecordDataStoreWrapper } from './record-data-store-wrapper';
|
|
38
38
|
|
|
39
|
-
export { default as WeakCache } from './
|
|
39
|
+
export { default as WeakCache } from './weak-cache';
|