@ember-data/store 4.2.0-alpha.8 → 4.2.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.
@@ -1,12 +1,20 @@
1
+ import { getOwner, setOwner } from '@ember/application';
1
2
  import { A, default as EmberArray } from '@ember/array';
2
3
  import { assert, inspect } from '@ember/debug';
3
4
  import EmberError from '@ember/error';
4
- import { get } from '@ember/object';
5
+ import { get, set } from '@ember/object';
5
6
  import { _backburner as emberBackburner, cancel, run } from '@ember/runloop';
6
7
  import { DEBUG } from '@glimmer/env';
7
8
 
8
9
  import RSVP, { Promise } from 'rsvp';
9
10
 
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';
10
18
  import { HAS_MODEL_PACKAGE, HAS_RECORD_DATA_PACKAGE } from '@ember-data/private-build-infra';
11
19
  import type {
12
20
  BelongsToRelationship,
@@ -23,13 +31,15 @@ import type { JsonApiResource, JsonApiValidationError } from '../../ts-interface
23
31
  import type { RecordInstance } from '../../ts-interfaces/record-instance';
24
32
  import type { FindOptions } from '../../ts-interfaces/store';
25
33
  import type { ConfidentDict } from '../../ts-interfaces/utils';
34
+ import coerceId from '../coerce-id';
26
35
  import type CoreStore from '../core-store';
27
36
  import type Store from '../ds-model-store';
28
37
  import { errorsHashToArray } from '../errors-utils';
38
+ import { recordArraysForIdentifier } from '../record-array-manager';
29
39
  import recordDataFor from '../record-data-for';
30
40
  import { BelongsToReference, HasManyReference, RecordReference } from '../references';
31
41
  import Snapshot from '../snapshot';
32
- import { internalModelFactoryFor } from '../store/internal-model-factory';
42
+ import { internalModelFactoryFor, setRecordIdentifier } from '../store/internal-model-factory';
33
43
  import RootState from './states';
34
44
 
35
45
  // move to TS hacks module that we can delete when this is no longer a necessary recast
@@ -62,6 +72,11 @@ if (HAS_MODEL_PACKAGE) {
62
72
  };
63
73
  }
64
74
 
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
+ }
65
80
  interface BelongsToMetaWrapper {
66
81
  key: string;
67
82
  store: CoreStore;
@@ -218,40 +233,60 @@ export default class InternalModel {
218
233
  return true;
219
234
  }
220
235
 
221
- if (this.currentState.isLoading) {
222
- return false;
236
+ if (RECORD_DATA_STATE) {
237
+ if (this.currentState.isLoading) {
238
+ return false;
239
+ }
223
240
  }
224
241
 
225
- let isRecordFullyDeleted = this._isRecordFullyDeleted();
242
+ let isRecordFullyDeleted;
243
+ if (RECORD_DATA_STATE) {
244
+ isRecordFullyDeleted = this._isRecordFullyDeleted();
245
+ } else {
246
+ isRecordFullyDeleted = this.currentState.stateName === 'root.deleted.saved';
247
+ }
226
248
  return this._isDematerializing || this.hasScheduledDestroy() || this.isDestroyed || isRecordFullyDeleted;
227
249
  }
228
250
 
229
251
  _isRecordFullyDeleted(): boolean {
230
- if (this._recordData.isDeletionCommitted && this._recordData.isDeletionCommitted()) {
231
- return true;
232
- } else if (
233
- this._recordData.isNew &&
234
- this._recordData.isDeleted &&
235
- this._recordData.isNew() &&
236
- this._recordData.isDeleted()
237
- ) {
238
- return true;
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
+ }
239
265
  } else {
240
- return this.currentState.stateName === 'root.deleted.saved';
266
+ // assert here
267
+ return false;
241
268
  }
242
269
  }
243
270
 
244
271
  isDeleted() {
245
- if (this._recordData.isDeleted) {
246
- return this._recordData.isDeleted();
272
+ if (RECORD_DATA_STATE) {
273
+ if (this._recordData.isDeleted) {
274
+ return this._recordData.isDeleted();
275
+ } else {
276
+ return this.currentState.isDeleted;
277
+ }
247
278
  } else {
248
279
  return this.currentState.isDeleted;
249
280
  }
250
281
  }
251
282
 
252
283
  isNew() {
253
- if (this._recordData.isNew) {
254
- return this._recordData.isNew();
284
+ if (RECORD_DATA_STATE) {
285
+ if (this._recordData.isNew) {
286
+ return this._recordData.isNew();
287
+ } else {
288
+ return this.currentState.isNew;
289
+ }
255
290
  } else {
256
291
  return this.currentState.isNew;
257
292
  }
@@ -261,7 +296,73 @@ export default class InternalModel {
261
296
  if (!this._record && !this._isDematerializing) {
262
297
  let { store } = this;
263
298
 
264
- this._record = store._instantiateRecord(this, this.modelName, this._recordData, this.identifier, properties);
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
+ }
265
366
  this._triggerDeferredTriggers();
266
367
  }
267
368
 
@@ -276,8 +377,15 @@ export default class InternalModel {
276
377
  this._doNotDestroy = false;
277
378
  // this has to occur before the internal model is removed
278
379
  // for legacy compat.
380
+ if (!REMOVE_RECORD_ARRAY_MANAGER_LEGACY_COMPAT) {
381
+ this.store.recordArrayManager.recordDidChange(this.identifier);
382
+ }
279
383
  if (this._record) {
280
- this.store.teardownRecord(this._record);
384
+ if (CUSTOM_MODEL_CLASS) {
385
+ this.store.teardownRecord(this._record);
386
+ } else {
387
+ this._record.destroy();
388
+ }
281
389
  }
282
390
 
283
391
  // move to an empty never-loaded state
@@ -301,15 +409,19 @@ export default class InternalModel {
301
409
  this.error = null;
302
410
  this._previousState = this.currentState;
303
411
  this.currentState = RootState.empty;
304
- this.store.recordArrayManager.recordDidChange(this.identifier);
412
+ if (REMOVE_RECORD_ARRAY_MANAGER_LEGACY_COMPAT) {
413
+ this.store.recordArrayManager.recordDidChange(this.identifier);
414
+ }
305
415
  }
306
416
 
307
417
  deleteRecord() {
308
418
  run(() => {
309
419
  const backburner = this.store._backburner;
310
420
  backburner.run(() => {
311
- if (this._recordData.setIsDeleted) {
312
- this._recordData.setIsDeleted(true);
421
+ if (RECORD_DATA_STATE) {
422
+ if (this._recordData.setIsDeleted) {
423
+ this._recordData.setIsDeleted(true);
424
+ }
313
425
  }
314
426
 
315
427
  if (this.isNew()) {
@@ -332,26 +444,50 @@ export default class InternalModel {
332
444
  let promiseLabel = 'DS: Model#save ' + this;
333
445
  let resolver = RSVP.defer<void>(promiseLabel);
334
446
 
335
- // Casting to promise to narrow due to the feature flag paths inside scheduleSave
336
- return this.store.scheduleSave(this, resolver, options) as Promise<void>;
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
+ }
337
454
  }
338
455
 
339
456
  reload(options) {
340
- if (!options) {
341
- options = {};
342
- }
343
- let internalModel = this;
344
-
345
- return internalModel.store._reloadRecord(internalModel, options).then(
346
- function () {
347
- //TODO NOW seems like we shouldn't need to do this
348
- return internalModel;
349
- },
350
- function (error) {
351
- throw error;
352
- },
353
- 'DS: Model#reload complete, update flags'
354
- );
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
+ }
355
491
  }
356
492
 
357
493
  /*
@@ -439,8 +575,6 @@ export default class InternalModel {
439
575
  let identifier =
440
576
  resource && resource.data ? identifierCacheFor(this.store).getOrCreateRecordIdentifier(resource.data) : null;
441
577
  let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key);
442
- if (!relationshipMeta) return;
443
-
444
578
  let store = this.store;
445
579
  let parentInternalModel = this;
446
580
  let async = relationshipMeta.options.async;
@@ -731,17 +865,31 @@ export default class InternalModel {
731
865
  }
732
866
 
733
867
  hasChangedAttributes() {
734
- if (!this.__recordData) {
735
- // no need to calculate changed attributes when calling `findRecord`
736
- return false;
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
+ }
737
878
  }
738
879
  return this._recordData.hasChangedAttributes();
739
880
  }
740
881
 
741
882
  changedAttributes() {
742
- if (!this.__recordData) {
743
- // no need to calculate changed attributes when calling `findRecord`
744
- return {};
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
+ }
745
893
  }
746
894
  return this._recordData.changedAttributes();
747
895
  }
@@ -776,29 +924,64 @@ export default class InternalModel {
776
924
  return;
777
925
  }
778
926
 
779
- this.store._notificationManager.notify(this.identifier, 'relationships', key);
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
+ }
780
941
  }
781
942
  }
782
943
 
783
944
  notifyBelongsToChange(key: string) {
784
945
  if (this.hasRecord) {
785
- this.store._notificationManager.notify(this.identifier, 'relationships', key);
946
+ if (CUSTOM_MODEL_CLASS) {
947
+ this.store._notificationManager.notify(this.identifier, 'relationships', key);
948
+ } else {
949
+ this._record.notifyPropertyChange(key, this._record);
950
+ }
786
951
  }
787
952
  }
788
953
 
789
954
  notifyPropertyChange(key) {
790
955
  if (this.hasRecord) {
791
- // TODO this should likely *mostly* be the `attributes` bucket
792
- // but it seems for local mutations we rely on computed updating
793
- // iteself when set. As we design our own thing we may need to change
794
- // that.
795
- this.store._notificationManager.notify(this.identifier, 'property', key);
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
+ }
796
969
  }
797
970
  }
798
971
 
799
972
  notifyStateChange(key?) {
973
+ assert('Cannot notify state change if Record Data State flag is not on', !!RECORD_DATA_STATE);
800
974
  if (this.hasRecord) {
801
- this.store._notificationManager.notify(this.identifier, 'state');
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
+ }
802
985
  }
803
986
  if (!key || key === 'isDeletionCommitted') {
804
987
  this.store.recordArrayManager.recordDidChange(this.identifier);
@@ -874,13 +1057,17 @@ export default class InternalModel {
874
1057
  }
875
1058
 
876
1059
  this.currentState = state;
877
- if (this.hasRecord && typeof this._record.notifyPropertyChange === 'function') {
878
- // TODO refactor Model to have all flags pull from the notification manager
879
- // and for currentState.stateName to be constructed from flag state.
880
- // Probably just port this work from ember-m3
881
- // After that we can eliminate this.
882
- this.notifyStateChange('currentState');
883
- // this._record.notifyPropertyChange('currentState');
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');
884
1071
  }
885
1072
 
886
1073
  for (i = 0, l = setups.length; i < l; i++) {
@@ -1031,14 +1218,42 @@ export default class InternalModel {
1031
1218
  }
1032
1219
 
1033
1220
  if (didChange && this.hasRecord) {
1034
- this.store._notificationManager.notify(this.identifier, 'identity');
1221
+ if (CUSTOM_MODEL_CLASS) {
1222
+ this.store._notificationManager.notify(this.identifier, 'identity');
1223
+ } else {
1224
+ this.notifyPropertyChange('id');
1225
+ }
1035
1226
  }
1036
1227
  this._isUpdatingId = false;
1037
1228
  }
1038
1229
 
1039
- didError() {}
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
+ }
1040
1243
 
1041
- didCleanError() {}
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
+ }
1042
1257
 
1043
1258
  /*
1044
1259
  If the adapter did not return a hash in response to a commit,
@@ -1048,19 +1263,29 @@ export default class InternalModel {
1048
1263
  adapterDidCommit(data) {
1049
1264
  this.didCleanError();
1050
1265
 
1051
- this._recordData.didCommit(data);
1266
+ let changedKeys = this._recordData.didCommit(data);
1267
+
1052
1268
  this.send('didCommit');
1053
1269
  this.store.recordArrayManager.recordDidChange(this.identifier);
1054
1270
 
1055
1271
  if (!data) {
1056
1272
  return;
1057
1273
  }
1058
- this.store._notificationManager.notify(this.identifier, 'attributes');
1274
+ if (CUSTOM_MODEL_CLASS) {
1275
+ this.store._notificationManager.notify(this.identifier, 'attributes');
1276
+ } else {
1277
+ this._record._notifyProperties(changedKeys);
1278
+ }
1059
1279
  }
1060
1280
 
1061
1281
  hasErrors() {
1062
- if (this._recordData.getErrors) {
1063
- return this._recordData.getErrors(this.identifier).length > 0;
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
+ }
1064
1289
  } else {
1065
1290
  let errors = (this.getRecord() as DSModel).errors;
1066
1291
  return errors.length > 0;
@@ -1069,37 +1294,54 @@ export default class InternalModel {
1069
1294
 
1070
1295
  // FOR USE DURING COMMIT PROCESS
1071
1296
  adapterDidInvalidate(parsedErrors, error) {
1072
- // TODO @runspired this should be handled by RecordState
1073
- // and errors should be dirtied but lazily fetch if at
1074
- // all possible. We should only notify errors here.
1075
- let attribute;
1076
- if (error && parsedErrors) {
1077
- if (!this._recordData.getErrors) {
1078
- for (attribute in parsedErrors) {
1079
- if (hasOwnProperty.call(parsedErrors, attribute)) {
1080
- (this.getRecord() as DSModel).errors._add(attribute, parsedErrors[attribute]);
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
+ }
1081
1308
  }
1082
1309
  }
1083
- }
1084
1310
 
1085
- let jsonApiErrors: JsonApiValidationError[] = errorsHashToArray(parsedErrors);
1086
- this.send('becameInvalid');
1087
- if (jsonApiErrors.length === 0) {
1088
- jsonApiErrors = [{ title: 'Invalid Error', detail: '', source: { pointer: '/data' } }];
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);
1089
1320
  }
1090
- this._recordData.commitWasRejected(this.identifier, jsonApiErrors);
1091
1321
  } else {
1092
- this.send('becameError');
1093
- this._recordData.commitWasRejected(this.identifier);
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
+ }
1329
+
1330
+ this.send('becameInvalid');
1331
+
1332
+ this._recordData.commitWasRejected();
1094
1333
  }
1095
1334
  }
1096
1335
 
1097
1336
  notifyErrorsChange() {
1098
- this.store._notificationManager.notify(this.identifier, 'errors');
1337
+ if (CUSTOM_MODEL_CLASS) {
1338
+ this.store._notificationManager.notify(this.identifier, 'errors');
1339
+ }
1099
1340
  }
1100
1341
 
1101
- adapterDidError() {
1342
+ adapterDidError(error) {
1102
1343
  this.send('becameError');
1344
+ this.didError(error);
1103
1345
 
1104
1346
  this._recordData.commitWasRejected();
1105
1347
  }
@@ -1146,6 +1388,16 @@ export default class InternalModel {
1146
1388
  }
1147
1389
  }
1148
1390
 
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
+
1149
1401
  function handleCompletedRelationshipRequest(internalModel, key, relationship, value, error) {
1150
1402
  delete internalModel._relationshipPromisesCache[key];
1151
1403
  relationship.state.shouldForceReload = false;
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { assert } from '@ember/debug';
5
5
 
6
+ import { CUSTOM_MODEL_CLASS, REQUEST_SERVICE } from '@ember-data/canary-features';
6
7
  /*
7
8
  This file encapsulates the various states that a record can transition
8
9
  through during its lifecycle.
@@ -431,7 +432,11 @@ createdState.uncommitted.rollback = function (internalModel) {
431
432
 
432
433
  createdState.uncommitted.pushedData = function (internalModel) {
433
434
  // TODO @runspired consider where to do this once we kill off state machine
434
- internalModel.store._notificationManager.notify(internalModel.identifier, 'identity');
435
+ if (CUSTOM_MODEL_CLASS) {
436
+ internalModel.store._notificationManager.notify(internalModel.identifier, 'identity');
437
+ } else {
438
+ internalModel.notifyPropertyChange('id');
439
+ }
435
440
  internalModel.transitionTo('loaded.updated.uncommitted');
436
441
  internalModel.triggerLater('didLoad');
437
442
  };
@@ -495,6 +500,9 @@ const RootState = {
495
500
 
496
501
  // EVENTS
497
502
  loadingData(internalModel, promise) {
503
+ if (!REQUEST_SERVICE) {
504
+ internalModel._promiseProxy = promise;
505
+ }
498
506
  internalModel.transitionTo('loading');
499
507
  },
500
508
 
@@ -585,7 +593,11 @@ const RootState = {
585
593
  internalModel.transitionTo('updated.inFlight');
586
594
  },
587
595
 
588
- reloadRecord() {},
596
+ reloadRecord(internalModel, { resolve, options }) {
597
+ if (!REQUEST_SERVICE) {
598
+ resolve(internalModel.store._reloadRecord(internalModel, options));
599
+ }
600
+ },
589
601
 
590
602
  deleteRecord(internalModel) {
591
603
  internalModel.transitionTo('deleted.uncommitted');