@ember-data/store 4.10.0-alpha.2 → 4.10.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.
@@ -423,16 +423,21 @@ export class InstanceCache {
423
423
  }
424
424
  }
425
425
 
426
+ let removeFromRecordArray = true;
426
427
  if (recordData) {
428
+ removeFromRecordArray = !recordData.isDeletionCommitted(identifier);
427
429
  recordData.unloadRecord(identifier);
428
430
  this.__instances.recordData.delete(identifier);
429
431
  removeRecordDataFor(identifier);
430
432
  } else {
433
+ removeFromRecordArray = false;
431
434
  this.disconnect(identifier);
432
435
  }
433
436
 
434
437
  this.store._fetchManager.clearEntries(identifier);
435
- this.store.recordArrayManager.identifierRemoved(identifier);
438
+ if (removeFromRecordArray) {
439
+ this.store.recordArrayManager.identifierRemoved(identifier);
440
+ }
436
441
  if (LOG_INSTANCE_CACHE) {
437
442
  // eslint-disable-next-line no-console
438
443
  console.log(`InstanceCache: unloaded RecordData for ${String(identifier)}`);
@@ -471,12 +476,6 @@ export class InstanceCache {
471
476
  const isEmpty = _isEmpty(this, identifier);
472
477
  const isLoading = _isLoading(this, identifier);
473
478
 
474
- if (options.preload) {
475
- this.store._join(() => {
476
- preloadData(this.store, identifier, options.preload!);
477
- });
478
- }
479
-
480
479
  let promise: Promise<StableRecordIdentifier>;
481
480
  if (isEmpty) {
482
481
  assertIdentifierHasId(identifier);
@@ -612,7 +611,7 @@ export function recordDataIsFullyDeleted(cache: InstanceCache, identifier: Stabl
612
611
  models.
613
612
  */
614
613
  type PreloadRelationshipValue = RecordInstance | string;
615
- function preloadData(store: Store, identifier: StableRecordIdentifier, preload: Dict<unknown>) {
614
+ export function preloadData(store: Store, identifier: StableRecordIdentifier, preload: Dict<unknown>) {
616
615
  let jsonPayload: JsonApiResource = {};
617
616
  //TODO(Igor) consider the polymorphic case
618
617
  const schemas = store.getSchemaDefinitionService();
@@ -81,16 +81,11 @@ export default class ShimModelClass implements ModelSchema {
81
81
  });
82
82
  }
83
83
 
84
- eachTransformedAttribute<T>(
85
- callback: (this: T | undefined, key: string, relationship: RelationshipSchema) => void,
86
- binding?: T
87
- ) {
88
- let relationshipDefs = this.__store
89
- .getSchemaDefinitionService()
90
- .relationshipsDefinitionFor({ type: this.modelName });
91
- Object.keys(relationshipDefs).forEach((key) => {
92
- if (relationshipDefs[key]!.type) {
93
- callback.call(binding, key, relationshipDefs[key] as RelationshipSchema);
84
+ eachTransformedAttribute<T>(callback: (this: T | undefined, key: string, type: string) => void, binding?: T) {
85
+ const attrDefs = this.__store.getSchemaDefinitionService().attributesDefinitionFor({ type: this.modelName });
86
+ Object.keys(attrDefs).forEach((key) => {
87
+ if (attrDefs[key]!.type) {
88
+ callback.call(binding, key, attrDefs[key]!.type);
94
89
  }
95
90
  });
96
91
  }
@@ -357,7 +357,10 @@ function sync(array: IdentifierArray, changes: Map<StableRecordIdentifier, 'add'
357
357
  // state = array[SOURCE] = [];
358
358
  } else {
359
359
  removes.forEach((i) => {
360
- state.splice(state.indexOf(i), 1);
360
+ const index = state.indexOf(i);
361
+ if (index !== -1) {
362
+ state.splice(index, 1);
363
+ }
361
364
  });
362
365
  }
363
366
  }
@@ -119,7 +119,7 @@ export class NonSingletonRecordDataManager implements RecordData {
119
119
  // called by something V1
120
120
  if (!isStableIdentifier(identifier)) {
121
121
  data = identifier as JsonApiResource;
122
- hasRecord = data as boolean;
122
+ hasRecord = data as unknown as boolean;
123
123
  identifier = this.#identifier;
124
124
  }
125
125
  if (this.#isDeprecated(recordData)) {
@@ -114,6 +114,33 @@ interface PrivateState {
114
114
  links: Links | PaginationLinks | null;
115
115
  meta: Dict<unknown> | null;
116
116
  }
117
+ type ForEachCB = (record: RecordInstance, index: number, context: IdentifierArray) => void;
118
+ function safeForEach(
119
+ instance: IdentifierArray,
120
+ arr: StableRecordIdentifier[],
121
+ store: Store,
122
+ callback: ForEachCB,
123
+ target: unknown
124
+ ) {
125
+ if (target === undefined) {
126
+ target = null;
127
+ }
128
+ // clone to prevent mutation
129
+ arr = arr.slice();
130
+ assert('`forEach` expects a function as first argument.', typeof callback === 'function');
131
+
132
+ // because we retrieveLatest above we need not worry if array is mutated during iteration
133
+ // by unloadRecord/rollbackAttributes
134
+ // push/add/removeObject may still be problematic
135
+ // but this is a more traditionally expected forEach bug.
136
+ const length = arr.length; // we need to access length to ensure we are consumed
137
+
138
+ for (let index = 0; index < length; index++) {
139
+ callback.call(target, store._instanceCache.getRecord(arr[index]), index, instance);
140
+ }
141
+
142
+ return instance;
143
+ }
117
144
 
118
145
  /**
119
146
  A record array is an array that contains records of a certain type (or modelName).
@@ -241,15 +268,25 @@ class IdentifierArray {
241
268
  let fn = boundFns.get(prop);
242
269
 
243
270
  if (fn === undefined) {
244
- fn = function () {
245
- subscribe(_TAG);
246
- // array functions must run through Reflect to work properly
247
- // binding via other means will not work.
248
- transaction = true;
249
- let result = Reflect.apply(target[prop] as ProxiedMethod, receiver, arguments) as unknown;
250
- transaction = false;
251
- return result;
252
- };
271
+ if (prop === 'forEach') {
272
+ fn = function () {
273
+ subscribe(_TAG);
274
+ transaction = true;
275
+ let result = safeForEach(receiver, target, store, arguments[0] as ForEachCB, arguments[1]);
276
+ transaction = false;
277
+ return result;
278
+ };
279
+ } else {
280
+ fn = function () {
281
+ subscribe(_TAG);
282
+ // array functions must run through Reflect to work properly
283
+ // binding via other means will not work.
284
+ transaction = true;
285
+ let result = Reflect.apply(target[prop] as ProxiedMethod, receiver, arguments) as unknown;
286
+ transaction = false;
287
+ return result;
288
+ };
289
+ }
253
290
 
254
291
  boundFns.set(prop, fn);
255
292
  }
@@ -271,7 +308,7 @@ class IdentifierArray {
271
308
  const args: unknown[] = Array.prototype.slice.call(arguments);
272
309
  assert(`Cannot start a new array transaction while a previous transaction is underway`, !transaction);
273
310
  transaction = true;
274
- let result = Reflect.apply(target[prop] as ProxiedMethod, receiver, args) as unknown;
311
+ let result: unknown = Reflect.apply(target[prop] as ProxiedMethod, receiver, args);
275
312
  self[MUTATE]!(prop as string, args, result);
276
313
  addToTransaction(_TAG);
277
314
  // TODO handle cache updates
@@ -658,13 +695,21 @@ if (DEPRECATE_ARRAY_LIKE) {
658
695
 
659
696
  IdentifierArray.prototype.removeObject = function (obj: RecordInstance) {
660
697
  deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'removeObject', 'splice');
661
- this.splice(this.indexOf(obj), 1);
698
+ const index = this.indexOf(obj);
699
+ if (index !== -1) {
700
+ this.splice(index, 1);
701
+ }
662
702
  return this;
663
703
  };
664
704
 
665
705
  IdentifierArray.prototype.removeObjects = function (objs: RecordInstance[]) {
666
706
  deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'removeObjects', 'splice');
667
- objs.forEach((obj) => this.splice(this.indexOf(obj), 1));
707
+ objs.forEach((obj) => {
708
+ const index = this.indexOf(obj);
709
+ if (index !== -1) {
710
+ this.splice(index, 1);
711
+ }
712
+ });
668
713
  return this;
669
714
  };
670
715
 
@@ -45,6 +45,7 @@ import { IdentifierCache } from './caches/identifier-cache';
45
45
  import {
46
46
  InstanceCache,
47
47
  peekRecordIdentifier,
48
+ preloadData,
48
49
  recordDataIsFullyDeleted,
49
50
  recordIdentifierFor,
50
51
  setRecordIdentifier,
@@ -482,6 +483,7 @@ class Store extends Service {
482
483
  @return {subclass of Model | ShimModelClass}
483
484
  */
484
485
  // TODO @deprecate in favor of schema APIs, requires adapter/serializer overhaul or replacement
486
+ declare _forceShim: boolean;
485
487
  modelFor(modelName: string): ShimModelClass | DSModelClass {
486
488
  if (DEBUG) {
487
489
  assertDestroyedStoreOnly(this, 'modelFor');
@@ -497,7 +499,7 @@ class Store extends Service {
497
499
 
498
500
  // for factorFor factory/class split
499
501
  let klass = maybeFactory && maybeFactory.class ? maybeFactory.class : maybeFactory;
500
- if (!klass || !klass.isModel) {
502
+ if (!klass || !klass.isModel || this._forceShim) {
501
503
  assert(
502
504
  `No model was found for '${modelName}' and no schema handles the type`,
503
505
  this.getSchemaDefinitionService().doesTypeExist(modelName)
@@ -1127,6 +1129,12 @@ class Store extends Service {
1127
1129
  let promise;
1128
1130
  options = options || {};
1129
1131
 
1132
+ if (options.preload) {
1133
+ this._join(() => {
1134
+ preloadData(this, identifier, options!.preload!);
1135
+ });
1136
+ }
1137
+
1130
1138
  // if not loaded start loading
1131
1139
  if (!this._instanceCache.recordIsLoaded(identifier)) {
1132
1140
  promise = this._instanceCache._fetchDataIfNeededForIdentifier(identifier, options);
@@ -1134,6 +1142,7 @@ class Store extends Service {
1134
1142
  // Refetch if the reload option is passed
1135
1143
  } else if (options.reload) {
1136
1144
  assertIdentifierHasId(identifier);
1145
+
1137
1146
  promise = this._fetchManager.scheduleFetch(identifier, options);
1138
1147
  } else {
1139
1148
  let snapshot: Snapshot | null = null;
@@ -2310,8 +2319,8 @@ class Store extends Service {
2310
2319
 
2311
2320
  const saveOptions = Object.assign({ [SaveOp]: operation }, options);
2312
2321
  let fetchManagerPromise = this._fetchManager.scheduleSave(identifier, saveOptions);
2313
- return fetchManagerPromise.then(
2314
- (payload) => {
2322
+ return fetchManagerPromise
2323
+ .then((payload) => {
2315
2324
  if (LOG_PAYLOADS) {
2316
2325
  try {
2317
2326
  let data = payload ? JSON.parse(JSON.stringify(payload)) : payload;
@@ -2366,8 +2375,8 @@ class Store extends Service {
2366
2375
  }
2367
2376
  });
2368
2377
  return record;
2369
- },
2370
- (e) => {
2378
+ })
2379
+ .catch((e) => {
2371
2380
  let err = e;
2372
2381
  if (!e) {
2373
2382
  err = new Error(`Unknown Error Occurred During Request`);
@@ -2376,8 +2385,7 @@ class Store extends Service {
2376
2385
  }
2377
2386
  adapterDidInvalidate(this, identifier, err);
2378
2387
  throw err;
2379
- }
2380
- );
2388
+ });
2381
2389
  }
2382
2390
 
2383
2391
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ember-data/store",
3
- "version": "4.10.0-alpha.2",
3
+ "version": "4.10.0-alpha.4",
4
4
  "description": "The core of EmberData. Provides the Store service which coordinates the cache with the network and presentation layers.",
5
5
  "keywords": [
6
6
  "ember-addon"
@@ -14,9 +14,9 @@
14
14
  "author": "",
15
15
  "directories": {},
16
16
  "peerDependencies": {
17
- "@ember-data/model": "4.10.0-alpha.2",
18
- "@ember-data/record-data": "4.10.0-alpha.2",
19
- "@ember-data/tracking": "4.10.0-alpha.2",
17
+ "@ember-data/model": "4.10.0-alpha.4",
18
+ "@ember-data/record-data": "4.10.0-alpha.4",
19
+ "@ember-data/tracking": "4.10.0-alpha.4",
20
20
  "@ember/string": "^3.0.0",
21
21
  "@glimmer/tracking": "^1.1.2"
22
22
  },
@@ -37,8 +37,8 @@
37
37
  }
38
38
  },
39
39
  "dependencies": {
40
- "@ember-data/canary-features": "4.10.0-alpha.2",
41
- "@ember-data/private-build-infra": "4.10.0-alpha.2",
40
+ "@ember-data/canary-features": "4.10.0-alpha.4",
41
+ "@ember-data/private-build-infra": "4.10.0-alpha.4",
42
42
  "@embroider/macros": "^1.10.0",
43
43
  "ember-auto-import": "^2.5.0",
44
44
  "ember-cached-decorator-polyfill": "^1.0.1",
@@ -57,5 +57,5 @@
57
57
  "volta": {
58
58
  "extends": "../../package.json"
59
59
  },
60
- "packageManager": "pnpm@7.15.0"
60
+ "packageManager": "pnpm@7.18.0"
61
61
  }