@ember-data/model 5.6.0-alpha.2 → 5.6.0-alpha.4
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.
- package/dist/-private.js +1 -2
- package/dist/-private.js.map +1 -1
- package/dist/{model-Dkk-TZlL.js → errors-DsUSZ9m8.js} +41 -2335
- package/dist/errors-DsUSZ9m8.js.map +1 -0
- package/dist/{hooks-o1U_cEA3.js → hooks-rXIjX2-H.js} +1 -2
- package/dist/{hooks-o1U_cEA3.js.map → hooks-rXIjX2-H.js.map} +1 -1
- package/dist/hooks.js +2 -2
- package/dist/index.js +667 -5
- package/dist/index.js.map +1 -1
- package/dist/migration-support.js +7 -14
- package/dist/migration-support.js.map +1 -1
- package/dist/schema-provider-B6-5uzxP.js +2229 -0
- package/dist/schema-provider-B6-5uzxP.js.map +1 -0
- package/package.json +16 -19
- package/unstable-preview-types/-private/attr.d.ts +4 -12
- package/unstable-preview-types/-private/attr.d.ts.map +1 -1
- package/unstable-preview-types/-private/belongs-to.d.ts +0 -6
- package/unstable-preview-types/-private/belongs-to.d.ts.map +1 -1
- package/unstable-preview-types/-private/errors.d.ts +4 -15
- package/unstable-preview-types/-private/errors.d.ts.map +1 -1
- package/unstable-preview-types/-private/has-many.d.ts +0 -3
- package/unstable-preview-types/-private/has-many.d.ts.map +1 -1
- package/unstable-preview-types/-private/model.d.ts +531 -562
- package/unstable-preview-types/-private/model.d.ts.map +1 -1
- package/unstable-preview-types/-private/promise-belongs-to.d.ts +0 -4
- package/unstable-preview-types/-private/promise-belongs-to.d.ts.map +1 -1
- package/unstable-preview-types/-private/promise-many-array.d.ts +3 -11
- package/unstable-preview-types/-private/promise-many-array.d.ts.map +1 -1
- package/unstable-preview-types/-private/references/belongs-to.d.ts +3 -12
- package/unstable-preview-types/-private/references/belongs-to.d.ts.map +1 -1
- package/unstable-preview-types/-private/references/has-many.d.ts +7 -19
- package/unstable-preview-types/-private/references/has-many.d.ts.map +1 -1
- package/unstable-preview-types/-private/type-utils.d.ts +0 -5
- package/unstable-preview-types/-private/type-utils.d.ts.map +1 -1
- package/unstable-preview-types/-private.d.ts +0 -4
- package/unstable-preview-types/-private.d.ts.map +1 -1
- package/unstable-preview-types/index.d.ts +23 -20
- package/unstable-preview-types/index.d.ts.map +1 -1
- package/unstable-preview-types/migration-support.d.ts +4 -10
- package/unstable-preview-types/migration-support.d.ts.map +1 -1
- package/dist/has-many-BXU96bZ9.js +0 -682
- package/dist/has-many-BXU96bZ9.js.map +0 -1
- package/dist/model-Dkk-TZlL.js.map +0 -1
- package/dist/schema-provider-DyG6fJXt.js +0 -259
- package/dist/schema-provider-DyG6fJXt.js.map +0 -1
|
@@ -1,50 +1,14 @@
|
|
|
1
|
-
import { deprecate } from '@ember/debug';
|
|
2
|
-
import { dasherize } from '@ember-data/request-utils/string';
|
|
3
1
|
import { macroCondition, getGlobalConfig, dependencySatisfies, importSync } from '@embroider/macros';
|
|
4
|
-
import EmberObject, { computed, get } from '@ember/object';
|
|
5
|
-
import { recordIdentifierFor as recordIdentifierFor$1, storeFor as storeFor$1 } from '@ember-data/store';
|
|
6
|
-
import { memoized, defineSignal, defineNonEnumerableSignal, isStableIdentifier, recordIdentifierFor, storeFor, peekCache, SOURCE, fastPush, RelatedCollection, notifyInternalSignal, ARRAY_SIGNAL, peekInternalSignal, withSignalStore, gate, coerceId, entangleSignal } from '@ember-data/store/-private';
|
|
7
|
-
import { RecordStore } from '@warp-drive/core-types/symbols';
|
|
8
|
-
import { A } from '@ember/array';
|
|
9
|
-
import ArrayProxy from '@ember/array/proxy';
|
|
10
|
-
import { mapBy, not } from '@ember/object/computed';
|
|
11
2
|
import { upgradeStore } from '@ember-data/legacy-compat/-private';
|
|
3
|
+
import { memoized, defineSignal, defineNonEnumerableSignal, isStableIdentifier, recordIdentifierFor, storeFor, peekCache, SOURCE, fastPush, RelatedCollection, notifyInternalSignal, ARRAY_SIGNAL } from '@ember-data/store/-private';
|
|
12
4
|
import { getOrSetGlobal } from '@warp-drive/core-types/-private';
|
|
13
5
|
import { EnableHydration } from '@warp-drive/core-types/request';
|
|
6
|
+
import { computed, get } from '@ember/object';
|
|
14
7
|
import PromiseProxyMixin from '@ember/object/promise-proxy-mixin';
|
|
15
8
|
import ObjectProxy from '@ember/object/proxy';
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
// Ensure we have the right number of args
|
|
21
|
-
args.length === 3 && (
|
|
22
|
-
// Make sure the target is a class or object (prototype)
|
|
23
|
-
typeof maybeTarget === 'function' || typeof maybeTarget === 'object' && maybeTarget !== null) &&
|
|
24
|
-
// Make sure the key is a string
|
|
25
|
-
typeof maybeKey === 'string' && (
|
|
26
|
-
// Make sure the descriptor is the right shape
|
|
27
|
-
typeof maybeDesc === 'object' && maybeDesc !== null && 'enumerable' in maybeDesc && 'configurable' in maybeDesc ||
|
|
28
|
-
// TS compatibility
|
|
29
|
-
maybeDesc === undefined)
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
function normalizeModelName(type) {
|
|
33
|
-
if (macroCondition(getGlobalConfig().WarpDrive.deprecations.DEPRECATE_NON_STRICT_TYPES)) {
|
|
34
|
-
const result = dasherize(type);
|
|
35
|
-
deprecate(`The resource type '${type}' is not normalized. Update your application code to use '${result}' instead of '${type}'.`, result === type, {
|
|
36
|
-
id: 'ember-data:deprecate-non-strict-types',
|
|
37
|
-
until: '6.0',
|
|
38
|
-
for: 'ember-data',
|
|
39
|
-
since: {
|
|
40
|
-
available: '4.13',
|
|
41
|
-
enabled: '5.3'
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
return result;
|
|
45
|
-
}
|
|
46
|
-
return type;
|
|
47
|
-
}
|
|
9
|
+
import { A } from '@ember/array';
|
|
10
|
+
import ArrayProxy from '@ember/array/proxy';
|
|
11
|
+
import { mapBy, not } from '@ember/object/computed';
|
|
48
12
|
const PromiseObject = ObjectProxy.extend(PromiseProxyMixin);
|
|
49
13
|
const deferred = /* @__PURE__ */new WeakMap();
|
|
50
14
|
function deferDecorator(proto, prop, desc) {
|
|
@@ -116,17 +80,12 @@ const LegacyPromiseProxy = Symbol.for('LegacyPromiseProxy');
|
|
|
116
80
|
|
|
117
81
|
const Extended = PromiseObject;
|
|
118
82
|
|
|
119
|
-
/**
|
|
120
|
-
@module @ember-data/model
|
|
121
|
-
*/
|
|
122
|
-
|
|
123
83
|
/**
|
|
124
84
|
A PromiseBelongsTo is a PromiseObject that also proxies certain method calls
|
|
125
85
|
to the underlying belongsTo model.
|
|
126
86
|
Right now we proxy:
|
|
127
87
|
* `reload()`
|
|
128
88
|
@class PromiseBelongsTo
|
|
129
|
-
@extends PromiseObject
|
|
130
89
|
@private
|
|
131
90
|
*/
|
|
132
91
|
class PromiseBelongsTo extends Extended {
|
|
@@ -175,9 +134,6 @@ class PromiseBelongsTo extends Extended {
|
|
|
175
134
|
[LegacyPromiseProxy] = true;
|
|
176
135
|
}
|
|
177
136
|
|
|
178
|
-
/**
|
|
179
|
-
@module @ember-data/model
|
|
180
|
-
*/
|
|
181
137
|
/**
|
|
182
138
|
This class is returned as the result of accessing an async hasMany relationship
|
|
183
139
|
on an instance of a Model extending from `@ember-data/model`.
|
|
@@ -235,7 +191,6 @@ class PromiseManyArray {
|
|
|
235
191
|
* We do not guarantee that forEach will always be available. This
|
|
236
192
|
* may eventually be made to use Symbol.Iterator once glimmer supports it.
|
|
237
193
|
*
|
|
238
|
-
* @method forEach
|
|
239
194
|
* @param cb
|
|
240
195
|
* @return
|
|
241
196
|
* @private
|
|
@@ -251,7 +206,6 @@ class PromiseManyArray {
|
|
|
251
206
|
|
|
252
207
|
/**
|
|
253
208
|
* Reload the relationship
|
|
254
|
-
* @method reload
|
|
255
209
|
* @public
|
|
256
210
|
* @param options
|
|
257
211
|
* @return
|
|
@@ -303,11 +257,10 @@ class PromiseManyArray {
|
|
|
303
257
|
/**
|
|
304
258
|
* chain this promise
|
|
305
259
|
*
|
|
306
|
-
* @method then
|
|
307
260
|
* @public
|
|
308
261
|
* @param success
|
|
309
262
|
* @param fail
|
|
310
|
-
* @return Promise
|
|
263
|
+
* @return {Promise}
|
|
311
264
|
*/
|
|
312
265
|
then(s, f) {
|
|
313
266
|
return this.promise.then(s, f);
|
|
@@ -315,10 +268,9 @@ class PromiseManyArray {
|
|
|
315
268
|
|
|
316
269
|
/**
|
|
317
270
|
* catch errors thrown by this promise
|
|
318
|
-
* @method catch
|
|
319
271
|
* @public
|
|
320
272
|
* @param callback
|
|
321
|
-
* @return Promise
|
|
273
|
+
* @return {Promise}
|
|
322
274
|
*/
|
|
323
275
|
catch(cb) {
|
|
324
276
|
return this.promise.catch(cb);
|
|
@@ -327,10 +279,9 @@ class PromiseManyArray {
|
|
|
327
279
|
/**
|
|
328
280
|
* run cleanup after this promise completes
|
|
329
281
|
*
|
|
330
|
-
* @method finally
|
|
331
282
|
* @public
|
|
332
283
|
* @param callback
|
|
333
|
-
* @return Promise
|
|
284
|
+
* @return {Promise}
|
|
334
285
|
*/
|
|
335
286
|
finally(cb) {
|
|
336
287
|
return this.promise.finally(cb);
|
|
@@ -577,7 +528,7 @@ class HasManyReference {
|
|
|
577
528
|
looked up when it is loaded. If the relationship has a link it will
|
|
578
529
|
use the "link" otherwise it defaults to "id".
|
|
579
530
|
Example
|
|
580
|
-
```app/models/post.js
|
|
531
|
+
```js [app/models/post.js]
|
|
581
532
|
import Model, { hasMany } from '@ember-data/model';
|
|
582
533
|
export default class PostModel extends Model {
|
|
583
534
|
@hasMany('comment', { async: true, inverse: null }) comments;
|
|
@@ -603,8 +554,7 @@ class HasManyReference {
|
|
|
603
554
|
let link = commentsRef.link();
|
|
604
555
|
}
|
|
605
556
|
```
|
|
606
|
-
@
|
|
607
|
-
@public
|
|
557
|
+
@public
|
|
608
558
|
@return {String} The name of the remote type. This should either be `link` or `ids`
|
|
609
559
|
*/
|
|
610
560
|
remoteType() {
|
|
@@ -618,7 +568,7 @@ class HasManyReference {
|
|
|
618
568
|
/**
|
|
619
569
|
`ids()` returns an array of the record IDs in this relationship.
|
|
620
570
|
Example
|
|
621
|
-
```app/models/post.js
|
|
571
|
+
```js [app/models/post.js]
|
|
622
572
|
import Model, { hasMany } from '@ember-data/model';
|
|
623
573
|
export default class PostModel extends Model {
|
|
624
574
|
@hasMany('comment', { async: true, inverse: null }) comments;
|
|
@@ -639,8 +589,7 @@ class HasManyReference {
|
|
|
639
589
|
let commentsRef = post.hasMany('comments');
|
|
640
590
|
commentsRef.ids(); // ['1']
|
|
641
591
|
```
|
|
642
|
-
|
|
643
|
-
@public
|
|
592
|
+
@public
|
|
644
593
|
@return {Array} The ids in this has-many relationship
|
|
645
594
|
*/
|
|
646
595
|
ids() {
|
|
@@ -676,8 +625,7 @@ class HasManyReference {
|
|
|
676
625
|
let link = userRef.link();
|
|
677
626
|
}
|
|
678
627
|
```
|
|
679
|
-
@
|
|
680
|
-
@public
|
|
628
|
+
@public
|
|
681
629
|
@return {String} The link Ember Data will use to fetch or reload this belongs-to relationship.
|
|
682
630
|
*/
|
|
683
631
|
link() {
|
|
@@ -694,7 +642,6 @@ class HasManyReference {
|
|
|
694
642
|
/**
|
|
695
643
|
* any links that have been received for this relationship
|
|
696
644
|
*
|
|
697
|
-
* @method links
|
|
698
645
|
* @public
|
|
699
646
|
* @return
|
|
700
647
|
*/
|
|
@@ -733,8 +680,7 @@ class HasManyReference {
|
|
|
733
680
|
let usersRef = blog.hasMany('user');
|
|
734
681
|
usersRef.meta() // { lastUpdated: 1458014400000 }
|
|
735
682
|
```
|
|
736
|
-
@
|
|
737
|
-
@public
|
|
683
|
+
@public
|
|
738
684
|
@return {Object|null} The meta information for the belongs-to relationship.
|
|
739
685
|
*/
|
|
740
686
|
meta() {
|
|
@@ -752,7 +698,7 @@ class HasManyReference {
|
|
|
752
698
|
the backend. An empty array will signify the canonical value should be
|
|
753
699
|
empty.
|
|
754
700
|
Example model
|
|
755
|
-
```app/models/post.js
|
|
701
|
+
```js [app/models/post.js]
|
|
756
702
|
import Model, { hasMany } from '@ember-data/model';
|
|
757
703
|
export default class PostModel extends Model {
|
|
758
704
|
@hasMany('comment', { async: true, inverse: null }) comments;
|
|
@@ -820,8 +766,7 @@ class HasManyReference {
|
|
|
820
766
|
and instead the promise will resolve with void without attempting to fetch. This is
|
|
821
767
|
particularly useful if you want to update the state of the relationship without
|
|
822
768
|
forcing the load of all of the associated records.
|
|
823
|
-
@
|
|
824
|
-
@public
|
|
769
|
+
@public
|
|
825
770
|
@param {Array|Object} doc a JSONAPI document object describing the new value of this relationship.
|
|
826
771
|
@param {Boolean} [skipFetch] if `true`, do not attempt to fetch unloaded records
|
|
827
772
|
@return {Promise<ManyArray | void>}
|
|
@@ -890,7 +835,7 @@ class HasManyReference {
|
|
|
890
835
|
relationship is not yet loaded. If the relationship is not loaded
|
|
891
836
|
it will always return `null`.
|
|
892
837
|
Example
|
|
893
|
-
```app/models/post.js
|
|
838
|
+
```js [app/models/post.js]
|
|
894
839
|
import Model, { hasMany } from '@ember-data/model';
|
|
895
840
|
export default class PostModel extends Model {
|
|
896
841
|
@hasMany('comment', { async: true, inverse: null }) comments;
|
|
@@ -913,8 +858,7 @@ class HasManyReference {
|
|
|
913
858
|
commentsRef.value() === comments
|
|
914
859
|
})
|
|
915
860
|
```
|
|
916
|
-
|
|
917
|
-
@public
|
|
861
|
+
@public
|
|
918
862
|
@return {ManyArray}
|
|
919
863
|
*/
|
|
920
864
|
value() {
|
|
@@ -933,7 +877,7 @@ class HasManyReference {
|
|
|
933
877
|
load. This causes a request to the specified
|
|
934
878
|
relationship link or reloads all items currently in the relationship.
|
|
935
879
|
Example
|
|
936
|
-
```app/models/post.js
|
|
880
|
+
```js [app/models/post.js]
|
|
937
881
|
import Model, { hasMany } from '@ember-data/model';
|
|
938
882
|
export default class PostModel extends Model {
|
|
939
883
|
@hasMany('comment', { async: true, inverse: null }) comments;
|
|
@@ -966,7 +910,7 @@ class HasManyReference {
|
|
|
966
910
|
//...
|
|
967
911
|
});
|
|
968
912
|
```
|
|
969
|
-
```app/adapters/comment.js
|
|
913
|
+
```js [app/adapters/comment.js]
|
|
970
914
|
export default ApplicationAdapter.extend({
|
|
971
915
|
findMany(store, type, id, snapshots) {
|
|
972
916
|
// In the adapter you will have access to adapterOptions.
|
|
@@ -974,8 +918,7 @@ class HasManyReference {
|
|
|
974
918
|
}
|
|
975
919
|
});
|
|
976
920
|
```
|
|
977
|
-
@
|
|
978
|
-
@public
|
|
921
|
+
@public
|
|
979
922
|
@param {Object} options the options to pass in.
|
|
980
923
|
@return {Promise} a promise that resolves with the ManyArray in
|
|
981
924
|
this has-many relationship.
|
|
@@ -993,7 +936,7 @@ class HasManyReference {
|
|
|
993
936
|
Reloads this has-many relationship. This causes a request to the specified
|
|
994
937
|
relationship link or reloads all items currently in the relationship.
|
|
995
938
|
Example
|
|
996
|
-
```app/models/post.js
|
|
939
|
+
```js [app/models/post.js]
|
|
997
940
|
import Model, { hasMany } from '@ember-data/model';
|
|
998
941
|
export default class PostModel extends Model {
|
|
999
942
|
@hasMany('comment', { async: true, inverse: null }) comments;
|
|
@@ -1024,8 +967,7 @@ class HasManyReference {
|
|
|
1024
967
|
```javascript
|
|
1025
968
|
commentsRef.reload({ adapterOptions: { isPrivate: true } })
|
|
1026
969
|
```
|
|
1027
|
-
|
|
1028
|
-
@public
|
|
970
|
+
@public
|
|
1029
971
|
@param {Object} options the options to pass in.
|
|
1030
972
|
@return {Promise} a promise that resolves with the ManyArray in this has-many relationship.
|
|
1031
973
|
*/
|
|
@@ -1193,8 +1135,7 @@ class BelongsToReference {
|
|
|
1193
1135
|
let id = userRef.id();
|
|
1194
1136
|
}
|
|
1195
1137
|
```
|
|
1196
|
-
@
|
|
1197
|
-
@public
|
|
1138
|
+
@public
|
|
1198
1139
|
@return {String} The id of the record in this belongsTo relationship.
|
|
1199
1140
|
*/
|
|
1200
1141
|
static {
|
|
@@ -1233,8 +1174,7 @@ class BelongsToReference {
|
|
|
1233
1174
|
let link = userRef.link();
|
|
1234
1175
|
}
|
|
1235
1176
|
```
|
|
1236
|
-
@
|
|
1237
|
-
@public
|
|
1177
|
+
@public
|
|
1238
1178
|
@return {String} The link Ember Data will use to fetch or reload this belongs-to relationship.
|
|
1239
1179
|
*/
|
|
1240
1180
|
link() {
|
|
@@ -1251,7 +1191,6 @@ class BelongsToReference {
|
|
|
1251
1191
|
/**
|
|
1252
1192
|
* any links that have been received for this relationship
|
|
1253
1193
|
*
|
|
1254
|
-
* @method links
|
|
1255
1194
|
* @public
|
|
1256
1195
|
* @return
|
|
1257
1196
|
*/
|
|
@@ -1290,8 +1229,7 @@ class BelongsToReference {
|
|
|
1290
1229
|
let userRef = blog.belongsTo('user');
|
|
1291
1230
|
userRef.meta() // { lastUpdated: 1458014400000 }
|
|
1292
1231
|
```
|
|
1293
|
-
|
|
1294
|
-
@public
|
|
1232
|
+
@public
|
|
1295
1233
|
@return {Object} The meta information for the belongs-to relationship.
|
|
1296
1234
|
*/
|
|
1297
1235
|
meta() {
|
|
@@ -1314,7 +1252,7 @@ class BelongsToReference {
|
|
|
1314
1252
|
looked up when it is loaded. If the relationship has a link it will
|
|
1315
1253
|
use the "link" otherwise it defaults to "id".
|
|
1316
1254
|
Example
|
|
1317
|
-
```app/models/post.js
|
|
1255
|
+
```js [app/models/post.js]
|
|
1318
1256
|
import Model, { hasMany } from '@ember-data/model';
|
|
1319
1257
|
export default class PostModel extends Model {
|
|
1320
1258
|
@hasMany('comment', { async: true, inverse: null }) comments;
|
|
@@ -1340,8 +1278,7 @@ class BelongsToReference {
|
|
|
1340
1278
|
let link = commentsRef.link();
|
|
1341
1279
|
}
|
|
1342
1280
|
```
|
|
1343
|
-
@
|
|
1344
|
-
@public
|
|
1281
|
+
@public
|
|
1345
1282
|
@return {String} The name of the remote type. This should either be `link` or `id`
|
|
1346
1283
|
*/
|
|
1347
1284
|
remoteType() {
|
|
@@ -1358,7 +1295,7 @@ class BelongsToReference {
|
|
|
1358
1295
|
the backend. A value of `null` (e.g. `{ data: null }`) can be passed to
|
|
1359
1296
|
clear the relationship.
|
|
1360
1297
|
Example model
|
|
1361
|
-
```app/models/blog.js
|
|
1298
|
+
```js [app/models/blog.js]
|
|
1362
1299
|
import Model, { belongsTo } from '@ember-data/model';
|
|
1363
1300
|
export default class BlogModel extends Model {
|
|
1364
1301
|
@belongsTo('user', { async: true, inverse: null }) user;
|
|
@@ -1424,8 +1361,7 @@ class BelongsToReference {
|
|
|
1424
1361
|
and instead the promise will resolve with void without attempting to fetch. This is
|
|
1425
1362
|
particularly useful if you want to update the state of the relationship without
|
|
1426
1363
|
forcing the load of all of the associated record.
|
|
1427
|
-
@
|
|
1428
|
-
@public
|
|
1364
|
+
@public
|
|
1429
1365
|
@param {Object} doc a JSONAPI document object describing the new value of this relationship.
|
|
1430
1366
|
@param {Boolean} [skipFetch] if `true`, do not attempt to fetch unloaded records
|
|
1431
1367
|
@return {Promise<OpaqueRecordInstance | null | void>}
|
|
@@ -1506,8 +1442,7 @@ class BelongsToReference {
|
|
|
1506
1442
|
userRef.value(); // user
|
|
1507
1443
|
});
|
|
1508
1444
|
```
|
|
1509
|
-
|
|
1510
|
-
@public
|
|
1445
|
+
@public
|
|
1511
1446
|
@return {Model} the record in this relationship
|
|
1512
1447
|
*/
|
|
1513
1448
|
value() {
|
|
@@ -1552,7 +1487,7 @@ class BelongsToReference {
|
|
|
1552
1487
|
userRef.value() === user;
|
|
1553
1488
|
});
|
|
1554
1489
|
```
|
|
1555
|
-
```app/adapters/user.js
|
|
1490
|
+
```js [app/adapters/user.js]
|
|
1556
1491
|
import Adapter from '@ember-data/adapter';
|
|
1557
1492
|
export default class UserAdapter extends Adapter {
|
|
1558
1493
|
findRecord(store, type, id, snapshot) {
|
|
@@ -1561,8 +1496,7 @@ class BelongsToReference {
|
|
|
1561
1496
|
}
|
|
1562
1497
|
});
|
|
1563
1498
|
```
|
|
1564
|
-
|
|
1565
|
-
@public
|
|
1499
|
+
@public
|
|
1566
1500
|
@param {Object} options the options to pass in.
|
|
1567
1501
|
@return {Promise} a promise that resolves with the record in this belongs-to relationship.
|
|
1568
1502
|
*/
|
|
@@ -1611,8 +1545,7 @@ class BelongsToReference {
|
|
|
1611
1545
|
```javascript
|
|
1612
1546
|
userRef.reload({ adapterOptions: { isPrivate: true } })
|
|
1613
1547
|
```
|
|
1614
|
-
|
|
1615
|
-
@public
|
|
1548
|
+
@public
|
|
1616
1549
|
@param {Object} options the options to pass in.
|
|
1617
1550
|
@return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed.
|
|
1618
1551
|
*/
|
|
@@ -2329,7 +2262,7 @@ const ArrayProxyWithCustomOverrides = ArrayProxy;
|
|
|
2329
2262
|
|
|
2330
2263
|
For Example, if you had a `User` model that looked like this:
|
|
2331
2264
|
|
|
2332
|
-
```app/models/user.js
|
|
2265
|
+
```js [app/models/user.js]
|
|
2333
2266
|
import Model, { attr } from '@ember-data/model';
|
|
2334
2267
|
|
|
2335
2268
|
export default class UserModel extends Model {
|
|
@@ -2391,7 +2324,6 @@ const ArrayProxyWithCustomOverrides = ArrayProxy;
|
|
|
2391
2324
|
|
|
2392
2325
|
@class Errors
|
|
2393
2326
|
@public
|
|
2394
|
-
@extends Ember.ArrayProxy
|
|
2395
2327
|
*/
|
|
2396
2328
|
class Errors extends ArrayProxyWithCustomOverrides {
|
|
2397
2329
|
/**
|
|
@@ -2415,8 +2347,7 @@ class Errors extends ArrayProxyWithCustomOverrides {
|
|
|
2415
2347
|
// [{attribute: "email", message: "Doesn't look like a valid email."}]
|
|
2416
2348
|
});
|
|
2417
2349
|
```
|
|
2418
|
-
@
|
|
2419
|
-
@public
|
|
2350
|
+
@public
|
|
2420
2351
|
@param {String} attribute
|
|
2421
2352
|
@return {Array}
|
|
2422
2353
|
*/
|
|
@@ -2467,7 +2398,6 @@ class Errors extends ArrayProxyWithCustomOverrides {
|
|
|
2467
2398
|
}
|
|
2468
2399
|
|
|
2469
2400
|
/**
|
|
2470
|
-
@method unknownProperty
|
|
2471
2401
|
@private
|
|
2472
2402
|
*/
|
|
2473
2403
|
static {
|
|
@@ -2486,7 +2416,7 @@ class Errors extends ArrayProxyWithCustomOverrides {
|
|
|
2486
2416
|
@property length
|
|
2487
2417
|
@type {Number}
|
|
2488
2418
|
@public
|
|
2489
|
-
@
|
|
2419
|
+
@readonly
|
|
2490
2420
|
*/
|
|
2491
2421
|
|
|
2492
2422
|
/**
|
|
@@ -2494,7 +2424,7 @@ class Errors extends ArrayProxyWithCustomOverrides {
|
|
|
2494
2424
|
@property isEmpty
|
|
2495
2425
|
@type {Boolean}
|
|
2496
2426
|
@public
|
|
2497
|
-
@
|
|
2427
|
+
@readonly
|
|
2498
2428
|
*/
|
|
2499
2429
|
static {
|
|
2500
2430
|
decorateFieldV2(this.prototype, "isEmpty", [not('length')]);
|
|
@@ -2527,7 +2457,6 @@ class Errors extends ArrayProxyWithCustomOverrides {
|
|
|
2527
2457
|
// { attribute: 'username', message: 'This field is required' },
|
|
2528
2458
|
// ]
|
|
2529
2459
|
```
|
|
2530
|
-
@method add
|
|
2531
2460
|
@public
|
|
2532
2461
|
@param {String} attribute - the property name of an attribute or relationship
|
|
2533
2462
|
@param {string[]|string} messages - an error message or array of error messages for the attribute
|
|
@@ -2541,7 +2470,6 @@ class Errors extends ArrayProxyWithCustomOverrides {
|
|
|
2541
2470
|
}
|
|
2542
2471
|
|
|
2543
2472
|
/**
|
|
2544
|
-
@method _findOrCreateMessages
|
|
2545
2473
|
@private
|
|
2546
2474
|
*/
|
|
2547
2475
|
_findOrCreateMessages(attribute, messages) {
|
|
@@ -2581,7 +2509,6 @@ class Errors extends ArrayProxyWithCustomOverrides {
|
|
|
2581
2509
|
errors.errorsFor('phone');
|
|
2582
2510
|
// => undefined
|
|
2583
2511
|
```
|
|
2584
|
-
@method remove
|
|
2585
2512
|
@public
|
|
2586
2513
|
@param {String} member - the property name of an attribute or relationship
|
|
2587
2514
|
*/
|
|
@@ -2635,7 +2562,6 @@ class Errors extends ArrayProxyWithCustomOverrides {
|
|
|
2635
2562
|
errors.messages
|
|
2636
2563
|
// => []
|
|
2637
2564
|
```
|
|
2638
|
-
@method clear
|
|
2639
2565
|
@public
|
|
2640
2566
|
*/
|
|
2641
2567
|
clear() {
|
|
@@ -2657,7 +2583,7 @@ class Errors extends ArrayProxyWithCustomOverrides {
|
|
|
2657
2583
|
|
|
2658
2584
|
/**
|
|
2659
2585
|
Checks if there are error messages for the given attribute.
|
|
2660
|
-
```app/controllers/user/edit.js
|
|
2586
|
+
```js [app/controllers/user/edit.js]
|
|
2661
2587
|
export default class UserEditController extends Controller {
|
|
2662
2588
|
@action
|
|
2663
2589
|
save(user) {
|
|
@@ -2668,8 +2594,7 @@ class Errors extends ArrayProxyWithCustomOverrides {
|
|
|
2668
2594
|
}
|
|
2669
2595
|
}
|
|
2670
2596
|
```
|
|
2671
|
-
@
|
|
2672
|
-
@public
|
|
2597
|
+
@public
|
|
2673
2598
|
@param {String} attribute
|
|
2674
2599
|
@return {Boolean} true if there some errors on given attribute
|
|
2675
2600
|
*/
|
|
@@ -2677,2223 +2602,4 @@ class Errors extends ArrayProxyWithCustomOverrides {
|
|
|
2677
2602
|
return this.errorsFor(attribute).length > 0;
|
|
2678
2603
|
}
|
|
2679
2604
|
}
|
|
2680
|
-
|
|
2681
|
-
const {
|
|
2682
|
-
currentState
|
|
2683
|
-
} = this;
|
|
2684
|
-
const {
|
|
2685
|
-
isNew
|
|
2686
|
-
} = currentState;
|
|
2687
|
-
this[RecordStore]._join(() => {
|
|
2688
|
-
peekCache(this).rollbackAttrs(recordIdentifierFor$1(this));
|
|
2689
|
-
this.errors.clear();
|
|
2690
|
-
currentState.cleanErrorRequests();
|
|
2691
|
-
if (isNew) {
|
|
2692
|
-
this.unloadRecord();
|
|
2693
|
-
}
|
|
2694
|
-
});
|
|
2695
|
-
}
|
|
2696
|
-
function unloadRecord() {
|
|
2697
|
-
if (this.currentState.isNew && (this.isDestroyed || this.isDestroying)) {
|
|
2698
|
-
return;
|
|
2699
|
-
}
|
|
2700
|
-
this[RecordStore].unloadRecord(this);
|
|
2701
|
-
}
|
|
2702
|
-
function belongsTo(prop) {
|
|
2703
|
-
return lookupLegacySupport(this).referenceFor('belongsTo', prop);
|
|
2704
|
-
}
|
|
2705
|
-
function hasMany(prop) {
|
|
2706
|
-
return lookupLegacySupport(this).referenceFor('hasMany', prop);
|
|
2707
|
-
}
|
|
2708
|
-
function reload(options = {}) {
|
|
2709
|
-
options.isReloading = true;
|
|
2710
|
-
options.reload = true;
|
|
2711
|
-
const identifier = recordIdentifierFor$1(this);
|
|
2712
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2713
|
-
if (!test) {
|
|
2714
|
-
throw new Error(`You cannot reload a record without an ID`);
|
|
2715
|
-
}
|
|
2716
|
-
})(identifier.id) : {};
|
|
2717
|
-
this.isReloading = true;
|
|
2718
|
-
const promise = this[RecordStore].request({
|
|
2719
|
-
op: 'findRecord',
|
|
2720
|
-
data: {
|
|
2721
|
-
options,
|
|
2722
|
-
record: identifier
|
|
2723
|
-
},
|
|
2724
|
-
cacheOptions: {
|
|
2725
|
-
[Symbol.for('wd:skip-cache')]: true
|
|
2726
|
-
}
|
|
2727
|
-
}).then(() => this).finally(() => {
|
|
2728
|
-
this.isReloading = false;
|
|
2729
|
-
});
|
|
2730
|
-
return promise;
|
|
2731
|
-
}
|
|
2732
|
-
function changedAttributes() {
|
|
2733
|
-
return peekCache(this).changedAttrs(recordIdentifierFor$1(this));
|
|
2734
|
-
}
|
|
2735
|
-
function serialize(options) {
|
|
2736
|
-
upgradeStore(this[RecordStore]);
|
|
2737
|
-
return this[RecordStore].serializeRecord(this, options);
|
|
2738
|
-
}
|
|
2739
|
-
function deleteRecord() {
|
|
2740
|
-
// ensure we've populated currentState prior to deleting a new record
|
|
2741
|
-
if (this.currentState) {
|
|
2742
|
-
this[RecordStore].deleteRecord(this);
|
|
2743
|
-
}
|
|
2744
|
-
}
|
|
2745
|
-
function save(options) {
|
|
2746
|
-
let promise;
|
|
2747
|
-
if (this.currentState.isNew && this.currentState.isDeleted) {
|
|
2748
|
-
promise = Promise.resolve(this);
|
|
2749
|
-
} else {
|
|
2750
|
-
this.errors.clear();
|
|
2751
|
-
promise = this[RecordStore].saveRecord(this, options);
|
|
2752
|
-
}
|
|
2753
|
-
return promise;
|
|
2754
|
-
}
|
|
2755
|
-
function destroyRecord(options) {
|
|
2756
|
-
const {
|
|
2757
|
-
isNew
|
|
2758
|
-
} = this.currentState;
|
|
2759
|
-
this.deleteRecord();
|
|
2760
|
-
if (isNew) {
|
|
2761
|
-
return Promise.resolve(this);
|
|
2762
|
-
}
|
|
2763
|
-
return this.save(options).then(_ => {
|
|
2764
|
-
this.unloadRecord();
|
|
2765
|
-
return this;
|
|
2766
|
-
});
|
|
2767
|
-
}
|
|
2768
|
-
function createSnapshot() {
|
|
2769
|
-
const store = this[RecordStore];
|
|
2770
|
-
upgradeStore(store);
|
|
2771
|
-
if (!store._fetchManager) {
|
|
2772
|
-
const FetchManager = importSync('@ember-data/legacy-compat/-private').FetchManager;
|
|
2773
|
-
store._fetchManager = new FetchManager(store);
|
|
2774
|
-
}
|
|
2775
|
-
|
|
2776
|
-
// @ts-expect-error Typescript isn't able to curry narrowed args that are divorced from each other.
|
|
2777
|
-
return store._fetchManager.createSnapshot(recordIdentifierFor$1(this));
|
|
2778
|
-
}
|
|
2779
|
-
function notifyChanges(identifier, value, key, record, store) {
|
|
2780
|
-
switch (value) {
|
|
2781
|
-
case 'added':
|
|
2782
|
-
case 'attributes':
|
|
2783
|
-
if (key) {
|
|
2784
|
-
notifyAttribute(store, identifier, key, record);
|
|
2785
|
-
} else {
|
|
2786
|
-
record.eachAttribute(name => {
|
|
2787
|
-
notifyAttribute(store, identifier, name, record);
|
|
2788
|
-
});
|
|
2789
|
-
}
|
|
2790
|
-
break;
|
|
2791
|
-
case 'relationships':
|
|
2792
|
-
if (key) {
|
|
2793
|
-
const meta = record.constructor.relationshipsByName.get(key);
|
|
2794
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2795
|
-
if (!test) {
|
|
2796
|
-
throw new Error(`Expected to find a relationship for ${key} on ${identifier.type}`);
|
|
2797
|
-
}
|
|
2798
|
-
})(meta) : {};
|
|
2799
|
-
notifyRelationship(identifier, key, record, meta);
|
|
2800
|
-
} else {
|
|
2801
|
-
record.eachRelationship((name, meta) => {
|
|
2802
|
-
notifyRelationship(identifier, name, record, meta);
|
|
2803
|
-
});
|
|
2804
|
-
}
|
|
2805
|
-
break;
|
|
2806
|
-
case 'identity':
|
|
2807
|
-
notifyInternalSignal(peekInternalSignal(withSignalStore(record), 'id'));
|
|
2808
|
-
break;
|
|
2809
|
-
}
|
|
2810
|
-
}
|
|
2811
|
-
function notifyRelationship(identifier, key, record, meta) {
|
|
2812
|
-
if (meta.kind === 'belongsTo') {
|
|
2813
|
-
record.notifyPropertyChange(key);
|
|
2814
|
-
} else if (meta.kind === 'hasMany') {
|
|
2815
|
-
const support = LEGACY_SUPPORT.get(identifier);
|
|
2816
|
-
const manyArray = support && support._manyArrayCache[key];
|
|
2817
|
-
const hasPromise = support && support._relationshipPromisesCache[key];
|
|
2818
|
-
if (manyArray && hasPromise) {
|
|
2819
|
-
// do nothing, we will notify the ManyArray directly
|
|
2820
|
-
// once the fetch has completed.
|
|
2821
|
-
return;
|
|
2822
|
-
}
|
|
2823
|
-
if (manyArray) {
|
|
2824
|
-
notifyInternalSignal(manyArray[ARRAY_SIGNAL]);
|
|
2825
|
-
|
|
2826
|
-
//We need to notifyPropertyChange in the adding case because we need to make sure
|
|
2827
|
-
//we fetch the newly added record in case it is unloaded
|
|
2828
|
-
//TODO(Igor): Consider whether we could do this only if the record state is unloaded
|
|
2829
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2830
|
-
if (!test) {
|
|
2831
|
-
throw new Error(`Expected options to exist on relationship meta`);
|
|
2832
|
-
}
|
|
2833
|
-
})(meta.options) : {};
|
|
2834
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2835
|
-
if (!test) {
|
|
2836
|
-
throw new Error(`Expected async to exist on relationship meta options`);
|
|
2837
|
-
}
|
|
2838
|
-
})('async' in meta.options) : {};
|
|
2839
|
-
if (meta.options.async) {
|
|
2840
|
-
record.notifyPropertyChange(key);
|
|
2841
|
-
}
|
|
2842
|
-
}
|
|
2843
|
-
}
|
|
2844
|
-
}
|
|
2845
|
-
function notifyAttribute(store, identifier, key, record) {
|
|
2846
|
-
const currentValue = cacheFor(record, key);
|
|
2847
|
-
const cache = store.cache;
|
|
2848
|
-
if (currentValue !== cache.getAttr(identifier, key)) {
|
|
2849
|
-
record.notifyPropertyChange(key);
|
|
2850
|
-
}
|
|
2851
|
-
}
|
|
2852
|
-
const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/;
|
|
2853
|
-
const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/;
|
|
2854
|
-
const PRIMARY_ATTRIBUTE_KEY = 'base';
|
|
2855
|
-
function isInvalidError(error) {
|
|
2856
|
-
return !!error && error instanceof Error && 'isAdapterError' in error && error.isAdapterError === true && 'code' in error && error.code === 'InvalidError';
|
|
2857
|
-
}
|
|
2858
|
-
|
|
2859
|
-
/**
|
|
2860
|
-
Historically EmberData managed a state machine
|
|
2861
|
-
for each record, the localState for which
|
|
2862
|
-
was reflected onto Model.
|
|
2863
|
-
|
|
2864
|
-
This implements the flags and stateName for backwards compat
|
|
2865
|
-
with the state tree that used to be possible (listed below).
|
|
2866
|
-
|
|
2867
|
-
stateName and dirtyType are candidates for deprecation.
|
|
2868
|
-
|
|
2869
|
-
root
|
|
2870
|
-
empty
|
|
2871
|
-
deleted // hidden from stateName
|
|
2872
|
-
preloaded // hidden from stateName
|
|
2873
|
-
|
|
2874
|
-
loading
|
|
2875
|
-
empty // hidden from stateName
|
|
2876
|
-
preloaded // hidden from stateName
|
|
2877
|
-
|
|
2878
|
-
loaded
|
|
2879
|
-
saved
|
|
2880
|
-
updated
|
|
2881
|
-
uncommitted
|
|
2882
|
-
invalid
|
|
2883
|
-
inFlight
|
|
2884
|
-
created
|
|
2885
|
-
uncommitted
|
|
2886
|
-
invalid
|
|
2887
|
-
inFlight
|
|
2888
|
-
|
|
2889
|
-
deleted
|
|
2890
|
-
saved
|
|
2891
|
-
new // hidden from stateName
|
|
2892
|
-
uncommitted
|
|
2893
|
-
invalid
|
|
2894
|
-
inFlight
|
|
2895
|
-
|
|
2896
|
-
@internal
|
|
2897
|
-
*/
|
|
2898
|
-
class RecordState {
|
|
2899
|
-
constructor(record) {
|
|
2900
|
-
const store = storeFor$1(record);
|
|
2901
|
-
const identity = recordIdentifierFor(record);
|
|
2902
|
-
this.identifier = identity;
|
|
2903
|
-
this.record = record;
|
|
2904
|
-
this.cache = store.cache;
|
|
2905
|
-
this.pendingCount = 0;
|
|
2906
|
-
this.fulfilledCount = 0;
|
|
2907
|
-
this.rejectedCount = 0;
|
|
2908
|
-
this._errorRequests = [];
|
|
2909
|
-
this._lastError = null;
|
|
2910
|
-
const requests = store.getRequestStateService();
|
|
2911
|
-
const notifications = store.notifications;
|
|
2912
|
-
const handleRequest = req => {
|
|
2913
|
-
if (req.type === 'mutation') {
|
|
2914
|
-
switch (req.state) {
|
|
2915
|
-
case 'pending':
|
|
2916
|
-
this.isSaving = true;
|
|
2917
|
-
break;
|
|
2918
|
-
case 'rejected':
|
|
2919
|
-
this.isSaving = false;
|
|
2920
|
-
this._lastError = req;
|
|
2921
|
-
if (!(req.response && isInvalidError(req.response.data))) {
|
|
2922
|
-
this._errorRequests.push(req);
|
|
2923
|
-
}
|
|
2924
|
-
notifyErrorsStateChanged(this);
|
|
2925
|
-
break;
|
|
2926
|
-
case 'fulfilled':
|
|
2927
|
-
this._errorRequests = [];
|
|
2928
|
-
this._lastError = null;
|
|
2929
|
-
this.isSaving = false;
|
|
2930
|
-
this.notify('isDirty');
|
|
2931
|
-
notifyErrorsStateChanged(this);
|
|
2932
|
-
break;
|
|
2933
|
-
}
|
|
2934
|
-
} else {
|
|
2935
|
-
switch (req.state) {
|
|
2936
|
-
case 'pending':
|
|
2937
|
-
this.pendingCount++;
|
|
2938
|
-
this.notify('isLoading');
|
|
2939
|
-
break;
|
|
2940
|
-
case 'rejected':
|
|
2941
|
-
this.pendingCount--;
|
|
2942
|
-
this._lastError = req;
|
|
2943
|
-
if (!(req.response && isInvalidError(req.response.data))) {
|
|
2944
|
-
this._errorRequests.push(req);
|
|
2945
|
-
}
|
|
2946
|
-
this.notify('isLoading');
|
|
2947
|
-
notifyErrorsStateChanged(this);
|
|
2948
|
-
break;
|
|
2949
|
-
case 'fulfilled':
|
|
2950
|
-
this.pendingCount--;
|
|
2951
|
-
this.fulfilledCount++;
|
|
2952
|
-
this.notify('isLoading');
|
|
2953
|
-
this.notify('isDirty');
|
|
2954
|
-
notifyErrorsStateChanged(this);
|
|
2955
|
-
this._errorRequests = [];
|
|
2956
|
-
this._lastError = null;
|
|
2957
|
-
break;
|
|
2958
|
-
}
|
|
2959
|
-
}
|
|
2960
|
-
};
|
|
2961
|
-
requests.subscribeForRecord(identity, handleRequest);
|
|
2962
|
-
|
|
2963
|
-
// we instantiate lazily
|
|
2964
|
-
// so we grab anything we don't have yet
|
|
2965
|
-
const lastRequest = requests.getLastRequestForRecord(identity);
|
|
2966
|
-
if (lastRequest) {
|
|
2967
|
-
handleRequest(lastRequest);
|
|
2968
|
-
}
|
|
2969
|
-
this.handler = notifications.subscribe(identity, (identifier, type, key) => {
|
|
2970
|
-
switch (type) {
|
|
2971
|
-
case 'state':
|
|
2972
|
-
this.notify('isSaved');
|
|
2973
|
-
this.notify('isNew');
|
|
2974
|
-
this.notify('isDeleted');
|
|
2975
|
-
this.notify('isDirty');
|
|
2976
|
-
break;
|
|
2977
|
-
case 'attributes':
|
|
2978
|
-
this.notify('isEmpty');
|
|
2979
|
-
this.notify('isDirty');
|
|
2980
|
-
break;
|
|
2981
|
-
case 'errors':
|
|
2982
|
-
this.updateInvalidErrors(this.record.errors);
|
|
2983
|
-
this.notify('isValid');
|
|
2984
|
-
break;
|
|
2985
|
-
}
|
|
2986
|
-
});
|
|
2987
|
-
}
|
|
2988
|
-
destroy() {
|
|
2989
|
-
storeFor$1(this.record).notifications.unsubscribe(this.handler);
|
|
2990
|
-
}
|
|
2991
|
-
notify(key) {
|
|
2992
|
-
const signals = withSignalStore(this);
|
|
2993
|
-
const signal = peekInternalSignal(signals, key);
|
|
2994
|
-
if (signal) {
|
|
2995
|
-
notifyInternalSignal(signal);
|
|
2996
|
-
}
|
|
2997
|
-
}
|
|
2998
|
-
updateInvalidErrors(errors) {
|
|
2999
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3000
|
-
if (!test) {
|
|
3001
|
-
throw new Error(`Expected the Cache instance for ${this.identifier.lid} to implement getErrors(identifier)`);
|
|
3002
|
-
}
|
|
3003
|
-
})(typeof this.cache.getErrors === 'function') : {};
|
|
3004
|
-
const jsonApiErrors = this.cache.getErrors(this.identifier);
|
|
3005
|
-
errors.clear();
|
|
3006
|
-
for (let i = 0; i < jsonApiErrors.length; i++) {
|
|
3007
|
-
const error = jsonApiErrors[i];
|
|
3008
|
-
if (error.source && error.source.pointer) {
|
|
3009
|
-
const keyMatch = error.source.pointer.match(SOURCE_POINTER_REGEXP);
|
|
3010
|
-
let key;
|
|
3011
|
-
if (keyMatch) {
|
|
3012
|
-
key = keyMatch[2];
|
|
3013
|
-
} else if (error.source.pointer.search(SOURCE_POINTER_PRIMARY_REGEXP) !== -1) {
|
|
3014
|
-
key = PRIMARY_ATTRIBUTE_KEY;
|
|
3015
|
-
}
|
|
3016
|
-
if (key) {
|
|
3017
|
-
const errMsg = error.detail || error.title;
|
|
3018
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3019
|
-
if (!test) {
|
|
3020
|
-
throw new Error(`Expected field error to have a detail or title to use as the message`);
|
|
3021
|
-
}
|
|
3022
|
-
})(errMsg) : {};
|
|
3023
|
-
errors.add(key, errMsg);
|
|
3024
|
-
}
|
|
3025
|
-
}
|
|
3026
|
-
}
|
|
3027
|
-
}
|
|
3028
|
-
cleanErrorRequests() {
|
|
3029
|
-
this.notify('isValid');
|
|
3030
|
-
this.notify('isError');
|
|
3031
|
-
this.notify('adapterError');
|
|
3032
|
-
this._errorRequests = [];
|
|
3033
|
-
this._lastError = null;
|
|
3034
|
-
}
|
|
3035
|
-
get isLoading() {
|
|
3036
|
-
return !this.isLoaded && this.pendingCount > 0 && this.fulfilledCount === 0;
|
|
3037
|
-
}
|
|
3038
|
-
static {
|
|
3039
|
-
decorateMethodV2(this.prototype, "isLoading", [gate]);
|
|
3040
|
-
}
|
|
3041
|
-
get isLoaded() {
|
|
3042
|
-
if (this.isNew) {
|
|
3043
|
-
return true;
|
|
3044
|
-
}
|
|
3045
|
-
return this.fulfilledCount > 0 || !this.isEmpty;
|
|
3046
|
-
}
|
|
3047
|
-
static {
|
|
3048
|
-
decorateMethodV2(this.prototype, "isLoaded", [gate]);
|
|
3049
|
-
}
|
|
3050
|
-
get isSaved() {
|
|
3051
|
-
const rd = this.cache;
|
|
3052
|
-
if (this.isDeleted) {
|
|
3053
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3054
|
-
if (!test) {
|
|
3055
|
-
throw new Error(`Expected Cache to implement isDeletionCommitted()`);
|
|
3056
|
-
}
|
|
3057
|
-
})(typeof rd.isDeletionCommitted === 'function') : {};
|
|
3058
|
-
return rd.isDeletionCommitted(this.identifier);
|
|
3059
|
-
}
|
|
3060
|
-
if (this.isNew || this.isEmpty || !this.isValid || this.isDirty || this.isLoading) {
|
|
3061
|
-
return false;
|
|
3062
|
-
}
|
|
3063
|
-
return true;
|
|
3064
|
-
}
|
|
3065
|
-
static {
|
|
3066
|
-
decorateMethodV2(this.prototype, "isSaved", [gate]);
|
|
3067
|
-
}
|
|
3068
|
-
get isEmpty() {
|
|
3069
|
-
const rd = this.cache;
|
|
3070
|
-
// TODO this is not actually an RFC'd concept. Determine the
|
|
3071
|
-
// correct heuristic to replace this with.
|
|
3072
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3073
|
-
if (!test) {
|
|
3074
|
-
throw new Error(`Expected Cache to implement isEmpty()`);
|
|
3075
|
-
}
|
|
3076
|
-
})(typeof rd.isEmpty === 'function') : {};
|
|
3077
|
-
return !this.isNew && rd.isEmpty(this.identifier);
|
|
3078
|
-
}
|
|
3079
|
-
static {
|
|
3080
|
-
decorateMethodV2(this.prototype, "isEmpty", [gate]);
|
|
3081
|
-
}
|
|
3082
|
-
get isNew() {
|
|
3083
|
-
const rd = this.cache;
|
|
3084
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3085
|
-
if (!test) {
|
|
3086
|
-
throw new Error(`Expected Cache to implement isNew()`);
|
|
3087
|
-
}
|
|
3088
|
-
})(typeof rd.isNew === 'function') : {};
|
|
3089
|
-
return rd.isNew(this.identifier);
|
|
3090
|
-
}
|
|
3091
|
-
static {
|
|
3092
|
-
decorateMethodV2(this.prototype, "isNew", [gate]);
|
|
3093
|
-
}
|
|
3094
|
-
get isDeleted() {
|
|
3095
|
-
const rd = this.cache;
|
|
3096
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3097
|
-
if (!test) {
|
|
3098
|
-
throw new Error(`Expected Cache to implement isDeleted()`);
|
|
3099
|
-
}
|
|
3100
|
-
})(typeof rd.isDeleted === 'function') : {};
|
|
3101
|
-
return rd.isDeleted(this.identifier);
|
|
3102
|
-
}
|
|
3103
|
-
static {
|
|
3104
|
-
decorateMethodV2(this.prototype, "isDeleted", [gate]);
|
|
3105
|
-
}
|
|
3106
|
-
get isValid() {
|
|
3107
|
-
return this.record.errors.length === 0;
|
|
3108
|
-
}
|
|
3109
|
-
static {
|
|
3110
|
-
decorateMethodV2(this.prototype, "isValid", [gate]);
|
|
3111
|
-
}
|
|
3112
|
-
get isDirty() {
|
|
3113
|
-
const rd = this.cache;
|
|
3114
|
-
if (this.isEmpty || rd.isDeletionCommitted(this.identifier) || this.isDeleted && this.isNew) {
|
|
3115
|
-
return false;
|
|
3116
|
-
}
|
|
3117
|
-
return this.isDeleted || this.isNew || rd.hasChangedAttrs(this.identifier);
|
|
3118
|
-
}
|
|
3119
|
-
static {
|
|
3120
|
-
decorateMethodV2(this.prototype, "isDirty", [gate]);
|
|
3121
|
-
}
|
|
3122
|
-
get isError() {
|
|
3123
|
-
const errorReq = this._errorRequests[this._errorRequests.length - 1];
|
|
3124
|
-
if (!errorReq) {
|
|
3125
|
-
return false;
|
|
3126
|
-
} else {
|
|
3127
|
-
return true;
|
|
3128
|
-
}
|
|
3129
|
-
}
|
|
3130
|
-
static {
|
|
3131
|
-
decorateMethodV2(this.prototype, "isError", [gate]);
|
|
3132
|
-
}
|
|
3133
|
-
get adapterError() {
|
|
3134
|
-
const request = this._lastError;
|
|
3135
|
-
if (!request) {
|
|
3136
|
-
return null;
|
|
3137
|
-
}
|
|
3138
|
-
return request.state === 'rejected' && request.response.data;
|
|
3139
|
-
}
|
|
3140
|
-
static {
|
|
3141
|
-
decorateMethodV2(this.prototype, "adapterError", [gate]);
|
|
3142
|
-
}
|
|
3143
|
-
get isPreloaded() {
|
|
3144
|
-
return !this.isEmpty && this.isLoading;
|
|
3145
|
-
}
|
|
3146
|
-
static {
|
|
3147
|
-
decorateMethodV2(this.prototype, "isPreloaded", [memoized]);
|
|
3148
|
-
}
|
|
3149
|
-
get stateName() {
|
|
3150
|
-
// we might be empty while loading so check this first
|
|
3151
|
-
if (this.isLoading) {
|
|
3152
|
-
return 'root.loading';
|
|
3153
|
-
|
|
3154
|
-
// got nothing yet or were unloaded
|
|
3155
|
-
} else if (this.isEmpty) {
|
|
3156
|
-
return 'root.empty';
|
|
3157
|
-
|
|
3158
|
-
// deleted substates
|
|
3159
|
-
} else if (this.isDeleted) {
|
|
3160
|
-
if (this.isSaving) {
|
|
3161
|
-
return 'root.deleted.inFlight';
|
|
3162
|
-
} else if (this.isSaved) {
|
|
3163
|
-
// TODO ensure isSaved isn't true from previous requests
|
|
3164
|
-
return 'root.deleted.saved';
|
|
3165
|
-
} else if (!this.isValid) {
|
|
3166
|
-
return 'root.deleted.invalid';
|
|
3167
|
-
} else {
|
|
3168
|
-
return 'root.deleted.uncommitted';
|
|
3169
|
-
}
|
|
3170
|
-
|
|
3171
|
-
// loaded.created substates
|
|
3172
|
-
} else if (this.isNew) {
|
|
3173
|
-
if (this.isSaving) {
|
|
3174
|
-
return 'root.loaded.created.inFlight';
|
|
3175
|
-
} else if (!this.isValid) {
|
|
3176
|
-
return 'root.loaded.created.invalid';
|
|
3177
|
-
}
|
|
3178
|
-
return 'root.loaded.created.uncommitted';
|
|
3179
|
-
|
|
3180
|
-
// loaded.updated substates
|
|
3181
|
-
} else if (this.isSaving) {
|
|
3182
|
-
return 'root.loaded.updated.inFlight';
|
|
3183
|
-
} else if (!this.isValid) {
|
|
3184
|
-
return 'root.loaded.updated.invalid';
|
|
3185
|
-
} else if (this.isDirty) {
|
|
3186
|
-
return 'root.loaded.updated.uncommitted';
|
|
3187
|
-
|
|
3188
|
-
// if nothing remains, we are loaded saved!
|
|
3189
|
-
} else {
|
|
3190
|
-
return 'root.loaded.saved';
|
|
3191
|
-
}
|
|
3192
|
-
}
|
|
3193
|
-
static {
|
|
3194
|
-
decorateMethodV2(this.prototype, "stateName", [memoized]);
|
|
3195
|
-
}
|
|
3196
|
-
get dirtyType() {
|
|
3197
|
-
// we might be empty while loading so check this first
|
|
3198
|
-
if (this.isLoading || this.isEmpty) {
|
|
3199
|
-
return '';
|
|
3200
|
-
|
|
3201
|
-
// deleted substates
|
|
3202
|
-
} else if (this.isDirty && this.isDeleted) {
|
|
3203
|
-
return 'deleted';
|
|
3204
|
-
|
|
3205
|
-
// loaded.created substates
|
|
3206
|
-
} else if (this.isNew) {
|
|
3207
|
-
return 'created';
|
|
3208
|
-
|
|
3209
|
-
// loaded.updated substates
|
|
3210
|
-
} else if (this.isSaving || !this.isValid || this.isDirty) {
|
|
3211
|
-
return 'updated';
|
|
3212
|
-
|
|
3213
|
-
// if nothing remains, we are loaded saved!
|
|
3214
|
-
} else {
|
|
3215
|
-
return '';
|
|
3216
|
-
}
|
|
3217
|
-
}
|
|
3218
|
-
static {
|
|
3219
|
-
decorateMethodV2(this.prototype, "dirtyType", [memoized]);
|
|
3220
|
-
}
|
|
3221
|
-
}
|
|
3222
|
-
defineSignal(RecordState.prototype, 'isSaving', false);
|
|
3223
|
-
function notifyErrorsStateChanged(state) {
|
|
3224
|
-
state.notify('isValid');
|
|
3225
|
-
state.notify('isError');
|
|
3226
|
-
state.notify('adapterError');
|
|
3227
|
-
}
|
|
3228
|
-
|
|
3229
|
-
/**
|
|
3230
|
-
@module @ember-data/model
|
|
3231
|
-
*/
|
|
3232
|
-
|
|
3233
|
-
/*
|
|
3234
|
-
* This decorator allows us to lazily compute
|
|
3235
|
-
* an expensive getter on first-access and thereafter
|
|
3236
|
-
* never recompute it.
|
|
3237
|
-
*/
|
|
3238
|
-
function computeOnce(target, propertyName, desc) {
|
|
3239
|
-
const cache = new WeakMap();
|
|
3240
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
3241
|
-
const getter = desc.get;
|
|
3242
|
-
desc.get = function () {
|
|
3243
|
-
let meta = cache.get(this);
|
|
3244
|
-
if (!meta) {
|
|
3245
|
-
meta = {
|
|
3246
|
-
hasComputed: false,
|
|
3247
|
-
value: undefined
|
|
3248
|
-
};
|
|
3249
|
-
cache.set(this, meta);
|
|
3250
|
-
}
|
|
3251
|
-
if (!meta.hasComputed) {
|
|
3252
|
-
meta.value = getter.call(this);
|
|
3253
|
-
meta.hasComputed = true;
|
|
3254
|
-
}
|
|
3255
|
-
return meta.value;
|
|
3256
|
-
};
|
|
3257
|
-
return desc;
|
|
3258
|
-
}
|
|
3259
|
-
|
|
3260
|
-
/**
|
|
3261
|
-
Base class from which Models can be defined.
|
|
3262
|
-
|
|
3263
|
-
```js
|
|
3264
|
-
import Model, { attr } from '@ember-data/model';
|
|
3265
|
-
|
|
3266
|
-
export default class User extends Model {
|
|
3267
|
-
@attr name;
|
|
3268
|
-
}
|
|
3269
|
-
```
|
|
3270
|
-
|
|
3271
|
-
Models are used both to define the static schema for a
|
|
3272
|
-
particular resource type as well as the class to instantiate
|
|
3273
|
-
to present that data from cache.
|
|
3274
|
-
|
|
3275
|
-
@class Model
|
|
3276
|
-
@public
|
|
3277
|
-
@extends Ember.EmberObject
|
|
3278
|
-
*/
|
|
3279
|
-
|
|
3280
|
-
class Model extends EmberObject {
|
|
3281
|
-
// set during create by the store
|
|
3282
|
-
|
|
3283
|
-
init(options) {
|
|
3284
|
-
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
3285
|
-
if (!options?._secretInit && !options?._createProps) {
|
|
3286
|
-
throw new Error('You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.');
|
|
3287
|
-
}
|
|
3288
|
-
}
|
|
3289
|
-
const createProps = options._createProps;
|
|
3290
|
-
const _secretInit = options._secretInit;
|
|
3291
|
-
options._createProps = null;
|
|
3292
|
-
options._secretInit = null;
|
|
3293
|
-
const store = this.store = _secretInit.store;
|
|
3294
|
-
super.init(options);
|
|
3295
|
-
this[RecordStore] = store;
|
|
3296
|
-
const identity = _secretInit.identifier;
|
|
3297
|
-
_secretInit.cb(this, _secretInit.cache, identity, _secretInit.store);
|
|
3298
|
-
this.___recordState = macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? new RecordState(this) : null;
|
|
3299
|
-
this.setProperties(createProps);
|
|
3300
|
-
const notifications = store.notifications;
|
|
3301
|
-
this.___private_notifications = notifications.subscribe(identity, (identifier, type, field) => {
|
|
3302
|
-
notifyChanges(identifier, type, field, this, store);
|
|
3303
|
-
});
|
|
3304
|
-
}
|
|
3305
|
-
|
|
3306
|
-
// @ts-expect-error destroy should not return a value, but ember's types force it to
|
|
3307
|
-
destroy() {
|
|
3308
|
-
const identifier = recordIdentifierFor$1(this);
|
|
3309
|
-
this.___recordState?.destroy();
|
|
3310
|
-
const store = storeFor$1(this);
|
|
3311
|
-
store.notifications.unsubscribe(this.___private_notifications);
|
|
3312
|
-
LEGACY_SUPPORT.get(this)?.destroy();
|
|
3313
|
-
LEGACY_SUPPORT.delete(this);
|
|
3314
|
-
LEGACY_SUPPORT.delete(identifier);
|
|
3315
|
-
super.destroy();
|
|
3316
|
-
}
|
|
3317
|
-
|
|
3318
|
-
/**
|
|
3319
|
-
If this property is `true` the record is in the `empty`
|
|
3320
|
-
state. Empty is the first state all records enter after they have
|
|
3321
|
-
been created. Most records created by the store will quickly
|
|
3322
|
-
transition to the `loading` state if data needs to be fetched from
|
|
3323
|
-
the server or the `created` state if the record is created on the
|
|
3324
|
-
client. A record can also enter the empty state if the adapter is
|
|
3325
|
-
unable to locate the record.
|
|
3326
|
-
@property isEmpty
|
|
3327
|
-
@public
|
|
3328
|
-
@type {Boolean}
|
|
3329
|
-
@readOnly
|
|
3330
|
-
*/
|
|
3331
|
-
get isEmpty() {
|
|
3332
|
-
return this.currentState.isEmpty;
|
|
3333
|
-
}
|
|
3334
|
-
|
|
3335
|
-
/**
|
|
3336
|
-
If this property is `true` the record is in the `loading` state. A
|
|
3337
|
-
record enters this state when the store asks the adapter for its
|
|
3338
|
-
data. It remains in this state until the adapter provides the
|
|
3339
|
-
requested data.
|
|
3340
|
-
@property isLoading
|
|
3341
|
-
@public
|
|
3342
|
-
@type {Boolean}
|
|
3343
|
-
@readOnly
|
|
3344
|
-
*/
|
|
3345
|
-
static {
|
|
3346
|
-
decorateMethodV2(this.prototype, "isEmpty", [memoized]);
|
|
3347
|
-
}
|
|
3348
|
-
get isLoading() {
|
|
3349
|
-
return this.currentState.isLoading;
|
|
3350
|
-
}
|
|
3351
|
-
|
|
3352
|
-
/**
|
|
3353
|
-
If this property is `true` the record is in the `loaded` state. A
|
|
3354
|
-
record enters this state when its data is populated. Most of a
|
|
3355
|
-
record's lifecycle is spent inside substates of the `loaded`
|
|
3356
|
-
state.
|
|
3357
|
-
Example
|
|
3358
|
-
```javascript
|
|
3359
|
-
let record = store.createRecord('model');
|
|
3360
|
-
record.isLoaded; // true
|
|
3361
|
-
const { content: { data: model } } = await store.request(findRecord({ type: 'model', id: '1' }));
|
|
3362
|
-
model.isLoaded;
|
|
3363
|
-
```
|
|
3364
|
-
@property isLoaded
|
|
3365
|
-
@public
|
|
3366
|
-
@type {Boolean}
|
|
3367
|
-
@readOnly
|
|
3368
|
-
*/
|
|
3369
|
-
static {
|
|
3370
|
-
decorateMethodV2(this.prototype, "isLoading", [memoized]);
|
|
3371
|
-
}
|
|
3372
|
-
get isLoaded() {
|
|
3373
|
-
return this.currentState.isLoaded;
|
|
3374
|
-
}
|
|
3375
|
-
|
|
3376
|
-
/**
|
|
3377
|
-
If this property is `true` the record is in the `dirty` state. The
|
|
3378
|
-
record has local changes that have not yet been saved by the
|
|
3379
|
-
adapter. This includes records that have been created (but not yet
|
|
3380
|
-
saved) or deleted.
|
|
3381
|
-
Example
|
|
3382
|
-
```javascript
|
|
3383
|
-
let record = store.createRecord('model');
|
|
3384
|
-
record.hasDirtyAttributes; // true
|
|
3385
|
-
const { content: { data: model } } = await store.request(findRecord({ type: 'model', id: '1' }));
|
|
3386
|
-
model.hasDirtyAttributes; // false
|
|
3387
|
-
model.foo = 'some value';
|
|
3388
|
-
model.hasDirtyAttributes; // true
|
|
3389
|
-
```
|
|
3390
|
-
@since 1.13.0
|
|
3391
|
-
@property hasDirtyAttributes
|
|
3392
|
-
@public
|
|
3393
|
-
@type {Boolean}
|
|
3394
|
-
@readOnly
|
|
3395
|
-
*/
|
|
3396
|
-
static {
|
|
3397
|
-
decorateMethodV2(this.prototype, "isLoaded", [memoized]);
|
|
3398
|
-
}
|
|
3399
|
-
get hasDirtyAttributes() {
|
|
3400
|
-
return this.currentState.isDirty;
|
|
3401
|
-
}
|
|
3402
|
-
|
|
3403
|
-
/**
|
|
3404
|
-
If this property is `true` the record is in the `saving` state. A
|
|
3405
|
-
record enters the saving state when `save` is called, but the
|
|
3406
|
-
adapter has not yet acknowledged that the changes have been
|
|
3407
|
-
persisted to the backend.
|
|
3408
|
-
Example
|
|
3409
|
-
```javascript
|
|
3410
|
-
let record = store.createRecord('model');
|
|
3411
|
-
record.isSaving; // false
|
|
3412
|
-
let promise = record.save();
|
|
3413
|
-
record.isSaving; // true
|
|
3414
|
-
promise.then(function() {
|
|
3415
|
-
record.isSaving; // false
|
|
3416
|
-
});
|
|
3417
|
-
```
|
|
3418
|
-
@property isSaving
|
|
3419
|
-
@public
|
|
3420
|
-
@type {Boolean}
|
|
3421
|
-
@readOnly
|
|
3422
|
-
*/
|
|
3423
|
-
static {
|
|
3424
|
-
decorateMethodV2(this.prototype, "hasDirtyAttributes", [memoized]);
|
|
3425
|
-
}
|
|
3426
|
-
get isSaving() {
|
|
3427
|
-
return this.currentState.isSaving;
|
|
3428
|
-
}
|
|
3429
|
-
|
|
3430
|
-
/**
|
|
3431
|
-
If this property is `true` the record is in the `deleted` state
|
|
3432
|
-
and has been marked for deletion. When `isDeleted` is true and
|
|
3433
|
-
`hasDirtyAttributes` is true, the record is deleted locally but the deletion
|
|
3434
|
-
was not yet persisted. When `isSaving` is true, the change is
|
|
3435
|
-
in-flight. When both `hasDirtyAttributes` and `isSaving` are false, the
|
|
3436
|
-
change has persisted.
|
|
3437
|
-
Example
|
|
3438
|
-
```javascript
|
|
3439
|
-
let record = store.createRecord('model');
|
|
3440
|
-
record.isDeleted; // false
|
|
3441
|
-
record.deleteRecord();
|
|
3442
|
-
// Locally deleted
|
|
3443
|
-
record.isDeleted; // true
|
|
3444
|
-
record.hasDirtyAttributes; // true
|
|
3445
|
-
record.isSaving; // false
|
|
3446
|
-
// Persisting the deletion
|
|
3447
|
-
let promise = record.save();
|
|
3448
|
-
record.isDeleted; // true
|
|
3449
|
-
record.isSaving; // true
|
|
3450
|
-
// Deletion Persisted
|
|
3451
|
-
promise.then(function() {
|
|
3452
|
-
record.isDeleted; // true
|
|
3453
|
-
record.isSaving; // false
|
|
3454
|
-
record.hasDirtyAttributes; // false
|
|
3455
|
-
});
|
|
3456
|
-
```
|
|
3457
|
-
@property isDeleted
|
|
3458
|
-
@public
|
|
3459
|
-
@type {Boolean}
|
|
3460
|
-
@readOnly
|
|
3461
|
-
*/
|
|
3462
|
-
static {
|
|
3463
|
-
decorateMethodV2(this.prototype, "isSaving", [memoized]);
|
|
3464
|
-
}
|
|
3465
|
-
get isDeleted() {
|
|
3466
|
-
return this.currentState.isDeleted;
|
|
3467
|
-
}
|
|
3468
|
-
|
|
3469
|
-
/**
|
|
3470
|
-
If this property is `true` the record is in the `new` state. A
|
|
3471
|
-
record will be in the `new` state when it has been created on the
|
|
3472
|
-
client and the adapter has not yet report that it was successfully
|
|
3473
|
-
saved.
|
|
3474
|
-
Example
|
|
3475
|
-
```javascript
|
|
3476
|
-
let record = store.createRecord('model');
|
|
3477
|
-
record.isNew; // true
|
|
3478
|
-
record.save().then(function(model) {
|
|
3479
|
-
model.isNew; // false
|
|
3480
|
-
});
|
|
3481
|
-
```
|
|
3482
|
-
@property isNew
|
|
3483
|
-
@public
|
|
3484
|
-
@type {Boolean}
|
|
3485
|
-
@readOnly
|
|
3486
|
-
*/
|
|
3487
|
-
static {
|
|
3488
|
-
decorateMethodV2(this.prototype, "isDeleted", [memoized]);
|
|
3489
|
-
}
|
|
3490
|
-
get isNew() {
|
|
3491
|
-
return this.currentState.isNew;
|
|
3492
|
-
}
|
|
3493
|
-
|
|
3494
|
-
/**
|
|
3495
|
-
If this property is `true` the record is in the `valid` state.
|
|
3496
|
-
A record will be in the `valid` state when the adapter did not report any
|
|
3497
|
-
server-side validation failures.
|
|
3498
|
-
@property isValid
|
|
3499
|
-
@public
|
|
3500
|
-
@type {Boolean}
|
|
3501
|
-
@readOnly
|
|
3502
|
-
*/
|
|
3503
|
-
static {
|
|
3504
|
-
decorateMethodV2(this.prototype, "isNew", [memoized]);
|
|
3505
|
-
}
|
|
3506
|
-
get isValid() {
|
|
3507
|
-
return this.currentState.isValid;
|
|
3508
|
-
}
|
|
3509
|
-
|
|
3510
|
-
/**
|
|
3511
|
-
If the record is in the dirty state this property will report what
|
|
3512
|
-
kind of change has caused it to move into the dirty
|
|
3513
|
-
state. Possible values are:
|
|
3514
|
-
- `created` The record has been created by the client and not yet saved to the adapter.
|
|
3515
|
-
- `updated` The record has been updated by the client and not yet saved to the adapter.
|
|
3516
|
-
- `deleted` The record has been deleted by the client and not yet saved to the adapter.
|
|
3517
|
-
Example
|
|
3518
|
-
```javascript
|
|
3519
|
-
let record = store.createRecord('model');
|
|
3520
|
-
record.dirtyType; // 'created'
|
|
3521
|
-
```
|
|
3522
|
-
@property dirtyType
|
|
3523
|
-
@public
|
|
3524
|
-
@type {String}
|
|
3525
|
-
@readOnly
|
|
3526
|
-
*/
|
|
3527
|
-
static {
|
|
3528
|
-
decorateMethodV2(this.prototype, "isValid", [memoized]);
|
|
3529
|
-
}
|
|
3530
|
-
get dirtyType() {
|
|
3531
|
-
return this.currentState.dirtyType;
|
|
3532
|
-
}
|
|
3533
|
-
|
|
3534
|
-
/**
|
|
3535
|
-
If `true` the adapter reported that it was unable to save local
|
|
3536
|
-
changes to the backend for any reason other than a server-side
|
|
3537
|
-
validation error.
|
|
3538
|
-
Example
|
|
3539
|
-
```javascript
|
|
3540
|
-
record.isError; // false
|
|
3541
|
-
record.set('foo', 'valid value');
|
|
3542
|
-
record.save().then(null, function() {
|
|
3543
|
-
record.isError; // true
|
|
3544
|
-
});
|
|
3545
|
-
```
|
|
3546
|
-
@property isError
|
|
3547
|
-
@public
|
|
3548
|
-
@type {Boolean}
|
|
3549
|
-
@readOnly
|
|
3550
|
-
*/
|
|
3551
|
-
static {
|
|
3552
|
-
decorateMethodV2(this.prototype, "dirtyType", [memoized]);
|
|
3553
|
-
}
|
|
3554
|
-
get isError() {
|
|
3555
|
-
return this.currentState.isError;
|
|
3556
|
-
}
|
|
3557
|
-
static {
|
|
3558
|
-
decorateMethodV2(this.prototype, "isError", [memoized]);
|
|
3559
|
-
}
|
|
3560
|
-
set isError(v) {
|
|
3561
|
-
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
3562
|
-
throw new Error(`isError is not directly settable`);
|
|
3563
|
-
}
|
|
3564
|
-
}
|
|
3565
|
-
|
|
3566
|
-
/**
|
|
3567
|
-
If `true` the store is attempting to reload the record from the adapter.
|
|
3568
|
-
Example
|
|
3569
|
-
```javascript
|
|
3570
|
-
record.isReloading; // false
|
|
3571
|
-
record.reload();
|
|
3572
|
-
record.isReloading; // true
|
|
3573
|
-
```
|
|
3574
|
-
@property isReloading
|
|
3575
|
-
@public
|
|
3576
|
-
@type {Boolean}
|
|
3577
|
-
@readOnly
|
|
3578
|
-
*/
|
|
3579
|
-
|
|
3580
|
-
/**
|
|
3581
|
-
All ember models have an id property. This is an identifier
|
|
3582
|
-
managed by an external source. These are always coerced to be
|
|
3583
|
-
strings before being used internally. Note when declaring the
|
|
3584
|
-
attributes for a model it is an error to declare an id
|
|
3585
|
-
attribute.
|
|
3586
|
-
```javascript
|
|
3587
|
-
let record = store.createRecord('model');
|
|
3588
|
-
record.id; // null
|
|
3589
|
-
const { content: { data: model } } = await store.request(findRecord({ type: 'model', id: '1' }));
|
|
3590
|
-
model.id; // '1'
|
|
3591
|
-
```
|
|
3592
|
-
@property id
|
|
3593
|
-
@public
|
|
3594
|
-
@type {String}
|
|
3595
|
-
*/
|
|
3596
|
-
get id() {
|
|
3597
|
-
// this guard exists, because some dev-only deprecation code
|
|
3598
|
-
// (addListener via validatePropertyInjections) invokes toString before the
|
|
3599
|
-
// object is real.
|
|
3600
|
-
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
3601
|
-
try {
|
|
3602
|
-
return recordIdentifierFor$1(this).id;
|
|
3603
|
-
} catch {
|
|
3604
|
-
return null;
|
|
3605
|
-
}
|
|
3606
|
-
}
|
|
3607
|
-
return recordIdentifierFor$1(this).id;
|
|
3608
|
-
}
|
|
3609
|
-
static {
|
|
3610
|
-
decorateMethodV2(this.prototype, "id", [gate]);
|
|
3611
|
-
}
|
|
3612
|
-
set id(id) {
|
|
3613
|
-
const normalizedId = coerceId(id);
|
|
3614
|
-
const identifier = recordIdentifierFor$1(this);
|
|
3615
|
-
const didChange = normalizedId !== identifier.id;
|
|
3616
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3617
|
-
if (!test) {
|
|
3618
|
-
throw new Error(`Cannot set ${identifier.type} record's id to ${id}, because id is already ${identifier.id}`);
|
|
3619
|
-
}
|
|
3620
|
-
})(!didChange || identifier.id === null) : {};
|
|
3621
|
-
if (normalizedId !== null && didChange) {
|
|
3622
|
-
this.store._instanceCache.setRecordId(identifier, normalizedId);
|
|
3623
|
-
this.store.notifications.notify(identifier, 'identity');
|
|
3624
|
-
}
|
|
3625
|
-
}
|
|
3626
|
-
toString() {
|
|
3627
|
-
return `<model::${this.constructor.modelName}:${this.id}>`;
|
|
3628
|
-
}
|
|
3629
|
-
|
|
3630
|
-
/**
|
|
3631
|
-
@property currentState
|
|
3632
|
-
@private
|
|
3633
|
-
@type {Object}
|
|
3634
|
-
*/
|
|
3635
|
-
// TODO we can probably make this a computeOnce
|
|
3636
|
-
// we likely do not need to notify the currentState root anymore
|
|
3637
|
-
get currentState() {
|
|
3638
|
-
// descriptors are called with the wrong `this` context during mergeMixins
|
|
3639
|
-
// when using legacy/classic ember classes. Basically: lazy in prod and eager in dev.
|
|
3640
|
-
// so we do this to try to steer folks to the nicer "dont user currentState"
|
|
3641
|
-
// error.
|
|
3642
|
-
if (macroCondition(!getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
3643
|
-
if (!this.___recordState) {
|
|
3644
|
-
this.___recordState = new RecordState(this);
|
|
3645
|
-
}
|
|
3646
|
-
}
|
|
3647
|
-
return this.___recordState;
|
|
3648
|
-
}
|
|
3649
|
-
static {
|
|
3650
|
-
decorateMethodV2(this.prototype, "currentState", [gate]);
|
|
3651
|
-
}
|
|
3652
|
-
set currentState(_v) {
|
|
3653
|
-
throw new Error('cannot set currentState');
|
|
3654
|
-
}
|
|
3655
|
-
|
|
3656
|
-
/**
|
|
3657
|
-
The store service instance which created this record instance
|
|
3658
|
-
@property store
|
|
3659
|
-
@public
|
|
3660
|
-
*/
|
|
3661
|
-
|
|
3662
|
-
/**
|
|
3663
|
-
When the record is in the `invalid` state this object will contain
|
|
3664
|
-
any errors returned by the adapter. When present the errors hash
|
|
3665
|
-
contains keys corresponding to the invalid property names
|
|
3666
|
-
and values which are arrays of Javascript objects with two keys:
|
|
3667
|
-
- `message` A string containing the error message from the backend
|
|
3668
|
-
- `attribute` The name of the property associated with this error message
|
|
3669
|
-
```javascript
|
|
3670
|
-
record.errors.length; // 0
|
|
3671
|
-
record.set('foo', 'invalid value');
|
|
3672
|
-
record.save().catch(function() {
|
|
3673
|
-
record.errors.foo;
|
|
3674
|
-
// [{message: 'foo should be a number.', attribute: 'foo'}]
|
|
3675
|
-
});
|
|
3676
|
-
```
|
|
3677
|
-
The `errors` property is useful for displaying error messages to
|
|
3678
|
-
the user.
|
|
3679
|
-
```handlebars
|
|
3680
|
-
<label>Username: <Input @value={{@model.username}} /> </label>
|
|
3681
|
-
{{#each @model.errors.username as |error|}}
|
|
3682
|
-
<div class="error">
|
|
3683
|
-
{{error.message}}
|
|
3684
|
-
</div>
|
|
3685
|
-
{{/each}}
|
|
3686
|
-
<label>Email: <Input @value={{@model.email}} /> </label>
|
|
3687
|
-
{{#each @model.errors.email as |error|}}
|
|
3688
|
-
<div class="error">
|
|
3689
|
-
{{error.message}}
|
|
3690
|
-
</div>
|
|
3691
|
-
{{/each}}
|
|
3692
|
-
```
|
|
3693
|
-
You can also access the special `messages` property on the error
|
|
3694
|
-
object to get an array of all the error strings.
|
|
3695
|
-
```handlebars
|
|
3696
|
-
{{#each @model.errors.messages as |message|}}
|
|
3697
|
-
<div class="error">
|
|
3698
|
-
{{message}}
|
|
3699
|
-
</div>
|
|
3700
|
-
{{/each}}
|
|
3701
|
-
```
|
|
3702
|
-
@property errors
|
|
3703
|
-
@public
|
|
3704
|
-
@type {Errors}
|
|
3705
|
-
*/
|
|
3706
|
-
get errors() {
|
|
3707
|
-
const errors = Errors.create({
|
|
3708
|
-
__record: this
|
|
3709
|
-
});
|
|
3710
|
-
this.currentState.updateInvalidErrors(errors);
|
|
3711
|
-
return errors;
|
|
3712
|
-
}
|
|
3713
|
-
|
|
3714
|
-
/**
|
|
3715
|
-
This property holds the `AdapterError` object with which
|
|
3716
|
-
last adapter operation was rejected.
|
|
3717
|
-
@property adapterError
|
|
3718
|
-
@public
|
|
3719
|
-
@type {AdapterError}
|
|
3720
|
-
*/
|
|
3721
|
-
static {
|
|
3722
|
-
decorateMethodV2(this.prototype, "errors", [computeOnce]);
|
|
3723
|
-
}
|
|
3724
|
-
get adapterError() {
|
|
3725
|
-
return this.currentState.adapterError;
|
|
3726
|
-
}
|
|
3727
|
-
static {
|
|
3728
|
-
decorateMethodV2(this.prototype, "adapterError", [memoized]);
|
|
3729
|
-
}
|
|
3730
|
-
set adapterError(v) {
|
|
3731
|
-
throw new Error(`adapterError is not directly settable`);
|
|
3732
|
-
}
|
|
3733
|
-
|
|
3734
|
-
/**
|
|
3735
|
-
Create a JSON representation of the record, using the serialization
|
|
3736
|
-
strategy of the store's adapter.
|
|
3737
|
-
`serialize` takes an optional hash as a parameter, currently
|
|
3738
|
-
supported options are:
|
|
3739
|
-
- `includeId`: `true` if the record's ID should be included in the
|
|
3740
|
-
JSON representation.
|
|
3741
|
-
@method serialize
|
|
3742
|
-
@public
|
|
3743
|
-
@param {Object} options
|
|
3744
|
-
@return {Object} an object whose values are primitive JSON values only
|
|
3745
|
-
*/
|
|
3746
|
-
/*
|
|
3747
|
-
We hook the default implementation to ensure
|
|
3748
|
-
our tagged properties are properly notified
|
|
3749
|
-
as well. We still super for everything because
|
|
3750
|
-
sync observers require a direct call occuring
|
|
3751
|
-
to trigger their flush. We wouldn't need to
|
|
3752
|
-
super in 4.0+ where sync observers are removed.
|
|
3753
|
-
*/
|
|
3754
|
-
// @ts-expect-error no return is necessary, but Ember's types are forcing it
|
|
3755
|
-
notifyPropertyChange(prop) {
|
|
3756
|
-
const signals = withSignalStore(this);
|
|
3757
|
-
entangleSignal(signals, this, prop, undefined);
|
|
3758
|
-
super.notifyPropertyChange(prop);
|
|
3759
|
-
}
|
|
3760
|
-
|
|
3761
|
-
/**
|
|
3762
|
-
Marks the record as deleted but does not save it. You must call
|
|
3763
|
-
`save` afterwards if you want to persist it. You might use this
|
|
3764
|
-
method if you want to allow the user to still `rollbackAttributes()`
|
|
3765
|
-
after a delete was made.
|
|
3766
|
-
Example
|
|
3767
|
-
```js
|
|
3768
|
-
import Component from '@glimmer/component';
|
|
3769
|
-
export default class extends Component {
|
|
3770
|
-
softDelete = () => {
|
|
3771
|
-
this.args.model.deleteRecord();
|
|
3772
|
-
}
|
|
3773
|
-
confirm = () => {
|
|
3774
|
-
this.args.model.save();
|
|
3775
|
-
}
|
|
3776
|
-
undo = () => {
|
|
3777
|
-
this.args.model.rollbackAttributes();
|
|
3778
|
-
}
|
|
3779
|
-
}
|
|
3780
|
-
```
|
|
3781
|
-
@method deleteRecord
|
|
3782
|
-
@public
|
|
3783
|
-
*/
|
|
3784
|
-
|
|
3785
|
-
/**
|
|
3786
|
-
Same as `deleteRecord`, but saves the record immediately.
|
|
3787
|
-
Example
|
|
3788
|
-
```js
|
|
3789
|
-
import Component from '@glimmer/component';
|
|
3790
|
-
export default class extends Component {
|
|
3791
|
-
delete = () => {
|
|
3792
|
-
this.args.model.destroyRecord().then(function() {
|
|
3793
|
-
this.transitionToRoute('model.index');
|
|
3794
|
-
});
|
|
3795
|
-
}
|
|
3796
|
-
}
|
|
3797
|
-
```
|
|
3798
|
-
If you pass an object on the `adapterOptions` property of the options
|
|
3799
|
-
argument it will be passed to your adapter via the snapshot
|
|
3800
|
-
```js
|
|
3801
|
-
record.destroyRecord({ adapterOptions: { subscribe: false } });
|
|
3802
|
-
```
|
|
3803
|
-
```app/adapters/post.js
|
|
3804
|
-
import MyCustomAdapter from './custom-adapter';
|
|
3805
|
-
export default class PostAdapter extends MyCustomAdapter {
|
|
3806
|
-
deleteRecord(store, type, snapshot) {
|
|
3807
|
-
if (snapshot.adapterOptions.subscribe) {
|
|
3808
|
-
// ...
|
|
3809
|
-
}
|
|
3810
|
-
// ...
|
|
3811
|
-
}
|
|
3812
|
-
}
|
|
3813
|
-
```
|
|
3814
|
-
@method destroyRecord
|
|
3815
|
-
@public
|
|
3816
|
-
@param {Object} options
|
|
3817
|
-
@return {Promise} a promise that will be resolved when the adapter returns
|
|
3818
|
-
successfully or rejected if the adapter returns with an error.
|
|
3819
|
-
*/
|
|
3820
|
-
|
|
3821
|
-
/**
|
|
3822
|
-
Unloads the record from the store. This will not send a delete request
|
|
3823
|
-
to your server, it just unloads the record from memory.
|
|
3824
|
-
@method unloadRecord
|
|
3825
|
-
@public
|
|
3826
|
-
*/
|
|
3827
|
-
|
|
3828
|
-
/**
|
|
3829
|
-
Returns an object, whose keys are changed properties, and value is
|
|
3830
|
-
an [oldProp, newProp] array.
|
|
3831
|
-
The array represents the diff of the canonical state with the local state
|
|
3832
|
-
of the model. Note: if the model is created locally, the canonical state is
|
|
3833
|
-
empty since the adapter hasn't acknowledged the attributes yet:
|
|
3834
|
-
Example
|
|
3835
|
-
```app/models/mascot.js
|
|
3836
|
-
import Model, { attr } from '@ember-data/model';
|
|
3837
|
-
export default class MascotModel extends Model {
|
|
3838
|
-
@attr('string') name;
|
|
3839
|
-
@attr('boolean', {
|
|
3840
|
-
defaultValue: false
|
|
3841
|
-
})
|
|
3842
|
-
isAdmin;
|
|
3843
|
-
}
|
|
3844
|
-
```
|
|
3845
|
-
```javascript
|
|
3846
|
-
let mascot = store.createRecord('mascot');
|
|
3847
|
-
mascot.changedAttributes(); // {}
|
|
3848
|
-
mascot.set('name', 'Tomster');
|
|
3849
|
-
mascot.changedAttributes(); // { name: [undefined, 'Tomster'] }
|
|
3850
|
-
mascot.set('isAdmin', true);
|
|
3851
|
-
mascot.changedAttributes(); // { isAdmin: [undefined, true], name: [undefined, 'Tomster'] }
|
|
3852
|
-
mascot.save().then(function() {
|
|
3853
|
-
mascot.changedAttributes(); // {}
|
|
3854
|
-
mascot.set('isAdmin', false);
|
|
3855
|
-
mascot.changedAttributes(); // { isAdmin: [true, false] }
|
|
3856
|
-
});
|
|
3857
|
-
```
|
|
3858
|
-
@method changedAttributes
|
|
3859
|
-
@public
|
|
3860
|
-
@return {Object} an object, whose keys are changed properties,
|
|
3861
|
-
and value is an [oldProp, newProp] array.
|
|
3862
|
-
*/
|
|
3863
|
-
|
|
3864
|
-
/**
|
|
3865
|
-
If the model `hasDirtyAttributes` this function will discard any unsaved
|
|
3866
|
-
changes. If the model `isNew` it will be removed from the store.
|
|
3867
|
-
Example
|
|
3868
|
-
```javascript
|
|
3869
|
-
record.name; // 'Untitled Document'
|
|
3870
|
-
record.set('name', 'Doc 1');
|
|
3871
|
-
record.name; // 'Doc 1'
|
|
3872
|
-
record.rollbackAttributes();
|
|
3873
|
-
record.name; // 'Untitled Document'
|
|
3874
|
-
```
|
|
3875
|
-
@since 1.13.0
|
|
3876
|
-
@method rollbackAttributes
|
|
3877
|
-
@public
|
|
3878
|
-
*/
|
|
3879
|
-
|
|
3880
|
-
/**
|
|
3881
|
-
@method _createSnapshot
|
|
3882
|
-
@private
|
|
3883
|
-
*/
|
|
3884
|
-
// TODO @deprecate in favor of a public API or examples of how to test successfully
|
|
3885
|
-
|
|
3886
|
-
/**
|
|
3887
|
-
Save the record and persist any changes to the record to an
|
|
3888
|
-
external source via the adapter.
|
|
3889
|
-
Example
|
|
3890
|
-
```javascript
|
|
3891
|
-
record.set('name', 'Tomster');
|
|
3892
|
-
record.save().then(function() {
|
|
3893
|
-
// Success callback
|
|
3894
|
-
}, function() {
|
|
3895
|
-
// Error callback
|
|
3896
|
-
});
|
|
3897
|
-
```
|
|
3898
|
-
If you pass an object using the `adapterOptions` property of the options
|
|
3899
|
-
argument it will be passed to your adapter via the snapshot.
|
|
3900
|
-
```js
|
|
3901
|
-
record.save({ adapterOptions: { subscribe: false } });
|
|
3902
|
-
```
|
|
3903
|
-
```app/adapters/post.js
|
|
3904
|
-
import MyCustomAdapter from './custom-adapter';
|
|
3905
|
-
export default class PostAdapter extends MyCustomAdapter {
|
|
3906
|
-
updateRecord(store, type, snapshot) {
|
|
3907
|
-
if (snapshot.adapterOptions.subscribe) {
|
|
3908
|
-
// ...
|
|
3909
|
-
}
|
|
3910
|
-
// ...
|
|
3911
|
-
}
|
|
3912
|
-
}
|
|
3913
|
-
```
|
|
3914
|
-
@method save
|
|
3915
|
-
@public
|
|
3916
|
-
@param {Object} options
|
|
3917
|
-
@return {Promise} a promise that will be resolved when the adapter returns
|
|
3918
|
-
successfully or rejected if the adapter returns with an error.
|
|
3919
|
-
*/
|
|
3920
|
-
|
|
3921
|
-
/**
|
|
3922
|
-
Reload the record from the adapter.
|
|
3923
|
-
This will only work if the record has already finished loading.
|
|
3924
|
-
Example
|
|
3925
|
-
```js
|
|
3926
|
-
import Component from '@glimmer/component';
|
|
3927
|
-
export default class extends Component {
|
|
3928
|
-
async reload = () => {
|
|
3929
|
-
await this.args.model.reload();
|
|
3930
|
-
// do something with the reloaded model
|
|
3931
|
-
}
|
|
3932
|
-
}
|
|
3933
|
-
```
|
|
3934
|
-
@method reload
|
|
3935
|
-
@public
|
|
3936
|
-
@param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter request
|
|
3937
|
-
@return {Promise} a promise that will be resolved with the record when the
|
|
3938
|
-
adapter returns successfully or rejected if the adapter returns
|
|
3939
|
-
with an error.
|
|
3940
|
-
*/
|
|
3941
|
-
|
|
3942
|
-
attr() {
|
|
3943
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3944
|
-
{
|
|
3945
|
-
throw new Error('The `attr` method is not available on Model, a Snapshot was probably expected. Are you passing a Model instead of a Snapshot to your serializer?');
|
|
3946
|
-
}
|
|
3947
|
-
})() : {};
|
|
3948
|
-
}
|
|
3949
|
-
|
|
3950
|
-
/**
|
|
3951
|
-
Get the reference for the specified belongsTo relationship.
|
|
3952
|
-
For instance, given the following model
|
|
3953
|
-
```app/models/blog-post.js
|
|
3954
|
-
import Model, { belongsTo } from '@ember-data/model';
|
|
3955
|
-
export default class BlogPost extends Model {
|
|
3956
|
-
@belongsTo('user', { async: true, inverse: null }) author;
|
|
3957
|
-
}
|
|
3958
|
-
```
|
|
3959
|
-
Then the reference for the author relationship would be
|
|
3960
|
-
retrieved from a record instance like so:
|
|
3961
|
-
```js
|
|
3962
|
-
blogPost.belongsTo('author');
|
|
3963
|
-
```
|
|
3964
|
-
A `BelongsToReference` is a low-level API that allows access
|
|
3965
|
-
and manipulation of a belongsTo relationship.
|
|
3966
|
-
It is especially useful when you're dealing with `async` relationships
|
|
3967
|
-
as it allows synchronous access to the relationship data if loaded, as
|
|
3968
|
-
well as APIs for loading, reloading the data or accessing available
|
|
3969
|
-
information without triggering a load.
|
|
3970
|
-
It may also be useful when using `sync` relationships that need to be
|
|
3971
|
-
loaded/reloaded with more precise timing than marking the
|
|
3972
|
-
relationship as `async` and relying on autofetch would have allowed.
|
|
3973
|
-
However,keep in mind that marking a relationship as `async: false` will introduce
|
|
3974
|
-
bugs into your application if the data is not always guaranteed to be available
|
|
3975
|
-
by the time the relationship is accessed. Ergo, it is recommended when using this
|
|
3976
|
-
approach to utilize `links` for unloaded relationship state instead of identifiers.
|
|
3977
|
-
Reference APIs are entangled with the relationship's underlying state,
|
|
3978
|
-
thus any getters or cached properties that utilize these will properly
|
|
3979
|
-
invalidate if the relationship state changes.
|
|
3980
|
-
References are "stable", meaning that multiple calls to retrieve the reference
|
|
3981
|
-
for a given relationship will always return the same HasManyReference.
|
|
3982
|
-
@method belongsTo
|
|
3983
|
-
@public
|
|
3984
|
-
@param {String} name of the relationship
|
|
3985
|
-
@since 2.5.0
|
|
3986
|
-
@return {BelongsToReference} reference for this relationship
|
|
3987
|
-
*/
|
|
3988
|
-
|
|
3989
|
-
/**
|
|
3990
|
-
Get the reference for the specified hasMany relationship.
|
|
3991
|
-
For instance, given the following model
|
|
3992
|
-
```app/models/blog-post.js
|
|
3993
|
-
import Model, { hasMany } from '@ember-data/model';
|
|
3994
|
-
export default class BlogPost extends Model {
|
|
3995
|
-
@hasMany('comment', { async: true, inverse: null }) comments;
|
|
3996
|
-
}
|
|
3997
|
-
```
|
|
3998
|
-
Then the reference for the comments relationship would be
|
|
3999
|
-
retrieved from a record instance like so:
|
|
4000
|
-
```js
|
|
4001
|
-
blogPost.hasMany('comments');
|
|
4002
|
-
```
|
|
4003
|
-
A `HasManyReference` is a low-level API that allows access
|
|
4004
|
-
and manipulation of a hasMany relationship.
|
|
4005
|
-
It is especially useful when you are dealing with `async` relationships
|
|
4006
|
-
as it allows synchronous access to the relationship data if loaded, as
|
|
4007
|
-
well as APIs for loading, reloading the data or accessing available
|
|
4008
|
-
information without triggering a load.
|
|
4009
|
-
It may also be useful when using `sync` relationships with `@ember-data/model`
|
|
4010
|
-
that need to be loaded/reloaded with more precise timing than marking the
|
|
4011
|
-
relationship as `async` and relying on autofetch would have allowed.
|
|
4012
|
-
However,keep in mind that marking a relationship as `async: false` will introduce
|
|
4013
|
-
bugs into your application if the data is not always guaranteed to be available
|
|
4014
|
-
by the time the relationship is accessed. Ergo, it is recommended when using this
|
|
4015
|
-
approach to utilize `links` for unloaded relationship state instead of identifiers.
|
|
4016
|
-
Reference APIs are entangled with the relationship's underlying state,
|
|
4017
|
-
thus any getters or cached properties that utilize these will properly
|
|
4018
|
-
invalidate if the relationship state changes.
|
|
4019
|
-
References are "stable", meaning that multiple calls to retrieve the reference
|
|
4020
|
-
for a given relationship will always return the same HasManyReference.
|
|
4021
|
-
@method hasMany
|
|
4022
|
-
@public
|
|
4023
|
-
@param {String} name of the relationship
|
|
4024
|
-
@since 2.5.0
|
|
4025
|
-
@return {HasManyReference} reference for this relationship
|
|
4026
|
-
*/
|
|
4027
|
-
|
|
4028
|
-
/**
|
|
4029
|
-
Given a callback, iterates over each of the relationships in the model,
|
|
4030
|
-
invoking the callback with the name of each relationship and its relationship
|
|
4031
|
-
descriptor.
|
|
4032
|
-
The callback method you provide should have the following signature (all
|
|
4033
|
-
parameters are optional):
|
|
4034
|
-
```javascript
|
|
4035
|
-
function(name, descriptor);
|
|
4036
|
-
```
|
|
4037
|
-
- `name` the name of the current property in the iteration
|
|
4038
|
-
- `descriptor` the meta object that describes this relationship
|
|
4039
|
-
The relationship descriptor argument is an object with the following properties.
|
|
4040
|
-
- **name** <span class="type">String</span> the name of this relationship on the Model
|
|
4041
|
-
- **kind** <span class="type">String</span> "hasMany" or "belongsTo"
|
|
4042
|
-
- **options** <span class="type">Object</span> the original options hash passed when the relationship was declared
|
|
4043
|
-
- **parentType** <span class="type">Model</span> the type of the Model that owns this relationship
|
|
4044
|
-
- **type** <span class="type">String</span> the type name of the related Model
|
|
4045
|
-
Note that in addition to a callback, you can also pass an optional target
|
|
4046
|
-
object that will be set as `this` on the context.
|
|
4047
|
-
Example
|
|
4048
|
-
```app/serializers/application.js
|
|
4049
|
-
import JSONSerializer from '@ember-data/serializer/json';
|
|
4050
|
-
export default class ApplicationSerializer extends JSONSerializer {
|
|
4051
|
-
serialize(record, options) {
|
|
4052
|
-
let json = {};
|
|
4053
|
-
record.eachRelationship(function(name, descriptor) {
|
|
4054
|
-
if (descriptor.kind === 'hasMany') {
|
|
4055
|
-
let serializedHasManyName = name.toUpperCase() + '_IDS';
|
|
4056
|
-
json[serializedHasManyName] = record.get(name).map(r => r.id);
|
|
4057
|
-
}
|
|
4058
|
-
});
|
|
4059
|
-
return json;
|
|
4060
|
-
}
|
|
4061
|
-
}
|
|
4062
|
-
```
|
|
4063
|
-
@method eachRelationship
|
|
4064
|
-
@public
|
|
4065
|
-
@param {Function} callback the callback to invoke
|
|
4066
|
-
@param {any} binding the value to which the callback's `this` should be bound
|
|
4067
|
-
*/
|
|
4068
|
-
eachRelationship(callback, binding) {
|
|
4069
|
-
this.constructor.eachRelationship(callback, binding);
|
|
4070
|
-
}
|
|
4071
|
-
relationshipFor(name) {
|
|
4072
|
-
return this.constructor.relationshipsByName.get(name);
|
|
4073
|
-
}
|
|
4074
|
-
inverseFor(name) {
|
|
4075
|
-
return this.constructor.inverseFor(name, storeFor$1(this));
|
|
4076
|
-
}
|
|
4077
|
-
eachAttribute(callback, binding) {
|
|
4078
|
-
this.constructor.eachAttribute(callback, binding);
|
|
4079
|
-
}
|
|
4080
|
-
static isModel = true;
|
|
4081
|
-
|
|
4082
|
-
/**
|
|
4083
|
-
Create should only ever be called by the store. To create an instance of a
|
|
4084
|
-
`Model` in a dirty state use `store.createRecord`.
|
|
4085
|
-
To create instances of `Model` in a clean state, use `store.push`
|
|
4086
|
-
@method create
|
|
4087
|
-
@private
|
|
4088
|
-
@static
|
|
4089
|
-
*/
|
|
4090
|
-
|
|
4091
|
-
/**
|
|
4092
|
-
Represents the model's class name as a string. This can be used to look up the model's class name through
|
|
4093
|
-
`Store`'s modelFor method.
|
|
4094
|
-
`modelName` is generated for you by EmberData. It will be a lowercased, dasherized string.
|
|
4095
|
-
For example:
|
|
4096
|
-
```javascript
|
|
4097
|
-
store.modelFor('post').modelName; // 'post'
|
|
4098
|
-
store.modelFor('blog-post').modelName; // 'blog-post'
|
|
4099
|
-
```
|
|
4100
|
-
The most common place you'll want to access `modelName` is in your serializer's `payloadKeyFromModelName` method. For example, to change payload
|
|
4101
|
-
keys to underscore (instead of dasherized), you might use the following code:
|
|
4102
|
-
```javascript
|
|
4103
|
-
import RESTSerializer from '@ember-data/serializer/rest';
|
|
4104
|
-
import { underscore } from '<app-name>/utils/string-utils';
|
|
4105
|
-
export default const PostSerializer = RESTSerializer.extend({
|
|
4106
|
-
payloadKeyFromModelName(modelName) {
|
|
4107
|
-
return underscore(modelName);
|
|
4108
|
-
}
|
|
4109
|
-
});
|
|
4110
|
-
```
|
|
4111
|
-
@property modelName
|
|
4112
|
-
@public
|
|
4113
|
-
@type String
|
|
4114
|
-
@readonly
|
|
4115
|
-
@static
|
|
4116
|
-
*/
|
|
4117
|
-
static modelName = null;
|
|
4118
|
-
|
|
4119
|
-
/*
|
|
4120
|
-
These class methods below provide relationship
|
|
4121
|
-
introspection abilities about relationships.
|
|
4122
|
-
A note about the computed properties contained here:
|
|
4123
|
-
**These properties are effectively sealed once called for the first time.**
|
|
4124
|
-
To avoid repeatedly doing expensive iteration over a model's fields, these
|
|
4125
|
-
values are computed once and then cached for the remainder of the runtime of
|
|
4126
|
-
your application.
|
|
4127
|
-
If your application needs to modify a class after its initial definition
|
|
4128
|
-
(for example, using `reopen()` to add additional attributes), make sure you
|
|
4129
|
-
do it before using your model with the store, which uses these properties
|
|
4130
|
-
extensively.
|
|
4131
|
-
*/
|
|
4132
|
-
|
|
4133
|
-
/**
|
|
4134
|
-
For a given relationship name, returns the model type of the relationship.
|
|
4135
|
-
For example, if you define a model like this:
|
|
4136
|
-
```app/models/post.js
|
|
4137
|
-
import Model, { hasMany } from '@ember-data/model';
|
|
4138
|
-
export default class PostModel extends Model {
|
|
4139
|
-
@hasMany('comment') comments;
|
|
4140
|
-
}
|
|
4141
|
-
```
|
|
4142
|
-
Calling `store.modelFor('post').typeForRelationship('comments', store)` will return `Comment`.
|
|
4143
|
-
@method typeForRelationship
|
|
4144
|
-
@public
|
|
4145
|
-
@static
|
|
4146
|
-
@param {String} name the name of the relationship
|
|
4147
|
-
@param {store} store an instance of Store
|
|
4148
|
-
@return {Model} the type of the relationship, or undefined
|
|
4149
|
-
*/
|
|
4150
|
-
static typeForRelationship(name, store) {
|
|
4151
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4152
|
-
if (!test) {
|
|
4153
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4154
|
-
}
|
|
4155
|
-
})(this.modelName) : {};
|
|
4156
|
-
const relationship = this.relationshipsByName.get(name);
|
|
4157
|
-
return relationship && store.modelFor(relationship.type);
|
|
4158
|
-
}
|
|
4159
|
-
static get inverseMap() {
|
|
4160
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4161
|
-
if (!test) {
|
|
4162
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4163
|
-
}
|
|
4164
|
-
})(this.modelName) : {};
|
|
4165
|
-
return Object.create(null);
|
|
4166
|
-
}
|
|
4167
|
-
|
|
4168
|
-
/**
|
|
4169
|
-
Find the relationship which is the inverse of the one asked for.
|
|
4170
|
-
For example, if you define models like this:
|
|
4171
|
-
```app/models/post.js
|
|
4172
|
-
import Model, { hasMany } from '@ember-data/model';
|
|
4173
|
-
export default class PostModel extends Model {
|
|
4174
|
-
@hasMany('message') comments;
|
|
4175
|
-
}
|
|
4176
|
-
```
|
|
4177
|
-
```app/models/message.js
|
|
4178
|
-
import Model, { belongsTo } from '@ember-data/model';
|
|
4179
|
-
export default class MessageModel extends Model {
|
|
4180
|
-
@belongsTo('post') owner;
|
|
4181
|
-
}
|
|
4182
|
-
```
|
|
4183
|
-
``` js
|
|
4184
|
-
store.modelFor('post').inverseFor('comments', store) // { type: 'message', name: 'owner', kind: 'belongsTo' }
|
|
4185
|
-
store.modelFor('message').inverseFor('owner', store) // { type: 'post', name: 'comments', kind: 'hasMany' }
|
|
4186
|
-
```
|
|
4187
|
-
@method inverseFor
|
|
4188
|
-
@public
|
|
4189
|
-
@static
|
|
4190
|
-
@param {String} name the name of the relationship
|
|
4191
|
-
@param {Store} store
|
|
4192
|
-
@return {Object} the inverse relationship, or null
|
|
4193
|
-
*/
|
|
4194
|
-
static {
|
|
4195
|
-
decorateMethodV2(this, "inverseMap", [computeOnce]);
|
|
4196
|
-
}
|
|
4197
|
-
static inverseFor(name, store) {
|
|
4198
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4199
|
-
if (!test) {
|
|
4200
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4201
|
-
}
|
|
4202
|
-
})(this.modelName) : {};
|
|
4203
|
-
const inverseMap = this.inverseMap;
|
|
4204
|
-
if (inverseMap[name]) {
|
|
4205
|
-
return inverseMap[name];
|
|
4206
|
-
} else {
|
|
4207
|
-
const inverse = this._findInverseFor(name, store);
|
|
4208
|
-
inverseMap[name] = inverse;
|
|
4209
|
-
return inverse;
|
|
4210
|
-
}
|
|
4211
|
-
}
|
|
4212
|
-
|
|
4213
|
-
//Calculate the inverse, ignoring the cache
|
|
4214
|
-
static _findInverseFor(name, store) {
|
|
4215
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4216
|
-
if (!test) {
|
|
4217
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4218
|
-
}
|
|
4219
|
-
})(this.modelName) : {};
|
|
4220
|
-
const relationship = this.relationshipsByName.get(name);
|
|
4221
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4222
|
-
if (!test) {
|
|
4223
|
-
throw new Error(`No relationship named '${name}' on '${this.modelName}' exists.`);
|
|
4224
|
-
}
|
|
4225
|
-
})(relationship) : {};
|
|
4226
|
-
if (!relationship) {
|
|
4227
|
-
return null;
|
|
4228
|
-
}
|
|
4229
|
-
const {
|
|
4230
|
-
options
|
|
4231
|
-
} = relationship;
|
|
4232
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4233
|
-
if (!test) {
|
|
4234
|
-
throw new Error(`Expected the relationship ${name} on ${this.modelName} to define an inverse.`);
|
|
4235
|
-
}
|
|
4236
|
-
})(options.inverse === null || typeof options.inverse === 'string' && options.inverse.length > 0) : {};
|
|
4237
|
-
if (options.inverse === null) {
|
|
4238
|
-
return null;
|
|
4239
|
-
}
|
|
4240
|
-
const schemaExists = store.schema.hasResource(relationship);
|
|
4241
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4242
|
-
if (!test) {
|
|
4243
|
-
throw new Error(`No associated schema found for '${relationship.type}' while calculating the inverse of ${name} on ${this.modelName}`);
|
|
4244
|
-
}
|
|
4245
|
-
})(schemaExists) : {};
|
|
4246
|
-
if (!schemaExists) {
|
|
4247
|
-
return null;
|
|
4248
|
-
}
|
|
4249
|
-
const inverseField = store.schema.fields(relationship).get(options.inverse);
|
|
4250
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4251
|
-
if (!test) {
|
|
4252
|
-
throw new Error(`No inverse relationship found for '${name}' on '${this.modelName}'`);
|
|
4253
|
-
}
|
|
4254
|
-
})(inverseField && (inverseField.kind === 'belongsTo' || inverseField.kind === 'hasMany')) : {};
|
|
4255
|
-
return inverseField || null;
|
|
4256
|
-
}
|
|
4257
|
-
|
|
4258
|
-
/**
|
|
4259
|
-
The model's relationships as a map, keyed on the type of the
|
|
4260
|
-
relationship. The value of each entry is an array containing a descriptor
|
|
4261
|
-
for each relationship with that type, describing the name of the relationship
|
|
4262
|
-
as well as the type.
|
|
4263
|
-
For example, given the following model definition:
|
|
4264
|
-
```app/models/blog.js
|
|
4265
|
-
import Model, { belongsTo, hasMany } from '@ember-data/model';
|
|
4266
|
-
export default class BlogModel extends Model {
|
|
4267
|
-
@hasMany('user') users;
|
|
4268
|
-
@belongsTo('user') owner;
|
|
4269
|
-
@hasMany('post') posts;
|
|
4270
|
-
}
|
|
4271
|
-
```
|
|
4272
|
-
This computed property would return a map describing these
|
|
4273
|
-
relationships, like this:
|
|
4274
|
-
```javascript
|
|
4275
|
-
import Blog from 'app/models/blog';
|
|
4276
|
-
import User from 'app/models/user';
|
|
4277
|
-
import Post from 'app/models/post';
|
|
4278
|
-
let relationships = Blog.relationships;
|
|
4279
|
-
relationships.user;
|
|
4280
|
-
//=> [ { name: 'users', kind: 'hasMany' },
|
|
4281
|
-
// { name: 'owner', kind: 'belongsTo' } ]
|
|
4282
|
-
relationships.post;
|
|
4283
|
-
//=> [ { name: 'posts', kind: 'hasMany' } ]
|
|
4284
|
-
```
|
|
4285
|
-
@property relationships
|
|
4286
|
-
@public
|
|
4287
|
-
@static
|
|
4288
|
-
@type Map
|
|
4289
|
-
@readOnly
|
|
4290
|
-
*/
|
|
4291
|
-
|
|
4292
|
-
static get relationships() {
|
|
4293
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4294
|
-
if (!test) {
|
|
4295
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4296
|
-
}
|
|
4297
|
-
})(this.modelName) : {};
|
|
4298
|
-
const map = new Map();
|
|
4299
|
-
const relationshipsByName = this.relationshipsByName;
|
|
4300
|
-
|
|
4301
|
-
// Loop through each computed property on the class
|
|
4302
|
-
relationshipsByName.forEach(desc => {
|
|
4303
|
-
const {
|
|
4304
|
-
type
|
|
4305
|
-
} = desc;
|
|
4306
|
-
if (!map.has(type)) {
|
|
4307
|
-
map.set(type, []);
|
|
4308
|
-
}
|
|
4309
|
-
map.get(type).push(desc);
|
|
4310
|
-
});
|
|
4311
|
-
return map;
|
|
4312
|
-
}
|
|
4313
|
-
|
|
4314
|
-
/**
|
|
4315
|
-
A hash containing lists of the model's relationships, grouped
|
|
4316
|
-
by the relationship kind. For example, given a model with this
|
|
4317
|
-
definition:
|
|
4318
|
-
```app/models/blog.js
|
|
4319
|
-
import Model, { belongsTo, hasMany } from '@ember-data/model';
|
|
4320
|
-
export default class BlogModel extends Model {
|
|
4321
|
-
@hasMany('user') users;
|
|
4322
|
-
@belongsTo('user') owner;
|
|
4323
|
-
@hasMany('post') posts;
|
|
4324
|
-
}
|
|
4325
|
-
```
|
|
4326
|
-
This property would contain the following:
|
|
4327
|
-
```javascript
|
|
4328
|
-
import Blog from 'app/models/blog';
|
|
4329
|
-
let relationshipNames = Blog.relationshipNames;
|
|
4330
|
-
relationshipNames.hasMany;
|
|
4331
|
-
//=> ['users', 'posts']
|
|
4332
|
-
relationshipNames.belongsTo;
|
|
4333
|
-
//=> ['owner']
|
|
4334
|
-
```
|
|
4335
|
-
@property relationshipNames
|
|
4336
|
-
@public
|
|
4337
|
-
@static
|
|
4338
|
-
@type Object
|
|
4339
|
-
@readOnly
|
|
4340
|
-
*/
|
|
4341
|
-
static {
|
|
4342
|
-
decorateMethodV2(this, "relationships", [computeOnce]);
|
|
4343
|
-
}
|
|
4344
|
-
static get relationshipNames() {
|
|
4345
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4346
|
-
if (!test) {
|
|
4347
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4348
|
-
}
|
|
4349
|
-
})(this.modelName) : {};
|
|
4350
|
-
const names = {
|
|
4351
|
-
hasMany: [],
|
|
4352
|
-
belongsTo: []
|
|
4353
|
-
};
|
|
4354
|
-
this.eachComputedProperty((name, meta) => {
|
|
4355
|
-
if (isRelationshipSchema(meta)) {
|
|
4356
|
-
names[meta.kind].push(name);
|
|
4357
|
-
}
|
|
4358
|
-
});
|
|
4359
|
-
return names;
|
|
4360
|
-
}
|
|
4361
|
-
|
|
4362
|
-
/**
|
|
4363
|
-
An array of types directly related to a model. Each type will be
|
|
4364
|
-
included once, regardless of the number of relationships it has with
|
|
4365
|
-
the model.
|
|
4366
|
-
For example, given a model with this definition:
|
|
4367
|
-
```app/models/blog.js
|
|
4368
|
-
import Model, { belongsTo, hasMany } from '@ember-data/model';
|
|
4369
|
-
export default class BlogModel extends Model {
|
|
4370
|
-
@hasMany('user') users;
|
|
4371
|
-
@belongsTo('user') owner;
|
|
4372
|
-
@hasMany('post') posts;
|
|
4373
|
-
}
|
|
4374
|
-
```
|
|
4375
|
-
This property would contain the following:
|
|
4376
|
-
```javascript
|
|
4377
|
-
import Blog from 'app/models/blog';
|
|
4378
|
-
let relatedTypes = Blog.relatedTypes');
|
|
4379
|
-
//=> ['user', 'post']
|
|
4380
|
-
```
|
|
4381
|
-
@property relatedTypes
|
|
4382
|
-
@public
|
|
4383
|
-
@static
|
|
4384
|
-
@type Array
|
|
4385
|
-
@readOnly
|
|
4386
|
-
*/
|
|
4387
|
-
static {
|
|
4388
|
-
decorateMethodV2(this, "relationshipNames", [computeOnce]);
|
|
4389
|
-
}
|
|
4390
|
-
static get relatedTypes() {
|
|
4391
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4392
|
-
if (!test) {
|
|
4393
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4394
|
-
}
|
|
4395
|
-
})(this.modelName) : {};
|
|
4396
|
-
const types = [];
|
|
4397
|
-
const rels = this.relationshipsObject;
|
|
4398
|
-
const relationships = Object.keys(rels);
|
|
4399
|
-
|
|
4400
|
-
// create an array of the unique types involved
|
|
4401
|
-
// in relationships
|
|
4402
|
-
for (let i = 0; i < relationships.length; i++) {
|
|
4403
|
-
const name = relationships[i];
|
|
4404
|
-
const meta = rels[name];
|
|
4405
|
-
const modelName = meta.type;
|
|
4406
|
-
if (!types.includes(modelName)) {
|
|
4407
|
-
types.push(modelName);
|
|
4408
|
-
}
|
|
4409
|
-
}
|
|
4410
|
-
return types;
|
|
4411
|
-
}
|
|
4412
|
-
|
|
4413
|
-
/**
|
|
4414
|
-
A map whose keys are the relationships of a model and whose values are
|
|
4415
|
-
relationship descriptors.
|
|
4416
|
-
For example, given a model with this
|
|
4417
|
-
definition:
|
|
4418
|
-
```app/models/blog.js
|
|
4419
|
-
import Model, { belongsTo, hasMany } from '@ember-data/model';
|
|
4420
|
-
export default class BlogModel extends Model {
|
|
4421
|
-
@hasMany('user') users;
|
|
4422
|
-
@belongsTo('user') owner;
|
|
4423
|
-
@hasMany('post') posts;
|
|
4424
|
-
}
|
|
4425
|
-
```
|
|
4426
|
-
This property would contain the following:
|
|
4427
|
-
```javascript
|
|
4428
|
-
import Blog from 'app/models/blog';
|
|
4429
|
-
let relationshipsByName = Blog.relationshipsByName;
|
|
4430
|
-
relationshipsByName.users;
|
|
4431
|
-
//=> { name: 'users', kind: 'hasMany', type: 'user', options: Object }
|
|
4432
|
-
relationshipsByName.owner;
|
|
4433
|
-
//=> { name: 'owner', kind: 'belongsTo', type: 'user', options: Object }
|
|
4434
|
-
```
|
|
4435
|
-
@property relationshipsByName
|
|
4436
|
-
@public
|
|
4437
|
-
@static
|
|
4438
|
-
@type Map
|
|
4439
|
-
@readOnly
|
|
4440
|
-
*/
|
|
4441
|
-
static {
|
|
4442
|
-
decorateMethodV2(this, "relatedTypes", [computeOnce]);
|
|
4443
|
-
}
|
|
4444
|
-
static get relationshipsByName() {
|
|
4445
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4446
|
-
if (!test) {
|
|
4447
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4448
|
-
}
|
|
4449
|
-
})(this.modelName) : {};
|
|
4450
|
-
const map = new Map();
|
|
4451
|
-
const rels = this.relationshipsObject;
|
|
4452
|
-
const relationships = Object.keys(rels);
|
|
4453
|
-
for (let i = 0; i < relationships.length; i++) {
|
|
4454
|
-
const name = relationships[i];
|
|
4455
|
-
const value = rels[name];
|
|
4456
|
-
map.set(value.name, value);
|
|
4457
|
-
}
|
|
4458
|
-
return map;
|
|
4459
|
-
}
|
|
4460
|
-
static {
|
|
4461
|
-
decorateMethodV2(this, "relationshipsByName", [computeOnce]);
|
|
4462
|
-
}
|
|
4463
|
-
static get relationshipsObject() {
|
|
4464
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4465
|
-
if (!test) {
|
|
4466
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4467
|
-
}
|
|
4468
|
-
})(this.modelName) : {};
|
|
4469
|
-
const relationships = Object.create(null);
|
|
4470
|
-
const modelName = this.modelName;
|
|
4471
|
-
this.eachComputedProperty((name, meta) => {
|
|
4472
|
-
if (!isRelationshipSchema(meta)) {
|
|
4473
|
-
return;
|
|
4474
|
-
}
|
|
4475
|
-
// TODO deprecate key being here
|
|
4476
|
-
meta.key = name;
|
|
4477
|
-
meta.name = name;
|
|
4478
|
-
relationships[name] = meta;
|
|
4479
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4480
|
-
if (!test) {
|
|
4481
|
-
throw new Error(`Expected options in meta`);
|
|
4482
|
-
}
|
|
4483
|
-
})(meta.options && typeof meta.options === 'object') : {};
|
|
4484
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4485
|
-
if (!test) {
|
|
4486
|
-
throw new Error(`You should not specify both options.as and options.inverse as null on ${modelName}.${meta.name}, as if there is no inverse field there is no abstract type to conform to. You may have intended for this relationship to be polymorphic, or you may have mistakenly set inverse to null.`);
|
|
4487
|
-
}
|
|
4488
|
-
})(!(meta.options.inverse === null && meta.options.as?.length)) : {};
|
|
4489
|
-
});
|
|
4490
|
-
return relationships;
|
|
4491
|
-
}
|
|
4492
|
-
|
|
4493
|
-
/**
|
|
4494
|
-
A map whose keys are the fields of the model and whose values are strings
|
|
4495
|
-
describing the kind of the field. A model's fields are the union of all of its
|
|
4496
|
-
attributes and relationships.
|
|
4497
|
-
For example:
|
|
4498
|
-
```app/models/blog.js
|
|
4499
|
-
import Model, { attr, belongsTo, hasMany } from '@ember-data/model';
|
|
4500
|
-
export default class BlogModel extends Model {
|
|
4501
|
-
@hasMany('user') users;
|
|
4502
|
-
@belongsTo('user') owner;
|
|
4503
|
-
@hasMany('post') posts;
|
|
4504
|
-
@attr('string') title;
|
|
4505
|
-
}
|
|
4506
|
-
```
|
|
4507
|
-
```js
|
|
4508
|
-
import Blog from 'app/models/blog'
|
|
4509
|
-
let fields = Blog.fields;
|
|
4510
|
-
fields.forEach(function(kind, field) {
|
|
4511
|
-
// do thing
|
|
4512
|
-
});
|
|
4513
|
-
// prints:
|
|
4514
|
-
// users, hasMany
|
|
4515
|
-
// owner, belongsTo
|
|
4516
|
-
// posts, hasMany
|
|
4517
|
-
// title, attribute
|
|
4518
|
-
```
|
|
4519
|
-
@property fields
|
|
4520
|
-
@public
|
|
4521
|
-
@static
|
|
4522
|
-
@type Map
|
|
4523
|
-
@readOnly
|
|
4524
|
-
*/
|
|
4525
|
-
static {
|
|
4526
|
-
decorateMethodV2(this, "relationshipsObject", [computeOnce]);
|
|
4527
|
-
}
|
|
4528
|
-
static get fields() {
|
|
4529
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4530
|
-
if (!test) {
|
|
4531
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4532
|
-
}
|
|
4533
|
-
})(this.modelName) : {};
|
|
4534
|
-
const map = new Map();
|
|
4535
|
-
this.eachComputedProperty((name, meta) => {
|
|
4536
|
-
if (isRelationshipSchema(meta)) {
|
|
4537
|
-
map.set(name, meta.kind);
|
|
4538
|
-
} else if (isAttributeSchema(meta)) {
|
|
4539
|
-
map.set(name, 'attribute');
|
|
4540
|
-
}
|
|
4541
|
-
});
|
|
4542
|
-
return map;
|
|
4543
|
-
}
|
|
4544
|
-
|
|
4545
|
-
/**
|
|
4546
|
-
Given a callback, iterates over each of the relationships in the model,
|
|
4547
|
-
invoking the callback with the name of each relationship and its relationship
|
|
4548
|
-
descriptor.
|
|
4549
|
-
@method eachRelationship
|
|
4550
|
-
@public
|
|
4551
|
-
@static
|
|
4552
|
-
@param {Function} callback the callback to invoke
|
|
4553
|
-
@param {any} binding the value to which the callback's `this` should be bound
|
|
4554
|
-
*/
|
|
4555
|
-
static {
|
|
4556
|
-
decorateMethodV2(this, "fields", [computeOnce]);
|
|
4557
|
-
}
|
|
4558
|
-
static eachRelationship(callback, binding) {
|
|
4559
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4560
|
-
if (!test) {
|
|
4561
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4562
|
-
}
|
|
4563
|
-
})(this.modelName) : {};
|
|
4564
|
-
this.relationshipsByName.forEach((relationship, name) => {
|
|
4565
|
-
callback.call(binding, name, relationship);
|
|
4566
|
-
});
|
|
4567
|
-
}
|
|
4568
|
-
|
|
4569
|
-
/**
|
|
4570
|
-
Given a callback, iterates over each of the types related to a model,
|
|
4571
|
-
invoking the callback with the related type's class. Each type will be
|
|
4572
|
-
returned just once, regardless of how many different relationships it has
|
|
4573
|
-
with a model.
|
|
4574
|
-
@method eachRelatedType
|
|
4575
|
-
@public
|
|
4576
|
-
@static
|
|
4577
|
-
@param {Function} callback the callback to invoke
|
|
4578
|
-
@param {any} binding the value to which the callback's `this` should be bound
|
|
4579
|
-
*/
|
|
4580
|
-
static eachRelatedType(callback, binding) {
|
|
4581
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4582
|
-
if (!test) {
|
|
4583
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4584
|
-
}
|
|
4585
|
-
})(this.modelName) : {};
|
|
4586
|
-
const relationshipTypes = this.relatedTypes;
|
|
4587
|
-
for (let i = 0; i < relationshipTypes.length; i++) {
|
|
4588
|
-
const type = relationshipTypes[i];
|
|
4589
|
-
callback.call(binding, type);
|
|
4590
|
-
}
|
|
4591
|
-
}
|
|
4592
|
-
|
|
4593
|
-
/**
|
|
4594
|
-
*
|
|
4595
|
-
* @method determineRelationshipType
|
|
4596
|
-
* @private
|
|
4597
|
-
* @deprecated
|
|
4598
|
-
*/
|
|
4599
|
-
static determineRelationshipType(knownSide, store) {
|
|
4600
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4601
|
-
if (!test) {
|
|
4602
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4603
|
-
}
|
|
4604
|
-
})(this.modelName) : {};
|
|
4605
|
-
const knownKey = knownSide.name;
|
|
4606
|
-
const knownKind = knownSide.kind;
|
|
4607
|
-
const inverse = this.inverseFor(knownKey, store);
|
|
4608
|
-
// let key;
|
|
4609
|
-
|
|
4610
|
-
if (!inverse) {
|
|
4611
|
-
return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone';
|
|
4612
|
-
}
|
|
4613
|
-
|
|
4614
|
-
// key = inverse.name;
|
|
4615
|
-
const otherKind = inverse.kind;
|
|
4616
|
-
if (otherKind === 'belongsTo') {
|
|
4617
|
-
return knownKind === 'belongsTo' ? 'oneToOne' : 'manyToOne';
|
|
4618
|
-
} else {
|
|
4619
|
-
return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany';
|
|
4620
|
-
}
|
|
4621
|
-
}
|
|
4622
|
-
|
|
4623
|
-
/**
|
|
4624
|
-
A map whose keys are the attributes of the model (properties
|
|
4625
|
-
described by attr) and whose values are the meta object for the
|
|
4626
|
-
property.
|
|
4627
|
-
Example
|
|
4628
|
-
```app/models/person.js
|
|
4629
|
-
import Model, { attr } from '@ember-data/model';
|
|
4630
|
-
export default class PersonModel extends Model {
|
|
4631
|
-
@attr('string') firstName;
|
|
4632
|
-
@attr('string') lastName;
|
|
4633
|
-
@attr('date') birthday;
|
|
4634
|
-
}
|
|
4635
|
-
```
|
|
4636
|
-
```javascript
|
|
4637
|
-
import Person from 'app/models/person'
|
|
4638
|
-
let attributes = Person.attributes
|
|
4639
|
-
attributes.forEach(function(meta, name) {
|
|
4640
|
-
// do thing
|
|
4641
|
-
});
|
|
4642
|
-
// prints:
|
|
4643
|
-
// firstName {type: "string", kind: 'attribute', options: Object, parentType: function, name: "firstName"}
|
|
4644
|
-
// lastName {type: "string", kind: 'attribute', options: Object, parentType: function, name: "lastName"}
|
|
4645
|
-
// birthday {type: "date", kind: 'attribute', options: Object, parentType: function, name: "birthday"}
|
|
4646
|
-
```
|
|
4647
|
-
@property attributes
|
|
4648
|
-
@public
|
|
4649
|
-
@static
|
|
4650
|
-
@type {Map}
|
|
4651
|
-
@readOnly
|
|
4652
|
-
*/
|
|
4653
|
-
static get attributes() {
|
|
4654
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4655
|
-
if (!test) {
|
|
4656
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4657
|
-
}
|
|
4658
|
-
})(this.modelName) : {};
|
|
4659
|
-
const map = new Map();
|
|
4660
|
-
this.eachComputedProperty((name, meta) => {
|
|
4661
|
-
if (isAttributeSchema(meta)) {
|
|
4662
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4663
|
-
if (!test) {
|
|
4664
|
-
throw new Error("You may not set 'id' as an attribute on your model. Please remove any lines that look like: `id: attr('<type>')` from " + this.toString());
|
|
4665
|
-
}
|
|
4666
|
-
})(name !== 'id') : {};
|
|
4667
|
-
|
|
4668
|
-
// TODO deprecate key being here
|
|
4669
|
-
meta.key = name;
|
|
4670
|
-
meta.name = name;
|
|
4671
|
-
map.set(name, meta);
|
|
4672
|
-
}
|
|
4673
|
-
});
|
|
4674
|
-
return map;
|
|
4675
|
-
}
|
|
4676
|
-
|
|
4677
|
-
/**
|
|
4678
|
-
A map whose keys are the attributes of the model (properties
|
|
4679
|
-
described by attr) and whose values are type of transformation
|
|
4680
|
-
applied to each attribute. This map does not include any
|
|
4681
|
-
attributes that do not have an transformation type.
|
|
4682
|
-
Example
|
|
4683
|
-
```app/models/person.js
|
|
4684
|
-
import Model, { attr } from '@ember-data/model';
|
|
4685
|
-
export default class PersonModel extends Model {
|
|
4686
|
-
@attr firstName;
|
|
4687
|
-
@attr('string') lastName;
|
|
4688
|
-
@attr('date') birthday;
|
|
4689
|
-
}
|
|
4690
|
-
```
|
|
4691
|
-
```javascript
|
|
4692
|
-
import Person from 'app/models/person';
|
|
4693
|
-
let transformedAttributes = Person.transformedAttributes
|
|
4694
|
-
transformedAttributes.forEach(function(field, type) {
|
|
4695
|
-
// do thing
|
|
4696
|
-
});
|
|
4697
|
-
// prints:
|
|
4698
|
-
// lastName string
|
|
4699
|
-
// birthday date
|
|
4700
|
-
```
|
|
4701
|
-
@property transformedAttributes
|
|
4702
|
-
@public
|
|
4703
|
-
@static
|
|
4704
|
-
@type {Map}
|
|
4705
|
-
@readOnly
|
|
4706
|
-
*/
|
|
4707
|
-
static {
|
|
4708
|
-
decorateMethodV2(this, "attributes", [computeOnce]);
|
|
4709
|
-
}
|
|
4710
|
-
static get transformedAttributes() {
|
|
4711
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4712
|
-
if (!test) {
|
|
4713
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4714
|
-
}
|
|
4715
|
-
})(this.modelName) : {};
|
|
4716
|
-
const map = new Map();
|
|
4717
|
-
this.eachAttribute((name, meta) => {
|
|
4718
|
-
if (meta.type) {
|
|
4719
|
-
map.set(name, meta.type);
|
|
4720
|
-
}
|
|
4721
|
-
});
|
|
4722
|
-
return map;
|
|
4723
|
-
}
|
|
4724
|
-
|
|
4725
|
-
/**
|
|
4726
|
-
Iterates through the attributes of the model, calling the passed function on each
|
|
4727
|
-
attribute.
|
|
4728
|
-
The callback method you provide should have the following signature (all
|
|
4729
|
-
parameters are optional):
|
|
4730
|
-
```javascript
|
|
4731
|
-
function(name, meta);
|
|
4732
|
-
```
|
|
4733
|
-
- `name` the name of the current property in the iteration
|
|
4734
|
-
- `meta` the meta object for the attribute property in the iteration
|
|
4735
|
-
Note that in addition to a callback, you can also pass an optional target
|
|
4736
|
-
object that will be set as `this` on the context.
|
|
4737
|
-
Example
|
|
4738
|
-
```javascript
|
|
4739
|
-
import Model, { attr } from '@ember-data/model';
|
|
4740
|
-
class PersonModel extends Model {
|
|
4741
|
-
@attr('string') firstName;
|
|
4742
|
-
@attr('string') lastName;
|
|
4743
|
-
@attr('date') birthday;
|
|
4744
|
-
}
|
|
4745
|
-
PersonModel.eachAttribute(function(name, meta) {
|
|
4746
|
-
// do thing
|
|
4747
|
-
});
|
|
4748
|
-
// prints:
|
|
4749
|
-
// firstName {type: "string", kind: 'attribute', options: Object, parentType: function, name: "firstName"}
|
|
4750
|
-
// lastName {type: "string", kind: 'attribute', options: Object, parentType: function, name: "lastName"}
|
|
4751
|
-
// birthday {type: "date", kind: 'attribute', options: Object, parentType: function, name: "birthday"}
|
|
4752
|
-
```
|
|
4753
|
-
@method eachAttribute
|
|
4754
|
-
@public
|
|
4755
|
-
@param {Function} callback The callback to execute
|
|
4756
|
-
@param {Object} [binding] the value to which the callback's `this` should be bound
|
|
4757
|
-
@static
|
|
4758
|
-
*/
|
|
4759
|
-
static {
|
|
4760
|
-
decorateMethodV2(this, "transformedAttributes", [computeOnce]);
|
|
4761
|
-
}
|
|
4762
|
-
static eachAttribute(callback, binding) {
|
|
4763
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4764
|
-
if (!test) {
|
|
4765
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4766
|
-
}
|
|
4767
|
-
})(this.modelName) : {};
|
|
4768
|
-
this.attributes.forEach((meta, name) => {
|
|
4769
|
-
callback.call(binding, name, meta);
|
|
4770
|
-
});
|
|
4771
|
-
}
|
|
4772
|
-
|
|
4773
|
-
/**
|
|
4774
|
-
Iterates through the transformedAttributes of the model, calling
|
|
4775
|
-
the passed function on each attribute. Note the callback will not be
|
|
4776
|
-
called for any attributes that do not have an transformation type.
|
|
4777
|
-
The callback method you provide should have the following signature (all
|
|
4778
|
-
parameters are optional):
|
|
4779
|
-
```javascript
|
|
4780
|
-
function(name, type);
|
|
4781
|
-
```
|
|
4782
|
-
- `name` the name of the current property in the iteration
|
|
4783
|
-
- `type` a string containing the name of the type of transformed
|
|
4784
|
-
applied to the attribute
|
|
4785
|
-
Note that in addition to a callback, you can also pass an optional target
|
|
4786
|
-
object that will be set as `this` on the context.
|
|
4787
|
-
Example
|
|
4788
|
-
```javascript
|
|
4789
|
-
import Model, { attr } from '@ember-data/model';
|
|
4790
|
-
let Person = Model.extend({
|
|
4791
|
-
firstName: attr(),
|
|
4792
|
-
lastName: attr('string'),
|
|
4793
|
-
birthday: attr('date')
|
|
4794
|
-
});
|
|
4795
|
-
Person.eachTransformedAttribute(function(name, type) {
|
|
4796
|
-
// do thing
|
|
4797
|
-
});
|
|
4798
|
-
// prints:
|
|
4799
|
-
// lastName string
|
|
4800
|
-
// birthday date
|
|
4801
|
-
```
|
|
4802
|
-
@method eachTransformedAttribute
|
|
4803
|
-
@public
|
|
4804
|
-
@param {Function} callback The callback to execute
|
|
4805
|
-
@param {Object} [binding] the value to which the callback's `this` should be bound
|
|
4806
|
-
@static
|
|
4807
|
-
*/
|
|
4808
|
-
static eachTransformedAttribute(callback, binding) {
|
|
4809
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4810
|
-
if (!test) {
|
|
4811
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4812
|
-
}
|
|
4813
|
-
})(this.modelName) : {};
|
|
4814
|
-
this.transformedAttributes.forEach((type, name) => {
|
|
4815
|
-
callback.call(binding, name, type);
|
|
4816
|
-
});
|
|
4817
|
-
}
|
|
4818
|
-
|
|
4819
|
-
/**
|
|
4820
|
-
Returns the name of the model class.
|
|
4821
|
-
@method toString
|
|
4822
|
-
@public
|
|
4823
|
-
@static
|
|
4824
|
-
*/
|
|
4825
|
-
static toString() {
|
|
4826
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4827
|
-
if (!test) {
|
|
4828
|
-
throw new Error(`Accessing schema information on Models without looking up the model via the store is disallowed.`);
|
|
4829
|
-
}
|
|
4830
|
-
})(this.modelName) : {};
|
|
4831
|
-
return `model:${this.modelName}`;
|
|
4832
|
-
}
|
|
4833
|
-
}
|
|
4834
|
-
|
|
4835
|
-
// @ts-expect-error TS doesn't know how to do `this` function overloads
|
|
4836
|
-
Model.prototype.save = save;
|
|
4837
|
-
// @ts-expect-error TS doesn't know how to do `this` function overloads
|
|
4838
|
-
Model.prototype.destroyRecord = destroyRecord;
|
|
4839
|
-
Model.prototype.unloadRecord = unloadRecord;
|
|
4840
|
-
Model.prototype.hasMany = hasMany;
|
|
4841
|
-
Model.prototype.belongsTo = belongsTo;
|
|
4842
|
-
Model.prototype.serialize = serialize;
|
|
4843
|
-
Model.prototype._createSnapshot = createSnapshot;
|
|
4844
|
-
Model.prototype.deleteRecord = deleteRecord;
|
|
4845
|
-
Model.prototype.changedAttributes = changedAttributes;
|
|
4846
|
-
Model.prototype.rollbackAttributes = rollbackAttributes;
|
|
4847
|
-
Model.prototype.reload = reload;
|
|
4848
|
-
defineSignal(Model.prototype, 'isReloading', false);
|
|
4849
|
-
|
|
4850
|
-
// this is required to prevent `init` from passing
|
|
4851
|
-
// the values initialized during create to `setUnknownProperty`
|
|
4852
|
-
Model.prototype._createProps = null;
|
|
4853
|
-
Model.prototype._secretInit = null;
|
|
4854
|
-
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
4855
|
-
const lookupDescriptor = function lookupDescriptor(obj, keyName) {
|
|
4856
|
-
let current = obj;
|
|
4857
|
-
do {
|
|
4858
|
-
const descriptor = Object.getOwnPropertyDescriptor(current, keyName);
|
|
4859
|
-
if (descriptor !== undefined) {
|
|
4860
|
-
return descriptor;
|
|
4861
|
-
}
|
|
4862
|
-
current = Object.getPrototypeOf(current);
|
|
4863
|
-
} while (current !== null);
|
|
4864
|
-
return null;
|
|
4865
|
-
};
|
|
4866
|
-
|
|
4867
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
4868
|
-
const init = Model.prototype.init;
|
|
4869
|
-
Model.prototype.init = function (createArgs) {
|
|
4870
|
-
init.call(this, createArgs);
|
|
4871
|
-
const ourDescriptor = lookupDescriptor(Model.prototype, 'currentState');
|
|
4872
|
-
const theirDescriptor = lookupDescriptor(this, 'currentState');
|
|
4873
|
-
if (!ourDescriptor || !theirDescriptor) {
|
|
4874
|
-
throw new Error(`Unable to determine if 'currentState' is a reserved property name on instances of classes extending Model. Please ensure that 'currentState' is not defined as a property on ${this.constructor.toString()}`);
|
|
4875
|
-
}
|
|
4876
|
-
const realState = this.___recordState;
|
|
4877
|
-
if (ourDescriptor.get !== theirDescriptor.get || realState !== this.currentState) {
|
|
4878
|
-
throw new Error(`'currentState' is a reserved property name on instances of classes extending Model. Please choose a different property name for ${this.constructor.toString()}`);
|
|
4879
|
-
}
|
|
4880
|
-
const ID_DESCRIPTOR = lookupDescriptor(Model.prototype, 'id');
|
|
4881
|
-
const idDesc = lookupDescriptor(this, 'id');
|
|
4882
|
-
if (!ID_DESCRIPTOR || !idDesc) {
|
|
4883
|
-
throw new Error(`Unable to determine if 'id' is a reserved property name on instances of classes extending Model. Please ensure that 'id' is not defined as a property on ${this.constructor.toString()}`);
|
|
4884
|
-
}
|
|
4885
|
-
if (idDesc.get !== ID_DESCRIPTOR.get) {
|
|
4886
|
-
throw new Error(`You may not set 'id' as an attribute on your model. Please remove any lines that look like: \`id: attr('<type>')\` from ${this.constructor.toString()}`);
|
|
4887
|
-
}
|
|
4888
|
-
};
|
|
4889
|
-
delete Model.reopen;
|
|
4890
|
-
delete Model.reopenClass;
|
|
4891
|
-
}
|
|
4892
|
-
function isRelationshipSchema(meta) {
|
|
4893
|
-
const hasKind = typeof meta === 'object' && meta !== null && 'kind' in meta && 'options' in meta;
|
|
4894
|
-
return hasKind && (meta.kind === 'hasMany' || meta.kind === 'belongsTo');
|
|
4895
|
-
}
|
|
4896
|
-
function isAttributeSchema(meta) {
|
|
4897
|
-
return typeof meta === 'object' && meta !== null && 'kind' in meta && meta.kind === 'attribute';
|
|
4898
|
-
}
|
|
4899
|
-
export { Errors as E, LEGACY_SUPPORT as L, Model as M, PromiseBelongsTo as P, RecordState as R, PromiseManyArray as a, save as b, reload as c, destroyRecord as d, deleteRecord as e, changedAttributes as f, belongsTo as g, hasMany as h, createSnapshot as i, isElementDescriptor as j, lookupLegacySupport as l, normalizeModelName as n, rollbackAttributes as r, serialize as s, unloadRecord as u };
|
|
2605
|
+
export { Errors as E, LEGACY_SUPPORT as L, PromiseBelongsTo as P, PromiseManyArray as a, decorateMethodV2 as d, lookupLegacySupport as l };
|