@ember-data/model 4.8.0-alpha.3 → 4.8.0-alpha.6

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.
@@ -7,7 +7,6 @@ import EmberError from '@ember/error';
7
7
  import EmberObject from '@ember/object';
8
8
  import { dependentKeyCompat } from '@ember/object/compat';
9
9
  import { run } from '@ember/runloop';
10
- import { inject as service } from '@ember/service';
11
10
  import { isNone } from '@ember/utils';
12
11
  import { DEBUG } from '@glimmer/env';
13
12
  import { tracked } from '@glimmer/tracking';
@@ -19,11 +18,13 @@ import { HAS_DEBUG_PACKAGE } from '@ember-data/private-build-infra';
19
18
  import {
20
19
  DEPRECATE_EARLY_STATIC,
21
20
  DEPRECATE_MODEL_REOPEN,
21
+ DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE,
22
22
  DEPRECATE_SAVE_PROMISE_ACCESS,
23
23
  } from '@ember-data/private-build-infra/deprecations';
24
24
  import { recordIdentifierFor, storeFor } from '@ember-data/store';
25
- import { coerceId, deprecatedPromiseObject, recordDataFor, WeakCache } from '@ember-data/store/-private';
25
+ import { coerceId, recordDataFor } from '@ember-data/store/-private';
26
26
 
27
+ import { deprecatedPromiseObject } from './deprecated-promise-proxy';
27
28
  import Errors from './errors';
28
29
  import { LegacySupport } from './legacy-relationships-support';
29
30
  import notifyChanges from './notify-changes';
@@ -31,18 +32,21 @@ import RecordState, { peekTag, tagged } from './record-state';
31
32
  import { relationshipFromMeta } from './relationship-meta';
32
33
 
33
34
  const { changeProperties } = Ember;
34
- export const LEGACY_SUPPORT = new WeakCache(DEBUG ? 'legacy-relationships' : '');
35
- LEGACY_SUPPORT._generator = (record) => {
35
+ export const LEGACY_SUPPORT = new Map();
36
+
37
+ export function lookupLegacySupport(record) {
36
38
  const identifier = recordIdentifierFor(record);
37
39
  let support = LEGACY_SUPPORT.get(identifier);
38
40
 
39
41
  if (!support) {
40
42
  support = new LegacySupport(record);
41
43
  LEGACY_SUPPORT.set(identifier, support);
44
+ LEGACY_SUPPORT.set(record, support);
42
45
  }
43
46
 
44
47
  return support;
45
- };
48
+ }
49
+
46
50
  function findPossibleInverses(type, inverseType, name, relationshipsSoFar) {
47
51
  let possibleRelationships = relationshipsSoFar || [];
48
52
 
@@ -118,8 +122,7 @@ function computeOnce(target, key, desc) {
118
122
  @extends Ember.EmberObject
119
123
  */
120
124
  class Model extends EmberObject {
121
- @service store;
122
- #notifications;
125
+ ___private_notifications;
123
126
 
124
127
  init(options = {}) {
125
128
  if (DEBUG && !options._secretInit && !options._createProps) {
@@ -129,37 +132,46 @@ class Model extends EmberObject {
129
132
  }
130
133
  const createProps = options._createProps;
131
134
  const _secretInit = options._secretInit;
132
- delete options._createProps;
133
- delete options._secretInit;
135
+ options._createProps = null;
136
+ options._secretInit = null;
137
+
138
+ let store = (this.store = _secretInit.store);
134
139
  super.init(options);
135
140
 
136
- _secretInit(this);
141
+ let identity = _secretInit.identifier;
142
+ _secretInit.cb(this, _secretInit.recordData, identity, _secretInit.store);
143
+
137
144
  this.___recordState = DEBUG ? new RecordState(this) : null;
138
145
 
139
146
  this.setProperties(createProps);
140
147
 
141
- let store = storeFor(this);
142
148
  let notifications = store._notificationManager;
143
- let identity = recordIdentifierFor(this);
144
-
145
- this.#notifications = notifications.subscribe(identity, (identifier, type, key) => {
149
+ this.___private_notifications = notifications.subscribe(identity, (identifier, type, key) => {
146
150
  notifyChanges(identifier, type, key, this, store);
147
151
  });
148
152
  }
149
153
 
150
154
  destroy() {
151
- LEGACY_SUPPORT.get(this)?.destroy();
155
+ const identifier = recordIdentifierFor(this);
152
156
  this.___recordState?.destroy();
153
157
  const store = storeFor(this);
154
- const identifier = recordIdentifierFor(this);
155
- store._notificationManager.unsubscribe(this.#notifications);
158
+ store._notificationManager.unsubscribe(this.___private_notifications);
156
159
  // Legacy behavior is to notify the relationships on destroy
157
160
  // such that they "clear". It's uncertain this behavior would
158
161
  // be good for a new model paradigm, likely cheaper and safer
159
162
  // to simply not notify, for this reason the store does not itself
160
163
  // notify individual changes once the delete has been signaled,
161
164
  // this decision is left to model instances.
162
- notifyChanges(identifier, 'relationships', undefined, this, store);
165
+
166
+ this.eachRelationship((key, meta) => {
167
+ if (meta.kind === 'belongsTo') {
168
+ this.notifyPropertyChange(key);
169
+ }
170
+ });
171
+ LEGACY_SUPPORT.get(this)?.destroy();
172
+ LEGACY_SUPPORT.delete(this);
173
+ LEGACY_SUPPORT.delete(identifier);
174
+
163
175
  super.destroy();
164
176
  }
165
177
 
@@ -487,14 +499,13 @@ class Model extends EmberObject {
487
499
  );
488
500
 
489
501
  if (normalizedId !== null && didChange) {
490
- this.store._instanceCache.setRecordId(identifier.type, normalizedId, identifier.lid);
502
+ this.store._instanceCache.setRecordId(identifier, normalizedId);
491
503
  this.store._notificationManager.notify(identifier, 'identity');
492
504
  }
493
505
  }
494
506
 
495
- // TODO just write a nice toString
496
- toStringExtension() {
497
- return this.id;
507
+ toString() {
508
+ return `<model::${this.constructor.modelName}:${this.id}>`;
498
509
  }
499
510
 
500
511
  /**
@@ -813,7 +824,7 @@ class Model extends EmberObject {
813
824
  and value is an [oldProp, newProp] array.
814
825
  */
815
826
  changedAttributes() {
816
- return recordDataFor(this).changedAttributes();
827
+ return recordDataFor(this).changedAttrs(recordIdentifierFor(this));
817
828
  }
818
829
 
819
830
  /**
@@ -837,12 +848,15 @@ class Model extends EmberObject {
837
848
  rollbackAttributes() {
838
849
  const { currentState } = this;
839
850
  const { isNew } = currentState;
840
- recordDataFor(this).rollbackAttributes();
841
- this.errors.clear();
842
- currentState.cleanErrorRequests();
843
- if (isNew) {
844
- this.unloadRecord();
845
- }
851
+
852
+ storeFor(this)._join(() => {
853
+ recordDataFor(this).rollbackAttrs(recordIdentifierFor(this));
854
+ this.errors.clear();
855
+ currentState.cleanErrorRequests();
856
+ if (isNew) {
857
+ this.unloadRecord();
858
+ }
859
+ });
846
860
  }
847
861
 
848
862
  /**
@@ -980,7 +994,7 @@ class Model extends EmberObject {
980
994
  import Model, { belongsTo } from '@ember-data/model';
981
995
 
982
996
  export default class BlogModel extends Model {
983
- @belongsTo({ async: true }) user;
997
+ @belongsTo('user', { async: true, inverse: null }) user;
984
998
  }
985
999
  ```
986
1000
 
@@ -1036,7 +1050,7 @@ class Model extends EmberObject {
1036
1050
  @return {BelongsToReference} reference for this relationship
1037
1051
  */
1038
1052
  belongsTo(name) {
1039
- return LEGACY_SUPPORT.lookup(this).referenceFor('belongsTo', name);
1053
+ return lookupLegacySupport(this).referenceFor('belongsTo', name);
1040
1054
  }
1041
1055
 
1042
1056
  /**
@@ -1048,7 +1062,7 @@ class Model extends EmberObject {
1048
1062
  import Model, { hasMany } from '@ember-data/model';
1049
1063
 
1050
1064
  export default class BlogModel extends Model {
1051
- @hasMany({ async: true }) comments;
1065
+ @hasMany('comment', { async: true, inverse: null }) comments;
1052
1066
  }
1053
1067
 
1054
1068
  let blog = store.push({
@@ -1099,7 +1113,7 @@ class Model extends EmberObject {
1099
1113
  @return {HasManyReference} reference for this relationship
1100
1114
  */
1101
1115
  hasMany(name) {
1102
- return LEGACY_SUPPORT.lookup(this).referenceFor('hasMany', name);
1116
+ return lookupLegacySupport(this).referenceFor('hasMany', name);
1103
1117
  }
1104
1118
 
1105
1119
  /**
@@ -1141,7 +1155,7 @@ class Model extends EmberObject {
1141
1155
  record.eachRelationship(function(name, descriptor) {
1142
1156
  if (descriptor.kind === 'hasMany') {
1143
1157
  let serializedHasManyName = name.toUpperCase() + '_IDS';
1144
- json[serializedHasManyName] = record.get(name).mapBy('id');
1158
+ json[serializedHasManyName] = record.get(name).map(r => r.id);
1145
1159
  }
1146
1160
  });
1147
1161
 
@@ -1201,7 +1215,7 @@ class Model extends EmberObject {
1201
1215
 
1202
1216
  ```javascript
1203
1217
  import RESTSerializer from '@ember-data/serializer/rest';
1204
- import { underscore } from '@ember/string';
1218
+ import { underscore } from '<app-name>/utils/string-utils';
1205
1219
 
1206
1220
  export default const PostSerializer = RESTSerializer.extend({
1207
1221
  payloadKeyFromModelName(modelName) {
@@ -1795,7 +1809,7 @@ class Model extends EmberObject {
1795
1809
  meta.key = name;
1796
1810
  meta.name = name;
1797
1811
  meta.parentModelName = modelName;
1798
- relationships[name] = relationshipFromMeta(meta);
1812
+ relationships[name] = DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE ? relationshipFromMeta(meta) : meta;
1799
1813
  }
1800
1814
  });
1801
1815
  return relationships;
@@ -1865,6 +1879,7 @@ class Model extends EmberObject {
1865
1879
  let map = new Map();
1866
1880
 
1867
1881
  this.eachComputedProperty((name, meta) => {
1882
+ // TODO end reliance on these booleans and stop leaking them in the spec
1868
1883
  if (meta.isRelationship) {
1869
1884
  map.set(name, meta.kind);
1870
1885
  } else if (meta.isAttribute) {
@@ -2411,7 +2426,7 @@ if (DEBUG) {
2411
2426
  until: '5.0',
2412
2427
  since: { available: '4.8', enabled: '4.8' },
2413
2428
  });
2414
- return originalReopen.call(this, arguments);
2429
+ return originalReopen.call(this, ...arguments);
2415
2430
  };
2416
2431
 
2417
2432
  Model.reopenClass = function deprecatedReopenClass() {
@@ -2425,7 +2440,7 @@ if (DEBUG) {
2425
2440
  since: { available: '4.8', enabled: '4.8' },
2426
2441
  }
2427
2442
  );
2428
- return originalReopenClass.call(this, arguments);
2443
+ return originalReopenClass.call(this, ...arguments);
2429
2444
  };
2430
2445
  }
2431
2446
  }
@@ -66,7 +66,7 @@ function notifyRelationship(identifier: StableRecordIdentifier, key: string, rec
66
66
  function notifyAttribute(store: Store, identifier: StableRecordIdentifier, key: string, record: Model) {
67
67
  let currentValue = cacheFor(record, key);
68
68
 
69
- if (currentValue !== store._instanceCache.getRecordData(identifier).getAttr(key)) {
69
+ if (currentValue !== store._instanceCache.getRecordData(identifier).getAttr(identifier, key)) {
70
70
  record.notifyPropertyChange(key);
71
71
  }
72
72
  }
@@ -4,11 +4,11 @@ import type PromiseProxyMixin from '@ember/object/promise-proxy-mixin';
4
4
  import type ObjectProxy from '@ember/object/proxy';
5
5
 
6
6
  import type Store from '@ember-data/store';
7
- import { PromiseObject } from '@ember-data/store/-private';
8
7
  import type { RecordInstance } from '@ember-data/types/q/record-instance';
9
8
  import type { Dict } from '@ember-data/types/q/utils';
10
9
 
11
10
  import { LegacySupport } from './legacy-relationships-support';
11
+ import { PromiseObject } from './promise-proxy-base';
12
12
 
13
13
  export interface BelongsToProxyMeta {
14
14
  key: string;
@@ -2,18 +2,23 @@ import ArrayMixin, { NativeArray } from '@ember/array';
2
2
  import type ArrayProxy from '@ember/array/proxy';
3
3
  import { assert, deprecate } from '@ember/debug';
4
4
  import { dependentKeyCompat } from '@ember/object/compat';
5
+ import { DEBUG } from '@glimmer/env';
5
6
  import { tracked } from '@glimmer/tracking';
6
7
  import Ember from 'ember';
7
8
 
8
9
  import { resolve } from 'rsvp';
9
10
 
10
- import type { ManyArray } from 'ember-data/-private';
11
-
12
- import { DEPRECATE_PROMISE_MANY_ARRAY_BEHAVIORS } from '@ember-data/private-build-infra/deprecations';
11
+ import {
12
+ DEPRECATE_A_USAGE,
13
+ DEPRECATE_COMPUTED_CHAINS,
14
+ DEPRECATE_PROMISE_MANY_ARRAY_BEHAVIORS,
15
+ } from '@ember-data/private-build-infra/deprecations';
13
16
  import { StableRecordIdentifier } from '@ember-data/types/q/identifier';
14
17
  import type { RecordInstance } from '@ember-data/types/q/record-instance';
15
18
  import { FindOptions } from '@ember-data/types/q/store';
16
19
 
20
+ import type ManyArray from './many-array';
21
+
17
22
  export interface HasManyProxyCreateArgs {
18
23
  promise: Promise<ManyArray>;
19
24
  content?: ManyArray;
@@ -53,13 +58,27 @@ export default class PromiseManyArray {
53
58
  this.isDestroyed = false;
54
59
  this.isDestroying = false;
55
60
 
56
- const meta = Ember.meta(this);
57
- meta.hasMixin = (mixin: Object) => {
58
- if (mixin === NativeArray || mixin === ArrayMixin) {
59
- return true;
60
- }
61
- return false;
62
- };
61
+ if (DEPRECATE_A_USAGE) {
62
+ const meta = Ember.meta(this);
63
+ meta.hasMixin = (mixin: Object) => {
64
+ deprecate(`Do not use A() on an EmberData PromiseManyArray`, false, {
65
+ id: 'ember-data:no-a-with-array-like',
66
+ until: '5.0',
67
+ since: { enabled: '4.8', available: '4.8' },
68
+ for: 'ember-data',
69
+ });
70
+ // @ts-expect-error ArrayMixin is more than a type
71
+ if (mixin === NativeArray || mixin === ArrayMixin) {
72
+ return true;
73
+ }
74
+ return false;
75
+ };
76
+ } else if (DEBUG) {
77
+ const meta = Ember.meta(this);
78
+ meta.hasMixin = (mixin: Object) => {
79
+ assert(`Do not use A() on an EmberData PromiseManyArray`);
80
+ };
81
+ }
63
82
  }
64
83
 
65
84
  //---- Methods/Properties on ArrayProxy that we will keep as our API
@@ -75,7 +94,9 @@ export default class PromiseManyArray {
75
94
  get length(): number {
76
95
  // shouldn't be needed, but ends up being needed
77
96
  // for computed chains even in 4.x
78
- this['[]'];
97
+ if (DEPRECATE_COMPUTED_CHAINS) {
98
+ this['[]'];
99
+ }
79
100
  return this.content ? this.content.length : 0;
80
101
  }
81
102
 
@@ -85,7 +106,9 @@ export default class PromiseManyArray {
85
106
  // to recompute. We entangle the '[]' tag from
86
107
  @dependentKeyCompat
87
108
  get '[]'() {
88
- return this.content ? this.content['[]'] : this.content;
109
+ if (DEPRECATE_COMPUTED_CHAINS) {
110
+ return this.content?.length && this.content;
111
+ }
89
112
  }
90
113
 
91
114
  /**
@@ -99,7 +122,6 @@ export default class PromiseManyArray {
99
122
  * @private
100
123
  */
101
124
  forEach(cb) {
102
- this['[]']; // needed for < 3.23 support e.g. 3.20 lts
103
125
  if (this.content && this.length) {
104
126
  this.content.forEach(cb);
105
127
  }
@@ -0,0 +1,4 @@
1
+ import PromiseProxyMixin from '@ember/object/promise-proxy-mixin';
2
+ import ObjectProxy from '@ember/object/proxy';
3
+
4
+ export const PromiseObject = ObjectProxy.extend(PromiseProxyMixin);
@@ -105,7 +105,7 @@ export function tagged(_target, key, desc) {
105
105
 
106
106
  /**
107
107
  Historically EmberData managed a state machine
108
- for each record, the currentState for which
108
+ for each record, the localState for which
109
109
  was reflected onto Model.
110
110
 
111
111
  This implements the flags and stateName for backwards compat
@@ -247,10 +247,6 @@ export default class RecordState {
247
247
  this.notify('isEmpty');
248
248
  this.notify('isDirty');
249
249
  break;
250
- case 'unload':
251
- this.notify('isNew');
252
- this.notify('isDeleted');
253
- break;
254
250
  case 'errors':
255
251
  this.updateInvalidErrors(this.record.errors);
256
252
  this.notify('isValid');
@@ -326,7 +322,7 @@ export default class RecordState {
326
322
  let rd = this.recordData;
327
323
  if (this.isDeleted) {
328
324
  assert(`Expected RecordData to implement isDeletionCommitted()`, rd.isDeletionCommitted);
329
- return rd.isDeletionCommitted();
325
+ return rd.isDeletionCommitted(this.identifier);
330
326
  }
331
327
  if (this.isNew || this.isEmpty || !this.isValid || this.isDirty || this.isLoading) {
332
328
  return false;
@@ -340,21 +336,21 @@ export default class RecordState {
340
336
  // TODO this is not actually an RFC'd concept. Determine the
341
337
  // correct heuristic to replace this with.
342
338
  assert(`Expected RecordData to implement isEmpty()`, rd.isEmpty);
343
- return !this.isNew && rd.isEmpty();
339
+ return !this.isNew && rd.isEmpty(this.identifier);
344
340
  }
345
341
 
346
342
  @tagged
347
343
  get isNew() {
348
344
  let rd = this.recordData;
349
345
  assert(`Expected RecordData to implement isNew()`, rd.isNew);
350
- return rd.isNew();
346
+ return rd.isNew(this.identifier);
351
347
  }
352
348
 
353
349
  @tagged
354
350
  get isDeleted() {
355
351
  let rd = this.recordData;
356
352
  assert(`Expected RecordData to implement isDeleted()`, rd.isDeleted);
357
- return rd.isDeleted();
353
+ return rd.isDeleted(this.identifier);
358
354
  }
359
355
 
360
356
  @tagged
@@ -365,12 +361,10 @@ export default class RecordState {
365
361
  @tagged
366
362
  get isDirty() {
367
363
  let rd = this.recordData;
368
- assert(`Expected RecordData to implement hasChangedAttributes()`, rd.hasChangedAttributes);
369
- assert(`Expected RecordData to implement isDeletionCommitted()`, rd.isDeletionCommitted);
370
- if (rd.isDeletionCommitted() || (this.isDeleted && this.isNew)) {
364
+ if (rd.isDeletionCommitted(this.identifier) || (this.isDeleted && this.isNew)) {
371
365
  return false;
372
366
  }
373
- return this.isNew || rd.hasChangedAttributes();
367
+ return this.isNew || rd.hasChangedAttrs(this.identifier);
374
368
  }
375
369
 
376
370
  @tagged
@@ -1,15 +1,17 @@
1
+ import { deprecate } from '@ember/debug';
1
2
  import { dependentKeyCompat } from '@ember/object/compat';
2
3
  import { cached, tracked } from '@glimmer/tracking';
3
4
 
4
5
  import type { Object as JSONObject, Value as JSONValue } from 'json-typescript';
5
6
  import { resolve } from 'rsvp';
6
7
 
7
- import type { BelongsToRelationship } from '@ember-data/record-data/-private';
8
+ import { DEPRECATE_PROMISE_PROXIES } from '@ember-data/private-build-infra/deprecations';
9
+ import type { Graph } from '@ember-data/record-data/-private/graph';
10
+ import type BelongsToRelationship from '@ember-data/record-data/-private/relationships/state/belongs-to';
8
11
  import type Store from '@ember-data/store';
9
12
  import { assertPolymorphicType } from '@ember-data/store/-debug';
10
13
  import { recordIdentifierFor } from '@ember-data/store/-private';
11
14
  import type { NotificationType } from '@ember-data/store/-private/managers/record-notification-manager';
12
- import type { DebugWeakCache } from '@ember-data/store/-private/utils/weak-cache';
13
15
  import type {
14
16
  LinkObject,
15
17
  Links,
@@ -52,31 +54,34 @@ export default class BelongsToReference {
52
54
  declare key: string;
53
55
  declare belongsToRelationship: BelongsToRelationship;
54
56
  declare type: string;
55
- #identifier: StableRecordIdentifier;
57
+ ___identifier: StableRecordIdentifier;
56
58
  declare store: Store;
59
+ declare graph: Graph;
57
60
 
58
61
  // unsubscribe tokens given to us by the notification manager
59
- #token!: Object;
60
- #relatedToken: Object | null = null;
62
+ ___token!: object;
63
+ ___relatedToken: object | null = null;
61
64
 
62
65
  @tracked _ref = 0;
63
66
 
64
67
  constructor(
65
68
  store: Store,
69
+ graph: Graph,
66
70
  parentIdentifier: StableRecordIdentifier,
67
71
  belongsToRelationship: BelongsToRelationship,
68
72
  key: string
69
73
  ) {
74
+ this.graph = graph;
70
75
  this.key = key;
71
76
  this.belongsToRelationship = belongsToRelationship;
72
77
  this.type = belongsToRelationship.definition.type;
73
78
  this.store = store;
74
- this.#identifier = parentIdentifier;
79
+ this.___identifier = parentIdentifier;
75
80
 
76
- this.#token = store._notificationManager.subscribe(
81
+ this.___token = store._notificationManager.subscribe(
77
82
  parentIdentifier,
78
83
  (_: StableRecordIdentifier, bucket: NotificationType, notifiedKey?: string) => {
79
- if ((bucket === 'relationships' || bucket === 'property') && notifiedKey === key) {
84
+ if (bucket === 'relationships' && notifiedKey === key) {
80
85
  this._ref++;
81
86
  }
82
87
  }
@@ -88,9 +93,11 @@ export default class BelongsToReference {
88
93
  destroy() {
89
94
  // TODO @feature we need the notification manager often enough
90
95
  // we should potentially just expose it fully public
91
- this.store._notificationManager.unsubscribe(this.#token);
92
- if (this.#relatedToken) {
93
- this.store._notificationManager.unsubscribe(this.#relatedToken);
96
+ this.store._notificationManager.unsubscribe(this.___token);
97
+ this.___token = null as unknown as object;
98
+ if (this.___relatedToken) {
99
+ this.store._notificationManager.unsubscribe(this.___relatedToken);
100
+ this.___relatedToken = null;
94
101
  }
95
102
  }
96
103
 
@@ -98,17 +105,18 @@ export default class BelongsToReference {
98
105
  @dependentKeyCompat
99
106
  get _relatedIdentifier(): StableRecordIdentifier | null {
100
107
  this._ref; // consume the tracked prop
101
- if (this.#relatedToken) {
102
- this.store._notificationManager.unsubscribe(this.#relatedToken);
108
+ if (this.___relatedToken) {
109
+ this.store._notificationManager.unsubscribe(this.___relatedToken);
110
+ this.___relatedToken = null;
103
111
  }
104
112
 
105
113
  let resource = this._resource();
106
114
  if (resource && resource.data) {
107
115
  const identifier = this.store.identifierCache.getOrCreateRecordIdentifier(resource.data);
108
- this.#relatedToken = this.store._notificationManager.subscribe(
116
+ this.___relatedToken = this.store._notificationManager.subscribe(
109
117
  identifier,
110
118
  (_: StableRecordIdentifier, bucket: NotificationType, notifiedKey?: string) => {
111
- if (bucket === 'identity' || ((bucket === 'attributes' || bucket === 'property') && notifiedKey === 'id')) {
119
+ if (bucket === 'identity' || (bucket === 'attributes' && notifiedKey === 'id')) {
112
120
  this._ref++;
113
121
  }
114
122
  }
@@ -134,7 +142,7 @@ export default class BelongsToReference {
134
142
  import Model, { belongsTo } from '@ember-data/model';
135
143
 
136
144
  export default class BlogModel extends Model {
137
- @belongsTo({ async: true }) user;
145
+ @belongsTo('user', { async: true, inverse: null }) user;
138
146
  }
139
147
 
140
148
  let blog = store.push({
@@ -174,7 +182,7 @@ export default class BelongsToReference {
174
182
  // models/blog.js
175
183
  import Model, { belongsTo } from '@ember-data/model';
176
184
  export default Model.extend({
177
- user: belongsTo({ async: true })
185
+ user: belongsTo('user', { async: true, inverse: null })
178
186
  });
179
187
 
180
188
  let blog = store.push({
@@ -236,7 +244,7 @@ export default class BelongsToReference {
236
244
  // models/blog.js
237
245
  import Model, { belongsTo } from '@ember-data/model';
238
246
  export default Model.extend({
239
- user: belongsTo({ async: true })
247
+ user: belongsTo('user', { async: true, inverse: null })
240
248
  });
241
249
 
242
250
  let blog = store.push({
@@ -277,7 +285,9 @@ export default class BelongsToReference {
277
285
  }
278
286
 
279
287
  _resource() {
280
- return this.store._instanceCache.getRecordData(this.#identifier).getBelongsTo(this.key);
288
+ return this.store._instanceCache
289
+ .getRecordData(this.___identifier)
290
+ .getRelationship(this.___identifier, this.key) as SingleResourceRelationship;
281
291
  }
282
292
 
283
293
  /**
@@ -291,7 +301,7 @@ export default class BelongsToReference {
291
301
  import Model, { hasMany } from '@ember-data/model';
292
302
 
293
303
  export default class PostModel extends Model {
294
- @hasMany({ async: true }) comments;
304
+ @hasMany('comment', { async: true, inverse: null }) comments;
295
305
  }
296
306
  ```
297
307
 
@@ -341,7 +351,7 @@ export default class BelongsToReference {
341
351
  import Model, { belongsTo } from '@ember-data/model';
342
352
 
343
353
  export default class BlogModel extends Model {
344
- @belongsTo({ async: true }) user;
354
+ @belongsTo('user', { async: true, inverse: null }) user;
345
355
  }
346
356
 
347
357
  let blog = store.push({
@@ -377,8 +387,25 @@ export default class BelongsToReference {
377
387
  @return {Promise<record>} A promise that resolves with the new value in this belongs-to relationship.
378
388
  */
379
389
  async push(data: SingleResourceDocument | Promise<SingleResourceDocument>): Promise<RecordInstance> {
380
- // TODO @deprecate pushing unresolved payloads
381
- const jsonApiDoc = await resolve(data);
390
+ let jsonApiDoc: SingleResourceDocument = data as SingleResourceDocument;
391
+ if (DEPRECATE_PROMISE_PROXIES && (data as { then: unknown }).then) {
392
+ jsonApiDoc = await resolve(data);
393
+ if (jsonApiDoc !== data) {
394
+ deprecate(
395
+ `You passed in a Promise to a Reference API that now expects a resolved value. await the value before setting it.`,
396
+ false,
397
+ {
398
+ id: 'ember-data:deprecate-promise-proxies',
399
+ until: '5.0',
400
+ since: {
401
+ enabled: '4.8',
402
+ available: '4.8',
403
+ },
404
+ for: 'ember-data',
405
+ }
406
+ );
407
+ }
408
+ }
382
409
  let record = this.store.push(jsonApiDoc);
383
410
 
384
411
  // eslint-disable-next-line @typescript-eslint/no-unsafe-call
@@ -389,9 +416,9 @@ export default class BelongsToReference {
389
416
  this.store
390
417
  );
391
418
 
392
- const { graph, identifier } = this.belongsToRelationship;
393
- this.store._backburner.join(() => {
394
- graph.push({
419
+ const { identifier } = this.belongsToRelationship;
420
+ this.store._join(() => {
421
+ this.graph.push({
395
422
  op: 'replaceRelatedRecord',
396
423
  record: identifier,
397
424
  field: this.key,
@@ -416,7 +443,7 @@ export default class BelongsToReference {
416
443
  import Model, { belongsTo } from '@ember-data/model';
417
444
 
418
445
  export default class BlogModel extends Model {
419
- @belongsTo({ async: true }) user;
446
+ @belongsTo('user', { async: true, inverse: null }) user;
420
447
  }
421
448
 
422
449
  let blog = store.push({
@@ -469,7 +496,7 @@ export default class BelongsToReference {
469
496
  import Model, { belongsTo } from '@ember-data/model';
470
497
 
471
498
  export default class BlogModel extends Model {
472
- @belongsTo({ async: true }) user;
499
+ @belongsTo('user', { async: true, inverse: null }) user;
473
500
  }
474
501
 
475
502
  let blog = store.push({
@@ -520,9 +547,9 @@ export default class BelongsToReference {
520
547
  @return {Promise} a promise that resolves with the record in this belongs-to relationship.
521
548
  */
522
549
  load(options?: Dict<unknown>) {
523
- const support: LegacySupport = (
524
- LEGACY_SUPPORT as DebugWeakCache<StableRecordIdentifier, LegacySupport>
525
- ).getWithError(this.#identifier);
550
+ const support: LegacySupport = (LEGACY_SUPPORT as Map<StableRecordIdentifier, LegacySupport>).get(
551
+ this.___identifier
552
+ )!;
526
553
  return support.getBelongsTo(this.key, options);
527
554
  }
528
555
 
@@ -539,7 +566,7 @@ export default class BelongsToReference {
539
566
  import Model, { belongsTo } from '@ember-data/model';
540
567
 
541
568
  export default class BlogModel extends Model {
542
- @belongsTo({ async: true }) user;
569
+ @belongsTo('user', { async: true, inverse: null }) user;
543
570
  }
544
571
 
545
572
  let blog = store.push({
@@ -577,9 +604,9 @@ export default class BelongsToReference {
577
604
  @return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed.
578
605
  */
579
606
  reload(options?: Dict<unknown>) {
580
- const support: LegacySupport = (
581
- LEGACY_SUPPORT as DebugWeakCache<StableRecordIdentifier, LegacySupport>
582
- ).getWithError(this.#identifier);
607
+ const support: LegacySupport = (LEGACY_SUPPORT as Map<StableRecordIdentifier, LegacySupport>).get(
608
+ this.___identifier
609
+ )!;
583
610
  return support.reloadBelongsTo(this.key, options).then(() => this.value());
584
611
  }
585
612
  }