@ember-data/model 4.6.1 → 4.7.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.
@@ -2,13 +2,11 @@
2
2
  @module @ember-data/model
3
3
  */
4
4
 
5
- import { assert, warn } from '@ember/debug';
5
+ import { assert, deprecate, warn } from '@ember/debug';
6
6
  import EmberError from '@ember/error';
7
- import EmberObject, { get } from '@ember/object';
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
- import { isNone } from '@ember/utils';
12
10
  import { DEBUG } from '@glimmer/env';
13
11
  import { tracked } from '@glimmer/tracking';
14
12
  import Ember from 'ember';
@@ -16,17 +14,17 @@ import Ember from 'ember';
16
14
  import { resolve } from 'rsvp';
17
15
 
18
16
  import { HAS_DEBUG_PACKAGE } from '@ember-data/private-build-infra';
19
- import { DEPRECATE_SAVE_PROMISE_ACCESS } from '@ember-data/private-build-infra/deprecations';
20
- import { recordIdentifierFor, storeFor } from '@ember-data/store';
21
17
  import {
22
- coerceId,
23
- deprecatedPromiseObject,
24
- errorsArrayToHash,
25
- InternalModel,
26
- recordDataFor,
27
- WeakCache,
28
- } from '@ember-data/store/-private';
18
+ DEPRECATE_EARLY_STATIC,
19
+ DEPRECATE_MODEL_REOPEN,
20
+ DEPRECATE_NON_EXPLICIT_POLYMORPHISM,
21
+ DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE,
22
+ DEPRECATE_SAVE_PROMISE_ACCESS,
23
+ } from '@ember-data/private-build-infra/deprecations';
24
+ import { recordIdentifierFor, storeFor } from '@ember-data/store';
25
+ import { coerceId, recordDataFor } from '@ember-data/store/-private';
29
26
 
27
+ import { deprecatedPromiseObject } from './deprecated-promise-proxy';
30
28
  import Errors from './errors';
31
29
  import { LegacySupport } from './legacy-relationships-support';
32
30
  import notifyChanges from './notify-changes';
@@ -34,18 +32,21 @@ import RecordState, { peekTag, tagged } from './record-state';
34
32
  import { relationshipFromMeta } from './relationship-meta';
35
33
 
36
34
  const { changeProperties } = Ember;
37
- export const LEGACY_SUPPORT = new WeakCache(DEBUG ? 'legacy-relationships' : '');
38
- LEGACY_SUPPORT._generator = (record) => {
35
+ export const LEGACY_SUPPORT = new Map();
36
+
37
+ export function lookupLegacySupport(record) {
39
38
  const identifier = recordIdentifierFor(record);
40
39
  let support = LEGACY_SUPPORT.get(identifier);
41
40
 
42
41
  if (!support) {
43
42
  support = new LegacySupport(record);
44
43
  LEGACY_SUPPORT.set(identifier, support);
44
+ LEGACY_SUPPORT.set(record, support);
45
45
  }
46
46
 
47
47
  return support;
48
- };
48
+ }
49
+
49
50
  function findPossibleInverses(type, inverseType, name, relationshipsSoFar) {
50
51
  let possibleRelationships = relationshipsSoFar || [];
51
52
 
@@ -57,7 +58,7 @@ function findPossibleInverses(type, inverseType, name, relationshipsSoFar) {
57
58
  let relationshipsForType = relationshipMap.get(type.modelName);
58
59
  let relationships = Array.isArray(relationshipsForType)
59
60
  ? relationshipsForType.filter((relationship) => {
60
- let optionsForRelationship = inverseType.metaForProperty(relationship.name).options;
61
+ let optionsForRelationship = relationship.options;
61
62
 
62
63
  if (!optionsForRelationship.inverse && optionsForRelationship.inverse !== null) {
63
64
  return true;
@@ -121,38 +122,57 @@ function computeOnce(target, key, desc) {
121
122
  @extends Ember.EmberObject
122
123
  */
123
124
  class Model extends EmberObject {
124
- @service store;
125
+ ___private_notifications;
125
126
 
126
127
  init(options = {}) {
127
- if (DEBUG && !options._secretInit && !options._internalModel && !options._createProps) {
128
+ if (DEBUG && !options._secretInit && !options._createProps) {
128
129
  throw new EmberError(
129
130
  'You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.'
130
131
  );
131
132
  }
132
133
  const createProps = options._createProps;
133
134
  const _secretInit = options._secretInit;
134
- delete options._createProps;
135
- delete options._secretInit;
135
+ options._createProps = null;
136
+ options._secretInit = null;
137
+
138
+ let store = (this.store = _secretInit.store);
136
139
  super.init(options);
137
140
 
138
- _secretInit(this);
141
+ let identity = _secretInit.identifier;
142
+ _secretInit.cb(this, _secretInit.recordData, identity, _secretInit.store);
143
+
139
144
  this.___recordState = DEBUG ? new RecordState(this) : null;
140
145
 
141
146
  this.setProperties(createProps);
142
147
 
143
- // TODO pass something in such that we don't need internalModel
144
- // to get this info
145
- let store = storeFor(this);
146
148
  let notifications = store._notificationManager;
147
- let identity = recordIdentifierFor(this);
148
-
149
- notifications.subscribe(identity, (identifier, type, key) => {
149
+ this.___private_notifications = notifications.subscribe(identity, (identifier, type, key) => {
150
150
  notifyChanges(identifier, type, key, this, store);
151
151
  });
152
152
  }
153
153
 
154
- willDestroy() {
154
+ destroy() {
155
+ const identifier = recordIdentifierFor(this);
156
+ this.___recordState?.destroy();
157
+ const store = storeFor(this);
158
+ store._notificationManager.unsubscribe(this.___private_notifications);
159
+ // Legacy behavior is to notify the relationships on destroy
160
+ // such that they "clear". It's uncertain this behavior would
161
+ // be good for a new model paradigm, likely cheaper and safer
162
+ // to simply not notify, for this reason the store does not itself
163
+ // notify individual changes once the delete has been signaled,
164
+ // this decision is left to model instances.
165
+
166
+ this.eachRelationship((key, meta) => {
167
+ if (meta.kind === 'belongsTo') {
168
+ this.notifyPropertyChange(key);
169
+ }
170
+ });
155
171
  LEGACY_SUPPORT.get(this)?.destroy();
172
+ LEGACY_SUPPORT.delete(this);
173
+ LEGACY_SUPPORT.delete(identifier);
174
+
175
+ super.destroy();
156
176
  }
157
177
 
158
178
  /**
@@ -200,10 +220,10 @@ class Model extends EmberObject {
200
220
 
201
221
  ```javascript
202
222
  let record = store.createRecord('model');
203
- record.get('isLoaded'); // true
223
+ record.isLoaded; // true
204
224
 
205
225
  store.findRecord('model', 1).then(function(model) {
206
- model.get('isLoaded'); // true
226
+ model.isLoaded; // true
207
227
  });
208
228
  ```
209
229
 
@@ -227,12 +247,12 @@ class Model extends EmberObject {
227
247
 
228
248
  ```javascript
229
249
  let record = store.createRecord('model');
230
- record.get('hasDirtyAttributes'); // true
250
+ record.hasDirtyAttributes; // true
231
251
 
232
252
  store.findRecord('model', 1).then(function(model) {
233
- model.get('hasDirtyAttributes'); // false
253
+ model.hasDirtyAttributes; // false
234
254
  model.set('foo', 'some value');
235
- model.get('hasDirtyAttributes'); // true
255
+ model.hasDirtyAttributes; // true
236
256
  });
237
257
  ```
238
258
 
@@ -257,11 +277,11 @@ class Model extends EmberObject {
257
277
 
258
278
  ```javascript
259
279
  let record = store.createRecord('model');
260
- record.get('isSaving'); // false
280
+ record.isSaving; // false
261
281
  let promise = record.save();
262
- record.get('isSaving'); // true
282
+ record.isSaving; // true
263
283
  promise.then(function() {
264
- record.get('isSaving'); // false
284
+ record.isSaving; // false
265
285
  });
266
286
  ```
267
287
 
@@ -287,24 +307,24 @@ class Model extends EmberObject {
287
307
 
288
308
  ```javascript
289
309
  let record = store.createRecord('model');
290
- record.get('isDeleted'); // false
310
+ record.isDeleted; // false
291
311
  record.deleteRecord();
292
312
 
293
313
  // Locally deleted
294
- record.get('isDeleted'); // true
295
- record.get('hasDirtyAttributes'); // true
296
- record.get('isSaving'); // false
314
+ record.isDeleted; // true
315
+ record.hasDirtyAttributes; // true
316
+ record.isSaving; // false
297
317
 
298
318
  // Persisting the deletion
299
319
  let promise = record.save();
300
- record.get('isDeleted'); // true
301
- record.get('isSaving'); // true
320
+ record.isDeleted; // true
321
+ record.isSaving; // true
302
322
 
303
323
  // Deletion Persisted
304
324
  promise.then(function() {
305
- record.get('isDeleted'); // true
306
- record.get('isSaving'); // false
307
- record.get('hasDirtyAttributes'); // false
325
+ record.isDeleted; // true
326
+ record.isSaving; // false
327
+ record.hasDirtyAttributes; // false
308
328
  });
309
329
  ```
310
330
 
@@ -328,10 +348,10 @@ class Model extends EmberObject {
328
348
 
329
349
  ```javascript
330
350
  let record = store.createRecord('model');
331
- record.get('isNew'); // true
351
+ record.isNew; // true
332
352
 
333
353
  record.save().then(function(model) {
334
- model.get('isNew'); // false
354
+ model.isNew; // false
335
355
  });
336
356
  ```
337
357
 
@@ -374,7 +394,7 @@ class Model extends EmberObject {
374
394
 
375
395
  ```javascript
376
396
  let record = store.createRecord('model');
377
- record.get('dirtyType'); // 'created'
397
+ record.dirtyType; // 'created'
378
398
  ```
379
399
 
380
400
  @property dirtyType
@@ -395,10 +415,10 @@ class Model extends EmberObject {
395
415
  Example
396
416
 
397
417
  ```javascript
398
- record.get('isError'); // false
418
+ record.isError; // false
399
419
  record.set('foo', 'valid value');
400
420
  record.save().then(null, function() {
401
- record.get('isError'); // true
421
+ record.isError; // true
402
422
  });
403
423
  ```
404
424
 
@@ -444,10 +464,10 @@ class Model extends EmberObject {
444
464
 
445
465
  ```javascript
446
466
  let record = store.createRecord('model');
447
- record.get('id'); // null
467
+ record.id; // null
448
468
 
449
469
  store.findRecord('model', 1).then(function(model) {
450
- model.get('id'); // '1'
470
+ model.id; // '1'
451
471
  });
452
472
  ```
453
473
 
@@ -457,24 +477,37 @@ class Model extends EmberObject {
457
477
  */
458
478
  @tagged
459
479
  get id() {
460
- // the _internalModel guard exists, because some dev-only deprecation code
480
+ // this guard exists, because some dev-only deprecation code
461
481
  // (addListener via validatePropertyInjections) invokes toString before the
462
482
  // object is real.
463
483
  if (DEBUG) {
464
- if (!this._internalModel) {
484
+ try {
485
+ return recordIdentifierFor(this).id;
486
+ } catch {
465
487
  return void 0;
466
488
  }
467
489
  }
468
- return this._internalModel.id;
490
+ return recordIdentifierFor(this).id;
469
491
  }
470
492
  set id(id) {
471
493
  const normalizedId = coerceId(id);
494
+ const identifier = recordIdentifierFor(this);
495
+ let didChange = normalizedId !== identifier.id;
496
+ assert(
497
+ `Cannot set ${identifier.type} record's id to ${id}, because id is already ${identifier.id}`,
498
+ !didChange || identifier.id === null
499
+ );
472
500
 
473
- if (normalizedId !== null) {
474
- this._internalModel.setId(normalizedId);
501
+ if (normalizedId !== null && didChange) {
502
+ this.store._instanceCache.setRecordId(identifier, normalizedId);
503
+ this.store._notificationManager.notify(identifier, 'identity');
475
504
  }
476
505
  }
477
506
 
507
+ toString() {
508
+ return `<model::${this.constructor.modelName}:${this.id}>`;
509
+ }
510
+
478
511
  /**
479
512
  @property currentState
480
513
  @private
@@ -497,12 +530,6 @@ class Model extends EmberObject {
497
530
  throw new Error('cannot set currentState');
498
531
  }
499
532
 
500
- /**
501
- @property _internalModel
502
- @private
503
- @type {Object}
504
- */
505
-
506
533
  /**
507
534
  The store service instance which created this record instance
508
535
 
@@ -520,10 +547,10 @@ class Model extends EmberObject {
520
547
  - `attribute` The name of the property associated with this error message
521
548
 
522
549
  ```javascript
523
- record.get('errors.length'); // 0
550
+ record.errors.length; // 0
524
551
  record.set('foo', 'invalid value');
525
552
  record.save().catch(function() {
526
- record.get('errors').get('foo');
553
+ record.errors.foo;
527
554
  // [{message: 'foo should be a number.', attribute: 'foo'}]
528
555
  });
529
556
  ```
@@ -565,22 +592,7 @@ class Model extends EmberObject {
565
592
  @computeOnce
566
593
  get errors() {
567
594
  let errors = Errors.create({ __record: this });
568
- // TODO we should unify how errors gets populated
569
- // with the code managing the update. Probably a
570
- // lazy flush similar to retrieveLatest in ManyArray
571
- let recordData = recordDataFor(this);
572
- let jsonApiErrors;
573
- if (recordData.getErrors) {
574
- jsonApiErrors = recordData.getErrors();
575
- if (jsonApiErrors) {
576
- let errorsHash = errorsArrayToHash(jsonApiErrors);
577
- let errorKeys = Object.keys(errorsHash);
578
-
579
- for (let i = 0; i < errorKeys.length; i++) {
580
- errors.add(errorKeys[i], errorsHash[errorKeys[i]]);
581
- }
582
- }
583
- }
595
+ this.currentState.updateInvalidErrors(errors);
584
596
  return errors;
585
597
  }
586
598
 
@@ -812,7 +824,7 @@ class Model extends EmberObject {
812
824
  and value is an [oldProp, newProp] array.
813
825
  */
814
826
  changedAttributes() {
815
- return this._internalModel.changedAttributes();
827
+ return recordDataFor(this).changedAttrs(recordIdentifierFor(this));
816
828
  }
817
829
 
818
830
  /**
@@ -822,11 +834,11 @@ class Model extends EmberObject {
822
834
  Example
823
835
 
824
836
  ```javascript
825
- record.get('name'); // 'Untitled Document'
837
+ record.name; // 'Untitled Document'
826
838
  record.set('name', 'Doc 1');
827
- record.get('name'); // 'Doc 1'
839
+ record.name; // 'Doc 1'
828
840
  record.rollbackAttributes();
829
- record.get('name'); // 'Untitled Document'
841
+ record.name; // 'Untitled Document'
830
842
  ```
831
843
 
832
844
  @since 1.13.0
@@ -835,8 +847,16 @@ class Model extends EmberObject {
835
847
  */
836
848
  rollbackAttributes() {
837
849
  const { currentState } = this;
838
- this._internalModel.rollbackAttributes();
839
- currentState.cleanErrorRequests();
850
+ const { isNew } = currentState;
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
+ });
840
860
  }
841
861
 
842
862
  /**
@@ -848,13 +868,6 @@ class Model extends EmberObject {
848
868
  return storeFor(this)._instanceCache.createSnapshot(recordIdentifierFor(this));
849
869
  }
850
870
 
851
- toStringExtension() {
852
- // the _internalModel guard exists, because some dev-only deprecation code
853
- // (addListener via validatePropertyInjections) invokes toString before the
854
- // object is real.
855
- return this._internalModel && this._internalModel.id;
856
- }
857
-
858
871
  /**
859
872
  Save the record and persist any changes to the record to an
860
873
  external source via the adapter.
@@ -981,7 +994,7 @@ class Model extends EmberObject {
981
994
  import Model, { belongsTo } from '@ember-data/model';
982
995
 
983
996
  export default class BlogModel extends Model {
984
- @belongsTo({ async: true }) user;
997
+ @belongsTo('user', { async: true, inverse: null }) user;
985
998
  }
986
999
  ```
987
1000
 
@@ -1037,7 +1050,7 @@ class Model extends EmberObject {
1037
1050
  @return {BelongsToReference} reference for this relationship
1038
1051
  */
1039
1052
  belongsTo(name) {
1040
- return LEGACY_SUPPORT.lookup(this).referenceFor('belongsTo', name);
1053
+ return lookupLegacySupport(this).referenceFor('belongsTo', name);
1041
1054
  }
1042
1055
 
1043
1056
  /**
@@ -1049,7 +1062,7 @@ class Model extends EmberObject {
1049
1062
  import Model, { hasMany } from '@ember-data/model';
1050
1063
 
1051
1064
  export default class BlogModel extends Model {
1052
- @hasMany({ async: true }) comments;
1065
+ @hasMany('comment', { async: true, inverse: null }) comments;
1053
1066
  }
1054
1067
 
1055
1068
  let blog = store.push({
@@ -1100,7 +1113,7 @@ class Model extends EmberObject {
1100
1113
  @return {HasManyReference} reference for this relationship
1101
1114
  */
1102
1115
  hasMany(name) {
1103
- return LEGACY_SUPPORT.lookup(this).referenceFor('hasMany', name);
1116
+ return lookupLegacySupport(this).referenceFor('hasMany', name);
1104
1117
  }
1105
1118
 
1106
1119
  /**
@@ -1142,7 +1155,7 @@ class Model extends EmberObject {
1142
1155
  record.eachRelationship(function(name, descriptor) {
1143
1156
  if (descriptor.kind === 'hasMany') {
1144
1157
  let serializedHasManyName = name.toUpperCase() + '_IDS';
1145
- json[serializedHasManyName] = record.get(name).mapBy('id');
1158
+ json[serializedHasManyName] = record.get(name).map(r => r.id);
1146
1159
  }
1147
1160
  });
1148
1161
 
@@ -1202,7 +1215,7 @@ class Model extends EmberObject {
1202
1215
 
1203
1216
  ```javascript
1204
1217
  import RESTSerializer from '@ember-data/serializer/rest';
1205
- import { underscore } from '@ember/string';
1218
+ import { underscore } from '<app-name>/utils/string-utils';
1206
1219
 
1207
1220
  export default const PostSerializer = RESTSerializer.extend({
1208
1221
  payloadKeyFromModelName(modelName) {
@@ -1258,12 +1271,46 @@ class Model extends EmberObject {
1258
1271
  @return {Model} the type of the relationship, or undefined
1259
1272
  */
1260
1273
  static typeForRelationship(name, store) {
1274
+ if (DEPRECATE_EARLY_STATIC) {
1275
+ deprecate(
1276
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
1277
+ this.modelName,
1278
+ {
1279
+ id: 'ember-data:deprecate-early-static',
1280
+ for: 'ember-data',
1281
+ until: '5.0',
1282
+ since: { available: '4.8', enabled: '4.8' },
1283
+ }
1284
+ );
1285
+ } else {
1286
+ assert(
1287
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
1288
+ this.modelName
1289
+ );
1290
+ }
1261
1291
  let relationship = this.relationshipsByName.get(name);
1262
1292
  return relationship && store.modelFor(relationship.type);
1263
1293
  }
1264
1294
 
1265
1295
  @computeOnce
1266
1296
  static get inverseMap() {
1297
+ if (DEPRECATE_EARLY_STATIC) {
1298
+ deprecate(
1299
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
1300
+ this.modelName,
1301
+ {
1302
+ id: 'ember-data:deprecate-early-static',
1303
+ for: 'ember-data',
1304
+ until: '5.0',
1305
+ since: { available: '4.8', enabled: '4.8' },
1306
+ }
1307
+ );
1308
+ } else {
1309
+ assert(
1310
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
1311
+ this.modelName
1312
+ );
1313
+ }
1267
1314
  return Object.create(null);
1268
1315
  }
1269
1316
 
@@ -1301,6 +1348,23 @@ class Model extends EmberObject {
1301
1348
  @return {Object} the inverse relationship, or null
1302
1349
  */
1303
1350
  static inverseFor(name, store) {
1351
+ if (DEPRECATE_EARLY_STATIC) {
1352
+ deprecate(
1353
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
1354
+ this.modelName,
1355
+ {
1356
+ id: 'ember-data:deprecate-early-static',
1357
+ for: 'ember-data',
1358
+ until: '5.0',
1359
+ since: { available: '4.8', enabled: '4.8' },
1360
+ }
1361
+ );
1362
+ } else {
1363
+ assert(
1364
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
1365
+ this.modelName
1366
+ );
1367
+ }
1304
1368
  let inverseMap = this.inverseMap;
1305
1369
  if (inverseMap[name]) {
1306
1370
  return inverseMap[name];
@@ -1313,42 +1377,63 @@ class Model extends EmberObject {
1313
1377
 
1314
1378
  //Calculate the inverse, ignoring the cache
1315
1379
  static _findInverseFor(name, store) {
1316
- let inverseType = this.typeForRelationship(name, store);
1317
- if (!inverseType) {
1318
- return null;
1380
+ if (DEPRECATE_EARLY_STATIC) {
1381
+ deprecate(
1382
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
1383
+ this.modelName,
1384
+ {
1385
+ id: 'ember-data:deprecate-early-static',
1386
+ for: 'ember-data',
1387
+ until: '5.0',
1388
+ since: { available: '4.8', enabled: '4.8' },
1389
+ }
1390
+ );
1391
+ } else {
1392
+ assert(
1393
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
1394
+ this.modelName
1395
+ );
1319
1396
  }
1320
1397
 
1321
- let propertyMeta = this.metaForProperty(name);
1398
+ const relationship = this.relationshipsByName.get(name);
1399
+ const { options } = relationship;
1400
+ const isPolymorphic = options.polymorphic;
1401
+
1322
1402
  //If inverse is manually specified to be null, like `comments: hasMany('message', { inverse: null })`
1323
- let options = propertyMeta.options;
1324
- if (options.inverse === null) {
1403
+ const isExplicitInverseNull = options.inverse === null;
1404
+ const isAbstractType =
1405
+ !isExplicitInverseNull && isPolymorphic && !store.getSchemaDefinitionService().doesTypeExist(relationship.type);
1406
+
1407
+ if (isExplicitInverseNull || isAbstractType) {
1408
+ assert(
1409
+ `No schema for the abstract type '${relationship.type}' for the polymorphic relationship '${name}' on '${this.modelName}' was provided by the SchemaDefinitionService.`,
1410
+ !isPolymorphic || isExplicitInverseNull
1411
+ );
1325
1412
  return null;
1326
1413
  }
1327
1414
 
1328
- let inverseName, inverseKind, inverse, inverseOptions;
1415
+ let fieldOnInverse, inverseKind, inverseRelationship, inverseOptions;
1416
+ let inverseSchema = this.typeForRelationship(name, store);
1329
1417
 
1418
+ // if the type does not exist and we are not polymorphic
1330
1419
  //If inverse is specified manually, return the inverse
1331
- if (options.inverse) {
1332
- inverseName = options.inverse;
1333
- inverse = inverseType.relationshipsByName.get(inverseName);
1420
+ if (options.inverse !== undefined) {
1421
+ fieldOnInverse = options.inverse;
1422
+ inverseRelationship = inverseSchema && inverseSchema.relationshipsByName.get(fieldOnInverse);
1334
1423
 
1335
1424
  assert(
1336
- "We found no inverse relationships by the name of '" +
1337
- inverseName +
1338
- "' on the '" +
1339
- inverseType.modelName +
1340
- "' model. This is most likely due to a missing attribute on your model definition.",
1341
- !isNone(inverse)
1425
+ `We found no field named '${fieldOnInverse}' on the schema for '${inverseSchema.modelName}' to be the inverse of the '${name}' relationship on '${this.modelName}'. This is most likely due to a missing field on your model definition.`,
1426
+ inverseRelationship
1342
1427
  );
1343
1428
 
1344
1429
  // TODO probably just return the whole inverse here
1345
- inverseKind = inverse.kind;
1346
- inverseOptions = inverse.options;
1430
+ inverseKind = inverseRelationship.kind;
1431
+ inverseOptions = inverseRelationship.options;
1347
1432
  } else {
1348
1433
  //No inverse was specified manually, we need to use a heuristic to guess one
1349
- if (propertyMeta.type === propertyMeta.parentModelName) {
1434
+ if (relationship.type === relationship.parentModelName) {
1350
1435
  warn(
1351
- `Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at https://guides.emberjs.com/current/models/relationships/#toc_reflexive-relations for how to explicitly specify inverses.`,
1436
+ `Detected a reflexive relationship named '${name}' on the schema for '${relationship.type}' without an inverse option. Look at https://guides.emberjs.com/current/models/relationships/#toc_reflexive-relations for how to explicitly specify inverses.`,
1352
1437
  false,
1353
1438
  {
1354
1439
  id: 'ds.model.reflexive-relationship-without-inverse',
@@ -1356,30 +1441,33 @@ class Model extends EmberObject {
1356
1441
  );
1357
1442
  }
1358
1443
 
1359
- let possibleRelationships = findPossibleInverses(this, inverseType, name);
1444
+ let possibleRelationships = findPossibleInverses(this, inverseSchema, name);
1360
1445
 
1361
1446
  if (possibleRelationships.length === 0) {
1362
1447
  return null;
1363
1448
  }
1364
1449
 
1365
- let filteredRelationships = possibleRelationships.filter((possibleRelationship) => {
1366
- let optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options;
1367
- return name === optionsForRelationship.inverse;
1368
- });
1450
+ if (DEBUG) {
1451
+ let filteredRelationships = possibleRelationships.filter((possibleRelationship) => {
1452
+ let optionsForRelationship = possibleRelationship.options;
1453
+ return name === optionsForRelationship.inverse;
1454
+ });
1369
1455
 
1370
- assert(
1371
- "You defined the '" +
1372
- name +
1373
- "' relationship on " +
1374
- this +
1375
- ', but you defined the inverse relationships of type ' +
1376
- inverseType.toString() +
1377
- ' multiple times. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses',
1378
- filteredRelationships.length < 2
1379
- );
1456
+ assert(
1457
+ "You defined the '" +
1458
+ name +
1459
+ "' relationship on " +
1460
+ this +
1461
+ ', but you defined the inverse relationships of type ' +
1462
+ inverseSchema.toString() +
1463
+ ' multiple times. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses',
1464
+ filteredRelationships.length < 2
1465
+ );
1466
+ }
1380
1467
 
1381
- if (filteredRelationships.length === 1) {
1382
- possibleRelationships = filteredRelationships;
1468
+ let explicitRelationship = possibleRelationships.find((relationship) => relationship.options.inverse === name);
1469
+ if (explicitRelationship) {
1470
+ possibleRelationships = [explicitRelationship];
1383
1471
  }
1384
1472
 
1385
1473
  assert(
@@ -1390,24 +1478,78 @@ class Model extends EmberObject {
1390
1478
  ', but multiple possible inverse relationships of type ' +
1391
1479
  this +
1392
1480
  ' were found on ' +
1393
- inverseType +
1481
+ inverseSchema +
1394
1482
  '. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses',
1395
1483
  possibleRelationships.length === 1
1396
1484
  );
1397
1485
 
1398
- inverseName = possibleRelationships[0].name;
1486
+ fieldOnInverse = possibleRelationships[0].name;
1399
1487
  inverseKind = possibleRelationships[0].kind;
1400
1488
  inverseOptions = possibleRelationships[0].options;
1401
1489
  }
1402
1490
 
1491
+ // ensure inverse is properly configured
1492
+ if (DEBUG && isPolymorphic) {
1493
+ if (DEPRECATE_NON_EXPLICIT_POLYMORPHISM) {
1494
+ if (!inverseOptions.as) {
1495
+ deprecate(
1496
+ `Relationships that satisfy polymorphic relationships MUST define which abstract-type they are satisfying using 'as'. The field '${fieldOnInverse}' on type '${inverseSchema.modelName}' is misconfigured.`,
1497
+ false,
1498
+ {
1499
+ id: 'ember-data:non-explicit-relationships',
1500
+ since: { enabled: '4.8', available: '4.8' },
1501
+ until: '5.0',
1502
+ for: 'ember-data',
1503
+ }
1504
+ );
1505
+ }
1506
+ } else {
1507
+ assert(
1508
+ `Relationships that satisfy polymorphic relationships MUST define which abstract-type they are satisfying using 'as'. The field '${fieldOnInverse}' on type '${inverseSchema.modelName}' is misconfigured.`,
1509
+ inverseOptions.as
1510
+ );
1511
+ assert(
1512
+ `options.as should match the expected type of the polymorphic relationship. Expected field '${fieldOnInverse}' on type '${inverseSchema.modelName}' to specify '${relationship.type}' but found '${inverseOptions.as}'`,
1513
+ !!inverseOptions.as && relationship.type === inverseOptions.as
1514
+ );
1515
+ }
1516
+ }
1517
+
1518
+ // ensure we are properly configured
1519
+ if (DEBUG && inverseOptions.polymorphic) {
1520
+ if (DEPRECATE_NON_EXPLICIT_POLYMORPHISM) {
1521
+ if (!options.as) {
1522
+ deprecate(
1523
+ `Relationships that satisfy polymorphic relationships MUST define which abstract-type they are satisfying using 'as'. The field '${name}' on type '${this.modelName}' is misconfigured.`,
1524
+ false,
1525
+ {
1526
+ id: 'ember-data:non-explicit-relationships',
1527
+ since: { enabled: '4.8', available: '4.8' },
1528
+ until: '5.0',
1529
+ for: 'ember-data',
1530
+ }
1531
+ );
1532
+ }
1533
+ } else {
1534
+ assert(
1535
+ `Relationships that satisfy polymorphic relationships MUST define which abstract-type they are satisfying using 'as'. The field '${name}' on type '${this.modelName}' is misconfigured.`,
1536
+ options.as
1537
+ );
1538
+ assert(
1539
+ `options.as should match the expected type of the polymorphic relationship. Expected field '${name}' on type '${this.modelName}' to specify '${inverseRelationship.type}' but found '${options.as}'`,
1540
+ !!options.as && inverseRelationship.type === options.as
1541
+ );
1542
+ }
1543
+ }
1544
+
1403
1545
  assert(
1404
- `The ${inverseType.modelName}:${inverseName} relationship declares 'inverse: null', but it was resolved as the inverse for ${this.modelName}:${name}.`,
1405
- !inverseOptions || inverseOptions.inverse !== null
1546
+ `The ${inverseSchema.modelName}:${fieldOnInverse} relationship declares 'inverse: null', but it was resolved as the inverse for ${this.modelName}:${name}.`,
1547
+ inverseOptions.inverse !== null
1406
1548
  );
1407
1549
 
1408
1550
  return {
1409
- type: inverseType,
1410
- name: inverseName,
1551
+ type: inverseSchema,
1552
+ name: fieldOnInverse,
1411
1553
  kind: inverseKind,
1412
1554
  options: inverseOptions,
1413
1555
  };
@@ -1441,10 +1583,10 @@ class Model extends EmberObject {
1441
1583
  import Post from 'app/models/post';
1442
1584
 
1443
1585
  let relationships = Blog.relationships;
1444
- relationships.get('user');
1586
+ relationships.user;
1445
1587
  //=> [ { name: 'users', kind: 'hasMany' },
1446
1588
  // { name: 'owner', kind: 'belongsTo' } ]
1447
- relationships.get('post');
1589
+ relationships.post;
1448
1590
  //=> [ { name: 'posts', kind: 'hasMany' } ]
1449
1591
  ```
1450
1592
 
@@ -1457,6 +1599,23 @@ class Model extends EmberObject {
1457
1599
 
1458
1600
  @computeOnce
1459
1601
  static get relationships() {
1602
+ if (DEPRECATE_EARLY_STATIC) {
1603
+ deprecate(
1604
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
1605
+ this.modelName,
1606
+ {
1607
+ id: 'ember-data:deprecate-early-static',
1608
+ for: 'ember-data',
1609
+ until: '5.0',
1610
+ since: { available: '4.8', enabled: '4.8' },
1611
+ }
1612
+ );
1613
+ } else {
1614
+ assert(
1615
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
1616
+ this.modelName
1617
+ );
1618
+ }
1460
1619
  let map = new Map();
1461
1620
  let relationshipsByName = this.relationshipsByName;
1462
1621
 
@@ -1511,6 +1670,23 @@ class Model extends EmberObject {
1511
1670
  */
1512
1671
  @computeOnce
1513
1672
  static get relationshipNames() {
1673
+ if (DEPRECATE_EARLY_STATIC) {
1674
+ deprecate(
1675
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
1676
+ this.modelName,
1677
+ {
1678
+ id: 'ember-data:deprecate-early-static',
1679
+ for: 'ember-data',
1680
+ until: '5.0',
1681
+ since: { available: '4.8', enabled: '4.8' },
1682
+ }
1683
+ );
1684
+ } else {
1685
+ assert(
1686
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
1687
+ this.modelName
1688
+ );
1689
+ }
1514
1690
  let names = {
1515
1691
  hasMany: [],
1516
1692
  belongsTo: [],
@@ -1561,6 +1737,23 @@ class Model extends EmberObject {
1561
1737
  */
1562
1738
  @computeOnce
1563
1739
  static get relatedTypes() {
1740
+ if (DEPRECATE_EARLY_STATIC) {
1741
+ deprecate(
1742
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
1743
+ this.modelName,
1744
+ {
1745
+ id: 'ember-data:deprecate-early-static',
1746
+ for: 'ember-data',
1747
+ until: '5.0',
1748
+ since: { available: '4.8', enabled: '4.8' },
1749
+ }
1750
+ );
1751
+ } else {
1752
+ assert(
1753
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
1754
+ this.modelName
1755
+ );
1756
+ }
1564
1757
  let types = [];
1565
1758
 
1566
1759
  let rels = this.relationshipsObject;
@@ -1606,9 +1799,9 @@ class Model extends EmberObject {
1606
1799
  import Blog from 'app/models/blog';
1607
1800
 
1608
1801
  let relationshipsByName = Blog.relationshipsByName;
1609
- relationshipsByName.get('users');
1802
+ relationshipsByName.users;
1610
1803
  //=> { key: 'users', kind: 'hasMany', type: 'user', options: Object, isRelationship: true }
1611
- relationshipsByName.get('owner');
1804
+ relationshipsByName.owner;
1612
1805
  //=> { key: 'owner', kind: 'belongsTo', type: 'user', options: Object, isRelationship: true }
1613
1806
  ```
1614
1807
 
@@ -1620,6 +1813,23 @@ class Model extends EmberObject {
1620
1813
  */
1621
1814
  @computeOnce
1622
1815
  static get relationshipsByName() {
1816
+ if (DEPRECATE_EARLY_STATIC) {
1817
+ deprecate(
1818
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
1819
+ this.modelName,
1820
+ {
1821
+ id: 'ember-data:deprecate-early-static',
1822
+ for: 'ember-data',
1823
+ until: '5.0',
1824
+ since: { available: '4.8', enabled: '4.8' },
1825
+ }
1826
+ );
1827
+ } else {
1828
+ assert(
1829
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
1830
+ this.modelName
1831
+ );
1832
+ }
1623
1833
  let map = new Map();
1624
1834
  let rels = this.relationshipsObject;
1625
1835
  let relationships = Object.keys(rels);
@@ -1636,6 +1846,23 @@ class Model extends EmberObject {
1636
1846
 
1637
1847
  @computeOnce
1638
1848
  static get relationshipsObject() {
1849
+ if (DEPRECATE_EARLY_STATIC) {
1850
+ deprecate(
1851
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
1852
+ this.modelName,
1853
+ {
1854
+ id: 'ember-data:deprecate-early-static',
1855
+ for: 'ember-data',
1856
+ until: '5.0',
1857
+ since: { available: '4.8', enabled: '4.8' },
1858
+ }
1859
+ );
1860
+ } else {
1861
+ assert(
1862
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
1863
+ this.modelName
1864
+ );
1865
+ }
1639
1866
  let relationships = Object.create(null);
1640
1867
  let modelName = this.modelName;
1641
1868
  this.eachComputedProperty((name, meta) => {
@@ -1643,7 +1870,7 @@ class Model extends EmberObject {
1643
1870
  meta.key = name;
1644
1871
  meta.name = name;
1645
1872
  meta.parentModelName = modelName;
1646
- relationships[name] = relationshipFromMeta(meta);
1873
+ relationships[name] = DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE ? relationshipFromMeta(meta) : meta;
1647
1874
  }
1648
1875
  });
1649
1876
  return relationships;
@@ -1675,7 +1902,7 @@ class Model extends EmberObject {
1675
1902
 
1676
1903
  let fields = Blog.fields;
1677
1904
  fields.forEach(function(kind, field) {
1678
- console.log(field, kind);
1905
+ // do thing
1679
1906
  });
1680
1907
 
1681
1908
  // prints:
@@ -1693,9 +1920,27 @@ class Model extends EmberObject {
1693
1920
  */
1694
1921
  @computeOnce
1695
1922
  static get fields() {
1923
+ if (DEPRECATE_EARLY_STATIC) {
1924
+ deprecate(
1925
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
1926
+ this.modelName,
1927
+ {
1928
+ id: 'ember-data:deprecate-early-static',
1929
+ for: 'ember-data',
1930
+ until: '5.0',
1931
+ since: { available: '4.8', enabled: '4.8' },
1932
+ }
1933
+ );
1934
+ } else {
1935
+ assert(
1936
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
1937
+ this.modelName
1938
+ );
1939
+ }
1696
1940
  let map = new Map();
1697
1941
 
1698
1942
  this.eachComputedProperty((name, meta) => {
1943
+ // TODO end reliance on these booleans and stop leaking them in the spec
1699
1944
  if (meta.isRelationship) {
1700
1945
  map.set(name, meta.kind);
1701
1946
  } else if (meta.isAttribute) {
@@ -1718,6 +1963,23 @@ class Model extends EmberObject {
1718
1963
  @param {any} binding the value to which the callback's `this` should be bound
1719
1964
  */
1720
1965
  static eachRelationship(callback, binding) {
1966
+ if (DEPRECATE_EARLY_STATIC) {
1967
+ deprecate(
1968
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
1969
+ this.modelName,
1970
+ {
1971
+ id: 'ember-data:deprecate-early-static',
1972
+ for: 'ember-data',
1973
+ until: '5.0',
1974
+ since: { available: '4.8', enabled: '4.8' },
1975
+ }
1976
+ );
1977
+ } else {
1978
+ assert(
1979
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
1980
+ this.modelName
1981
+ );
1982
+ }
1721
1983
  this.relationshipsByName.forEach((relationship, name) => {
1722
1984
  callback.call(binding, name, relationship);
1723
1985
  });
@@ -1736,6 +1998,23 @@ class Model extends EmberObject {
1736
1998
  @param {any} binding the value to which the callback's `this` should be bound
1737
1999
  */
1738
2000
  static eachRelatedType(callback, binding) {
2001
+ if (DEPRECATE_EARLY_STATIC) {
2002
+ deprecate(
2003
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
2004
+ this.modelName,
2005
+ {
2006
+ id: 'ember-data:deprecate-early-static',
2007
+ for: 'ember-data',
2008
+ until: '5.0',
2009
+ since: { available: '4.8', enabled: '4.8' },
2010
+ }
2011
+ );
2012
+ } else {
2013
+ assert(
2014
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
2015
+ this.modelName
2016
+ );
2017
+ }
1739
2018
  let relationshipTypes = this.relatedTypes;
1740
2019
 
1741
2020
  for (let i = 0; i < relationshipTypes.length; i++) {
@@ -1745,6 +2024,23 @@ class Model extends EmberObject {
1745
2024
  }
1746
2025
 
1747
2026
  static determineRelationshipType(knownSide, store) {
2027
+ if (DEPRECATE_EARLY_STATIC) {
2028
+ deprecate(
2029
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
2030
+ this.modelName,
2031
+ {
2032
+ id: 'ember-data:deprecate-early-static',
2033
+ for: 'ember-data',
2034
+ until: '5.0',
2035
+ since: { available: '4.8', enabled: '4.8' },
2036
+ }
2037
+ );
2038
+ } else {
2039
+ assert(
2040
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
2041
+ this.modelName
2042
+ );
2043
+ }
1748
2044
  let knownKey = knownSide.key;
1749
2045
  let knownKind = knownSide.kind;
1750
2046
  let inverse = this.inverseFor(knownKey, store);
@@ -1789,7 +2085,7 @@ class Model extends EmberObject {
1789
2085
  let attributes = Person.attributes
1790
2086
 
1791
2087
  attributes.forEach(function(meta, name) {
1792
- console.log(name, meta);
2088
+ // do thing
1793
2089
  });
1794
2090
 
1795
2091
  // prints:
@@ -1806,6 +2102,23 @@ class Model extends EmberObject {
1806
2102
  */
1807
2103
  @computeOnce
1808
2104
  static get attributes() {
2105
+ if (DEPRECATE_EARLY_STATIC) {
2106
+ deprecate(
2107
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
2108
+ this.modelName,
2109
+ {
2110
+ id: 'ember-data:deprecate-early-static',
2111
+ for: 'ember-data',
2112
+ until: '5.0',
2113
+ since: { available: '4.8', enabled: '4.8' },
2114
+ }
2115
+ );
2116
+ } else {
2117
+ assert(
2118
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
2119
+ this.modelName
2120
+ );
2121
+ }
1809
2122
  let map = new Map();
1810
2123
 
1811
2124
  this.eachComputedProperty((name, meta) => {
@@ -1849,7 +2162,7 @@ class Model extends EmberObject {
1849
2162
  let transformedAttributes = Person.transformedAttributes
1850
2163
 
1851
2164
  transformedAttributes.forEach(function(field, type) {
1852
- console.log(field, type);
2165
+ // do thing
1853
2166
  });
1854
2167
 
1855
2168
  // prints:
@@ -1865,6 +2178,23 @@ class Model extends EmberObject {
1865
2178
  */
1866
2179
  @computeOnce
1867
2180
  static get transformedAttributes() {
2181
+ if (DEPRECATE_EARLY_STATIC) {
2182
+ deprecate(
2183
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
2184
+ this.modelName,
2185
+ {
2186
+ id: 'ember-data:deprecate-early-static',
2187
+ for: 'ember-data',
2188
+ until: '5.0',
2189
+ since: { available: '4.8', enabled: '4.8' },
2190
+ }
2191
+ );
2192
+ } else {
2193
+ assert(
2194
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
2195
+ this.modelName
2196
+ );
2197
+ }
1868
2198
  let map = new Map();
1869
2199
 
1870
2200
  this.eachAttribute((key, meta) => {
@@ -1905,7 +2235,7 @@ class Model extends EmberObject {
1905
2235
  }
1906
2236
 
1907
2237
  PersonModel.eachAttribute(function(name, meta) {
1908
- console.log(name, meta);
2238
+ // do thing
1909
2239
  });
1910
2240
 
1911
2241
  // prints:
@@ -1921,6 +2251,23 @@ class Model extends EmberObject {
1921
2251
  @static
1922
2252
  */
1923
2253
  static eachAttribute(callback, binding) {
2254
+ if (DEPRECATE_EARLY_STATIC) {
2255
+ deprecate(
2256
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
2257
+ this.modelName,
2258
+ {
2259
+ id: 'ember-data:deprecate-early-static',
2260
+ for: 'ember-data',
2261
+ until: '5.0',
2262
+ since: { available: '4.8', enabled: '4.8' },
2263
+ }
2264
+ );
2265
+ } else {
2266
+ assert(
2267
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
2268
+ this.modelName
2269
+ );
2270
+ }
1924
2271
  this.attributes.forEach((meta, name) => {
1925
2272
  callback.call(binding, name, meta);
1926
2273
  });
@@ -1957,7 +2304,7 @@ class Model extends EmberObject {
1957
2304
  });
1958
2305
 
1959
2306
  Person.eachTransformedAttribute(function(name, type) {
1960
- console.log(name, type);
2307
+ // do thing
1961
2308
  });
1962
2309
 
1963
2310
  // prints:
@@ -1972,6 +2319,23 @@ class Model extends EmberObject {
1972
2319
  @static
1973
2320
  */
1974
2321
  static eachTransformedAttribute(callback, binding) {
2322
+ if (DEPRECATE_EARLY_STATIC) {
2323
+ deprecate(
2324
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
2325
+ this.modelName,
2326
+ {
2327
+ id: 'ember-data:deprecate-early-static',
2328
+ for: 'ember-data',
2329
+ until: '5.0',
2330
+ since: { available: '4.8', enabled: '4.8' },
2331
+ }
2332
+ );
2333
+ } else {
2334
+ assert(
2335
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
2336
+ this.modelName
2337
+ );
2338
+ }
1975
2339
  this.transformedAttributes.forEach((type, name) => {
1976
2340
  callback.call(binding, name, type);
1977
2341
  });
@@ -1985,13 +2349,29 @@ class Model extends EmberObject {
1985
2349
  @static
1986
2350
  */
1987
2351
  static toString() {
1988
- return `model:${get(this, 'modelName')}`;
2352
+ if (DEPRECATE_EARLY_STATIC) {
2353
+ deprecate(
2354
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
2355
+ this.modelName,
2356
+ {
2357
+ id: 'ember-data:deprecate-early-static',
2358
+ for: 'ember-data',
2359
+ until: '5.0',
2360
+ since: { available: '4.8', enabled: '4.8' },
2361
+ }
2362
+ );
2363
+ } else {
2364
+ assert(
2365
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
2366
+ this.modelName
2367
+ );
2368
+ }
2369
+ return `model:${this.modelName}`;
1989
2370
  }
1990
2371
  }
1991
2372
 
1992
2373
  // this is required to prevent `init` from passing
1993
2374
  // the values initialized during create to `setUnknownProperty`
1994
- Model.prototype._internalModel = null;
1995
2375
  Model.prototype._createProps = null;
1996
2376
  Model.prototype._secretInit = null;
1997
2377
 
@@ -2071,27 +2451,11 @@ if (DEBUG) {
2071
2451
  } while (current !== null);
2072
2452
  return null;
2073
2453
  };
2074
- let isBasicDesc = function isBasicDesc(desc) {
2075
- return (
2076
- !desc ||
2077
- (!desc.get && !desc.set && desc.enumerable === true && desc.writable === true && desc.configurable === true)
2078
- );
2079
- };
2080
- let isDefaultEmptyDescriptor = function isDefaultEmptyDescriptor(obj, keyName) {
2081
- let instanceDesc = lookupDescriptor(obj, keyName);
2082
- return isBasicDesc(instanceDesc) && lookupDescriptor(obj.constructor, keyName) === null;
2083
- };
2084
2454
 
2085
2455
  Model.reopen({
2086
2456
  init() {
2087
2457
  this._super(...arguments);
2088
2458
 
2089
- if (!isDefaultEmptyDescriptor(this, '_internalModel') || !(this._internalModel instanceof InternalModel)) {
2090
- throw new Error(
2091
- `'_internalModel' is a reserved property name on instances of classes extending Model. Please choose a different property name for ${this.constructor.toString()}`
2092
- );
2093
- }
2094
-
2095
2459
  let ourDescriptor = lookupDescriptor(Model.prototype, 'currentState');
2096
2460
  let theirDescriptor = lookupDescriptor(this, 'currentState');
2097
2461
  let realState = this.___recordState;
@@ -2111,6 +2475,35 @@ if (DEBUG) {
2111
2475
  }
2112
2476
  },
2113
2477
  });
2478
+
2479
+ if (DEPRECATE_MODEL_REOPEN) {
2480
+ const originalReopen = Model.reopen;
2481
+ const originalReopenClass = Model.reopenClass;
2482
+
2483
+ Model.reopen = function deprecatedReopen() {
2484
+ deprecate(`Model.reopen is deprecated. Use Foo extends Model to extend your class instead.`, false, {
2485
+ id: 'ember-data:deprecate-model-reopen',
2486
+ for: 'ember-data',
2487
+ until: '5.0',
2488
+ since: { available: '4.8', enabled: '4.8' },
2489
+ });
2490
+ return originalReopen.call(this, ...arguments);
2491
+ };
2492
+
2493
+ Model.reopenClass = function deprecatedReopenClass() {
2494
+ deprecate(
2495
+ `Model.reopenClass is deprecated. Use Foo extends Model to add static methods and properties to your class instead.`,
2496
+ false,
2497
+ {
2498
+ id: 'ember-data:deprecate-model-reopenclass',
2499
+ for: 'ember-data',
2500
+ until: '5.0',
2501
+ since: { available: '4.8', enabled: '4.8' },
2502
+ }
2503
+ );
2504
+ return originalReopenClass.call(this, ...arguments);
2505
+ };
2506
+ }
2114
2507
  }
2115
2508
 
2116
2509
  export default Model;