@ember-data/model 5.3.0-alpha.1 → 5.3.0-alpha.11
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/addon/-private.js +2 -37
- package/addon/-private.js.map +1 -1
- package/addon/has-many-f41d4b96.js +507 -0
- package/addon/has-many-f41d4b96.js.map +1 -0
- package/addon/hooks-0482f3cc.js +157 -0
- package/addon/hooks-0482f3cc.js.map +1 -0
- package/addon/hooks.js +1 -0
- package/addon/hooks.js.map +1 -0
- package/addon/index.js +3 -1
- package/addon/index.js.map +1 -1
- package/addon/{index-8a7de041.js → model-48ae96f9.js} +82 -580
- package/addon/model-48ae96f9.js.map +1 -0
- package/package.json +27 -27
- package/addon/index-8a7de041.js.map +0 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { macroCondition, getOwnConfig, importSync } from '@embroider/macros';
|
|
2
|
-
import { assert, warn } from '@ember/debug';
|
|
3
|
-
import EmberObject, { computed, get } from '@ember/object';
|
|
4
|
-
import { recordIdentifierFor, storeFor as storeFor$1 } from '@ember-data/store';
|
|
5
|
-
import { peekCache, RecordArray, MUTATE, SOURCE, recordIdentifierFor as recordIdentifierFor$1, IDENTIFIER_ARRAY_TAG, notifyArray, isStableIdentifier, storeFor, fastPush, coerceId } from '@ember-data/store/-private';
|
|
2
|
+
import { deprecate, assert, warn } from '@ember/debug';
|
|
6
3
|
import { dasherize } from '@ember/string';
|
|
4
|
+
import EmberObject, { computed, get } from '@ember/object';
|
|
7
5
|
import { dependentKeyCompat } from '@ember/object/compat';
|
|
8
6
|
import { run } from '@ember/runloop';
|
|
9
7
|
import { cached, tracked } from '@glimmer/tracking';
|
|
10
8
|
import Ember from 'ember';
|
|
9
|
+
import { recordIdentifierFor as recordIdentifierFor$1, storeFor as storeFor$1 } from '@ember-data/store';
|
|
10
|
+
import { RecordArray, MUTATE, SOURCE, recordIdentifierFor, IDENTIFIER_ARRAY_TAG, notifyArray, isStableIdentifier, storeFor, peekCache, fastPush, coerceId } from '@ember-data/store/-private';
|
|
11
11
|
import { A } from '@ember/array';
|
|
12
12
|
import ArrayProxy from '@ember/array/proxy';
|
|
13
13
|
import { mapBy, not } from '@ember/object/computed';
|
|
@@ -15,7 +15,6 @@ import PromiseProxyMixin from '@ember/object/promise-proxy-mixin';
|
|
|
15
15
|
import ObjectProxy from '@ember/object/proxy';
|
|
16
16
|
import { cacheFor } from '@ember/object/internals';
|
|
17
17
|
import { addToTransaction, subscribe } from '@ember-data/tracking/-private';
|
|
18
|
-
import { singularize } from 'ember-inflector';
|
|
19
18
|
function isElementDescriptor(args) {
|
|
20
19
|
let [maybeTarget, maybeKey, maybeDesc] = args;
|
|
21
20
|
return (
|
|
@@ -34,152 +33,22 @@ function isElementDescriptor(args) {
|
|
|
34
33
|
function computedMacroWithOptionalParams(fn) {
|
|
35
34
|
return (...maybeDesc) => isElementDescriptor(maybeDesc) ? fn()(...maybeDesc) : fn(...maybeDesc);
|
|
36
35
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
`boolean` and `date`. You can define your own transforms by subclassing
|
|
48
|
-
[Transform](/ember-data/release/classes/Transform).
|
|
49
|
-
|
|
50
|
-
Note that you cannot use `attr` to define an attribute of `id`.
|
|
51
|
-
|
|
52
|
-
`attr` takes an optional hash as a second parameter, currently
|
|
53
|
-
supported options are:
|
|
54
|
-
|
|
55
|
-
- `defaultValue`: Pass a string or a function to be called to set the attribute
|
|
56
|
-
to a default value if and only if the key is absent from the payload response.
|
|
57
|
-
|
|
58
|
-
Example
|
|
59
|
-
|
|
60
|
-
```app/models/user.js
|
|
61
|
-
import Model, { attr } from '@ember-data/model';
|
|
62
|
-
|
|
63
|
-
export default class UserModel extends Model {
|
|
64
|
-
@attr('string') username;
|
|
65
|
-
@attr('string') email;
|
|
66
|
-
@attr('boolean', { defaultValue: false }) verified;
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Default value can also be a function. This is useful it you want to return
|
|
71
|
-
a new object for each attribute.
|
|
72
|
-
|
|
73
|
-
```app/models/user.js
|
|
74
|
-
import Model, { attr } from '@ember-data/model';
|
|
75
|
-
|
|
76
|
-
export default class UserModel extends Model {
|
|
77
|
-
@attr('string') username;
|
|
78
|
-
@attr('string') email;
|
|
79
|
-
|
|
80
|
-
@attr({
|
|
81
|
-
defaultValue() {
|
|
82
|
-
return {};
|
|
36
|
+
function normalizeModelName(type) {
|
|
37
|
+
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_NON_STRICT_TYPES)) {
|
|
38
|
+
const result = dasherize(type);
|
|
39
|
+
deprecate(`The resource type '${type}' is not normalized. Update your application code to use '${result}' instead of '${type}'.`, result === type, {
|
|
40
|
+
id: 'ember-data:deprecate-non-strict-types',
|
|
41
|
+
until: '6.0',
|
|
42
|
+
for: 'ember-data',
|
|
43
|
+
since: {
|
|
44
|
+
available: '5.3',
|
|
45
|
+
enabled: '5.3'
|
|
83
46
|
}
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
The `options` hash is passed as second argument to a transforms'
|
|
90
|
-
`serialize` and `deserialize` method. This allows to configure a
|
|
91
|
-
transformation and adapt the corresponding value, based on the config:
|
|
92
|
-
|
|
93
|
-
```app/models/post.js
|
|
94
|
-
import Model, { attr } from '@ember-data/model';
|
|
95
|
-
|
|
96
|
-
export default class PostModel extends Model {
|
|
97
|
-
@attr('text', {
|
|
98
|
-
uppercase: true
|
|
99
|
-
})
|
|
100
|
-
text;
|
|
101
|
-
}
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
```app/transforms/text.js
|
|
105
|
-
export default class TextTransform {
|
|
106
|
-
serialize(value, options) {
|
|
107
|
-
if (options.uppercase) {
|
|
108
|
-
return value.toUpperCase();
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return value;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
deserialize(value) {
|
|
115
|
-
return value;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
static create() {
|
|
119
|
-
return new this();
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
@method attr
|
|
125
|
-
@public
|
|
126
|
-
@static
|
|
127
|
-
@for @ember-data/model
|
|
128
|
-
@param {String|Object} type the attribute type
|
|
129
|
-
@param {Object} options a hash of options
|
|
130
|
-
@return {Attribute}
|
|
131
|
-
*/
|
|
132
|
-
function attr(type, options) {
|
|
133
|
-
if (typeof type === 'object') {
|
|
134
|
-
options = type;
|
|
135
|
-
type = undefined;
|
|
136
|
-
} else {
|
|
137
|
-
options = options || {};
|
|
47
|
+
});
|
|
48
|
+
return result;
|
|
138
49
|
}
|
|
139
|
-
|
|
140
|
-
type: type,
|
|
141
|
-
isAttribute: true,
|
|
142
|
-
options: options
|
|
143
|
-
};
|
|
144
|
-
return computed({
|
|
145
|
-
get(key) {
|
|
146
|
-
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
147
|
-
if (['currentState'].indexOf(key) !== -1) {
|
|
148
|
-
throw new Error(`'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your attr on ${this.constructor.toString()}`);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
if (this.isDestroyed || this.isDestroying) {
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
return peekCache(this).getAttr(recordIdentifierFor(this), key);
|
|
155
|
-
},
|
|
156
|
-
set(key, value) {
|
|
157
|
-
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
158
|
-
if (['currentState'].indexOf(key) !== -1) {
|
|
159
|
-
throw new Error(`'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your attr on ${this.constructor.toString()}`);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
assert(`Attempted to set '${key}' on the deleted record ${recordIdentifierFor(this)}`, !this.currentState.isDeleted);
|
|
163
|
-
const identifier = recordIdentifierFor(this);
|
|
164
|
-
const cache = peekCache(this);
|
|
165
|
-
let currentValue = cache.getAttr(identifier, key);
|
|
166
|
-
if (currentValue !== value) {
|
|
167
|
-
cache.setAttr(identifier, key, value);
|
|
168
|
-
if (!this.isValid) {
|
|
169
|
-
const {
|
|
170
|
-
errors
|
|
171
|
-
} = this;
|
|
172
|
-
if (errors.get(key)) {
|
|
173
|
-
errors.remove(key);
|
|
174
|
-
this.currentState.cleanErrorRequests();
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
return value;
|
|
179
|
-
}
|
|
180
|
-
}).meta(meta);
|
|
50
|
+
return type;
|
|
181
51
|
}
|
|
182
|
-
var attr$1 = computedMacroWithOptionalParams(attr);
|
|
183
52
|
function _initializerDefineProperty(target, property, descriptor, context) {
|
|
184
53
|
if (!descriptor) return;
|
|
185
54
|
Object.defineProperty(target, property, {
|
|
@@ -728,7 +597,7 @@ class RelatedCollection extends RecordArray {
|
|
|
728
597
|
op: 'removeFromRelatedRecords',
|
|
729
598
|
record: this.identifier,
|
|
730
599
|
field: this.key,
|
|
731
|
-
value: recordIdentifierFor
|
|
600
|
+
value: recordIdentifierFor(result)
|
|
732
601
|
});
|
|
733
602
|
}
|
|
734
603
|
break;
|
|
@@ -747,7 +616,7 @@ class RelatedCollection extends RecordArray {
|
|
|
747
616
|
op: 'removeFromRelatedRecords',
|
|
748
617
|
record: this.identifier,
|
|
749
618
|
field: this.key,
|
|
750
|
-
value: recordIdentifierFor
|
|
619
|
+
value: recordIdentifierFor(result),
|
|
751
620
|
index: 0
|
|
752
621
|
});
|
|
753
622
|
}
|
|
@@ -757,7 +626,7 @@ class RelatedCollection extends RecordArray {
|
|
|
757
626
|
op: 'sortRelatedRecords',
|
|
758
627
|
record: this.identifier,
|
|
759
628
|
field: this.key,
|
|
760
|
-
value: result.map(recordIdentifierFor
|
|
629
|
+
value: result.map(recordIdentifierFor)
|
|
761
630
|
});
|
|
762
631
|
break;
|
|
763
632
|
case 'splice':
|
|
@@ -778,7 +647,7 @@ class RelatedCollection extends RecordArray {
|
|
|
778
647
|
op: 'removeFromRelatedRecords',
|
|
779
648
|
record: this.identifier,
|
|
780
649
|
field: this.key,
|
|
781
|
-
value: result.map(recordIdentifierFor
|
|
650
|
+
value: result.map(recordIdentifierFor),
|
|
782
651
|
index: start
|
|
783
652
|
});
|
|
784
653
|
}
|
|
@@ -858,6 +727,9 @@ class RelatedCollection extends RecordArray {
|
|
|
858
727
|
this.push(record);
|
|
859
728
|
return record;
|
|
860
729
|
}
|
|
730
|
+
destroy() {
|
|
731
|
+
super.destroy(false);
|
|
732
|
+
}
|
|
861
733
|
}
|
|
862
734
|
RelatedCollection.prototype.isAsync = false;
|
|
863
735
|
RelatedCollection.prototype.isPolymorphic = false;
|
|
@@ -869,7 +741,7 @@ RelatedCollection.prototype.DEPRECATED_CLASS_NAME = 'ManyArray';
|
|
|
869
741
|
function assertRecordPassedToHasMany(record) {
|
|
870
742
|
assert(`All elements of a hasMany relationship must be instances of Model, you passed $${typeof record}`, function () {
|
|
871
743
|
try {
|
|
872
|
-
recordIdentifierFor
|
|
744
|
+
recordIdentifierFor(record);
|
|
873
745
|
return true;
|
|
874
746
|
} catch {
|
|
875
747
|
return false;
|
|
@@ -881,7 +753,7 @@ function extractIdentifiersFromRecords(records) {
|
|
|
881
753
|
}
|
|
882
754
|
function extractIdentifierFromRecord$1(recordOrPromiseRecord) {
|
|
883
755
|
assertRecordPassedToHasMany(recordOrPromiseRecord);
|
|
884
|
-
return recordIdentifierFor
|
|
756
|
+
return recordIdentifierFor(recordOrPromiseRecord);
|
|
885
757
|
}
|
|
886
758
|
const PromiseObject = ObjectProxy.extend(PromiseProxyMixin);
|
|
887
759
|
var _dec, _class$5;
|
|
@@ -919,7 +791,7 @@ let PromiseBelongsTo = (_dec = computed(), (_class$5 = class PromiseBelongsTo ex
|
|
|
919
791
|
get meta() {
|
|
920
792
|
// eslint-disable-next-line no-constant-condition
|
|
921
793
|
{
|
|
922
|
-
assert('You attempted to access meta on the promise for the async belongsTo relationship ' + `${this.
|
|
794
|
+
assert('You attempted to access meta on the promise for the async belongsTo relationship ' + `${this._belongsToState.modelName}:${this._belongsToState.key}'.` + '\nUse `record.belongsTo(relationshipName).meta()` instead.', false);
|
|
923
795
|
}
|
|
924
796
|
return;
|
|
925
797
|
}
|
|
@@ -1224,12 +1096,8 @@ function isResourceIdentiferWithRelatedLinks$1(value) {
|
|
|
1224
1096
|
@public
|
|
1225
1097
|
*/
|
|
1226
1098
|
let BelongsToReference = (_class$3 = class BelongsToReference {
|
|
1227
|
-
// unsubscribe tokens given to us by the notification manager
|
|
1228
|
-
|
|
1229
1099
|
constructor(store, graph, parentIdentifier, belongsToRelationship, key) {
|
|
1230
|
-
|
|
1231
|
-
this.___token = void 0;
|
|
1232
|
-
this.___relatedToken = null;
|
|
1100
|
+
// unsubscribe tokens given to us by the notification manager
|
|
1233
1101
|
_initializerDefineProperty(this, "_ref", _descriptor$3, this);
|
|
1234
1102
|
this.graph = graph;
|
|
1235
1103
|
this.key = key;
|
|
@@ -1237,6 +1105,7 @@ let BelongsToReference = (_class$3 = class BelongsToReference {
|
|
|
1237
1105
|
this.type = belongsToRelationship.definition.type;
|
|
1238
1106
|
this.store = store;
|
|
1239
1107
|
this.___identifier = parentIdentifier;
|
|
1108
|
+
this.___relatedToken = null;
|
|
1240
1109
|
this.___token = store.notifications.subscribe(parentIdentifier, (_, bucket, notifiedKey) => {
|
|
1241
1110
|
if (bucket === 'relationships' && notifiedKey === key) {
|
|
1242
1111
|
this._ref++;
|
|
@@ -1512,7 +1381,7 @@ let BelongsToReference = (_class$3 = class BelongsToReference {
|
|
|
1512
1381
|
let record = this.store.push(jsonApiDoc);
|
|
1513
1382
|
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
1514
1383
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
1515
|
-
assertPolymorphicType(this.belongsToRelationship.identifier, this.belongsToRelationship.definition, recordIdentifierFor
|
|
1384
|
+
assertPolymorphicType(this.belongsToRelationship.identifier, this.belongsToRelationship.definition, recordIdentifierFor(record), this.store);
|
|
1516
1385
|
}
|
|
1517
1386
|
const {
|
|
1518
1387
|
identifier
|
|
@@ -1522,7 +1391,7 @@ let BelongsToReference = (_class$3 = class BelongsToReference {
|
|
|
1522
1391
|
op: 'replaceRelatedRecord',
|
|
1523
1392
|
record: identifier,
|
|
1524
1393
|
field: this.key,
|
|
1525
|
-
value: recordIdentifierFor
|
|
1394
|
+
value: recordIdentifierFor(record)
|
|
1526
1395
|
});
|
|
1527
1396
|
});
|
|
1528
1397
|
return Promise.resolve(record);
|
|
@@ -1704,9 +1573,8 @@ function isResourceIdentiferWithRelatedLinks(value) {
|
|
|
1704
1573
|
@extends Reference
|
|
1705
1574
|
*/
|
|
1706
1575
|
let HasManyReference = (_class$2 = class HasManyReference {
|
|
1707
|
-
// unsubscribe tokens given to us by the notification manager
|
|
1708
|
-
|
|
1709
1576
|
constructor(store, graph, parentIdentifier, hasManyRelationship, key) {
|
|
1577
|
+
// unsubscribe tokens given to us by the notification manager
|
|
1710
1578
|
this.___token = void 0;
|
|
1711
1579
|
this.___identifier = void 0;
|
|
1712
1580
|
this.___relatedTokenMap = void 0;
|
|
@@ -2010,9 +1878,9 @@ let HasManyReference = (_class$2 = class HasManyReference {
|
|
|
2010
1878
|
let identifier = this.hasManyRelationship.identifier;
|
|
2011
1879
|
|
|
2012
1880
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
2013
|
-
assertPolymorphicType(identifier, relationshipMeta, recordIdentifierFor(record), store);
|
|
1881
|
+
assertPolymorphicType(identifier, relationshipMeta, recordIdentifierFor$1(record), store);
|
|
2014
1882
|
}
|
|
2015
|
-
return recordIdentifierFor(record);
|
|
1883
|
+
return recordIdentifierFor$1(record);
|
|
2016
1884
|
});
|
|
2017
1885
|
const {
|
|
2018
1886
|
identifier
|
|
@@ -2199,8 +2067,12 @@ class LegacySupport {
|
|
|
2199
2067
|
constructor(record) {
|
|
2200
2068
|
this.record = record;
|
|
2201
2069
|
this.store = storeFor(record);
|
|
2202
|
-
this.identifier = recordIdentifierFor
|
|
2070
|
+
this.identifier = recordIdentifierFor(record);
|
|
2203
2071
|
this.cache = peekCache(record);
|
|
2072
|
+
if (macroCondition(getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
|
|
2073
|
+
const graphFor = importSync('@ember-data/graph/-private').graphFor;
|
|
2074
|
+
this.graph = graphFor(this.store);
|
|
2075
|
+
}
|
|
2204
2076
|
this._manyArrayCache = Object.create(null);
|
|
2205
2077
|
this._relationshipPromisesCache = Object.create(null);
|
|
2206
2078
|
this._relationshipProxyCache = Object.create(null);
|
|
@@ -2237,14 +2109,14 @@ class LegacySupport {
|
|
|
2237
2109
|
if (loadingPromise) {
|
|
2238
2110
|
return loadingPromise;
|
|
2239
2111
|
}
|
|
2240
|
-
const
|
|
2241
|
-
const relationship = graphFor(this.store).get(this.identifier, key);
|
|
2112
|
+
const relationship = this.graph.get(this.identifier, key);
|
|
2242
2113
|
assert(`Expected ${key} to be a belongs-to relationship`, isBelongsTo(relationship));
|
|
2243
2114
|
let resource = this.cache.getRelationship(this.identifier, key);
|
|
2244
2115
|
relationship.state.hasFailedLoadAttempt = false;
|
|
2245
2116
|
relationship.state.shouldForceReload = true;
|
|
2246
2117
|
let promise = this._findBelongsTo(key, resource, relationship, options);
|
|
2247
2118
|
if (this._relationshipProxyCache[key]) {
|
|
2119
|
+
// @ts-expect-error
|
|
2248
2120
|
return this._updatePromiseProxyFor('belongsTo', key, {
|
|
2249
2121
|
promise
|
|
2250
2122
|
});
|
|
@@ -2260,8 +2132,7 @@ class LegacySupport {
|
|
|
2260
2132
|
let relatedIdentifier = resource && resource.data ? resource.data : null;
|
|
2261
2133
|
assert(`Expected a stable identifier`, !relatedIdentifier || isStableIdentifier(relatedIdentifier));
|
|
2262
2134
|
const store = this.store;
|
|
2263
|
-
const
|
|
2264
|
-
const relationship = graphFor(store).get(this.identifier, key);
|
|
2135
|
+
const relationship = this.graph.get(this.identifier, key);
|
|
2265
2136
|
assert(`Expected ${key} to be a belongs-to relationship`, isBelongsTo(relationship));
|
|
2266
2137
|
let isAsync = relationship.definition.isAsync;
|
|
2267
2138
|
let _belongsToState = {
|
|
@@ -2307,10 +2178,10 @@ class LegacySupport {
|
|
|
2307
2178
|
let identifiers = [];
|
|
2308
2179
|
if (jsonApi.data) {
|
|
2309
2180
|
for (let i = 0; i < jsonApi.data.length; i++) {
|
|
2310
|
-
const
|
|
2311
|
-
assert(`Expected a stable identifier`, isStableIdentifier(
|
|
2312
|
-
if (cache.recordIsLoaded(
|
|
2313
|
-
identifiers.push(
|
|
2181
|
+
const relatedIdentifier = jsonApi.data[i];
|
|
2182
|
+
assert(`Expected a stable identifier`, isStableIdentifier(relatedIdentifier));
|
|
2183
|
+
if (cache.recordIsLoaded(relatedIdentifier, true)) {
|
|
2184
|
+
identifiers.push(relatedIdentifier);
|
|
2314
2185
|
}
|
|
2315
2186
|
}
|
|
2316
2187
|
}
|
|
@@ -2320,8 +2191,7 @@ class LegacySupport {
|
|
|
2320
2191
|
if (macroCondition(getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
|
|
2321
2192
|
let manyArray = this._manyArrayCache[key];
|
|
2322
2193
|
if (!definition) {
|
|
2323
|
-
|
|
2324
|
-
definition = graphFor(this.store).get(this.identifier, key).definition;
|
|
2194
|
+
definition = this.graph.get(this.identifier, key).definition;
|
|
2325
2195
|
}
|
|
2326
2196
|
if (!manyArray) {
|
|
2327
2197
|
const [identifiers, doc] = this._getCurrentState(this.identifier, key);
|
|
@@ -2371,8 +2241,7 @@ class LegacySupport {
|
|
|
2371
2241
|
if (loadingPromise) {
|
|
2372
2242
|
return loadingPromise;
|
|
2373
2243
|
}
|
|
2374
|
-
const
|
|
2375
|
-
const relationship = graphFor(this.store).get(this.identifier, key);
|
|
2244
|
+
const relationship = this.graph.get(this.identifier, key);
|
|
2376
2245
|
const {
|
|
2377
2246
|
definition,
|
|
2378
2247
|
state
|
|
@@ -2392,8 +2261,7 @@ class LegacySupport {
|
|
|
2392
2261
|
}
|
|
2393
2262
|
getHasMany(key, options) {
|
|
2394
2263
|
if (macroCondition(getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
|
|
2395
|
-
const
|
|
2396
|
-
const relationship = graphFor(this.store).get(this.identifier, key);
|
|
2264
|
+
const relationship = this.graph.get(this.identifier, key);
|
|
2397
2265
|
const {
|
|
2398
2266
|
definition,
|
|
2399
2267
|
state
|
|
@@ -2455,21 +2323,23 @@ class LegacySupport {
|
|
|
2455
2323
|
// because of the intimate API access involved. This is something we will need to redesign.
|
|
2456
2324
|
assert(`snapshot.belongsTo only supported for @ember-data/json-api`);
|
|
2457
2325
|
}
|
|
2458
|
-
const
|
|
2459
|
-
|
|
2460
|
-
|
|
2326
|
+
const {
|
|
2327
|
+
graph,
|
|
2328
|
+
identifier
|
|
2329
|
+
} = this;
|
|
2330
|
+
const relationship = graph.get(identifier, name);
|
|
2461
2331
|
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
2462
2332
|
if (kind) {
|
|
2463
|
-
let modelName =
|
|
2333
|
+
let modelName = identifier.type;
|
|
2464
2334
|
let actualRelationshipKind = relationship.definition.kind;
|
|
2465
2335
|
assert(`You tried to get the '${name}' relationship on a '${modelName}' via record.${kind}('${name}'), but the relationship is of kind '${actualRelationshipKind}'. Use record.${actualRelationshipKind}('${name}') instead.`, actualRelationshipKind === kind);
|
|
2466
2336
|
}
|
|
2467
2337
|
}
|
|
2468
2338
|
let relationshipKind = relationship.definition.kind;
|
|
2469
2339
|
if (relationshipKind === 'belongsTo') {
|
|
2470
|
-
reference = new BelongsToReference(this.store, graph,
|
|
2340
|
+
reference = new BelongsToReference(this.store, graph, identifier, relationship, name);
|
|
2471
2341
|
} else if (relationshipKind === 'hasMany') {
|
|
2472
|
-
reference = new HasManyReference(this.store, graph,
|
|
2342
|
+
reference = new HasManyReference(this.store, graph, identifier, relationship, name);
|
|
2473
2343
|
}
|
|
2474
2344
|
this.references[name] = reference;
|
|
2475
2345
|
}
|
|
@@ -2699,7 +2569,7 @@ function extractIdentifierFromRecord(record) {
|
|
|
2699
2569
|
if (!record) {
|
|
2700
2570
|
return null;
|
|
2701
2571
|
}
|
|
2702
|
-
return recordIdentifierFor
|
|
2572
|
+
return recordIdentifierFor(record);
|
|
2703
2573
|
}
|
|
2704
2574
|
function anyUnloaded(store, relationship) {
|
|
2705
2575
|
let state = relationship.localState;
|
|
@@ -2733,8 +2603,8 @@ function notifyChanges(identifier, value, key, record, store) {
|
|
|
2733
2603
|
if (key) {
|
|
2734
2604
|
notifyAttribute(store, identifier, key, record);
|
|
2735
2605
|
} else {
|
|
2736
|
-
record.eachAttribute(
|
|
2737
|
-
notifyAttribute(store, identifier,
|
|
2606
|
+
record.eachAttribute(name => {
|
|
2607
|
+
notifyAttribute(store, identifier, name, record);
|
|
2738
2608
|
});
|
|
2739
2609
|
}
|
|
2740
2610
|
} else if (value === 'relationships') {
|
|
@@ -2742,8 +2612,8 @@ function notifyChanges(identifier, value, key, record, store) {
|
|
|
2742
2612
|
let meta = record.constructor.relationshipsByName.get(key);
|
|
2743
2613
|
notifyRelationship(identifier, key, record, meta);
|
|
2744
2614
|
} else {
|
|
2745
|
-
record.eachRelationship((
|
|
2746
|
-
notifyRelationship(identifier,
|
|
2615
|
+
record.eachRelationship((name, meta) => {
|
|
2616
|
+
notifyRelationship(identifier, name, record, meta);
|
|
2747
2617
|
});
|
|
2748
2618
|
}
|
|
2749
2619
|
} else if (value === 'identity') {
|
|
@@ -2803,6 +2673,11 @@ function isInvalidError(error) {
|
|
|
2803
2673
|
let Tag = (_class$1 = class Tag {
|
|
2804
2674
|
constructor() {
|
|
2805
2675
|
_initializerDefineProperty(this, "ref", _descriptor$1, this);
|
|
2676
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
2677
|
+
const [base, prop] = arguments;
|
|
2678
|
+
this._debug_base = base;
|
|
2679
|
+
this._debug_prop = prop;
|
|
2680
|
+
}
|
|
2806
2681
|
this.rev = 1;
|
|
2807
2682
|
this.isDirty = true;
|
|
2808
2683
|
this.value = undefined;
|
|
@@ -2835,7 +2710,8 @@ function getTag(record, key) {
|
|
|
2835
2710
|
tags = Object.create(null);
|
|
2836
2711
|
Tags.set(record, tags);
|
|
2837
2712
|
}
|
|
2838
|
-
|
|
2713
|
+
// @ts-expect-error
|
|
2714
|
+
return tags[key] = tags[key] || (macroCondition(getOwnConfig().env.DEBUG) ? new Tag(record.constructor.modelName, key) : new Tag());
|
|
2839
2715
|
}
|
|
2840
2716
|
function peekTag(record, key) {
|
|
2841
2717
|
let tags = Tags.get(record);
|
|
@@ -2913,7 +2789,7 @@ let RecordState = (_class3 = class RecordState {
|
|
|
2913
2789
|
constructor(record) {
|
|
2914
2790
|
_initializerDefineProperty(this, "isSaving", _descriptor2, this);
|
|
2915
2791
|
const store = storeFor$1(record);
|
|
2916
|
-
const identity = recordIdentifierFor
|
|
2792
|
+
const identity = recordIdentifierFor(record);
|
|
2917
2793
|
this.identifier = identity;
|
|
2918
2794
|
this.record = record;
|
|
2919
2795
|
this.cache = store.cache;
|
|
@@ -3184,7 +3060,7 @@ const {
|
|
|
3184
3060
|
} = Ember;
|
|
3185
3061
|
const LEGACY_SUPPORT = new Map();
|
|
3186
3062
|
function lookupLegacySupport(record) {
|
|
3187
|
-
const identifier = recordIdentifierFor(record);
|
|
3063
|
+
const identifier = recordIdentifierFor$1(record);
|
|
3188
3064
|
let support = LEGACY_SUPPORT.get(identifier);
|
|
3189
3065
|
if (!support) {
|
|
3190
3066
|
assert(`Memory Leak Detected`, !record.isDestroyed && !record.isDestroying);
|
|
@@ -3301,7 +3177,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
3301
3177
|
});
|
|
3302
3178
|
}
|
|
3303
3179
|
destroy() {
|
|
3304
|
-
const identifier = recordIdentifierFor(this);
|
|
3180
|
+
const identifier = recordIdentifierFor$1(this);
|
|
3305
3181
|
this.___recordState?.destroy();
|
|
3306
3182
|
const store = storeFor$1(this);
|
|
3307
3183
|
store.notifications.unsubscribe(this.___private_notifications);
|
|
@@ -3565,16 +3441,16 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
3565
3441
|
// object is real.
|
|
3566
3442
|
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
3567
3443
|
try {
|
|
3568
|
-
return recordIdentifierFor(this).id;
|
|
3444
|
+
return recordIdentifierFor$1(this).id;
|
|
3569
3445
|
} catch {
|
|
3570
3446
|
return void 0;
|
|
3571
3447
|
}
|
|
3572
3448
|
}
|
|
3573
|
-
return recordIdentifierFor(this).id;
|
|
3449
|
+
return recordIdentifierFor$1(this).id;
|
|
3574
3450
|
}
|
|
3575
3451
|
set id(id) {
|
|
3576
3452
|
const normalizedId = coerceId(id);
|
|
3577
|
-
const identifier = recordIdentifierFor(this);
|
|
3453
|
+
const identifier = recordIdentifierFor$1(this);
|
|
3578
3454
|
let didChange = normalizedId !== identifier.id;
|
|
3579
3455
|
assert(`Cannot set ${identifier.type} record's id to ${id}, because id is already ${identifier.id}`, !didChange || identifier.id === null);
|
|
3580
3456
|
if (normalizedId !== null && didChange) {
|
|
@@ -3866,7 +3742,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
3866
3742
|
and value is an [oldProp, newProp] array.
|
|
3867
3743
|
*/
|
|
3868
3744
|
changedAttributes() {
|
|
3869
|
-
return peekCache(this).changedAttrs(recordIdentifierFor(this));
|
|
3745
|
+
return peekCache(this).changedAttrs(recordIdentifierFor$1(this));
|
|
3870
3746
|
}
|
|
3871
3747
|
|
|
3872
3748
|
/**
|
|
@@ -3892,7 +3768,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
3892
3768
|
isNew
|
|
3893
3769
|
} = currentState;
|
|
3894
3770
|
storeFor$1(this)._join(() => {
|
|
3895
|
-
peekCache(this).rollbackAttrs(recordIdentifierFor(this));
|
|
3771
|
+
peekCache(this).rollbackAttrs(recordIdentifierFor$1(this));
|
|
3896
3772
|
this.errors.clear();
|
|
3897
3773
|
currentState.cleanErrorRequests();
|
|
3898
3774
|
if (isNew) {
|
|
@@ -3912,7 +3788,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
3912
3788
|
const FetchManager = importSync('@ember-data/legacy-compat/-private').FetchManager;
|
|
3913
3789
|
store._fetchManager = new FetchManager(store);
|
|
3914
3790
|
}
|
|
3915
|
-
return store._fetchManager.createSnapshot(recordIdentifierFor(this));
|
|
3791
|
+
return store._fetchManager.createSnapshot(recordIdentifierFor$1(this));
|
|
3916
3792
|
}
|
|
3917
3793
|
|
|
3918
3794
|
/**
|
|
@@ -3954,6 +3830,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
3954
3830
|
if (this.currentState.isNew && this.currentState.isDeleted) {
|
|
3955
3831
|
promise = Promise.resolve(this);
|
|
3956
3832
|
} else {
|
|
3833
|
+
this.errors.clear();
|
|
3957
3834
|
promise = storeFor$1(this).saveRecord(this, options);
|
|
3958
3835
|
}
|
|
3959
3836
|
return promise;
|
|
@@ -3985,7 +3862,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
3985
3862
|
reload(options = {}) {
|
|
3986
3863
|
options.isReloading = true;
|
|
3987
3864
|
options.reload = true;
|
|
3988
|
-
const identifier = recordIdentifierFor(this);
|
|
3865
|
+
const identifier = recordIdentifierFor$1(this);
|
|
3989
3866
|
assert(`You cannot reload a record without an ID`, identifier.id);
|
|
3990
3867
|
this.isReloading = true;
|
|
3991
3868
|
const promise = storeFor$1(this).request({
|
|
@@ -4167,41 +4044,6 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4167
4044
|
eachAttribute(callback, binding) {
|
|
4168
4045
|
this.constructor.eachAttribute(callback, binding);
|
|
4169
4046
|
}
|
|
4170
|
-
|
|
4171
|
-
/**
|
|
4172
|
-
Create should only ever be called by the store. To create an instance of a
|
|
4173
|
-
`Model` in a dirty state use `store.createRecord`.
|
|
4174
|
-
To create instances of `Model` in a clean state, use `store.push`
|
|
4175
|
-
@method create
|
|
4176
|
-
@private
|
|
4177
|
-
@static
|
|
4178
|
-
*/
|
|
4179
|
-
/**
|
|
4180
|
-
Represents the model's class name as a string. This can be used to look up the model's class name through
|
|
4181
|
-
`Store`'s modelFor method.
|
|
4182
|
-
`modelName` is generated for you by Ember Data. It will be a lowercased, dasherized string.
|
|
4183
|
-
For example:
|
|
4184
|
-
```javascript
|
|
4185
|
-
store.modelFor('post').modelName; // 'post'
|
|
4186
|
-
store.modelFor('blog-post').modelName; // 'blog-post'
|
|
4187
|
-
```
|
|
4188
|
-
The most common place you'll want to access `modelName` is in your serializer's `payloadKeyFromModelName` method. For example, to change payload
|
|
4189
|
-
keys to underscore (instead of dasherized), you might use the following code:
|
|
4190
|
-
```javascript
|
|
4191
|
-
import RESTSerializer from '@ember-data/serializer/rest';
|
|
4192
|
-
import { underscore } from '<app-name>/utils/string-utils';
|
|
4193
|
-
export default const PostSerializer = RESTSerializer.extend({
|
|
4194
|
-
payloadKeyFromModelName(modelName) {
|
|
4195
|
-
return underscore(modelName);
|
|
4196
|
-
}
|
|
4197
|
-
});
|
|
4198
|
-
```
|
|
4199
|
-
@property modelName
|
|
4200
|
-
@public
|
|
4201
|
-
@type String
|
|
4202
|
-
@readonly
|
|
4203
|
-
@static
|
|
4204
|
-
*/
|
|
4205
4047
|
/*
|
|
4206
4048
|
These class methods below provide relationship
|
|
4207
4049
|
introspection abilities about relationships.
|
|
@@ -4868,7 +4710,7 @@ if (macroCondition(getOwnConfig().includeDataAdapter)) {
|
|
|
4868
4710
|
Model.prototype._debugInfo = function () {
|
|
4869
4711
|
let relationships = {};
|
|
4870
4712
|
let expensiveProperties = [];
|
|
4871
|
-
const identifier = recordIdentifierFor(this);
|
|
4713
|
+
const identifier = recordIdentifierFor$1(this);
|
|
4872
4714
|
const schema = this.store.getSchemaDefinitionService();
|
|
4873
4715
|
const attrDefs = schema.attributesDefinitionFor(identifier);
|
|
4874
4716
|
const relDefs = schema.relationshipsDefinitionFor(identifier);
|
|
@@ -4943,344 +4785,4 @@ if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
|
4943
4785
|
assert(`Model.reopenClass is deprecated. Use Foo extends Model to add static methods and properties to your class instead.`);
|
|
4944
4786
|
};
|
|
4945
4787
|
}
|
|
4946
|
-
|
|
4947
|
-
return dasherize(type);
|
|
4948
|
-
}
|
|
4949
|
-
/**
|
|
4950
|
-
@module @ember-data/model
|
|
4951
|
-
*/
|
|
4952
|
-
|
|
4953
|
-
/**
|
|
4954
|
-
`belongsTo` is used to define One-To-One and One-To-Many
|
|
4955
|
-
relationships on a [Model](/ember-data/release/classes/Model).
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
`belongsTo` takes an optional hash as a second parameter, currently
|
|
4959
|
-
supported options are:
|
|
4960
|
-
|
|
4961
|
-
- `async`: A boolean value used to explicitly declare this to be an async relationship. The default is true.
|
|
4962
|
-
- `inverse`: A string used to identify the inverse property on a
|
|
4963
|
-
related model in a One-To-Many relationship. See [Explicit Inverses](#explicit-inverses)
|
|
4964
|
-
- `polymorphic` A boolean value to mark the relationship as polymorphic
|
|
4965
|
-
|
|
4966
|
-
#### One-To-One
|
|
4967
|
-
To declare a one-to-one relationship between two models, use
|
|
4968
|
-
`belongsTo`:
|
|
4969
|
-
|
|
4970
|
-
```app/models/user.js
|
|
4971
|
-
import Model, { belongsTo } from '@ember-data/model';
|
|
4972
|
-
|
|
4973
|
-
export default class UserModel extends Model {
|
|
4974
|
-
@belongsTo('profile') profile;
|
|
4975
|
-
}
|
|
4976
|
-
```
|
|
4977
|
-
|
|
4978
|
-
```app/models/profile.js
|
|
4979
|
-
import Model, { belongsTo } from '@ember-data/model';
|
|
4980
|
-
|
|
4981
|
-
export default class ProfileModel extends Model {
|
|
4982
|
-
@belongsTo('user') user;
|
|
4983
|
-
}
|
|
4984
|
-
```
|
|
4985
|
-
|
|
4986
|
-
#### One-To-Many
|
|
4987
|
-
|
|
4988
|
-
To declare a one-to-many relationship between two models, use
|
|
4989
|
-
`belongsTo` in combination with `hasMany`, like this:
|
|
4990
|
-
|
|
4991
|
-
```app/models/post.js
|
|
4992
|
-
import Model, { hasMany } from '@ember-data/model';
|
|
4993
|
-
|
|
4994
|
-
export default class PostModel extends Model {
|
|
4995
|
-
@hasMany('comment', { async: false, inverse: 'post' }) comments;
|
|
4996
|
-
}
|
|
4997
|
-
```
|
|
4998
|
-
|
|
4999
|
-
```app/models/comment.js
|
|
5000
|
-
import Model, { belongsTo } from '@ember-data/model';
|
|
5001
|
-
|
|
5002
|
-
export default class CommentModel extends Model {
|
|
5003
|
-
@belongsTo('post', { async: false, inverse: 'comments' }) post;
|
|
5004
|
-
}
|
|
5005
|
-
```
|
|
5006
|
-
|
|
5007
|
-
#### Sync relationships
|
|
5008
|
-
|
|
5009
|
-
Ember Data resolves sync relationships with the related resources
|
|
5010
|
-
available in its local store, hence it is expected these resources
|
|
5011
|
-
to be loaded before or along-side the primary resource.
|
|
5012
|
-
|
|
5013
|
-
```app/models/comment.js
|
|
5014
|
-
import Model, { belongsTo } from '@ember-data/model';
|
|
5015
|
-
|
|
5016
|
-
export default class CommentModel extends Model {
|
|
5017
|
-
@belongsTo('post', {
|
|
5018
|
-
async: false,
|
|
5019
|
-
inverse: null
|
|
5020
|
-
})
|
|
5021
|
-
post;
|
|
5022
|
-
}
|
|
5023
|
-
```
|
|
5024
|
-
|
|
5025
|
-
In contrast to async relationship, accessing a sync relationship
|
|
5026
|
-
will always return the record (Model instance) for the existing
|
|
5027
|
-
local resource, or null. But it will error on access when
|
|
5028
|
-
a related resource is known to exist and it has not been loaded.
|
|
5029
|
-
|
|
5030
|
-
```
|
|
5031
|
-
let post = comment.post;
|
|
5032
|
-
|
|
5033
|
-
```
|
|
5034
|
-
|
|
5035
|
-
@method belongsTo
|
|
5036
|
-
@public
|
|
5037
|
-
@static
|
|
5038
|
-
@for @ember-data/model
|
|
5039
|
-
@param {String} modelName (optional) type of the relationship
|
|
5040
|
-
@param {Object} options (optional) a hash of options
|
|
5041
|
-
@return {Ember.computed} relationship
|
|
5042
|
-
*/
|
|
5043
|
-
function belongsTo(modelName, options) {
|
|
5044
|
-
let opts = options;
|
|
5045
|
-
let userEnteredModelName = modelName;
|
|
5046
|
-
assert(`Expected belongsTo options.async to be a boolean`, opts && typeof opts.async === 'boolean');
|
|
5047
|
-
assert(`Expected belongsTo options.inverse to be either null or the string type of the related resource.`, opts.inverse === null || typeof opts.inverse === 'string' && opts.inverse.length > 0);
|
|
5048
|
-
let meta = {
|
|
5049
|
-
type: normalizeType$1(userEnteredModelName),
|
|
5050
|
-
isRelationship: true,
|
|
5051
|
-
options: opts,
|
|
5052
|
-
kind: 'belongsTo',
|
|
5053
|
-
name: 'Belongs To',
|
|
5054
|
-
key: null
|
|
5055
|
-
};
|
|
5056
|
-
return computed({
|
|
5057
|
-
get(key) {
|
|
5058
|
-
// this is a legacy behavior we may not carry into a new model setup
|
|
5059
|
-
// it's better to error on disconnected records so users find errors
|
|
5060
|
-
// in their logic.
|
|
5061
|
-
if (this.isDestroying || this.isDestroyed) {
|
|
5062
|
-
return null;
|
|
5063
|
-
}
|
|
5064
|
-
const support = lookupLegacySupport(this);
|
|
5065
|
-
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5066
|
-
if (['currentState'].indexOf(key) !== -1) {
|
|
5067
|
-
throw new Error(`'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your belongsTo on ${this.constructor.toString()}`);
|
|
5068
|
-
}
|
|
5069
|
-
if (Object.prototype.hasOwnProperty.call(opts, 'serialize')) {
|
|
5070
|
-
warn(`You provided a serialize option on the "${key}" property in the "${support.identifier.type}" class, this belongs in the serializer. See Serializer and it's implementations https://api.emberjs.com/ember-data/release/classes/Serializer`, false, {
|
|
5071
|
-
id: 'ds.model.serialize-option-in-belongs-to'
|
|
5072
|
-
});
|
|
5073
|
-
}
|
|
5074
|
-
if (Object.prototype.hasOwnProperty.call(opts, 'embedded')) {
|
|
5075
|
-
warn(`You provided an embedded option on the "${key}" property in the "${support.identifier.type}" class, this belongs in the serializer. See EmbeddedRecordsMixin https://api.emberjs.com/ember-data/release/classes/EmbeddedRecordsMixin`, false, {
|
|
5076
|
-
id: 'ds.model.embedded-option-in-belongs-to'
|
|
5077
|
-
});
|
|
5078
|
-
}
|
|
5079
|
-
}
|
|
5080
|
-
return support.getBelongsTo(key);
|
|
5081
|
-
},
|
|
5082
|
-
set(key, value) {
|
|
5083
|
-
const support = lookupLegacySupport(this);
|
|
5084
|
-
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5085
|
-
if (['currentState'].indexOf(key) !== -1) {
|
|
5086
|
-
throw new Error(`'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your belongsTo on ${this.constructor.toString()}`);
|
|
5087
|
-
}
|
|
5088
|
-
}
|
|
5089
|
-
this.store._join(() => {
|
|
5090
|
-
support.setDirtyBelongsTo(key, value);
|
|
5091
|
-
});
|
|
5092
|
-
return support.getBelongsTo(key);
|
|
5093
|
-
}
|
|
5094
|
-
}).meta(meta);
|
|
5095
|
-
}
|
|
5096
|
-
var belongsTo$1 = computedMacroWithOptionalParams(belongsTo);
|
|
5097
|
-
function normalizeType(type) {
|
|
5098
|
-
return singularize(dasherize(type));
|
|
5099
|
-
}
|
|
5100
|
-
|
|
5101
|
-
/**
|
|
5102
|
-
`hasMany` is used to define One-To-Many and Many-To-Many
|
|
5103
|
-
relationships on a [Model](/ember-data/release/classes/Model).
|
|
5104
|
-
|
|
5105
|
-
`hasMany` takes an optional hash as a second parameter, currently
|
|
5106
|
-
supported options are:
|
|
5107
|
-
|
|
5108
|
-
- `async`: A boolean value used to explicitly declare this to be an async relationship. The default is true.
|
|
5109
|
-
- `inverse`: A string used to identify the inverse property on a related model.
|
|
5110
|
-
- `polymorphic` A boolean value to mark the relationship as polymorphic
|
|
5111
|
-
|
|
5112
|
-
#### One-To-Many
|
|
5113
|
-
To declare a one-to-many relationship between two models, use
|
|
5114
|
-
`belongsTo` in combination with `hasMany`, like this:
|
|
5115
|
-
|
|
5116
|
-
```app/models/post.js
|
|
5117
|
-
import Model, { hasMany } from '@ember-data/model';
|
|
5118
|
-
|
|
5119
|
-
export default class PostModel extends Model {
|
|
5120
|
-
@hasMany('comment') comments;
|
|
5121
|
-
}
|
|
5122
|
-
```
|
|
5123
|
-
|
|
5124
|
-
```app/models/comment.js
|
|
5125
|
-
import Model, { belongsTo } from '@ember-data/model';
|
|
5126
|
-
|
|
5127
|
-
export default class CommentModel extends Model {
|
|
5128
|
-
@belongsTo('post') post;
|
|
5129
|
-
}
|
|
5130
|
-
```
|
|
5131
|
-
|
|
5132
|
-
#### Many-To-Many
|
|
5133
|
-
To declare a many-to-many relationship between two models, use
|
|
5134
|
-
`hasMany`:
|
|
5135
|
-
|
|
5136
|
-
```app/models/post.js
|
|
5137
|
-
import Model, { hasMany } from '@ember-data/model';
|
|
5138
|
-
|
|
5139
|
-
export default class PostModel extends Model {
|
|
5140
|
-
@hasMany('tag') tags;
|
|
5141
|
-
}
|
|
5142
|
-
```
|
|
5143
|
-
|
|
5144
|
-
```app/models/tag.js
|
|
5145
|
-
import Model, { hasMany } from '@ember-data/model';
|
|
5146
|
-
|
|
5147
|
-
export default class TagModel extends Model {
|
|
5148
|
-
@hasMany('post') posts;
|
|
5149
|
-
}
|
|
5150
|
-
```
|
|
5151
|
-
|
|
5152
|
-
You can avoid passing a string as the first parameter. In that case Ember Data
|
|
5153
|
-
will infer the type from the singularized key name.
|
|
5154
|
-
|
|
5155
|
-
```app/models/post.js
|
|
5156
|
-
import Model, { hasMany } from '@ember-data/model';
|
|
5157
|
-
|
|
5158
|
-
export default class PostModel extends Model {
|
|
5159
|
-
@hasMany tags;
|
|
5160
|
-
}
|
|
5161
|
-
```
|
|
5162
|
-
|
|
5163
|
-
will lookup for a Tag type.
|
|
5164
|
-
|
|
5165
|
-
#### Explicit Inverses
|
|
5166
|
-
|
|
5167
|
-
Ember Data will do its best to discover which relationships map to
|
|
5168
|
-
one another. In the one-to-many code above, for example, Ember Data
|
|
5169
|
-
can figure out that changing the `comments` relationship should update
|
|
5170
|
-
the `post` relationship on the inverse because post is the only
|
|
5171
|
-
relationship to that model.
|
|
5172
|
-
|
|
5173
|
-
However, sometimes you may have multiple `belongsTo`/`hasMany` for the
|
|
5174
|
-
same type. You can specify which property on the related model is
|
|
5175
|
-
the inverse using `hasMany`'s `inverse` option:
|
|
5176
|
-
|
|
5177
|
-
```app/models/comment.js
|
|
5178
|
-
import Model, { belongsTo } from '@ember-data/model';
|
|
5179
|
-
|
|
5180
|
-
export default class CommentModel extends Model {
|
|
5181
|
-
@belongsTo('post') onePost;
|
|
5182
|
-
@belongsTo('post') twoPost
|
|
5183
|
-
@belongsTo('post') redPost;
|
|
5184
|
-
@belongsTo('post') bluePost;
|
|
5185
|
-
}
|
|
5186
|
-
```
|
|
5187
|
-
|
|
5188
|
-
```app/models/post.js
|
|
5189
|
-
import Model, { hasMany } from '@ember-data/model';
|
|
5190
|
-
|
|
5191
|
-
export default class PostModel extends Model {
|
|
5192
|
-
@hasMany('comment', {
|
|
5193
|
-
inverse: 'redPost'
|
|
5194
|
-
})
|
|
5195
|
-
comments;
|
|
5196
|
-
}
|
|
5197
|
-
```
|
|
5198
|
-
|
|
5199
|
-
You can also specify an inverse on a `belongsTo`, which works how
|
|
5200
|
-
you'd expect.
|
|
5201
|
-
|
|
5202
|
-
#### Sync relationships
|
|
5203
|
-
|
|
5204
|
-
Ember Data resolves sync relationships with the related resources
|
|
5205
|
-
available in its local store, hence it is expected these resources
|
|
5206
|
-
to be loaded before or along-side the primary resource.
|
|
5207
|
-
|
|
5208
|
-
```app/models/post.js
|
|
5209
|
-
import Model, { hasMany } from '@ember-data/model';
|
|
5210
|
-
|
|
5211
|
-
export default class PostModel extends Model {
|
|
5212
|
-
@hasMany('comment', {
|
|
5213
|
-
async: false
|
|
5214
|
-
})
|
|
5215
|
-
comments;
|
|
5216
|
-
}
|
|
5217
|
-
```
|
|
5218
|
-
|
|
5219
|
-
In contrast to async relationship, accessing a sync relationship
|
|
5220
|
-
will always return a [ManyArray](/ember-data/release/classes/ManyArray) instance
|
|
5221
|
-
containing the existing local resources. But it will error on access
|
|
5222
|
-
when any of the known related resources have not been loaded.
|
|
5223
|
-
|
|
5224
|
-
```
|
|
5225
|
-
post.comments.forEach((comment) => {
|
|
5226
|
-
|
|
5227
|
-
});
|
|
5228
|
-
|
|
5229
|
-
```
|
|
5230
|
-
|
|
5231
|
-
If you are using `links` with sync relationships, you have to use
|
|
5232
|
-
`ref.reload` to fetch the resources.
|
|
5233
|
-
|
|
5234
|
-
@method hasMany
|
|
5235
|
-
@public
|
|
5236
|
-
@static
|
|
5237
|
-
@for @ember-data/model
|
|
5238
|
-
@param {String} type (optional) type of the relationship
|
|
5239
|
-
@param {Object} options (optional) a hash of options
|
|
5240
|
-
@return {Ember.computed} relationship
|
|
5241
|
-
*/
|
|
5242
|
-
function hasMany(type, options) {
|
|
5243
|
-
assert(`Expected hasMany options.async to be a boolean`, options && typeof options.async === 'boolean');
|
|
5244
|
-
|
|
5245
|
-
// Metadata about relationships is stored on the meta of
|
|
5246
|
-
// the relationship. This is used for introspection and
|
|
5247
|
-
// serialization. Note that `key` is populated lazily
|
|
5248
|
-
// the first time the CP is called.
|
|
5249
|
-
let meta = {
|
|
5250
|
-
type: normalizeType(type),
|
|
5251
|
-
options,
|
|
5252
|
-
isRelationship: true,
|
|
5253
|
-
kind: 'hasMany',
|
|
5254
|
-
name: 'Has Many',
|
|
5255
|
-
key: null
|
|
5256
|
-
};
|
|
5257
|
-
return computed({
|
|
5258
|
-
get(key) {
|
|
5259
|
-
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5260
|
-
if (['currentState'].indexOf(key) !== -1) {
|
|
5261
|
-
throw new Error(`'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your hasMany on ${this.constructor.toString()}`);
|
|
5262
|
-
}
|
|
5263
|
-
}
|
|
5264
|
-
if (this.isDestroying || this.isDestroyed) {
|
|
5265
|
-
return A();
|
|
5266
|
-
}
|
|
5267
|
-
return lookupLegacySupport(this).getHasMany(key);
|
|
5268
|
-
},
|
|
5269
|
-
set(key, records) {
|
|
5270
|
-
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5271
|
-
if (['currentState'].indexOf(key) !== -1) {
|
|
5272
|
-
throw new Error(`'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your hasMany on ${this.constructor.toString()}`);
|
|
5273
|
-
}
|
|
5274
|
-
}
|
|
5275
|
-
const support = lookupLegacySupport(this);
|
|
5276
|
-
const manyArray = support.getManyArray(key);
|
|
5277
|
-
assert(`You must pass an array of records to set a hasMany relationship`, Array.isArray(records));
|
|
5278
|
-
this.store._join(() => {
|
|
5279
|
-
manyArray.splice(0, manyArray.length, ...records);
|
|
5280
|
-
});
|
|
5281
|
-
return support.getHasMany(key);
|
|
5282
|
-
}
|
|
5283
|
-
}).meta(meta);
|
|
5284
|
-
}
|
|
5285
|
-
var hasMany$1 = computedMacroWithOptionalParams(hasMany);
|
|
5286
|
-
export { Errors as E, LEGACY_SUPPORT as L, Model as M, PromiseBelongsTo as P, RelatedCollection as R, attr$1 as a, belongsTo$1 as b, PromiseManyArray as c, hasMany$1 as h };
|
|
4788
|
+
export { Errors as E, LEGACY_SUPPORT as L, Model as M, PromiseBelongsTo as P, RelatedCollection as R, PromiseManyArray as a, computedMacroWithOptionalParams as c, lookupLegacySupport as l, normalizeModelName as n };
|