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

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';
@@ -22,7 +22,7 @@ import {
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, InternalModel, WeakCache } from '@ember-data/store/-private';
25
+ import { coerceId, deprecatedPromiseObject, recordDataFor, WeakCache } from '@ember-data/store/-private';
26
26
 
27
27
  import Errors from './errors';
28
28
  import { LegacySupport } from './legacy-relationships-support';
@@ -119,9 +119,10 @@ function computeOnce(target, key, desc) {
119
119
  */
120
120
  class Model extends EmberObject {
121
121
  @service store;
122
+ #notifications;
122
123
 
123
124
  init(options = {}) {
124
- if (DEBUG && !options._secretInit && !options._internalModel && !options._createProps) {
125
+ if (DEBUG && !options._secretInit && !options._createProps) {
125
126
  throw new EmberError(
126
127
  'You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.'
127
128
  );
@@ -137,19 +138,29 @@ class Model extends EmberObject {
137
138
 
138
139
  this.setProperties(createProps);
139
140
 
140
- // TODO pass something in such that we don't need internalModel
141
- // to get this info
142
141
  let store = storeFor(this);
143
142
  let notifications = store._notificationManager;
144
143
  let identity = recordIdentifierFor(this);
145
144
 
146
- notifications.subscribe(identity, (identifier, type, key) => {
145
+ this.#notifications = notifications.subscribe(identity, (identifier, type, key) => {
147
146
  notifyChanges(identifier, type, key, this, store);
148
147
  });
149
148
  }
150
149
 
151
- willDestroy() {
150
+ destroy() {
152
151
  LEGACY_SUPPORT.get(this)?.destroy();
152
+ this.___recordState?.destroy();
153
+ const store = storeFor(this);
154
+ const identifier = recordIdentifierFor(this);
155
+ store._notificationManager.unsubscribe(this.#notifications);
156
+ // Legacy behavior is to notify the relationships on destroy
157
+ // such that they "clear". It's uncertain this behavior would
158
+ // be good for a new model paradigm, likely cheaper and safer
159
+ // to simply not notify, for this reason the store does not itself
160
+ // notify individual changes once the delete has been signaled,
161
+ // this decision is left to model instances.
162
+ notifyChanges(identifier, 'relationships', undefined, this, store);
163
+ super.destroy();
153
164
  }
154
165
 
155
166
  /**
@@ -197,10 +208,10 @@ class Model extends EmberObject {
197
208
 
198
209
  ```javascript
199
210
  let record = store.createRecord('model');
200
- record.get('isLoaded'); // true
211
+ record.isLoaded; // true
201
212
 
202
213
  store.findRecord('model', 1).then(function(model) {
203
- model.get('isLoaded'); // true
214
+ model.isLoaded; // true
204
215
  });
205
216
  ```
206
217
 
@@ -224,12 +235,12 @@ class Model extends EmberObject {
224
235
 
225
236
  ```javascript
226
237
  let record = store.createRecord('model');
227
- record.get('hasDirtyAttributes'); // true
238
+ record.hasDirtyAttributes; // true
228
239
 
229
240
  store.findRecord('model', 1).then(function(model) {
230
- model.get('hasDirtyAttributes'); // false
241
+ model.hasDirtyAttributes; // false
231
242
  model.set('foo', 'some value');
232
- model.get('hasDirtyAttributes'); // true
243
+ model.hasDirtyAttributes; // true
233
244
  });
234
245
  ```
235
246
 
@@ -254,11 +265,11 @@ class Model extends EmberObject {
254
265
 
255
266
  ```javascript
256
267
  let record = store.createRecord('model');
257
- record.get('isSaving'); // false
268
+ record.isSaving; // false
258
269
  let promise = record.save();
259
- record.get('isSaving'); // true
270
+ record.isSaving; // true
260
271
  promise.then(function() {
261
- record.get('isSaving'); // false
272
+ record.isSaving; // false
262
273
  });
263
274
  ```
264
275
 
@@ -284,24 +295,24 @@ class Model extends EmberObject {
284
295
 
285
296
  ```javascript
286
297
  let record = store.createRecord('model');
287
- record.get('isDeleted'); // false
298
+ record.isDeleted; // false
288
299
  record.deleteRecord();
289
300
 
290
301
  // Locally deleted
291
- record.get('isDeleted'); // true
292
- record.get('hasDirtyAttributes'); // true
293
- record.get('isSaving'); // false
302
+ record.isDeleted; // true
303
+ record.hasDirtyAttributes; // true
304
+ record.isSaving; // false
294
305
 
295
306
  // Persisting the deletion
296
307
  let promise = record.save();
297
- record.get('isDeleted'); // true
298
- record.get('isSaving'); // true
308
+ record.isDeleted; // true
309
+ record.isSaving; // true
299
310
 
300
311
  // Deletion Persisted
301
312
  promise.then(function() {
302
- record.get('isDeleted'); // true
303
- record.get('isSaving'); // false
304
- record.get('hasDirtyAttributes'); // false
313
+ record.isDeleted; // true
314
+ record.isSaving; // false
315
+ record.hasDirtyAttributes; // false
305
316
  });
306
317
  ```
307
318
 
@@ -325,10 +336,10 @@ class Model extends EmberObject {
325
336
 
326
337
  ```javascript
327
338
  let record = store.createRecord('model');
328
- record.get('isNew'); // true
339
+ record.isNew; // true
329
340
 
330
341
  record.save().then(function(model) {
331
- model.get('isNew'); // false
342
+ model.isNew; // false
332
343
  });
333
344
  ```
334
345
 
@@ -371,7 +382,7 @@ class Model extends EmberObject {
371
382
 
372
383
  ```javascript
373
384
  let record = store.createRecord('model');
374
- record.get('dirtyType'); // 'created'
385
+ record.dirtyType; // 'created'
375
386
  ```
376
387
 
377
388
  @property dirtyType
@@ -392,10 +403,10 @@ class Model extends EmberObject {
392
403
  Example
393
404
 
394
405
  ```javascript
395
- record.get('isError'); // false
406
+ record.isError; // false
396
407
  record.set('foo', 'valid value');
397
408
  record.save().then(null, function() {
398
- record.get('isError'); // true
409
+ record.isError; // true
399
410
  });
400
411
  ```
401
412
 
@@ -441,10 +452,10 @@ class Model extends EmberObject {
441
452
 
442
453
  ```javascript
443
454
  let record = store.createRecord('model');
444
- record.get('id'); // null
455
+ record.id; // null
445
456
 
446
457
  store.findRecord('model', 1).then(function(model) {
447
- model.get('id'); // '1'
458
+ model.id; // '1'
448
459
  });
449
460
  ```
450
461
 
@@ -454,24 +465,38 @@ class Model extends EmberObject {
454
465
  */
455
466
  @tagged
456
467
  get id() {
457
- // the _internalModel guard exists, because some dev-only deprecation code
468
+ // this guard exists, because some dev-only deprecation code
458
469
  // (addListener via validatePropertyInjections) invokes toString before the
459
470
  // object is real.
460
471
  if (DEBUG) {
461
- if (!this._internalModel) {
472
+ try {
473
+ return recordIdentifierFor(this).id;
474
+ } catch {
462
475
  return void 0;
463
476
  }
464
477
  }
465
- return this._internalModel.id;
478
+ return recordIdentifierFor(this).id;
466
479
  }
467
480
  set id(id) {
468
481
  const normalizedId = coerceId(id);
482
+ const identifier = recordIdentifierFor(this);
483
+ let didChange = normalizedId !== identifier.id;
484
+ assert(
485
+ `Cannot set ${identifier.type} record's id to ${id}, because id is already ${identifier.id}`,
486
+ !didChange || identifier.id === null
487
+ );
469
488
 
470
- if (normalizedId !== null) {
471
- this._internalModel.setId(normalizedId);
489
+ if (normalizedId !== null && didChange) {
490
+ this.store._instanceCache.setRecordId(identifier.type, normalizedId, identifier.lid);
491
+ this.store._notificationManager.notify(identifier, 'identity');
472
492
  }
473
493
  }
474
494
 
495
+ // TODO just write a nice toString
496
+ toStringExtension() {
497
+ return this.id;
498
+ }
499
+
475
500
  /**
476
501
  @property currentState
477
502
  @private
@@ -494,12 +519,6 @@ class Model extends EmberObject {
494
519
  throw new Error('cannot set currentState');
495
520
  }
496
521
 
497
- /**
498
- @property _internalModel
499
- @private
500
- @type {Object}
501
- */
502
-
503
522
  /**
504
523
  The store service instance which created this record instance
505
524
 
@@ -517,10 +536,10 @@ class Model extends EmberObject {
517
536
  - `attribute` The name of the property associated with this error message
518
537
 
519
538
  ```javascript
520
- record.get('errors.length'); // 0
539
+ record.errors.length; // 0
521
540
  record.set('foo', 'invalid value');
522
541
  record.save().catch(function() {
523
- record.get('errors').get('foo');
542
+ record.errors.foo;
524
543
  // [{message: 'foo should be a number.', attribute: 'foo'}]
525
544
  });
526
545
  ```
@@ -794,7 +813,7 @@ class Model extends EmberObject {
794
813
  and value is an [oldProp, newProp] array.
795
814
  */
796
815
  changedAttributes() {
797
- return this._internalModel.changedAttributes();
816
+ return recordDataFor(this).changedAttributes();
798
817
  }
799
818
 
800
819
  /**
@@ -804,11 +823,11 @@ class Model extends EmberObject {
804
823
  Example
805
824
 
806
825
  ```javascript
807
- record.get('name'); // 'Untitled Document'
826
+ record.name; // 'Untitled Document'
808
827
  record.set('name', 'Doc 1');
809
- record.get('name'); // 'Doc 1'
828
+ record.name; // 'Doc 1'
810
829
  record.rollbackAttributes();
811
- record.get('name'); // 'Untitled Document'
830
+ record.name; // 'Untitled Document'
812
831
  ```
813
832
 
814
833
  @since 1.13.0
@@ -817,8 +836,13 @@ class Model extends EmberObject {
817
836
  */
818
837
  rollbackAttributes() {
819
838
  const { currentState } = this;
820
- this._internalModel.rollbackAttributes();
839
+ const { isNew } = currentState;
840
+ recordDataFor(this).rollbackAttributes();
841
+ this.errors.clear();
821
842
  currentState.cleanErrorRequests();
843
+ if (isNew) {
844
+ this.unloadRecord();
845
+ }
822
846
  }
823
847
 
824
848
  /**
@@ -830,13 +854,6 @@ class Model extends EmberObject {
830
854
  return storeFor(this)._instanceCache.createSnapshot(recordIdentifierFor(this));
831
855
  }
832
856
 
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
857
  /**
841
858
  Save the record and persist any changes to the record to an
842
859
  external source via the adapter.
@@ -1491,10 +1508,10 @@ class Model extends EmberObject {
1491
1508
  import Post from 'app/models/post';
1492
1509
 
1493
1510
  let relationships = Blog.relationships;
1494
- relationships.get('user');
1511
+ relationships.user;
1495
1512
  //=> [ { name: 'users', kind: 'hasMany' },
1496
1513
  // { name: 'owner', kind: 'belongsTo' } ]
1497
- relationships.get('post');
1514
+ relationships.post;
1498
1515
  //=> [ { name: 'posts', kind: 'hasMany' } ]
1499
1516
  ```
1500
1517
 
@@ -1707,9 +1724,9 @@ class Model extends EmberObject {
1707
1724
  import Blog from 'app/models/blog';
1708
1725
 
1709
1726
  let relationshipsByName = Blog.relationshipsByName;
1710
- relationshipsByName.get('users');
1727
+ relationshipsByName.users;
1711
1728
  //=> { key: 'users', kind: 'hasMany', type: 'user', options: Object, isRelationship: true }
1712
- relationshipsByName.get('owner');
1729
+ relationshipsByName.owner;
1713
1730
  //=> { key: 'owner', kind: 'belongsTo', type: 'user', options: Object, isRelationship: true }
1714
1731
  ```
1715
1732
 
@@ -1810,7 +1827,7 @@ class Model extends EmberObject {
1810
1827
 
1811
1828
  let fields = Blog.fields;
1812
1829
  fields.forEach(function(kind, field) {
1813
- console.log(field, kind);
1830
+ // do thing
1814
1831
  });
1815
1832
 
1816
1833
  // prints:
@@ -1992,7 +2009,7 @@ class Model extends EmberObject {
1992
2009
  let attributes = Person.attributes
1993
2010
 
1994
2011
  attributes.forEach(function(meta, name) {
1995
- console.log(name, meta);
2012
+ // do thing
1996
2013
  });
1997
2014
 
1998
2015
  // prints:
@@ -2069,7 +2086,7 @@ class Model extends EmberObject {
2069
2086
  let transformedAttributes = Person.transformedAttributes
2070
2087
 
2071
2088
  transformedAttributes.forEach(function(field, type) {
2072
- console.log(field, type);
2089
+ // do thing
2073
2090
  });
2074
2091
 
2075
2092
  // prints:
@@ -2142,7 +2159,7 @@ class Model extends EmberObject {
2142
2159
  }
2143
2160
 
2144
2161
  PersonModel.eachAttribute(function(name, meta) {
2145
- console.log(name, meta);
2162
+ // do thing
2146
2163
  });
2147
2164
 
2148
2165
  // prints:
@@ -2211,7 +2228,7 @@ class Model extends EmberObject {
2211
2228
  });
2212
2229
 
2213
2230
  Person.eachTransformedAttribute(function(name, type) {
2214
- console.log(name, type);
2231
+ // do thing
2215
2232
  });
2216
2233
 
2217
2234
  // prints:
@@ -2273,13 +2290,12 @@ class Model extends EmberObject {
2273
2290
  this.modelName
2274
2291
  );
2275
2292
  }
2276
- return `model:${get(this, 'modelName')}`;
2293
+ return `model:${this.modelName}`;
2277
2294
  }
2278
2295
  }
2279
2296
 
2280
2297
  // this is required to prevent `init` from passing
2281
2298
  // the values initialized during create to `setUnknownProperty`
2282
- Model.prototype._internalModel = null;
2283
2299
  Model.prototype._createProps = null;
2284
2300
  Model.prototype._secretInit = null;
2285
2301
 
@@ -2359,27 +2375,11 @@ if (DEBUG) {
2359
2375
  } while (current !== null);
2360
2376
  return null;
2361
2377
  };
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
2378
 
2373
2379
  Model.reopen({
2374
2380
  init() {
2375
2381
  this._super(...arguments);
2376
2382
 
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
2383
  let ourDescriptor = lookupDescriptor(Model.prototype, 'currentState');
2384
2384
  let theirDescriptor = lookupDescriptor(this, 'currentState');
2385
2385
  let realState = this.___recordState;
@@ -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';