@ember-data/model 4.7.0-beta.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.
@@ -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
  }
@@ -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;
@@ -1,16 +1,23 @@
1
1
  import ArrayMixin, { NativeArray } from '@ember/array';
2
2
  import type ArrayProxy from '@ember/array/proxy';
3
- import { assert } from '@ember/debug';
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 type { InternalModel } from '@ember-data/store/-private';
11
+ import {
12
+ DEPRECATE_A_USAGE,
13
+ DEPRECATE_COMPUTED_CHAINS,
14
+ DEPRECATE_PROMISE_MANY_ARRAY_BEHAVIORS,
15
+ } from '@ember-data/private-build-infra/deprecations';
16
+ import { StableRecordIdentifier } from '@ember-data/types/q/identifier';
13
17
  import type { RecordInstance } from '@ember-data/types/q/record-instance';
18
+ import { FindOptions } from '@ember-data/types/q/store';
19
+
20
+ import type ManyArray from './many-array';
14
21
 
15
22
  export interface HasManyProxyCreateArgs {
16
23
  promise: Promise<ManyArray>;
@@ -24,16 +31,10 @@ export interface HasManyProxyCreateArgs {
24
31
  This class is returned as the result of accessing an async hasMany relationship
25
32
  on an instance of a Model extending from `@ember-data/model`.
26
33
 
27
- A PromiseManyArray is an array-like proxy that also proxies certain method calls
28
- to the underlying ManyArray in addition to being "promisified".
29
-
30
- Right now we proxy:
31
-
32
- * `reload()`
33
- * `createRecord()`
34
+ A PromiseManyArray is an iterable proxy that allows templates to consume related
35
+ ManyArrays and update once their contents are no longer pending.
34
36
 
35
- This promise-proxy behavior is primarily to ensure that async relationship interact
36
- nicely with templates. In your JS code you should resolve the promise first.
37
+ In your JS code you should resolve the promise first.
37
38
 
38
39
  ```js
39
40
  const comments = await post.comments;
@@ -42,10 +43,14 @@ export interface HasManyProxyCreateArgs {
42
43
  @class PromiseManyArray
43
44
  @public
44
45
  */
45
- export default interface PromiseManyArray extends Omit<ArrayProxy<InternalModel, RecordInstance>, 'destroy'> {}
46
+ export default interface PromiseManyArray extends Omit<ArrayProxy<StableRecordIdentifier, RecordInstance>, 'destroy'> {
47
+ createRecord(): RecordInstance;
48
+ reload(options: FindOptions): PromiseManyArray;
49
+ }
46
50
  export default class PromiseManyArray {
47
51
  declare promise: Promise<ManyArray> | null;
48
52
  declare isDestroyed: boolean;
53
+ // @deprecated (isDestroyed is not deprecated)
49
54
  declare isDestroying: boolean;
50
55
 
51
56
  constructor(promise: Promise<ManyArray>, 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,11 +106,15 @@ 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
  /**
92
115
  * Iterate the proxied content. Called by the glimmer iterator in #each
116
+ * We do not guarantee that forEach will always be available. This
117
+ * may eventually be made to use Symbol.Iterator once glimmer supports it.
93
118
  *
94
119
  * @method forEach
95
120
  * @param cb
@@ -97,12 +122,24 @@ export default class PromiseManyArray {
97
122
  * @private
98
123
  */
99
124
  forEach(cb) {
100
- this['[]']; // needed for < 3.23 support e.g. 3.20 lts
101
125
  if (this.content && this.length) {
102
126
  this.content.forEach(cb);
103
127
  }
104
128
  }
105
129
 
130
+ /**
131
+ * Reload the relationship
132
+ * @method reload
133
+ * @public
134
+ * @param options
135
+ * @returns
136
+ */
137
+ reload(options: FindOptions) {
138
+ assert('You are trying to reload an async manyArray before it has been created', this.content);
139
+ this.content.reload(options);
140
+ return this;
141
+ }
142
+
106
143
  //---- Properties/Methods from the PromiseProxyMixin that we will keep as our API
107
144
 
108
145
  /**
@@ -201,19 +238,6 @@ export default class PromiseManyArray {
201
238
  return this.content ? this.content.meta : undefined;
202
239
  }
203
240
 
204
- /**
205
- * Reload the relationship
206
- * @method reload
207
- * @public
208
- * @param options
209
- * @returns
210
- */
211
- reload(options) {
212
- assert('You are trying to reload an async manyArray before it has been created', this.content);
213
- this.content.reload(options);
214
- return this;
215
- }
216
-
217
241
  //---- Our own stuff
218
242
 
219
243
  _update(promise: Promise<ManyArray>, content?: ManyArray) {
@@ -227,22 +251,55 @@ export default class PromiseManyArray {
227
251
  static create({ promise, content }: HasManyProxyCreateArgs): PromiseManyArray {
228
252
  return new this(promise, content);
229
253
  }
254
+ }
230
255
 
231
- // Methods on ManyArray which people should resolve the relationship first before calling
232
- createRecord(...args) {
256
+ if (DEPRECATE_PROMISE_MANY_ARRAY_BEHAVIORS) {
257
+ PromiseManyArray.prototype.createRecord = function createRecord(...args) {
258
+ deprecate(
259
+ `The createRecord method on ember-data's PromiseManyArray is deprecated. await the promise and work with the ManyArray directly.`,
260
+ false,
261
+ {
262
+ id: 'ember-data:deprecate-promise-many-array-behaviors',
263
+ until: '5.0',
264
+ since: { enabled: '4.8', available: '4.8' },
265
+ for: 'ember-data',
266
+ }
267
+ );
233
268
  assert('You are trying to createRecord on an async manyArray before it has been created', this.content);
234
269
  return this.content.createRecord(...args);
235
- }
236
-
237
- // Properties/Methods on ArrayProxy we should deprecate
238
-
239
- get firstObject() {
240
- return this.content ? this.content.firstObject : undefined;
241
- }
270
+ };
242
271
 
243
- get lastObject() {
244
- return this.content ? this.content.lastObject : undefined;
245
- }
272
+ Object.defineProperty(PromiseManyArray.prototype, 'firstObject', {
273
+ get() {
274
+ deprecate(
275
+ `The firstObject property on ember-data's PromiseManyArray is deprecated. await the promise and work with the ManyArray directly.`,
276
+ false,
277
+ {
278
+ id: 'ember-data:deprecate-promise-many-array-behaviors',
279
+ until: '5.0',
280
+ since: { enabled: '4.8', available: '4.8' },
281
+ for: 'ember-data',
282
+ }
283
+ );
284
+ return this.content ? this.content.firstObject : undefined;
285
+ },
286
+ });
287
+
288
+ Object.defineProperty(PromiseManyArray.prototype, 'lastObject', {
289
+ get() {
290
+ deprecate(
291
+ `The lastObject property on ember-data's PromiseManyArray is deprecated. await the promise and work with the ManyArray directly.`,
292
+ false,
293
+ {
294
+ id: 'ember-data:deprecate-promise-many-array-behaviors',
295
+ until: '5.0',
296
+ since: { enabled: '4.8', available: '4.8' },
297
+ for: 'ember-data',
298
+ }
299
+ );
300
+ return this.content ? this.content.lastObject : undefined;
301
+ },
302
+ });
246
303
  }
247
304
 
248
305
  function tapPromise(proxy: PromiseManyArray, promise: Promise<ManyArray>) {
@@ -268,78 +325,101 @@ function tapPromise(proxy: PromiseManyArray, promise: Promise<ManyArray>) {
268
325
  );
269
326
  }
270
327
 
271
- const EmberObjectMethods = [
272
- 'addObserver',
273
- 'cacheFor',
274
- 'decrementProperty',
275
- 'get',
276
- 'getProperties',
277
- 'incrementProperty',
278
- 'notifyPropertyChange',
279
- 'removeObserver',
280
- 'set',
281
- 'setProperties',
282
- 'toggleProperty',
283
- ];
284
- EmberObjectMethods.forEach((method) => {
285
- PromiseManyArray.prototype[method] = function delegatedMethod(...args) {
286
- return Ember[method](this, ...args);
287
- };
288
- });
289
-
290
- const InheritedProxyMethods = [
291
- 'addArrayObserver',
292
- 'addObject',
293
- 'addObjects',
294
- 'any',
295
- 'arrayContentDidChange',
296
- 'arrayContentWillChange',
297
- 'clear',
298
- 'compact',
299
- 'every',
300
- 'filter',
301
- 'filterBy',
302
- 'find',
303
- 'findBy',
304
- 'getEach',
305
- 'includes',
306
- 'indexOf',
307
- 'insertAt',
308
- 'invoke',
309
- 'isAny',
310
- 'isEvery',
311
- 'lastIndexOf',
312
- 'map',
313
- 'mapBy',
314
- 'objectAt',
315
- 'objectsAt',
316
- 'popObject',
317
- 'pushObject',
318
- 'pushObjects',
319
- 'reduce',
320
- 'reject',
321
- 'rejectBy',
322
- 'removeArrayObserver',
323
- 'removeAt',
324
- 'removeObject',
325
- 'removeObjects',
326
- 'replace',
327
- 'reverseObjects',
328
- 'setEach',
329
- 'setObjects',
330
- 'shiftObject',
331
- 'slice',
332
- 'sortBy',
333
- 'toArray',
334
- 'uniq',
335
- 'uniqBy',
336
- 'unshiftObject',
337
- 'unshiftObjects',
338
- 'without',
339
- ];
340
- InheritedProxyMethods.forEach((method) => {
341
- PromiseManyArray.prototype[method] = function proxiedMethod(...args) {
342
- assert(`Cannot call ${method} before content is assigned.`, this.content);
343
- return this.content[method](...args);
344
- };
345
- });
328
+ if (DEPRECATE_PROMISE_MANY_ARRAY_BEHAVIORS) {
329
+ const EmberObjectMethods = [
330
+ 'addObserver',
331
+ 'cacheFor',
332
+ 'decrementProperty',
333
+ 'get',
334
+ 'getProperties',
335
+ 'incrementProperty',
336
+ 'notifyPropertyChange',
337
+ 'removeObserver',
338
+ 'set',
339
+ 'setProperties',
340
+ 'toggleProperty',
341
+ ];
342
+ EmberObjectMethods.forEach((method) => {
343
+ PromiseManyArray.prototype[method] = function delegatedMethod(...args) {
344
+ deprecate(
345
+ `The ${method} method on ember-data's PromiseManyArray is deprecated. await the promise and work with the ManyArray directly.`,
346
+ false,
347
+ {
348
+ id: 'ember-data:deprecate-promise-many-array-behaviors',
349
+ until: '5.0',
350
+ since: { enabled: '4.8', available: '4.8' },
351
+ for: 'ember-data',
352
+ }
353
+ );
354
+ return Ember[method](this, ...args);
355
+ };
356
+ });
357
+
358
+ const InheritedProxyMethods = [
359
+ 'addArrayObserver',
360
+ 'addObject',
361
+ 'addObjects',
362
+ 'any',
363
+ 'arrayContentDidChange',
364
+ 'arrayContentWillChange',
365
+ 'clear',
366
+ 'compact',
367
+ 'every',
368
+ 'filter',
369
+ 'filterBy',
370
+ 'find',
371
+ 'findBy',
372
+ 'getEach',
373
+ 'includes',
374
+ 'indexOf',
375
+ 'insertAt',
376
+ 'invoke',
377
+ 'isAny',
378
+ 'isEvery',
379
+ 'lastIndexOf',
380
+ 'map',
381
+ 'mapBy',
382
+ // TODO update RFC to note objectAt was deprecated (forEach was left for iteration)
383
+ 'objectAt',
384
+ 'objectsAt',
385
+ 'popObject',
386
+ 'pushObject',
387
+ 'pushObjects',
388
+ 'reduce',
389
+ 'reject',
390
+ 'rejectBy',
391
+ 'removeArrayObserver',
392
+ 'removeAt',
393
+ 'removeObject',
394
+ 'removeObjects',
395
+ 'replace',
396
+ 'reverseObjects',
397
+ 'setEach',
398
+ 'setObjects',
399
+ 'shiftObject',
400
+ 'slice',
401
+ 'sortBy',
402
+ 'toArray',
403
+ 'uniq',
404
+ 'uniqBy',
405
+ 'unshiftObject',
406
+ 'unshiftObjects',
407
+ 'without',
408
+ ];
409
+ InheritedProxyMethods.forEach((method) => {
410
+ PromiseManyArray.prototype[method] = function proxiedMethod(...args) {
411
+ deprecate(
412
+ `The ${method} method on ember-data's PromiseManyArray is deprecated. await the promise and work with the ManyArray directly.`,
413
+ false,
414
+ {
415
+ id: 'ember-data:deprecate-promise-many-array-behaviors',
416
+ until: '5.0',
417
+ since: { enabled: '4.8', available: '4.8' },
418
+ for: 'ember-data',
419
+ }
420
+ );
421
+ assert(`Cannot call ${method} before content is assigned.`, this.content);
422
+ return this.content[method](...args);
423
+ };
424
+ });
425
+ }
@@ -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);
@@ -5,14 +5,17 @@ import { cached, tracked } from '@glimmer/tracking';
5
5
 
6
6
  import type Store from '@ember-data/store';
7
7
  import { storeFor } from '@ember-data/store';
8
- import { errorsArrayToHash, recordIdentifierFor } from '@ember-data/store/-private';
9
- import type { NotificationType } from '@ember-data/store/-private/record-notification-manager';
10
- import type RequestCache from '@ember-data/store/-private/request-cache';
8
+ import { recordIdentifierFor } from '@ember-data/store/-private';
9
+ import type { NotificationType } from '@ember-data/store/-private/managers/record-notification-manager';
10
+ import type RequestCache from '@ember-data/store/-private/network/request-cache';
11
11
  import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
12
12
  import type { RecordData } from '@ember-data/types/q/record-data';
13
13
 
14
14
  type Model = InstanceType<typeof import('./model')>;
15
15
 
16
+ const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/;
17
+ const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/;
18
+ const PRIMARY_ATTRIBUTE_KEY = 'base';
16
19
  function isInvalidError(error) {
17
20
  return error && error.isAdapterError === true && error.code === 'InvalidError';
18
21
  }
@@ -101,8 +104,9 @@ export function tagged(_target, key, desc) {
101
104
  }
102
105
 
103
106
  /**
104
- Historically InternalModel managed a state machine
105
- the currentState for which was reflected onto Model.
107
+ Historically EmberData managed a state machine
108
+ for each record, the localState for which
109
+ was reflected onto Model.
106
110
 
107
111
  This implements the flags and stateName for backwards compat
108
112
  with the state tree that used to be possible (listed below).
@@ -150,6 +154,7 @@ export default class RecordState {
150
154
  declare recordData: RecordData;
151
155
  declare _errorRequests: any[];
152
156
  declare _lastError: any;
157
+ declare handler: object;
153
158
 
154
159
  constructor(record: Model) {
155
160
  const store = storeFor(record)!;
@@ -176,7 +181,6 @@ export default class RecordState {
176
181
  break;
177
182
  case 'rejected':
178
183
  this.isSaving = false;
179
-
180
184
  this._lastError = req;
181
185
  if (!(req.response && isInvalidError(req.response.data))) {
182
186
  this._errorRequests.push(req);
@@ -230,47 +234,63 @@ export default class RecordState {
230
234
  }
231
235
  }
232
236
 
233
- notifications.subscribe(identity, (identifier: StableRecordIdentifier, type: NotificationType, key?: string) => {
234
- switch (type) {
235
- case 'state':
236
- this.notify('isNew');
237
- this.notify('isDeleted');
238
- this.notify('isDirty');
239
- break;
240
- case 'attributes':
241
- this.notify('isEmpty');
242
- this.notify('isDirty');
243
- break;
244
- case 'unload':
245
- this.notify('isNew');
246
- this.notify('isDeleted');
247
- break;
248
- case 'errors':
249
- // we only hit this if a foreign RecordData notifies
250
- // errors changed. Our own implementation does not
251
- // take this path currently, but we should probably
252
- // fix that.
253
- this.updateInvalidErrors();
254
- this.notify('isValid');
255
- break;
237
+ this.handler = notifications.subscribe(
238
+ identity,
239
+ (identifier: StableRecordIdentifier, type: NotificationType, key?: string) => {
240
+ switch (type) {
241
+ case 'state':
242
+ this.notify('isNew');
243
+ this.notify('isDeleted');
244
+ this.notify('isDirty');
245
+ break;
246
+ case 'attributes':
247
+ this.notify('isEmpty');
248
+ this.notify('isDirty');
249
+ break;
250
+ case 'errors':
251
+ this.updateInvalidErrors(this.record.errors);
252
+ this.notify('isValid');
253
+ break;
254
+ }
256
255
  }
257
- });
256
+ );
257
+ }
258
+
259
+ destroy() {
260
+ storeFor(this.record)!._notificationManager.unsubscribe(this.handler);
258
261
  }
259
262
 
260
263
  notify(key) {
261
264
  getTag(this, key).notify();
262
265
  }
263
266
 
264
- updateInvalidErrors() {
265
- let jsonApiErrors = this.recordData.getErrors!(this.identifier);
267
+ updateInvalidErrors(errors) {
268
+ assert(
269
+ `Expected the RecordData instance for ${this.identifier} to implement getErrors(identifier)`,
270
+ typeof this.recordData.getErrors === 'function'
271
+ );
272
+ let jsonApiErrors = this.recordData.getErrors(this.identifier);
266
273
 
267
- const { errors } = this.record;
268
274
  errors.clear();
269
- let newErrors = errorsArrayToHash(jsonApiErrors);
270
- let errorKeys = Object.keys(newErrors);
271
275
 
272
- for (let i = 0; i < errorKeys.length; i++) {
273
- errors.add(errorKeys[i], newErrors[errorKeys[i]]);
276
+ for (let i = 0; i < jsonApiErrors.length; i++) {
277
+ let error = jsonApiErrors[i];
278
+
279
+ if (error.source && error.source.pointer) {
280
+ let keyMatch = error.source.pointer.match(SOURCE_POINTER_REGEXP);
281
+ let key: string | undefined;
282
+
283
+ if (keyMatch) {
284
+ key = keyMatch[2];
285
+ } else if (error.source.pointer.search(SOURCE_POINTER_PRIMARY_REGEXP) !== -1) {
286
+ key = PRIMARY_ATTRIBUTE_KEY;
287
+ }
288
+
289
+ if (key) {
290
+ let errMsg = error.detail || error.title;
291
+ errors.add(key, errMsg);
292
+ }
293
+ }
274
294
  }
275
295
  }
276
296
 
@@ -289,7 +309,6 @@ export default class RecordState {
289
309
  return !this.isLoaded && this.pendingCount > 0 && this.fulfilledCount === 0;
290
310
  }
291
311
 
292
- // TODO @runspired handle "unloadRecord" see note in InternalModel
293
312
  @tagged
294
313
  get isLoaded() {
295
314
  if (this.isNew) {
@@ -303,7 +322,7 @@ export default class RecordState {
303
322
  let rd = this.recordData;
304
323
  if (this.isDeleted) {
305
324
  assert(`Expected RecordData to implement isDeletionCommitted()`, rd.isDeletionCommitted);
306
- return rd.isDeletionCommitted();
325
+ return rd.isDeletionCommitted(this.identifier);
307
326
  }
308
327
  if (this.isNew || this.isEmpty || !this.isValid || this.isDirty || this.isLoading) {
309
328
  return false;
@@ -317,21 +336,21 @@ export default class RecordState {
317
336
  // TODO this is not actually an RFC'd concept. Determine the
318
337
  // correct heuristic to replace this with.
319
338
  assert(`Expected RecordData to implement isEmpty()`, rd.isEmpty);
320
- return !this.isNew && rd.isEmpty();
339
+ return !this.isNew && rd.isEmpty(this.identifier);
321
340
  }
322
341
 
323
342
  @tagged
324
343
  get isNew() {
325
344
  let rd = this.recordData;
326
345
  assert(`Expected RecordData to implement isNew()`, rd.isNew);
327
- return rd.isNew();
346
+ return rd.isNew(this.identifier);
328
347
  }
329
348
 
330
349
  @tagged
331
350
  get isDeleted() {
332
351
  let rd = this.recordData;
333
352
  assert(`Expected RecordData to implement isDeleted()`, rd.isDeleted);
334
- return rd.isDeleted();
353
+ return rd.isDeleted(this.identifier);
335
354
  }
336
355
 
337
356
  @tagged
@@ -342,12 +361,10 @@ export default class RecordState {
342
361
  @tagged
343
362
  get isDirty() {
344
363
  let rd = this.recordData;
345
- assert(`Expected RecordData to implement hasChangedAttributes()`, rd.hasChangedAttributes);
346
- assert(`Expected RecordData to implement isDeletionCommitted()`, rd.isDeletionCommitted);
347
- if (rd.isDeletionCommitted() || (this.isDeleted && this.isNew)) {
364
+ if (rd.isDeletionCommitted(this.identifier) || (this.isDeleted && this.isNew)) {
348
365
  return false;
349
366
  }
350
- return this.isNew || rd.hasChangedAttributes();
367
+ return this.isNew || rd.hasChangedAttrs(this.identifier);
351
368
  }
352
369
 
353
370
  @tagged