@ember-data/model 4.8.0-alpha.2 → 4.8.0-alpha.5

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.
@@ -4,7 +4,7 @@
4
4
 
5
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
10
  import { inject as service } from '@ember/service';
@@ -19,10 +19,11 @@ import { HAS_DEBUG_PACKAGE } from '@ember-data/private-build-infra';
19
19
  import {
20
20
  DEPRECATE_EARLY_STATIC,
21
21
  DEPRECATE_MODEL_REOPEN,
22
+ DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE,
22
23
  DEPRECATE_SAVE_PROMISE_ACCESS,
23
24
  } from '@ember-data/private-build-infra/deprecations';
24
25
  import { recordIdentifierFor, storeFor } from '@ember-data/store';
25
- import { coerceId, deprecatedPromiseObject, InternalModel, WeakCache } from '@ember-data/store/-private';
26
+ import { coerceId, deprecatedPromiseObject, recordDataFor } from '@ember-data/store/-private';
26
27
 
27
28
  import Errors from './errors';
28
29
  import { LegacySupport } from './legacy-relationships-support';
@@ -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
 
@@ -119,37 +123,48 @@ function computeOnce(target, key, desc) {
119
123
  */
120
124
  class Model extends EmberObject {
121
125
  @service store;
126
+ ___private_notifications;
122
127
 
123
128
  init(options = {}) {
124
- if (DEBUG && !options._secretInit && !options._internalModel && !options._createProps) {
129
+ if (DEBUG && !options._secretInit && !options._createProps) {
125
130
  throw new EmberError(
126
131
  'You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.'
127
132
  );
128
133
  }
129
134
  const createProps = options._createProps;
130
135
  const _secretInit = options._secretInit;
131
- delete options._createProps;
132
- delete options._secretInit;
136
+ options._createProps = null;
137
+ options._secretInit = null;
133
138
  super.init(options);
134
139
 
135
- _secretInit(this);
140
+ let identity = _secretInit.identifier;
141
+ _secretInit.cb(this, _secretInit.recordData, identity, _secretInit.store);
136
142
  this.___recordState = DEBUG ? new RecordState(this) : null;
137
143
 
138
144
  this.setProperties(createProps);
139
145
 
140
- // TODO pass something in such that we don't need internalModel
141
- // to get this info
142
146
  let store = storeFor(this);
143
147
  let notifications = store._notificationManager;
144
- let identity = recordIdentifierFor(this);
145
148
 
146
- notifications.subscribe(identity, (identifier, type, key) => {
149
+ this.___private_notifications = notifications.subscribe(identity, (identifier, type, key) => {
147
150
  notifyChanges(identifier, type, key, this, store);
148
151
  });
149
152
  }
150
153
 
151
- willDestroy() {
154
+ destroy() {
152
155
  LEGACY_SUPPORT.get(this)?.destroy();
156
+ this.___recordState?.destroy();
157
+ const store = storeFor(this);
158
+ const identifier = recordIdentifierFor(this);
159
+ store._notificationManager.unsubscribe(this.___private_notifications);
160
+ // Legacy behavior is to notify the relationships on destroy
161
+ // such that they "clear". It's uncertain this behavior would
162
+ // be good for a new model paradigm, likely cheaper and safer
163
+ // to simply not notify, for this reason the store does not itself
164
+ // notify individual changes once the delete has been signaled,
165
+ // this decision is left to model instances.
166
+ notifyChanges(identifier, 'relationships', undefined, this, store);
167
+ super.destroy();
153
168
  }
154
169
 
155
170
  /**
@@ -197,10 +212,10 @@ class Model extends EmberObject {
197
212
 
198
213
  ```javascript
199
214
  let record = store.createRecord('model');
200
- record.get('isLoaded'); // true
215
+ record.isLoaded; // true
201
216
 
202
217
  store.findRecord('model', 1).then(function(model) {
203
- model.get('isLoaded'); // true
218
+ model.isLoaded; // true
204
219
  });
205
220
  ```
206
221
 
@@ -224,12 +239,12 @@ class Model extends EmberObject {
224
239
 
225
240
  ```javascript
226
241
  let record = store.createRecord('model');
227
- record.get('hasDirtyAttributes'); // true
242
+ record.hasDirtyAttributes; // true
228
243
 
229
244
  store.findRecord('model', 1).then(function(model) {
230
- model.get('hasDirtyAttributes'); // false
245
+ model.hasDirtyAttributes; // false
231
246
  model.set('foo', 'some value');
232
- model.get('hasDirtyAttributes'); // true
247
+ model.hasDirtyAttributes; // true
233
248
  });
234
249
  ```
235
250
 
@@ -254,11 +269,11 @@ class Model extends EmberObject {
254
269
 
255
270
  ```javascript
256
271
  let record = store.createRecord('model');
257
- record.get('isSaving'); // false
272
+ record.isSaving; // false
258
273
  let promise = record.save();
259
- record.get('isSaving'); // true
274
+ record.isSaving; // true
260
275
  promise.then(function() {
261
- record.get('isSaving'); // false
276
+ record.isSaving; // false
262
277
  });
263
278
  ```
264
279
 
@@ -284,24 +299,24 @@ class Model extends EmberObject {
284
299
 
285
300
  ```javascript
286
301
  let record = store.createRecord('model');
287
- record.get('isDeleted'); // false
302
+ record.isDeleted; // false
288
303
  record.deleteRecord();
289
304
 
290
305
  // Locally deleted
291
- record.get('isDeleted'); // true
292
- record.get('hasDirtyAttributes'); // true
293
- record.get('isSaving'); // false
306
+ record.isDeleted; // true
307
+ record.hasDirtyAttributes; // true
308
+ record.isSaving; // false
294
309
 
295
310
  // Persisting the deletion
296
311
  let promise = record.save();
297
- record.get('isDeleted'); // true
298
- record.get('isSaving'); // true
312
+ record.isDeleted; // true
313
+ record.isSaving; // true
299
314
 
300
315
  // Deletion Persisted
301
316
  promise.then(function() {
302
- record.get('isDeleted'); // true
303
- record.get('isSaving'); // false
304
- record.get('hasDirtyAttributes'); // false
317
+ record.isDeleted; // true
318
+ record.isSaving; // false
319
+ record.hasDirtyAttributes; // false
305
320
  });
306
321
  ```
307
322
 
@@ -325,10 +340,10 @@ class Model extends EmberObject {
325
340
 
326
341
  ```javascript
327
342
  let record = store.createRecord('model');
328
- record.get('isNew'); // true
343
+ record.isNew; // true
329
344
 
330
345
  record.save().then(function(model) {
331
- model.get('isNew'); // false
346
+ model.isNew; // false
332
347
  });
333
348
  ```
334
349
 
@@ -371,7 +386,7 @@ class Model extends EmberObject {
371
386
 
372
387
  ```javascript
373
388
  let record = store.createRecord('model');
374
- record.get('dirtyType'); // 'created'
389
+ record.dirtyType; // 'created'
375
390
  ```
376
391
 
377
392
  @property dirtyType
@@ -392,10 +407,10 @@ class Model extends EmberObject {
392
407
  Example
393
408
 
394
409
  ```javascript
395
- record.get('isError'); // false
410
+ record.isError; // false
396
411
  record.set('foo', 'valid value');
397
412
  record.save().then(null, function() {
398
- record.get('isError'); // true
413
+ record.isError; // true
399
414
  });
400
415
  ```
401
416
 
@@ -441,10 +456,10 @@ class Model extends EmberObject {
441
456
 
442
457
  ```javascript
443
458
  let record = store.createRecord('model');
444
- record.get('id'); // null
459
+ record.id; // null
445
460
 
446
461
  store.findRecord('model', 1).then(function(model) {
447
- model.get('id'); // '1'
462
+ model.id; // '1'
448
463
  });
449
464
  ```
450
465
 
@@ -454,24 +469,37 @@ class Model extends EmberObject {
454
469
  */
455
470
  @tagged
456
471
  get id() {
457
- // the _internalModel guard exists, because some dev-only deprecation code
472
+ // this guard exists, because some dev-only deprecation code
458
473
  // (addListener via validatePropertyInjections) invokes toString before the
459
474
  // object is real.
460
475
  if (DEBUG) {
461
- if (!this._internalModel) {
476
+ try {
477
+ return recordIdentifierFor(this).id;
478
+ } catch {
462
479
  return void 0;
463
480
  }
464
481
  }
465
- return this._internalModel.id;
482
+ return recordIdentifierFor(this).id;
466
483
  }
467
484
  set id(id) {
468
485
  const normalizedId = coerceId(id);
486
+ const identifier = recordIdentifierFor(this);
487
+ let didChange = normalizedId !== identifier.id;
488
+ assert(
489
+ `Cannot set ${identifier.type} record's id to ${id}, because id is already ${identifier.id}`,
490
+ !didChange || identifier.id === null
491
+ );
469
492
 
470
- if (normalizedId !== null) {
471
- this._internalModel.setId(normalizedId);
493
+ if (normalizedId !== null && didChange) {
494
+ this.store._instanceCache.setRecordId(identifier, normalizedId);
495
+ this.store._notificationManager.notify(identifier, 'identity');
472
496
  }
473
497
  }
474
498
 
499
+ toString() {
500
+ return `<model::${this.constructor.modelName}:${this.id}>`;
501
+ }
502
+
475
503
  /**
476
504
  @property currentState
477
505
  @private
@@ -494,12 +522,6 @@ class Model extends EmberObject {
494
522
  throw new Error('cannot set currentState');
495
523
  }
496
524
 
497
- /**
498
- @property _internalModel
499
- @private
500
- @type {Object}
501
- */
502
-
503
525
  /**
504
526
  The store service instance which created this record instance
505
527
 
@@ -517,10 +539,10 @@ class Model extends EmberObject {
517
539
  - `attribute` The name of the property associated with this error message
518
540
 
519
541
  ```javascript
520
- record.get('errors.length'); // 0
542
+ record.errors.length; // 0
521
543
  record.set('foo', 'invalid value');
522
544
  record.save().catch(function() {
523
- record.get('errors').get('foo');
545
+ record.errors.foo;
524
546
  // [{message: 'foo should be a number.', attribute: 'foo'}]
525
547
  });
526
548
  ```
@@ -794,7 +816,7 @@ class Model extends EmberObject {
794
816
  and value is an [oldProp, newProp] array.
795
817
  */
796
818
  changedAttributes() {
797
- return this._internalModel.changedAttributes();
819
+ return recordDataFor(this).changedAttrs(recordIdentifierFor(this));
798
820
  }
799
821
 
800
822
  /**
@@ -804,11 +826,11 @@ class Model extends EmberObject {
804
826
  Example
805
827
 
806
828
  ```javascript
807
- record.get('name'); // 'Untitled Document'
829
+ record.name; // 'Untitled Document'
808
830
  record.set('name', 'Doc 1');
809
- record.get('name'); // 'Doc 1'
831
+ record.name; // 'Doc 1'
810
832
  record.rollbackAttributes();
811
- record.get('name'); // 'Untitled Document'
833
+ record.name; // 'Untitled Document'
812
834
  ```
813
835
 
814
836
  @since 1.13.0
@@ -817,8 +839,15 @@ class Model extends EmberObject {
817
839
  */
818
840
  rollbackAttributes() {
819
841
  const { currentState } = this;
820
- this._internalModel.rollbackAttributes();
821
- currentState.cleanErrorRequests();
842
+ const { isNew } = currentState;
843
+ storeFor(this)._join(() => {
844
+ recordDataFor(this).rollbackAttrs(recordIdentifierFor(this));
845
+ this.errors.clear();
846
+ currentState.cleanErrorRequests();
847
+ if (isNew) {
848
+ this.unloadRecord();
849
+ }
850
+ });
822
851
  }
823
852
 
824
853
  /**
@@ -830,13 +859,6 @@ class Model extends EmberObject {
830
859
  return storeFor(this)._instanceCache.createSnapshot(recordIdentifierFor(this));
831
860
  }
832
861
 
833
- toStringExtension() {
834
- // the _internalModel guard exists, because some dev-only deprecation code
835
- // (addListener via validatePropertyInjections) invokes toString before the
836
- // object is real.
837
- return this._internalModel && this._internalModel.id;
838
- }
839
-
840
862
  /**
841
863
  Save the record and persist any changes to the record to an
842
864
  external source via the adapter.
@@ -963,7 +985,7 @@ class Model extends EmberObject {
963
985
  import Model, { belongsTo } from '@ember-data/model';
964
986
 
965
987
  export default class BlogModel extends Model {
966
- @belongsTo({ async: true }) user;
988
+ @belongsTo('user', { async: true, inverse: null }) user;
967
989
  }
968
990
  ```
969
991
 
@@ -1019,7 +1041,7 @@ class Model extends EmberObject {
1019
1041
  @return {BelongsToReference} reference for this relationship
1020
1042
  */
1021
1043
  belongsTo(name) {
1022
- return LEGACY_SUPPORT.lookup(this).referenceFor('belongsTo', name);
1044
+ return lookupLegacySupport(this).referenceFor('belongsTo', name);
1023
1045
  }
1024
1046
 
1025
1047
  /**
@@ -1031,7 +1053,7 @@ class Model extends EmberObject {
1031
1053
  import Model, { hasMany } from '@ember-data/model';
1032
1054
 
1033
1055
  export default class BlogModel extends Model {
1034
- @hasMany({ async: true }) comments;
1056
+ @hasMany('comment', { async: true, inverse: null }) comments;
1035
1057
  }
1036
1058
 
1037
1059
  let blog = store.push({
@@ -1082,7 +1104,7 @@ class Model extends EmberObject {
1082
1104
  @return {HasManyReference} reference for this relationship
1083
1105
  */
1084
1106
  hasMany(name) {
1085
- return LEGACY_SUPPORT.lookup(this).referenceFor('hasMany', name);
1107
+ return lookupLegacySupport(this).referenceFor('hasMany', name);
1086
1108
  }
1087
1109
 
1088
1110
  /**
@@ -1184,7 +1206,7 @@ class Model extends EmberObject {
1184
1206
 
1185
1207
  ```javascript
1186
1208
  import RESTSerializer from '@ember-data/serializer/rest';
1187
- import { underscore } from '@ember/string';
1209
+ import { underscore } from '<app-name>/utils/string-utils';
1188
1210
 
1189
1211
  export default const PostSerializer = RESTSerializer.extend({
1190
1212
  payloadKeyFromModelName(modelName) {
@@ -1491,10 +1513,10 @@ class Model extends EmberObject {
1491
1513
  import Post from 'app/models/post';
1492
1514
 
1493
1515
  let relationships = Blog.relationships;
1494
- relationships.get('user');
1516
+ relationships.user;
1495
1517
  //=> [ { name: 'users', kind: 'hasMany' },
1496
1518
  // { name: 'owner', kind: 'belongsTo' } ]
1497
- relationships.get('post');
1519
+ relationships.post;
1498
1520
  //=> [ { name: 'posts', kind: 'hasMany' } ]
1499
1521
  ```
1500
1522
 
@@ -1707,9 +1729,9 @@ class Model extends EmberObject {
1707
1729
  import Blog from 'app/models/blog';
1708
1730
 
1709
1731
  let relationshipsByName = Blog.relationshipsByName;
1710
- relationshipsByName.get('users');
1732
+ relationshipsByName.users;
1711
1733
  //=> { key: 'users', kind: 'hasMany', type: 'user', options: Object, isRelationship: true }
1712
- relationshipsByName.get('owner');
1734
+ relationshipsByName.owner;
1713
1735
  //=> { key: 'owner', kind: 'belongsTo', type: 'user', options: Object, isRelationship: true }
1714
1736
  ```
1715
1737
 
@@ -1778,7 +1800,7 @@ class Model extends EmberObject {
1778
1800
  meta.key = name;
1779
1801
  meta.name = name;
1780
1802
  meta.parentModelName = modelName;
1781
- relationships[name] = relationshipFromMeta(meta);
1803
+ relationships[name] = DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE ? relationshipFromMeta(meta) : meta;
1782
1804
  }
1783
1805
  });
1784
1806
  return relationships;
@@ -1810,7 +1832,7 @@ class Model extends EmberObject {
1810
1832
 
1811
1833
  let fields = Blog.fields;
1812
1834
  fields.forEach(function(kind, field) {
1813
- console.log(field, kind);
1835
+ // do thing
1814
1836
  });
1815
1837
 
1816
1838
  // prints:
@@ -1848,6 +1870,7 @@ class Model extends EmberObject {
1848
1870
  let map = new Map();
1849
1871
 
1850
1872
  this.eachComputedProperty((name, meta) => {
1873
+ // TODO end reliance on these booleans and stop leaking them in the spec
1851
1874
  if (meta.isRelationship) {
1852
1875
  map.set(name, meta.kind);
1853
1876
  } else if (meta.isAttribute) {
@@ -1992,7 +2015,7 @@ class Model extends EmberObject {
1992
2015
  let attributes = Person.attributes
1993
2016
 
1994
2017
  attributes.forEach(function(meta, name) {
1995
- console.log(name, meta);
2018
+ // do thing
1996
2019
  });
1997
2020
 
1998
2021
  // prints:
@@ -2069,7 +2092,7 @@ class Model extends EmberObject {
2069
2092
  let transformedAttributes = Person.transformedAttributes
2070
2093
 
2071
2094
  transformedAttributes.forEach(function(field, type) {
2072
- console.log(field, type);
2095
+ // do thing
2073
2096
  });
2074
2097
 
2075
2098
  // prints:
@@ -2142,7 +2165,7 @@ class Model extends EmberObject {
2142
2165
  }
2143
2166
 
2144
2167
  PersonModel.eachAttribute(function(name, meta) {
2145
- console.log(name, meta);
2168
+ // do thing
2146
2169
  });
2147
2170
 
2148
2171
  // prints:
@@ -2211,7 +2234,7 @@ class Model extends EmberObject {
2211
2234
  });
2212
2235
 
2213
2236
  Person.eachTransformedAttribute(function(name, type) {
2214
- console.log(name, type);
2237
+ // do thing
2215
2238
  });
2216
2239
 
2217
2240
  // prints:
@@ -2273,13 +2296,12 @@ class Model extends EmberObject {
2273
2296
  this.modelName
2274
2297
  );
2275
2298
  }
2276
- return `model:${get(this, 'modelName')}`;
2299
+ return `model:${this.modelName}`;
2277
2300
  }
2278
2301
  }
2279
2302
 
2280
2303
  // this is required to prevent `init` from passing
2281
2304
  // the values initialized during create to `setUnknownProperty`
2282
- Model.prototype._internalModel = null;
2283
2305
  Model.prototype._createProps = null;
2284
2306
  Model.prototype._secretInit = null;
2285
2307
 
@@ -2359,27 +2381,11 @@ if (DEBUG) {
2359
2381
  } while (current !== null);
2360
2382
  return null;
2361
2383
  };
2362
- let isBasicDesc = function isBasicDesc(desc) {
2363
- return (
2364
- !desc ||
2365
- (!desc.get && !desc.set && desc.enumerable === true && desc.writable === true && desc.configurable === true)
2366
- );
2367
- };
2368
- let isDefaultEmptyDescriptor = function isDefaultEmptyDescriptor(obj, keyName) {
2369
- let instanceDesc = lookupDescriptor(obj, keyName);
2370
- return isBasicDesc(instanceDesc) && lookupDescriptor(obj.constructor, keyName) === null;
2371
- };
2372
2384
 
2373
2385
  Model.reopen({
2374
2386
  init() {
2375
2387
  this._super(...arguments);
2376
2388
 
2377
- if (!isDefaultEmptyDescriptor(this, '_internalModel') || !(this._internalModel instanceof InternalModel)) {
2378
- throw new Error(
2379
- `'_internalModel' is a reserved property name on instances of classes extending Model. Please choose a different property name for ${this.constructor.toString()}`
2380
- );
2381
- }
2382
-
2383
2389
  let ourDescriptor = lookupDescriptor(Model.prototype, 'currentState');
2384
2390
  let theirDescriptor = lookupDescriptor(this, 'currentState');
2385
2391
  let realState = this.___recordState;
@@ -2411,7 +2417,7 @@ if (DEBUG) {
2411
2417
  until: '5.0',
2412
2418
  since: { available: '4.8', enabled: '4.8' },
2413
2419
  });
2414
- return originalReopen.call(this, arguments);
2420
+ return originalReopen.call(this, ...arguments);
2415
2421
  };
2416
2422
 
2417
2423
  Model.reopenClass = function deprecatedReopenClass() {
@@ -2425,7 +2431,7 @@ if (DEBUG) {
2425
2431
  since: { available: '4.8', enabled: '4.8' },
2426
2432
  }
2427
2433
  );
2428
- return originalReopenClass.call(this, arguments);
2434
+ return originalReopenClass.call(this, ...arguments);
2429
2435
  };
2430
2436
  }
2431
2437
  }
@@ -1,7 +1,7 @@
1
1
  import { cacheFor } from '@ember/object/internals';
2
2
 
3
3
  import type Store from '@ember-data/store';
4
- import type { NotificationType } from '@ember-data/store/-private/record-notification-manager';
4
+ import type { NotificationType } from '@ember-data/store/-private/managers/record-notification-manager';
5
5
  import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
6
6
 
7
7
  import type Model from './model';
@@ -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
  }