@ember-data/store 4.2.0-beta.0 → 4.3.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.
Files changed (30) hide show
  1. package/addon/-private/identifiers/cache.ts +3 -16
  2. package/addon/-private/identifiers/is-stable-identifier.ts +2 -2
  3. package/addon/-private/index.ts +1 -3
  4. package/addon/-private/system/core-store.ts +192 -958
  5. package/addon/-private/system/ds-model-store.ts +20 -111
  6. package/addon/-private/system/fetch-manager.ts +11 -5
  7. package/addon/-private/system/model/internal-model.ts +92 -345
  8. package/addon/-private/system/model/shim-model-class.ts +15 -16
  9. package/addon/-private/system/model/states.js +2 -14
  10. package/addon/-private/system/record-array-manager.js +21 -70
  11. package/addon/-private/system/record-arrays/adapter-populated-record-array.js +1 -20
  12. package/addon/-private/system/record-arrays/record-array.js +1 -8
  13. package/addon/-private/system/record-data-for.ts +10 -8
  14. package/addon/-private/system/record-notification-manager.ts +11 -10
  15. package/addon/-private/system/references/belongs-to.ts +32 -67
  16. package/addon/-private/system/references/has-many.ts +21 -41
  17. package/addon/-private/system/references/record.ts +15 -27
  18. package/addon/-private/system/references/reference.ts +4 -11
  19. package/addon/-private/system/schema-definition-service.ts +2 -2
  20. package/addon/-private/system/snapshot.ts +28 -48
  21. package/addon/-private/system/store/finders.js +2 -96
  22. package/addon/-private/system/store/internal-model-factory.ts +34 -28
  23. package/addon/-private/system/store/record-data-store-wrapper.ts +28 -36
  24. package/addon/-private/system/weak-cache.ts +125 -0
  25. package/addon/-private/ts-interfaces/fetch-manager.ts +4 -0
  26. package/addon/-private/ts-interfaces/identifier.ts +2 -2
  27. package/addon/-private/ts-interfaces/minimum-adapter-interface.ts +0 -1
  28. package/addon/-private/ts-interfaces/schema-definition-service.ts +2 -2
  29. package/package.json +16 -16
  30. package/addon/-private/system/deprecated-evented.js +0 -92
@@ -1,20 +1,12 @@
1
- import { getOwner, setOwner } from '@ember/application';
2
1
  import { A, default as EmberArray } from '@ember/array';
3
2
  import { assert, inspect } from '@ember/debug';
4
3
  import EmberError from '@ember/error';
5
- import { get, set } from '@ember/object';
4
+ import { get } from '@ember/object';
6
5
  import { _backburner as emberBackburner, cancel, run } from '@ember/runloop';
7
6
  import { DEBUG } from '@glimmer/env';
8
7
 
9
8
  import RSVP, { Promise } from 'rsvp';
10
9
 
11
- import {
12
- CUSTOM_MODEL_CLASS,
13
- RECORD_DATA_ERRORS,
14
- RECORD_DATA_STATE,
15
- REMOVE_RECORD_ARRAY_MANAGER_LEGACY_COMPAT,
16
- REQUEST_SERVICE,
17
- } from '@ember-data/canary-features';
18
10
  import { HAS_MODEL_PACKAGE, HAS_RECORD_DATA_PACKAGE } from '@ember-data/private-build-infra';
19
11
  import type {
20
12
  BelongsToRelationship,
@@ -23,7 +15,6 @@ import type {
23
15
  } from '@ember-data/record-data/-private';
24
16
  import type { UpgradedMeta } from '@ember-data/record-data/-private/graph/-edge-definition';
25
17
 
26
- import { identifierCacheFor } from '../../identifiers/cache';
27
18
  import { DSModel } from '../../ts-interfaces/ds-model';
28
19
  import type { StableRecordIdentifier } from '../../ts-interfaces/identifier';
29
20
  import type { RecordData } from '../../ts-interfaces/record-data';
@@ -31,15 +22,13 @@ import type { JsonApiResource, JsonApiValidationError } from '../../ts-interface
31
22
  import type { RecordInstance } from '../../ts-interfaces/record-instance';
32
23
  import type { FindOptions } from '../../ts-interfaces/store';
33
24
  import type { ConfidentDict } from '../../ts-interfaces/utils';
34
- import coerceId from '../coerce-id';
35
25
  import type CoreStore from '../core-store';
36
26
  import type Store from '../ds-model-store';
37
27
  import { errorsHashToArray } from '../errors-utils';
38
- import { recordArraysForIdentifier } from '../record-array-manager';
39
28
  import recordDataFor from '../record-data-for';
40
29
  import { BelongsToReference, HasManyReference, RecordReference } from '../references';
41
30
  import Snapshot from '../snapshot';
42
- import { internalModelFactoryFor, setRecordIdentifier } from '../store/internal-model-factory';
31
+ import { internalModelFactoryFor } from '../store/internal-model-factory';
43
32
  import RootState from './states';
44
33
 
45
34
  // move to TS hacks module that we can delete when this is no longer a necessary recast
@@ -72,11 +61,6 @@ if (HAS_MODEL_PACKAGE) {
72
61
  };
73
62
  }
74
63
 
75
- // TODO this should be integrated with the code removal so we can use it together with the if condition
76
- // and not alongside it
77
- function isNotCustomModelClass(store: CoreStore | Store): store is Store {
78
- return !CUSTOM_MODEL_CLASS;
79
- }
80
64
  interface BelongsToMetaWrapper {
81
65
  key: string;
82
66
  store: CoreStore;
@@ -189,7 +173,7 @@ export default class InternalModel {
189
173
  set id(value: string | null) {
190
174
  if (value !== this._id) {
191
175
  let newIdentifier = { type: this.identifier.type, lid: this.identifier.lid, id: value };
192
- identifierCacheFor(this.store).updateRecordIdentifier(this.identifier, newIdentifier);
176
+ this.store.identifierCache.updateRecordIdentifier(this.identifier, newIdentifier);
193
177
  this.notifyPropertyChange('id');
194
178
  }
195
179
  }
@@ -233,60 +217,40 @@ export default class InternalModel {
233
217
  return true;
234
218
  }
235
219
 
236
- if (RECORD_DATA_STATE) {
237
- if (this.currentState.isLoading) {
238
- return false;
239
- }
220
+ if (this.currentState.isLoading) {
221
+ return false;
240
222
  }
241
223
 
242
- let isRecordFullyDeleted;
243
- if (RECORD_DATA_STATE) {
244
- isRecordFullyDeleted = this._isRecordFullyDeleted();
245
- } else {
246
- isRecordFullyDeleted = this.currentState.stateName === 'root.deleted.saved';
247
- }
224
+ let isRecordFullyDeleted = this._isRecordFullyDeleted();
248
225
  return this._isDematerializing || this.hasScheduledDestroy() || this.isDestroyed || isRecordFullyDeleted;
249
226
  }
250
227
 
251
228
  _isRecordFullyDeleted(): boolean {
252
- if (RECORD_DATA_STATE) {
253
- if (this._recordData.isDeletionCommitted && this._recordData.isDeletionCommitted()) {
254
- return true;
255
- } else if (
256
- this._recordData.isNew &&
257
- this._recordData.isDeleted &&
258
- this._recordData.isNew() &&
259
- this._recordData.isDeleted()
260
- ) {
261
- return true;
262
- } else {
263
- return this.currentState.stateName === 'root.deleted.saved';
264
- }
229
+ if (this._recordData.isDeletionCommitted && this._recordData.isDeletionCommitted()) {
230
+ return true;
231
+ } else if (
232
+ this._recordData.isNew &&
233
+ this._recordData.isDeleted &&
234
+ this._recordData.isNew() &&
235
+ this._recordData.isDeleted()
236
+ ) {
237
+ return true;
265
238
  } else {
266
- // assert here
267
- return false;
239
+ return this.currentState.stateName === 'root.deleted.saved';
268
240
  }
269
241
  }
270
242
 
271
243
  isDeleted() {
272
- if (RECORD_DATA_STATE) {
273
- if (this._recordData.isDeleted) {
274
- return this._recordData.isDeleted();
275
- } else {
276
- return this.currentState.isDeleted;
277
- }
244
+ if (this._recordData.isDeleted) {
245
+ return this._recordData.isDeleted();
278
246
  } else {
279
247
  return this.currentState.isDeleted;
280
248
  }
281
249
  }
282
250
 
283
251
  isNew() {
284
- if (RECORD_DATA_STATE) {
285
- if (this._recordData.isNew) {
286
- return this._recordData.isNew();
287
- } else {
288
- return this.currentState.isNew;
289
- }
252
+ if (this._recordData.isNew) {
253
+ return this._recordData.isNew();
290
254
  } else {
291
255
  return this.currentState.isNew;
292
256
  }
@@ -296,73 +260,7 @@ export default class InternalModel {
296
260
  if (!this._record && !this._isDematerializing) {
297
261
  let { store } = this;
298
262
 
299
- if (CUSTOM_MODEL_CLASS) {
300
- this._record = store._instantiateRecord(this, this.modelName, this._recordData, this.identifier, properties);
301
- } else {
302
- if (isNotCustomModelClass(store)) {
303
- // lookupFactory should really return an object that creates
304
- // instances with the injections applied
305
- let createOptions: any = {
306
- store,
307
- _internalModel: this,
308
- };
309
-
310
- if (!REQUEST_SERVICE) {
311
- createOptions.isError = this.isError;
312
- createOptions.adapterError = this.error;
313
- }
314
-
315
- if (properties !== undefined) {
316
- assert(
317
- `You passed '${properties}' as properties for record creation instead of an object.`,
318
- typeof properties === 'object' && properties !== null
319
- );
320
-
321
- if ('id' in properties) {
322
- const id = coerceId(properties.id);
323
-
324
- if (id !== null) {
325
- this.setId(id);
326
- }
327
- }
328
-
329
- // convert relationship Records to RecordDatas before passing to RecordData
330
- let defs = store._relationshipsDefinitionFor(this.modelName);
331
-
332
- if (defs !== null) {
333
- let keys = Object.keys(properties);
334
- let relationshipValue;
335
-
336
- for (let i = 0; i < keys.length; i++) {
337
- let prop = keys[i];
338
- let def = defs[prop];
339
-
340
- if (def !== undefined) {
341
- if (def.kind === 'hasMany') {
342
- if (DEBUG) {
343
- assertRecordsPassedToHasMany(properties[prop]);
344
- }
345
- relationshipValue = extractRecordDatasFromRecords(properties[prop]);
346
- } else {
347
- relationshipValue = extractRecordDataFromRecord(properties[prop]);
348
- }
349
-
350
- properties[prop] = relationshipValue;
351
- }
352
- }
353
- }
354
- }
355
-
356
- let additionalCreateOptions = this._recordData._initRecordCreateOptions(properties);
357
- Object.assign(createOptions, additionalCreateOptions);
358
-
359
- // ensure that `getOwner(this)` works inside a model instance
360
- setOwner(createOptions, getOwner(store));
361
-
362
- this._record = store._modelFactoryFor(this.modelName).create(createOptions);
363
- setRecordIdentifier(this._record, this.identifier);
364
- }
365
- }
263
+ this._record = store._instantiateRecord(this, this.modelName, this._recordData, this.identifier, properties);
366
264
  this._triggerDeferredTriggers();
367
265
  }
368
266
 
@@ -377,15 +275,8 @@ export default class InternalModel {
377
275
  this._doNotDestroy = false;
378
276
  // this has to occur before the internal model is removed
379
277
  // for legacy compat.
380
- if (!REMOVE_RECORD_ARRAY_MANAGER_LEGACY_COMPAT) {
381
- this.store.recordArrayManager.recordDidChange(this.identifier);
382
- }
383
278
  if (this._record) {
384
- if (CUSTOM_MODEL_CLASS) {
385
- this.store.teardownRecord(this._record);
386
- } else {
387
- this._record.destroy();
388
- }
279
+ this.store.teardownRecord(this._record);
389
280
  }
390
281
 
391
282
  // move to an empty never-loaded state
@@ -409,19 +300,15 @@ export default class InternalModel {
409
300
  this.error = null;
410
301
  this._previousState = this.currentState;
411
302
  this.currentState = RootState.empty;
412
- if (REMOVE_RECORD_ARRAY_MANAGER_LEGACY_COMPAT) {
413
- this.store.recordArrayManager.recordDidChange(this.identifier);
414
- }
303
+ this.store.recordArrayManager.recordDidChange(this.identifier);
415
304
  }
416
305
 
417
306
  deleteRecord() {
418
307
  run(() => {
419
308
  const backburner = this.store._backburner;
420
309
  backburner.run(() => {
421
- if (RECORD_DATA_STATE) {
422
- if (this._recordData.setIsDeleted) {
423
- this._recordData.setIsDeleted(true);
424
- }
310
+ if (this._recordData.setIsDeleted) {
311
+ this._recordData.setIsDeleted(true);
425
312
  }
426
313
 
427
314
  if (this.isNew()) {
@@ -444,50 +331,26 @@ export default class InternalModel {
444
331
  let promiseLabel = 'DS: Model#save ' + this;
445
332
  let resolver = RSVP.defer<void>(promiseLabel);
446
333
 
447
- if (REQUEST_SERVICE) {
448
- // Casting to promise to narrow due to the feature flag paths inside scheduleSave
449
- return this.store.scheduleSave(this, resolver, options) as Promise<void>;
450
- } else {
451
- this.store.scheduleSave(this, resolver, options);
452
- return resolver.promise;
453
- }
334
+ // Casting to promise to narrow due to the feature flag paths inside scheduleSave
335
+ return this.store.scheduleSave(this, resolver, options) as Promise<void>;
454
336
  }
455
337
 
456
338
  reload(options) {
457
- if (REQUEST_SERVICE) {
458
- if (!options) {
459
- options = {};
460
- }
461
- let internalModel = this;
462
-
463
- return internalModel.store._reloadRecord(internalModel, options).then(
464
- function () {
465
- //TODO NOW seems like we shouldn't need to do this
466
- return internalModel;
467
- },
468
- function (error) {
469
- throw error;
470
- },
471
- 'DS: Model#reload complete, update flags'
472
- );
473
- } else {
474
- let internalModel = this;
475
- let promiseLabel = 'DS: Model#reload of ' + this;
476
-
477
- return new Promise(function (resolve) {
478
- internalModel.send('reloadRecord', { resolve, options });
479
- }, promiseLabel).then(
480
- function () {
481
- internalModel.didCleanError();
482
- return internalModel;
483
- },
484
- function (error) {
485
- internalModel.didError(error);
486
- throw error;
487
- },
488
- 'DS: Model#reload complete, update flags'
489
- );
490
- }
339
+ if (!options) {
340
+ options = {};
341
+ }
342
+ let internalModel = this;
343
+
344
+ return internalModel.store._reloadRecord(internalModel, options).then(
345
+ function () {
346
+ //TODO NOW seems like we shouldn't need to do this
347
+ return internalModel;
348
+ },
349
+ function (error) {
350
+ throw error;
351
+ },
352
+ 'DS: Model#reload complete, update flags'
353
+ );
491
354
  }
492
355
 
493
356
  /*
@@ -573,8 +436,10 @@ export default class InternalModel {
573
436
  getBelongsTo(key, options) {
574
437
  let resource = (this._recordData as DefaultRecordData).getBelongsTo(key);
575
438
  let identifier =
576
- resource && resource.data ? identifierCacheFor(this.store).getOrCreateRecordIdentifier(resource.data) : null;
439
+ resource && resource.data ? this.store.identifierCache.getOrCreateRecordIdentifier(resource.data) : null;
577
440
  let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key);
441
+ if (!relationshipMeta) return;
442
+
578
443
  let store = this.store;
579
444
  let parentInternalModel = this;
580
445
  let async = relationshipMeta.options.async;
@@ -865,31 +730,17 @@ export default class InternalModel {
865
730
  }
866
731
 
867
732
  hasChangedAttributes() {
868
- if (REQUEST_SERVICE) {
869
- if (!this.__recordData) {
870
- // no need to calculate changed attributes when calling `findRecord`
871
- return false;
872
- }
873
- } else {
874
- if (this.currentState.isLoading) {
875
- // no need to calculate changed attributes when calling `findRecord`
876
- return false;
877
- }
733
+ if (!this.__recordData) {
734
+ // no need to calculate changed attributes when calling `findRecord`
735
+ return false;
878
736
  }
879
737
  return this._recordData.hasChangedAttributes();
880
738
  }
881
739
 
882
740
  changedAttributes() {
883
- if (REQUEST_SERVICE) {
884
- if (!this.__recordData) {
885
- // no need to calculate changed attributes when calling `findRecord`
886
- return {};
887
- }
888
- } else {
889
- if (this.currentState.isLoading) {
890
- // no need to calculate changed attributes when calling `findRecord`
891
- return {};
892
- }
741
+ if (!this.__recordData) {
742
+ // no need to calculate changed attributes when calling `findRecord`
743
+ return {};
893
744
  }
894
745
  return this._recordData.changedAttributes();
895
746
  }
@@ -924,64 +775,29 @@ export default class InternalModel {
924
775
  return;
925
776
  }
926
777
 
927
- if (CUSTOM_MODEL_CLASS) {
928
- this.store._notificationManager.notify(this.identifier, 'relationships', key);
929
- } else {
930
- if (manyArray) {
931
- manyArray.notify();
932
-
933
- //We need to notifyPropertyChange in the adding case because we need to make sure
934
- //we fetch the newly added record in case it is unloaded
935
- //TODO(Igor): Consider whether we could do this only if the record state is unloaded
936
- if (manyArray.isAsync) {
937
- this._record.notifyPropertyChange(key);
938
- }
939
- }
940
- }
778
+ this.store._notificationManager.notify(this.identifier, 'relationships', key);
941
779
  }
942
780
  }
943
781
 
944
782
  notifyBelongsToChange(key: string) {
945
783
  if (this.hasRecord) {
946
- if (CUSTOM_MODEL_CLASS) {
947
- this.store._notificationManager.notify(this.identifier, 'relationships', key);
948
- } else {
949
- this._record.notifyPropertyChange(key, this._record);
950
- }
784
+ this.store._notificationManager.notify(this.identifier, 'relationships', key);
951
785
  }
952
786
  }
953
787
 
954
788
  notifyPropertyChange(key) {
955
789
  if (this.hasRecord) {
956
- if (CUSTOM_MODEL_CLASS) {
957
- // TODO this should likely *mostly* be the `attributes` bucket
958
- // but it seems for local mutations we rely on computed updating
959
- // iteself when set. As we design our own thing we may need to change
960
- // that.
961
- this.store._notificationManager.notify(this.identifier, 'property', key);
962
- } else {
963
- if (key === 'currentState') {
964
- set(this._record, 'currentState', this.currentState);
965
- } else {
966
- this._record.notifyPropertyChange(key);
967
- }
968
- }
790
+ // TODO this should likely *mostly* be the `attributes` bucket
791
+ // but it seems for local mutations we rely on computed updating
792
+ // iteself when set. As we design our own thing we may need to change
793
+ // that.
794
+ this.store._notificationManager.notify(this.identifier, 'property', key);
969
795
  }
970
796
  }
971
797
 
972
798
  notifyStateChange(key?) {
973
- assert('Cannot notify state change if Record Data State flag is not on', !!RECORD_DATA_STATE);
974
799
  if (this.hasRecord) {
975
- if (CUSTOM_MODEL_CLASS) {
976
- this.store._notificationManager.notify(this.identifier, 'state');
977
- } else {
978
- if (!key || key === 'isNew') {
979
- (this.getRecord() as DSModel).notifyPropertyChange('isNew');
980
- }
981
- if (!key || key === 'isDeleted') {
982
- (this.getRecord() as DSModel).notifyPropertyChange('isDeleted');
983
- }
984
- }
800
+ this.store._notificationManager.notify(this.identifier, 'state');
985
801
  }
986
802
  if (!key || key === 'isDeletionCommitted') {
987
803
  this.store.recordArrayManager.recordDidChange(this.identifier);
@@ -1057,17 +873,13 @@ export default class InternalModel {
1057
873
  }
1058
874
 
1059
875
  this.currentState = state;
1060
- if (CUSTOM_MODEL_CLASS) {
1061
- if (this.hasRecord && typeof this._record.notifyPropertyChange === 'function') {
1062
- // TODO refactor Model to have all flags pull from the notification manager
1063
- // and for currentState.stateName to be constructed from flag state.
1064
- // Probably just port this work from ember-m3
1065
- // After that we can eliminate this.
1066
- this.notifyStateChange('currentState');
1067
- // this._record.notifyPropertyChange('currentState');
1068
- }
1069
- } else {
1070
- this.notifyPropertyChange('currentState');
876
+ if (this.hasRecord && typeof this._record.notifyPropertyChange === 'function') {
877
+ // TODO refactor Model to have all flags pull from the notification manager
878
+ // and for currentState.stateName to be constructed from flag state.
879
+ // Probably just port this work from ember-m3
880
+ // After that we can eliminate this.
881
+ this.notifyStateChange('currentState');
882
+ // this._record.notifyPropertyChange('currentState');
1071
883
  }
1072
884
 
1073
885
  for (i = 0, l = setups.length; i < l; i++) {
@@ -1218,42 +1030,14 @@ export default class InternalModel {
1218
1030
  }
1219
1031
 
1220
1032
  if (didChange && this.hasRecord) {
1221
- if (CUSTOM_MODEL_CLASS) {
1222
- this.store._notificationManager.notify(this.identifier, 'identity');
1223
- } else {
1224
- this.notifyPropertyChange('id');
1225
- }
1033
+ this.store._notificationManager.notify(this.identifier, 'identity');
1226
1034
  }
1227
1035
  this._isUpdatingId = false;
1228
1036
  }
1229
1037
 
1230
- didError(error) {
1231
- if (!REQUEST_SERVICE) {
1232
- this.error = error;
1233
- this.isError = true;
1234
-
1235
- if (this.hasRecord) {
1236
- this._record.setProperties({
1237
- isError: true,
1238
- adapterError: error,
1239
- });
1240
- }
1241
- }
1242
- }
1038
+ didError() {}
1243
1039
 
1244
- didCleanError() {
1245
- if (!REQUEST_SERVICE) {
1246
- this.error = null;
1247
- this.isError = false;
1248
-
1249
- if (this.hasRecord) {
1250
- this._record.setProperties({
1251
- isError: false,
1252
- adapterError: null,
1253
- });
1254
- }
1255
- }
1256
- }
1040
+ didCleanError() {}
1257
1041
 
1258
1042
  /*
1259
1043
  If the adapter did not return a hash in response to a commit,
@@ -1263,29 +1047,19 @@ export default class InternalModel {
1263
1047
  adapterDidCommit(data) {
1264
1048
  this.didCleanError();
1265
1049
 
1266
- let changedKeys = this._recordData.didCommit(data);
1267
-
1050
+ this._recordData.didCommit(data);
1268
1051
  this.send('didCommit');
1269
1052
  this.store.recordArrayManager.recordDidChange(this.identifier);
1270
1053
 
1271
1054
  if (!data) {
1272
1055
  return;
1273
1056
  }
1274
- if (CUSTOM_MODEL_CLASS) {
1275
- this.store._notificationManager.notify(this.identifier, 'attributes');
1276
- } else {
1277
- this._record._notifyProperties(changedKeys);
1278
- }
1057
+ this.store._notificationManager.notify(this.identifier, 'attributes');
1279
1058
  }
1280
1059
 
1281
1060
  hasErrors() {
1282
- if (RECORD_DATA_ERRORS) {
1283
- if (this._recordData.getErrors) {
1284
- return this._recordData.getErrors(this.identifier).length > 0;
1285
- } else {
1286
- let errors = (this.getRecord() as DSModel).errors;
1287
- return errors.length > 0;
1288
- }
1061
+ if (this._recordData.getErrors) {
1062
+ return this._recordData.getErrors(this.identifier).length > 0;
1289
1063
  } else {
1290
1064
  let errors = (this.getRecord() as DSModel).errors;
1291
1065
  return errors.length > 0;
@@ -1294,54 +1068,37 @@ export default class InternalModel {
1294
1068
 
1295
1069
  // FOR USE DURING COMMIT PROCESS
1296
1070
  adapterDidInvalidate(parsedErrors, error) {
1297
- if (RECORD_DATA_ERRORS) {
1298
- // TODO @runspired this should be handled by RecordState
1299
- // and errors should be dirtied but lazily fetch if at
1300
- // all possible. We should only notify errors here.
1301
- let attribute;
1302
- if (error && parsedErrors) {
1303
- if (!this._recordData.getErrors) {
1304
- for (attribute in parsedErrors) {
1305
- if (hasOwnProperty.call(parsedErrors, attribute)) {
1306
- (this.getRecord() as DSModel).errors._add(attribute, parsedErrors[attribute]);
1307
- }
1071
+ // TODO @runspired this should be handled by RecordState
1072
+ // and errors should be dirtied but lazily fetch if at
1073
+ // all possible. We should only notify errors here.
1074
+ let attribute;
1075
+ if (error && parsedErrors) {
1076
+ if (!this._recordData.getErrors) {
1077
+ for (attribute in parsedErrors) {
1078
+ if (hasOwnProperty.call(parsedErrors, attribute)) {
1079
+ (this.getRecord() as DSModel).errors._add(attribute, parsedErrors[attribute]);
1308
1080
  }
1309
1081
  }
1310
-
1311
- let jsonApiErrors: JsonApiValidationError[] = errorsHashToArray(parsedErrors);
1312
- this.send('becameInvalid');
1313
- if (jsonApiErrors.length === 0) {
1314
- jsonApiErrors = [{ title: 'Invalid Error', detail: '', source: { pointer: '/data' } }];
1315
- }
1316
- this._recordData.commitWasRejected(this.identifier, jsonApiErrors);
1317
- } else {
1318
- this.send('becameError');
1319
- this._recordData.commitWasRejected(this.identifier);
1320
- }
1321
- } else {
1322
- let attribute;
1323
-
1324
- for (attribute in parsedErrors) {
1325
- if (hasOwnProperty.call(parsedErrors, attribute)) {
1326
- (this.getRecord() as DSModel).errors._add(attribute, parsedErrors[attribute]);
1327
- }
1328
1082
  }
1329
1083
 
1084
+ let jsonApiErrors: JsonApiValidationError[] = errorsHashToArray(parsedErrors);
1330
1085
  this.send('becameInvalid');
1331
-
1332
- this._recordData.commitWasRejected();
1086
+ if (jsonApiErrors.length === 0) {
1087
+ jsonApiErrors = [{ title: 'Invalid Error', detail: '', source: { pointer: '/data' } }];
1088
+ }
1089
+ this._recordData.commitWasRejected(this.identifier, jsonApiErrors);
1090
+ } else {
1091
+ this.send('becameError');
1092
+ this._recordData.commitWasRejected(this.identifier);
1333
1093
  }
1334
1094
  }
1335
1095
 
1336
1096
  notifyErrorsChange() {
1337
- if (CUSTOM_MODEL_CLASS) {
1338
- this.store._notificationManager.notify(this.identifier, 'errors');
1339
- }
1097
+ this.store._notificationManager.notify(this.identifier, 'errors');
1340
1098
  }
1341
1099
 
1342
- adapterDidError(error) {
1100
+ adapterDidError() {
1343
1101
  this.send('becameError');
1344
- this.didError(error);
1345
1102
 
1346
1103
  this._recordData.commitWasRejected();
1347
1104
  }
@@ -1388,16 +1145,6 @@ export default class InternalModel {
1388
1145
  }
1389
1146
  }
1390
1147
 
1391
- // in production code, this is only accesssed in `record-array-manager`
1392
- // if REMOVE_RECORD_ARRAY_MANAGER_LEGACY_COMPAT is also false
1393
- if (!REMOVE_RECORD_ARRAY_MANAGER_LEGACY_COMPAT) {
1394
- Object.defineProperty(InternalModel.prototype, '_recordArrays', {
1395
- get() {
1396
- return recordArraysForIdentifier(this.identifier);
1397
- },
1398
- });
1399
- }
1400
-
1401
1148
  function handleCompletedRelationshipRequest(internalModel, key, relationship, value, error) {
1402
1149
  delete internalModel._relationshipPromisesCache[key];
1403
1150
  relationship.state.shouldForceReload = false;