@ember-data/store 4.8.0-alpha.1 → 4.8.0-alpha.4

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.
Files changed (41) hide show
  1. package/addon/-debug/index.js +1 -1
  2. package/addon/-private/{identifier-cache.ts → caches/identifier-cache.ts} +114 -47
  3. package/addon/-private/caches/instance-cache.ts +702 -0
  4. package/addon/-private/{record-data-for.ts → caches/record-data-for.ts} +2 -2
  5. package/addon/-private/index.ts +38 -21
  6. package/addon/-private/{model → legacy-model-support}/record-reference.ts +15 -13
  7. package/addon/-private/{schema-definition-service.ts → legacy-model-support/schema-definition-service.ts} +13 -9
  8. package/addon/-private/{model → legacy-model-support}/shim-model-class.ts +8 -4
  9. package/addon/-private/{record-array-manager.ts → managers/record-array-manager.ts} +21 -44
  10. package/addon/-private/managers/record-data-manager.ts +830 -0
  11. package/addon/-private/managers/record-data-store-wrapper.ts +413 -0
  12. package/addon/-private/managers/record-notification-manager.ts +90 -0
  13. package/addon/-private/network/fetch-manager.ts +552 -0
  14. package/addon/-private/{finders.js → network/finders.js} +4 -12
  15. package/addon/-private/{request-cache.ts → network/request-cache.ts} +1 -1
  16. package/addon/-private/{snapshot-record-array.ts → network/snapshot-record-array.ts} +3 -3
  17. package/addon/-private/{snapshot.ts → network/snapshot.ts} +40 -49
  18. package/addon/-private/{promise-proxies.ts → proxies/promise-proxies.ts} +4 -4
  19. package/addon/-private/{promise-proxy-base.js → proxies/promise-proxy-base.js} +0 -0
  20. package/addon/-private/record-arrays/adapter-populated-record-array.ts +9 -11
  21. package/addon/-private/record-arrays/record-array.ts +25 -15
  22. package/addon/-private/{core-store.ts → store-service.ts} +412 -148
  23. package/addon/-private/{coerce-id.ts → utils/coerce-id.ts} +1 -1
  24. package/addon/-private/{common.js → utils/common.js} +1 -2
  25. package/addon/-private/utils/construct-resource.ts +2 -2
  26. package/addon/-private/{identifer-debug-consts.ts → utils/identifer-debug-consts.ts} +0 -0
  27. package/addon/-private/{normalize-model-name.ts → utils/normalize-model-name.ts} +1 -3
  28. package/addon/-private/utils/promise-record.ts +3 -3
  29. package/addon/-private/{serializer-response.ts → utils/serializer-response.ts} +2 -2
  30. package/addon/-private/utils/uuid-polyfill.ts +71 -0
  31. package/addon/-private/{weak-cache.ts → utils/weak-cache.ts} +0 -0
  32. package/package.json +11 -7
  33. package/addon/-private/errors-utils.js +0 -146
  34. package/addon/-private/fetch-manager.ts +0 -597
  35. package/addon/-private/identity-map.ts +0 -54
  36. package/addon/-private/instance-cache.ts +0 -387
  37. package/addon/-private/internal-model-factory.ts +0 -359
  38. package/addon/-private/internal-model-map.ts +0 -121
  39. package/addon/-private/model/internal-model.ts +0 -602
  40. package/addon/-private/record-data-store-wrapper.ts +0 -243
  41. package/addon/-private/record-notification-manager.ts +0 -73
@@ -5,7 +5,7 @@ import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
5
5
  import type { RecordData } from '@ember-data/types/q/record-data';
6
6
  import type { RecordInstance } from '@ember-data/types/q/record-instance';
7
7
 
8
- import WeakCache from './weak-cache';
8
+ import WeakCache from '../utils/weak-cache';
9
9
 
10
10
  /*
11
11
  * Returns the RecordData instance associated with a given
@@ -24,7 +24,7 @@ export function setRecordDataFor(identifier: StableRecordIdentifier | RecordInst
24
24
  RecordDataForIdentifierCache.set(identifier, recordData);
25
25
  }
26
26
 
27
- export function removeRecordDataFor(identifier: StableRecordIdentifier): void {
27
+ export function removeRecordDataFor(identifier: StableRecordIdentifier | RecordInstance): void {
28
28
  RecordDataForIdentifierCache.delete(identifier);
29
29
  }
30
30
 
@@ -2,38 +2,55 @@
2
2
  @module @ember-data/store
3
3
  */
4
4
 
5
- export { default as Store, storeFor } from './core-store';
5
+ import { assert, deprecate } from '@ember/debug';
6
6
 
7
- export { recordIdentifierFor } from './internal-model-factory';
7
+ import { DEPRECATE_HELPERS } from '@ember-data/private-build-infra/deprecations';
8
8
 
9
- export { default as Snapshot } from './snapshot';
9
+ import _normalize from './utils/normalize-model-name';
10
+
11
+ export { default as Store, storeFor } from './store-service';
12
+
13
+ export { recordIdentifierFor } from './caches/instance-cache';
14
+
15
+ export { default as Snapshot } from './network/snapshot';
10
16
  export {
11
17
  setIdentifierGenerationMethod,
12
18
  setIdentifierUpdateMethod,
13
19
  setIdentifierForgetMethod,
14
20
  setIdentifierResetMethod,
15
- } from './identifier-cache';
16
-
17
- export { default as normalizeModelName } from './normalize-model-name';
18
- export { default as coerceId } from './coerce-id';
19
-
20
- export { errorsHashToArray, errorsArrayToHash } from './errors-utils';
21
-
22
- // `ember-data-model-fragments` relies on `InternalModel`
23
- export { default as InternalModel } from './model/internal-model';
24
-
25
- export { PromiseArray, PromiseObject, deprecatedPromiseObject } from './promise-proxies';
21
+ } from './caches/identifier-cache';
22
+
23
+ export function normalizeModelName(modelName: string) {
24
+ if (DEPRECATE_HELPERS) {
25
+ deprecate(
26
+ `the helper function normalizeModelName is deprecated. You should use model names that are already normalized, or use string helpers of your own. This function is primarily an alias for dasherize from @ember/string.`,
27
+ false,
28
+ {
29
+ id: 'ember-data:deprecate-normalize-modelname-helper',
30
+ for: 'ember-data',
31
+ until: '5.0',
32
+ since: { available: '4.8', enabled: '4.8' },
33
+ }
34
+ );
35
+ return _normalize(modelName);
36
+ }
37
+ assert(`normalizeModelName support has been removed`);
38
+ }
39
+
40
+ // TODO this should be a deprecated helper but we have so much usage of it
41
+ // to also eliminate
42
+ export { default as coerceId } from './utils/coerce-id';
43
+
44
+ export { PromiseArray, PromiseObject, deprecatedPromiseObject } from './proxies/promise-proxies';
26
45
 
27
46
  export { default as RecordArray } from './record-arrays/record-array';
28
47
  export { default as AdapterPopulatedRecordArray } from './record-arrays/adapter-populated-record-array';
29
48
 
30
- export { default as RecordArrayManager } from './record-array-manager';
49
+ export { default as RecordArrayManager } from './managers/record-array-manager';
31
50
 
32
51
  // // Used by tests
33
- export { default as SnapshotRecordArray } from './snapshot-record-array';
34
-
35
- // New
36
- export { default as recordDataFor, removeRecordDataFor } from './record-data-for';
37
- export { default as RecordDataStoreWrapper } from './record-data-store-wrapper';
52
+ export { default as SnapshotRecordArray } from './network/snapshot-record-array';
38
53
 
39
- export { default as WeakCache } from './weak-cache';
54
+ // leaked for private use / test use, should investigate removing
55
+ export { default as recordDataFor, removeRecordDataFor } from './caches/record-data-for';
56
+ export { default as WeakCache } from './utils/weak-cache';
@@ -10,9 +10,9 @@ import type { SingleResourceDocument } from '@ember-data/types/q/ember-data-json
10
10
  import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
11
11
  import type { RecordInstance } from '@ember-data/types/q/record-instance';
12
12
 
13
- import type Store from '../core-store';
14
- import type { NotificationType } from '../record-notification-manager';
15
- import { unsubscribe } from '../record-notification-manager';
13
+ import type { NotificationType } from '../managers/record-notification-manager';
14
+ import { unsubscribe } from '../managers/record-notification-manager';
15
+ import type Store from '../store-service';
16
16
 
17
17
  /**
18
18
  @module @ember-data/store
@@ -27,18 +27,20 @@ import { unsubscribe } from '../record-notification-manager';
27
27
  @extends Reference
28
28
  */
29
29
  export default class RecordReference {
30
+ declare store: Store;
30
31
  // unsubscribe token given to us by the notification manager
31
- #token!: Object;
32
- #identifier: StableRecordIdentifier;
32
+ ___token!: Object;
33
+ ___identifier: StableRecordIdentifier;
33
34
 
34
35
  @tracked _ref = 0;
35
36
 
36
- constructor(public store: Store, identifier: StableRecordIdentifier) {
37
- this.#identifier = identifier;
38
- this.#token = store._notificationManager.subscribe(
37
+ constructor(store: Store, identifier: StableRecordIdentifier) {
38
+ this.store = store;
39
+ this.___identifier = identifier;
40
+ this.___token = store._notificationManager.subscribe(
39
41
  identifier,
40
42
  (_: StableRecordIdentifier, bucket: NotificationType, notifiedKey?: string) => {
41
- if (bucket === 'identity' || ((bucket === 'attributes' || bucket === 'property') && notifiedKey === 'id')) {
43
+ if (bucket === 'identity' || (bucket === 'attributes' && notifiedKey === 'id')) {
42
44
  this._ref++;
43
45
  }
44
46
  }
@@ -46,7 +48,7 @@ export default class RecordReference {
46
48
  }
47
49
 
48
50
  destroy() {
49
- unsubscribe(this.#token);
51
+ unsubscribe(this.___token);
50
52
  }
51
53
 
52
54
  get type(): string {
@@ -73,7 +75,7 @@ export default class RecordReference {
73
75
  */
74
76
  id() {
75
77
  this._ref; // consume the tracked prop
76
- return this.#identifier.id;
78
+ return this.___identifier.id;
77
79
  }
78
80
 
79
81
  /**
@@ -95,7 +97,7 @@ export default class RecordReference {
95
97
  @return {String} The identifier of the record.
96
98
  */
97
99
  identifier(): StableRecordIdentifier {
98
- return this.#identifier;
100
+ return this.___identifier;
99
101
  }
100
102
 
101
103
  /**
@@ -183,7 +185,7 @@ export default class RecordReference {
183
185
  @return {Model} the record for this RecordReference
184
186
  */
185
187
  value(): RecordInstance | null {
186
- return this.store.peekRecord(this.#identifier);
188
+ return this.store.peekRecord(this.___identifier);
187
189
  }
188
190
 
189
191
  /**
@@ -1,6 +1,5 @@
1
1
  import { getOwner } from '@ember/application';
2
2
  import { deprecate } from '@ember/debug';
3
- import { get } from '@ember/object';
4
3
 
5
4
  import { importSync } from '@embroider/macros';
6
5
 
@@ -10,8 +9,8 @@ import { DEPRECATE_STRING_ARG_SCHEMAS } from '@ember-data/private-build-infra/de
10
9
  import type { RecordIdentifier } from '@ember-data/types/q/identifier';
11
10
  import type { AttributesSchema, RelationshipsSchema } from '@ember-data/types/q/record-data-schemas';
12
11
 
13
- import type Store from './core-store';
14
- import normalizeModelName from './normalize-model-name';
12
+ import type Store from '../store-service';
13
+ import normalizeModelName from '../utils/normalize-model-name';
15
14
 
16
15
  type ModelForMixin = (store: Store, normalizedModelName: string) => Model | null;
17
16
 
@@ -27,10 +26,15 @@ if (HAS_MODEL_PACKAGE) {
27
26
  }
28
27
 
29
28
  export class DSModelSchemaDefinitionService {
30
- private _relationshipsDefCache = Object.create(null);
31
- private _attributesDefCache = Object.create(null);
32
-
33
- constructor(public store: Store) {}
29
+ declare store: Store;
30
+ declare _relationshipsDefCache;
31
+ declare _attributesDefCache;
32
+
33
+ constructor(store: Store) {
34
+ this.store = store;
35
+ this._relationshipsDefCache = Object.create(null);
36
+ this._attributesDefCache = Object.create(null);
37
+ }
34
38
 
35
39
  // Following the existing RD implementation
36
40
  attributesDefinitionFor(identifier: RecordIdentifier | { type: string }): AttributesSchema {
@@ -55,7 +59,7 @@ export class DSModelSchemaDefinitionService {
55
59
 
56
60
  if (attributes === undefined) {
57
61
  let modelClass = this.store.modelFor(modelName);
58
- let attributeMap = get(modelClass, 'attributes');
62
+ let attributeMap = modelClass.attributes;
59
63
 
60
64
  attributes = Object.create(null);
61
65
  attributeMap.forEach((meta, name) => (attributes[name] = meta));
@@ -88,7 +92,7 @@ export class DSModelSchemaDefinitionService {
88
92
 
89
93
  if (relationships === undefined) {
90
94
  let modelClass = this.store.modelFor(modelName);
91
- relationships = get(modelClass, 'relationshipsObject') || null;
95
+ relationships = modelClass.relationshipsObject || null;
92
96
  this._relationshipsDefCache[modelName] = relationships;
93
97
  }
94
98
 
@@ -4,8 +4,8 @@ import type { ModelSchema } from '@ember-data/types/q/ds-model';
4
4
  import type { AttributeSchema, RelationshipSchema } from '@ember-data/types/q/record-data-schemas';
5
5
  import type { Dict } from '@ember-data/types/q/utils';
6
6
 
7
- import type Store from '../core-store';
8
- import WeakCache from '../weak-cache';
7
+ import type Store from '../store-service';
8
+ import WeakCache from '../utils/weak-cache';
9
9
 
10
10
  const AvailableShims = new WeakCache<Store, Dict<ShimModelClass>>(DEBUG ? 'schema-shims' : '');
11
11
  AvailableShims._generator = () => {
@@ -33,8 +33,12 @@ function mapFromHash<T>(hash: Dict<T>): Map<string, T> {
33
33
 
34
34
  // Mimics the static apis of DSModel
35
35
  export default class ShimModelClass implements ModelSchema {
36
- // TODO Maybe expose the class here?
37
- constructor(private __store: Store, public modelName: string) {}
36
+ declare __store: Store;
37
+ declare modelName: string;
38
+ constructor(store: Store, modelName: string) {
39
+ this.__store = store;
40
+ this.modelName = modelName;
41
+ }
38
42
 
39
43
  get fields(): Map<string, 'attribute' | 'belongsTo' | 'hasMany'> {
40
44
  let attrs = this.__store.getSchemaDefinitionService().attributesDefinitionFor({ type: this.modelName });
@@ -4,20 +4,17 @@
4
4
 
5
5
  import { A } from '@ember/array';
6
6
  import { assert } from '@ember/debug';
7
- import { set } from '@ember/object';
8
7
  import { _backburner as emberBackburner } from '@ember/runloop';
9
8
  import { DEBUG } from '@glimmer/env';
10
9
 
11
- // import isStableIdentifier from '../identifiers/is-stable-identifier';
12
10
  import type { CollectionResourceDocument, Meta } from '@ember-data/types/q/ember-data-json-api';
13
11
  import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
14
12
  import type { Dict } from '@ember-data/types/q/utils';
15
13
 
16
- import type Store from './core-store';
17
- import { internalModelFactoryFor } from './internal-model-factory';
18
- import AdapterPopulatedRecordArray from './record-arrays/adapter-populated-record-array';
19
- import RecordArray from './record-arrays/record-array';
20
- import WeakCache from './weak-cache';
14
+ import AdapterPopulatedRecordArray from '../record-arrays/adapter-populated-record-array';
15
+ import RecordArray from '../record-arrays/record-array';
16
+ import type Store from '../store-service';
17
+ import WeakCache from '../utils/weak-cache';
21
18
 
22
19
  const RecordArraysCache = new WeakCache<StableRecordIdentifier, Set<RecordArray>>(DEBUG ? 'record-arrays' : '');
23
20
  RecordArraysCache._generator = () => new Set();
@@ -27,27 +24,6 @@ export function recordArraysForIdentifier(identifier: StableRecordIdentifier): S
27
24
 
28
25
  const pendingForIdentifier: Set<StableRecordIdentifier> = new Set([]);
29
26
 
30
- function getIdentifier(identifier: StableRecordIdentifier): StableRecordIdentifier {
31
- // during dematerialization we will get an identifier that
32
- // has already been removed from the identifiers cache
33
- // so it will not behave as if stable. This is a bug we should fix.
34
- // if (!isStableIdentifier(identifierOrInternalModel)) {
35
- // console.log({ unstable: i });
36
- // }
37
-
38
- return identifier;
39
- }
40
-
41
- function shouldIncludeInRecordArrays(store: Store, identifier: StableRecordIdentifier): boolean {
42
- const cache = internalModelFactoryFor(store);
43
- const internalModel = cache.peek(identifier);
44
-
45
- if (internalModel === null) {
46
- return false;
47
- }
48
- return !internalModel.isHiddenFromRecordArrays();
49
- }
50
-
51
27
  /**
52
28
  @class RecordArrayManager
53
29
  @internal
@@ -84,6 +60,7 @@ class RecordArrayManager {
84
60
  return;
85
61
  }
86
62
  let identifiersToRemove: StableRecordIdentifier[] = [];
63
+ let cache = this.store._instanceCache;
87
64
 
88
65
  for (let j = 0; j < identifiers.length; j++) {
89
66
  let i = identifiers[j];
@@ -91,8 +68,7 @@ class RecordArrayManager {
91
68
  // recordArrayManager
92
69
  pendingForIdentifier.delete(i);
93
70
  // build up a set of models to ensure we have purged correctly;
94
- let isIncluded = shouldIncludeInRecordArrays(this.store, i);
95
- if (!isIncluded) {
71
+ if (!cache.recordIsLoaded(i, true)) {
96
72
  identifiersToRemove.push(i);
97
73
  }
98
74
  }
@@ -130,8 +106,8 @@ class RecordArrayManager {
130
106
  return;
131
107
  }
132
108
  let hasNoPotentialDeletions = pending.length === 0;
133
- let map = internalModelFactoryFor(this.store).modelMapFor(modelName);
134
- let hasNoInsertionsOrRemovals = map.length === array.length;
109
+ let listSize = this.store._instanceCache.peekList[modelName]?.size;
110
+ let hasNoInsertionsOrRemovals = listSize === array.length;
135
111
 
136
112
  /*
137
113
  Ideally the recordArrayManager has knowledge of the changes to be applied to
@@ -144,6 +120,11 @@ class RecordArrayManager {
144
120
  }
145
121
 
146
122
  this._flushPendingIdentifiersForModelName(modelName, pending);
123
+ // TODO make this a map
124
+ // TODO we probably do way too much work here, probably can just take
125
+ // current all-known state and filter visible.
126
+ // We can then provide this directly to the RecordArray instance.
127
+ // If we deprecate RecordArray being an ArrayProxy this will be stellar.
147
128
  delete this._pendingIdentifiers[modelName];
148
129
 
149
130
  let identifiers = this._visibleIdentifiersByType(modelName);
@@ -165,7 +146,7 @@ class RecordArrayManager {
165
146
  _didUpdateAll(modelName: string): void {
166
147
  let recordArray = this._liveRecordArrays[modelName];
167
148
  if (recordArray) {
168
- set(recordArray, 'isUpdating', false);
149
+ recordArray.isUpdating = false;
169
150
  // TODO potentially we should sync here, currently
170
151
  // this occurs as a side-effect of individual records updating
171
152
  // this._syncLiveRecordArray(recordArray, modelName);
@@ -204,13 +185,14 @@ class RecordArrayManager {
204
185
  }
205
186
 
206
187
  _visibleIdentifiersByType(modelName: string) {
207
- let all = internalModelFactoryFor(this.store).modelMapFor(modelName).recordIdentifiers;
188
+ const cache = this.store._instanceCache;
189
+ const list = cache.peekList[modelName];
190
+ let all = list ? [...list.values()] : [];
208
191
  let visible: StableRecordIdentifier[] = [];
209
192
  for (let i = 0; i < all.length; i++) {
210
193
  let identifier = all[i];
211
- let shouldInclude = shouldIncludeInRecordArrays(this.store, identifier);
212
194
 
213
- if (shouldInclude) {
195
+ if (cache.recordIsLoaded(identifier, true)) {
214
196
  visible.push(identifier);
215
197
  }
216
198
  }
@@ -335,7 +317,6 @@ class RecordArrayManager {
335
317
  _associateWithRecordArray(identifiers: StableRecordIdentifier[], array: RecordArray): void {
336
318
  for (let i = 0, l = identifiers.length; i < l; i++) {
337
319
  let identifier = identifiers[i];
338
- identifier = getIdentifier(identifier);
339
320
  let recordArrays = this.getRecordArraysForIdentifier(identifier);
340
321
  recordArrays.add(array);
341
322
  }
@@ -350,7 +331,6 @@ class RecordArrayManager {
350
331
  return;
351
332
  }
352
333
  let modelName = identifier.type;
353
- identifier = getIdentifier(identifier);
354
334
 
355
335
  if (pendingForIdentifier.has(identifier)) {
356
336
  return;
@@ -397,20 +377,18 @@ function removeFromArray(array: RecordArray[], item: RecordArray): boolean {
397
377
  function updateLiveRecordArray(store: Store, recordArray: RecordArray, identifiers: StableRecordIdentifier[]): void {
398
378
  let identifiersToAdd: StableRecordIdentifier[] = [];
399
379
  let identifiersToRemove: StableRecordIdentifier[] = [];
380
+ const cache = store._instanceCache;
400
381
 
401
382
  for (let i = 0; i < identifiers.length; i++) {
402
383
  let identifier = identifiers[i];
403
- let shouldInclude = shouldIncludeInRecordArrays(store, identifier);
404
384
  let recordArrays = recordArraysForIdentifier(identifier);
405
385
 
406
- if (shouldInclude) {
386
+ if (cache.recordIsLoaded(identifier, true)) {
407
387
  if (!recordArrays.has(recordArray)) {
408
388
  identifiersToAdd.push(identifier);
409
389
  recordArrays.add(recordArray);
410
390
  }
411
- }
412
-
413
- if (!shouldInclude) {
391
+ } else {
414
392
  identifiersToRemove.push(identifier);
415
393
  recordArrays.delete(recordArray);
416
394
  }
@@ -431,7 +409,6 @@ function removeFromAdapterPopulatedRecordArrays(store: Store, identifiers: Stabl
431
409
  }
432
410
 
433
411
  function removeFromAll(store: Store, identifier: StableRecordIdentifier): void {
434
- identifier = getIdentifier(identifier);
435
412
  const recordArrays = recordArraysForIdentifier(identifier);
436
413
 
437
414
  recordArrays.forEach(function (recordArray) {