@ember-data/model 4.9.0-alpha.1 → 4.9.0-alpha.12
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/LICENSE.md +3 -1
- package/addon/-private/belongs-to.js +59 -48
- package/addon/-private/debug/assert-polymorphic-type.js +71 -0
- package/addon/-private/deprecated-promise-proxy.ts +29 -7
- package/addon/-private/has-many.js +53 -47
- package/addon/-private/legacy-data-fetch.js +36 -33
- package/addon/-private/legacy-relationships-support.ts +31 -27
- package/addon/-private/many-array.ts +23 -21
- package/addon/-private/model.js +75 -68
- package/addon/-private/promise-many-array.ts +6 -6
- package/addon/-private/record-state.ts +6 -7
- package/addon/-private/references/belongs-to.ts +39 -27
- package/addon/-private/references/has-many.ts +37 -20
- package/addon/-private/relationship-meta.ts +4 -2
- package/addon/index.ts +0 -1
- package/blueprints/model-test/mocha-files/__root__/__path__/__test__.js +4 -3
- package/blueprints/model-test/mocha-rfc-232-files/__root__/__path__/__test__.js +3 -2
- package/blueprints/model-test/qunit-files/__root__/__path__/__test__.js +3 -2
- package/index.js +1 -1
- package/package.json +34 -47
- package/config/environment.js +0 -5
package/LICENSE.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
The MIT License (MIT)
|
|
2
2
|
|
|
3
|
-
Copyright (
|
|
3
|
+
Copyright (C) 2017-2022 Ember.js contributors
|
|
4
|
+
Portions Copyright (C) 2011-2017 Tilde, Inc. and contributors.
|
|
5
|
+
Portions Copyright (C) 2011 LivingSocial Inc.
|
|
4
6
|
|
|
5
7
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
8
|
|
|
@@ -13,8 +13,10 @@ import { lookupLegacySupport } from './model';
|
|
|
13
13
|
import { computedMacroWithOptionalParams } from './util';
|
|
14
14
|
|
|
15
15
|
function normalizeType(type) {
|
|
16
|
-
if (DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE
|
|
17
|
-
|
|
16
|
+
if (DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE) {
|
|
17
|
+
if (!type) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
return dasherize(type);
|
|
@@ -127,60 +129,69 @@ function normalizeType(type) {
|
|
|
127
129
|
function belongsTo(modelName, options) {
|
|
128
130
|
let opts = options;
|
|
129
131
|
let userEnteredModelName = modelName;
|
|
130
|
-
if (DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (typeof modelName === 'object') {
|
|
139
|
-
opts = modelName;
|
|
140
|
-
userEnteredModelName = undefined;
|
|
141
|
-
} else {
|
|
142
|
-
opts = options;
|
|
143
|
-
userEnteredModelName = modelName;
|
|
144
|
-
}
|
|
132
|
+
if (DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE) {
|
|
133
|
+
if (typeof modelName !== 'string' || !modelName.length) {
|
|
134
|
+
deprecate('belongsTo() must specify the string type of the related resource as the first parameter', false, {
|
|
135
|
+
id: 'ember-data:deprecate-non-strict-relationships',
|
|
136
|
+
for: 'ember-data',
|
|
137
|
+
until: '5.0',
|
|
138
|
+
since: { enabled: '4.7', available: '4.7' },
|
|
139
|
+
});
|
|
145
140
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
141
|
+
if (typeof modelName === 'object') {
|
|
142
|
+
opts = modelName;
|
|
143
|
+
userEnteredModelName = undefined;
|
|
144
|
+
} else {
|
|
145
|
+
opts = options;
|
|
146
|
+
userEnteredModelName = modelName;
|
|
147
|
+
}
|
|
153
148
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
149
|
+
assert(
|
|
150
|
+
'The first argument to belongsTo must be a string representing a model type key, not an instance of ' +
|
|
151
|
+
typeof userEnteredModelName +
|
|
152
|
+
". E.g., to define a relation to the Person model, use belongsTo('person')",
|
|
153
|
+
typeof userEnteredModelName === 'string' || typeof userEnteredModelName === 'undefined'
|
|
154
|
+
);
|
|
158
155
|
}
|
|
159
|
-
deprecate('belongsTo(<type>, <options>) must specify options.async as either `true` or `false`.', false, {
|
|
160
|
-
id: 'ember-data:deprecate-non-strict-relationships',
|
|
161
|
-
for: 'ember-data',
|
|
162
|
-
until: '5.0',
|
|
163
|
-
since: { enabled: '4.8', available: '4.8' },
|
|
164
|
-
});
|
|
165
|
-
} else {
|
|
166
|
-
assert(`Expected belongsTo options.async to be a boolean`, opts && typeof opts.async === 'boolean');
|
|
167
156
|
}
|
|
168
157
|
|
|
169
|
-
if (
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
'belongsTo(<type>, <options>) must specify options.
|
|
176
|
-
false,
|
|
177
|
-
{
|
|
158
|
+
if (DEPRECATE_RELATIONSHIPS_WITHOUT_ASYNC) {
|
|
159
|
+
if (!opts || typeof opts.async !== 'boolean') {
|
|
160
|
+
opts = opts || {};
|
|
161
|
+
if (!('async' in opts)) {
|
|
162
|
+
opts.async = true;
|
|
163
|
+
}
|
|
164
|
+
deprecate('belongsTo(<type>, <options>) must specify options.async as either `true` or `false`.', false, {
|
|
178
165
|
id: 'ember-data:deprecate-non-strict-relationships',
|
|
179
166
|
for: 'ember-data',
|
|
180
167
|
until: '5.0',
|
|
181
|
-
since: { enabled: '4.
|
|
182
|
-
}
|
|
183
|
-
|
|
168
|
+
since: { enabled: '4.7', available: '4.7' },
|
|
169
|
+
});
|
|
170
|
+
} else {
|
|
171
|
+
assert(`Expected belongsTo options.async to be a boolean`, opts && typeof opts.async === 'boolean');
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
assert(`Expected belongsTo options.async to be a boolean`, opts && typeof opts.async === 'boolean');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE) {
|
|
178
|
+
if (opts.inverse !== null && (typeof opts.inverse !== 'string' || opts.inverse.length === 0)) {
|
|
179
|
+
deprecate(
|
|
180
|
+
'belongsTo(<type>, <options>) must specify options.inverse as either `null` or string type of the related resource.',
|
|
181
|
+
false,
|
|
182
|
+
{
|
|
183
|
+
id: 'ember-data:deprecate-non-strict-relationships',
|
|
184
|
+
for: 'ember-data',
|
|
185
|
+
until: '5.0',
|
|
186
|
+
since: { enabled: '4.7', available: '4.7' },
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
} else {
|
|
190
|
+
assert(
|
|
191
|
+
`Expected belongsTo options.inverse to be either null or the string type of the related resource.`,
|
|
192
|
+
opts.inverse === null || (typeof opts.inverse === 'string' && opts.inverse.length > 0)
|
|
193
|
+
);
|
|
194
|
+
}
|
|
184
195
|
} else {
|
|
185
196
|
assert(
|
|
186
197
|
`Expected belongsTo options.inverse to be either null or the string type of the related resource.`,
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { assert } from '@ember/debug';
|
|
2
|
+
import { DEBUG } from '@glimmer/env';
|
|
3
|
+
|
|
4
|
+
import { DEPRECATE_NON_EXPLICIT_POLYMORPHISM } from '@ember-data/private-build-infra/deprecations';
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
Assert that `addedRecord` has a valid type so it can be added to the
|
|
8
|
+
relationship of the `record`.
|
|
9
|
+
|
|
10
|
+
The assert basically checks if the `addedRecord` can be added to the
|
|
11
|
+
relationship (specified via `relationshipMeta`) of the `record`.
|
|
12
|
+
|
|
13
|
+
This utility should only be used internally, as both record parameters must
|
|
14
|
+
be stable record identifiers and the `relationshipMeta` needs to be the meta
|
|
15
|
+
information about the relationship, retrieved via
|
|
16
|
+
`record.relationshipFor(key)`.
|
|
17
|
+
*/
|
|
18
|
+
let assertPolymorphicType;
|
|
19
|
+
|
|
20
|
+
if (DEBUG) {
|
|
21
|
+
let checkPolymorphic = function checkPolymorphic(modelClass, addedModelClass) {
|
|
22
|
+
if (modelClass.__isMixin) {
|
|
23
|
+
return (
|
|
24
|
+
modelClass.__mixin.detect(addedModelClass.PrototypeMixin) ||
|
|
25
|
+
// handle native class extension e.g. `class Post extends Model.extend(Commentable) {}`
|
|
26
|
+
modelClass.__mixin.detect(Object.getPrototypeOf(addedModelClass).PrototypeMixin)
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return addedModelClass.prototype instanceof modelClass || modelClass.detect(addedModelClass);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
assertPolymorphicType = function assertPolymorphicType(parentIdentifier, parentDefinition, addedIdentifier, store) {
|
|
34
|
+
let asserted = false;
|
|
35
|
+
|
|
36
|
+
if (parentDefinition.inverseIsImplicit) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (parentDefinition.isPolymorphic) {
|
|
40
|
+
let meta = store.getSchemaDefinitionService().relationshipsDefinitionFor(addedIdentifier)[
|
|
41
|
+
parentDefinition.inverseKey
|
|
42
|
+
];
|
|
43
|
+
if (meta?.options?.as) {
|
|
44
|
+
asserted = true;
|
|
45
|
+
assert(
|
|
46
|
+
`The schema for the relationship '${parentDefinition.inverseKey}' on '${addedIdentifier.type}' type does not implement '${parentDefinition.type}' and thus cannot be assigned to the '${parentDefinition.key}' relationship in '${parentIdentifier.type}'. The definition should specify 'as: "${parentDefinition.type}"' in options.`,
|
|
47
|
+
meta.options.as === parentDefinition.type
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (DEPRECATE_NON_EXPLICIT_POLYMORPHISM) {
|
|
53
|
+
if (!asserted) {
|
|
54
|
+
store = store._store ? store._store : store; // allow usage with storeWrapper
|
|
55
|
+
let addedModelName = addedIdentifier.type;
|
|
56
|
+
let parentModelName = parentIdentifier.type;
|
|
57
|
+
let key = parentDefinition.key;
|
|
58
|
+
let relationshipModelName = parentDefinition.type;
|
|
59
|
+
let relationshipClass = store.modelFor(relationshipModelName);
|
|
60
|
+
let addedClass = store.modelFor(addedModelName);
|
|
61
|
+
|
|
62
|
+
let assertionMessage = `The '${addedModelName}' type does not implement '${relationshipModelName}' and thus cannot be assigned to the '${key}' relationship in '${parentModelName}'. Make it a descendant of '${relationshipModelName}' or use a mixin of the same name.`;
|
|
63
|
+
let isPolymorphic = checkPolymorphic(relationshipClass, addedClass);
|
|
64
|
+
|
|
65
|
+
assert(assertionMessage, isPolymorphic);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { assertPolymorphicType };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { deprecate } from '@ember/debug';
|
|
2
|
+
import { get } from '@ember/object';
|
|
3
|
+
import { DEBUG } from '@glimmer/env';
|
|
2
4
|
|
|
3
5
|
import { resolve } from 'rsvp';
|
|
4
6
|
|
|
@@ -12,18 +14,36 @@ function promiseObject<T>(promise: Promise<T>): PromiseObject<T> {
|
|
|
12
14
|
|
|
13
15
|
// constructor is accessed in some internals but not including it in the copyright for the deprecation
|
|
14
16
|
const ALLOWABLE_METHODS = ['constructor', 'then', 'catch', 'finally'];
|
|
17
|
+
const ALLOWABLE_PROPS = ['__ec_yieldable__', '__ec_cancel__'];
|
|
15
18
|
const PROXIED_OBJECT_PROPS = ['content', 'isPending', 'isSettled', 'isRejected', 'isFulfilled', 'promise', 'reason'];
|
|
16
19
|
|
|
20
|
+
const ProxySymbolString = String(Symbol.for('PROXY_CONTENT'));
|
|
21
|
+
|
|
17
22
|
export function deprecatedPromiseObject<T>(promise: Promise<T>): PromiseObject<T> {
|
|
18
23
|
const promiseObjectProxy: PromiseObject<T> = promiseObject(promise);
|
|
24
|
+
if (!DEBUG) {
|
|
25
|
+
return promiseObjectProxy;
|
|
26
|
+
}
|
|
19
27
|
const handler = {
|
|
20
|
-
get(target: object, prop: string, receiver
|
|
28
|
+
get(target: object, prop: string, receiver: object): unknown {
|
|
21
29
|
if (typeof prop === 'symbol') {
|
|
30
|
+
if (String(prop) === ProxySymbolString) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
22
33
|
return Reflect.get(target, prop, receiver);
|
|
23
34
|
}
|
|
35
|
+
|
|
36
|
+
if (prop === 'constructor') {
|
|
37
|
+
return target.constructor;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (ALLOWABLE_PROPS.includes(prop)) {
|
|
41
|
+
return target[prop];
|
|
42
|
+
}
|
|
43
|
+
|
|
24
44
|
if (!ALLOWABLE_METHODS.includes(prop)) {
|
|
25
45
|
deprecate(
|
|
26
|
-
`Accessing ${prop} is deprecated. The return type is being changed
|
|
46
|
+
`Accessing ${prop} is deprecated. The return type is being changed from PromiseObjectProxy to a Promise. The only available methods to access on this promise are .then, .catch and .finally`,
|
|
27
47
|
false,
|
|
28
48
|
{
|
|
29
49
|
id: 'ember-data:model-save-promise',
|
|
@@ -35,15 +55,17 @@ export function deprecatedPromiseObject<T>(promise: Promise<T>): PromiseObject<T
|
|
|
35
55
|
},
|
|
36
56
|
}
|
|
37
57
|
);
|
|
58
|
+
} else {
|
|
59
|
+
return (target[prop] as () => unknown).bind(target);
|
|
38
60
|
}
|
|
39
61
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return value.bind(target);
|
|
62
|
+
if (PROXIED_OBJECT_PROPS.includes(prop)) {
|
|
63
|
+
return target[prop];
|
|
43
64
|
}
|
|
44
65
|
|
|
45
|
-
|
|
46
|
-
|
|
66
|
+
const value: unknown = get(target, prop);
|
|
67
|
+
if (value && typeof value === 'function' && typeof value.bind === 'function') {
|
|
68
|
+
return value.bind(receiver);
|
|
47
69
|
}
|
|
48
70
|
|
|
49
71
|
return undefined;
|
|
@@ -19,8 +19,10 @@ import { lookupLegacySupport } from './model';
|
|
|
19
19
|
import { computedMacroWithOptionalParams } from './util';
|
|
20
20
|
|
|
21
21
|
function normalizeType(type) {
|
|
22
|
-
if (DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE
|
|
23
|
-
|
|
22
|
+
if (DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE) {
|
|
23
|
+
if (!type) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
return singularize(dasherize(type));
|
|
@@ -168,60 +170,64 @@ function normalizeType(type) {
|
|
|
168
170
|
@return {Ember.computed} relationship
|
|
169
171
|
*/
|
|
170
172
|
function hasMany(type, options) {
|
|
171
|
-
if (DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
173
|
+
if (DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE) {
|
|
174
|
+
if (typeof type !== 'string' || !type.length) {
|
|
175
|
+
deprecate(
|
|
176
|
+
'hasMany(<type>, <options>) must specify the string type of the related resource as the first parameter',
|
|
177
|
+
false,
|
|
178
|
+
{
|
|
179
|
+
id: 'ember-data:deprecate-non-strict-relationships',
|
|
180
|
+
for: 'ember-data',
|
|
181
|
+
until: '5.0',
|
|
182
|
+
since: { enabled: '4.7', available: '4.7' },
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
if (typeof type === 'object') {
|
|
186
|
+
options = type;
|
|
187
|
+
type = undefined;
|
|
180
188
|
}
|
|
181
|
-
);
|
|
182
|
-
if (typeof type === 'object') {
|
|
183
|
-
options = type;
|
|
184
|
-
type = undefined;
|
|
185
|
-
}
|
|
186
189
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
assert(
|
|
191
|
+
`The first argument to hasMany must be a string representing a model type key, not an instance of ${inspect(
|
|
192
|
+
type
|
|
193
|
+
)}. E.g., to define a relation to the Comment model, use hasMany('comment')`,
|
|
194
|
+
typeof type === 'string' || typeof type === 'undefined'
|
|
195
|
+
);
|
|
196
|
+
}
|
|
193
197
|
}
|
|
194
198
|
|
|
195
|
-
if (DEPRECATE_RELATIONSHIPS_WITHOUT_ASYNC
|
|
196
|
-
options
|
|
197
|
-
|
|
198
|
-
|
|
199
|
+
if (DEPRECATE_RELATIONSHIPS_WITHOUT_ASYNC) {
|
|
200
|
+
if (!options || typeof options.async !== 'boolean') {
|
|
201
|
+
options = options || {};
|
|
202
|
+
if (!('async' in options)) {
|
|
203
|
+
options.async = true;
|
|
204
|
+
}
|
|
205
|
+
deprecate('hasMany(<type>, <options>) must specify options.async as either `true` or `false`.', false, {
|
|
206
|
+
id: 'ember-data:deprecate-non-strict-relationships',
|
|
207
|
+
for: 'ember-data',
|
|
208
|
+
until: '5.0',
|
|
209
|
+
since: { enabled: '4.7', available: '4.7' },
|
|
210
|
+
});
|
|
211
|
+
} else {
|
|
212
|
+
assert(`Expected hasMany options.async to be a boolean`, options && typeof options.async === 'boolean');
|
|
199
213
|
}
|
|
200
|
-
deprecate('hasMany(<type>, <options>) must specify options.async as either `true` or `false`.', false, {
|
|
201
|
-
id: 'ember-data:deprecate-non-strict-relationships',
|
|
202
|
-
for: 'ember-data',
|
|
203
|
-
until: '5.0',
|
|
204
|
-
since: { enabled: '4.8', available: '4.8' },
|
|
205
|
-
});
|
|
206
214
|
} else {
|
|
207
215
|
assert(`Expected hasMany options.async to be a boolean`, options && typeof options.async === 'boolean');
|
|
208
216
|
}
|
|
209
217
|
|
|
210
|
-
if (
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
-
);
|
|
218
|
+
if (DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE) {
|
|
219
|
+
if (options.inverse !== null && (typeof options.inverse !== 'string' || options.inverse.length === 0)) {
|
|
220
|
+
deprecate(
|
|
221
|
+
'hasMany(<type>, <options>) must specify options.inverse as either `null` or string type of the related resource.',
|
|
222
|
+
false,
|
|
223
|
+
{
|
|
224
|
+
id: 'ember-data:deprecate-non-strict-relationships',
|
|
225
|
+
for: 'ember-data',
|
|
226
|
+
until: '5.0',
|
|
227
|
+
since: { enabled: '4.7', available: '4.7' },
|
|
228
|
+
}
|
|
229
|
+
);
|
|
230
|
+
}
|
|
225
231
|
}
|
|
226
232
|
|
|
227
233
|
// Metadata about relationships is stored on the meta of
|
|
@@ -195,36 +195,37 @@ function ensureRelationshipIsSetToParent(payload, parentIdentifier, store, paren
|
|
|
195
195
|
|
|
196
196
|
let relationshipData = relationships[inverseKey] && relationships[inverseKey].data;
|
|
197
197
|
|
|
198
|
-
if (
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
198
|
+
if (DEBUG) {
|
|
199
|
+
if (
|
|
200
|
+
typeof relationshipData !== 'undefined' &&
|
|
201
|
+
!relationshipDataPointsToParent(relationshipData, parentIdentifier)
|
|
202
|
+
) {
|
|
203
|
+
let inspect = function inspect(thing) {
|
|
204
|
+
return `'${JSON.stringify(thing)}'`;
|
|
205
|
+
};
|
|
206
|
+
let quotedType = inspect(type);
|
|
207
|
+
let quotedInverse = inspect(inverseKey);
|
|
208
|
+
let expected = inspect({
|
|
209
|
+
id: parentIdentifier.id,
|
|
210
|
+
type: parentIdentifier.type,
|
|
211
|
+
});
|
|
212
|
+
let expectedModel = `${parentIdentifier.type}:${parentIdentifier.id}`;
|
|
213
|
+
let got = inspect(relationshipData);
|
|
214
|
+
let prefix = typeof index === 'number' ? `data[${index}]` : `data`;
|
|
215
|
+
let path = `${prefix}.relationships.${inverseKey}.data`;
|
|
216
|
+
let other = relationshipData ? `<${relationshipData.type}:${relationshipData.id}>` : null;
|
|
217
|
+
let relationshipFetched = `${expectedModel}.${parentRelationship.kind}("${parentRelationship.name}")`;
|
|
218
|
+
let includedRecord = `<${type}:${id}>`;
|
|
219
|
+
let message = [
|
|
220
|
+
`Encountered mismatched relationship: Ember Data expected ${path} in the payload from ${relationshipFetched} to include ${expected} but got ${got} instead.\n`,
|
|
221
|
+
`The ${includedRecord} record loaded at ${prefix} in the payload specified ${other} as its ${quotedInverse}, but should have specified ${expectedModel} (the record the relationship is being loaded from) as its ${quotedInverse} instead.`,
|
|
222
|
+
`This could mean that the response for ${relationshipFetched} may have accidentally returned ${quotedType} records that aren't related to ${expectedModel} and could be related to a different ${parentIdentifier.type} record instead.`,
|
|
223
|
+
`Ember Data has corrected the ${includedRecord} record's ${quotedInverse} relationship to ${expectedModel} so that ${relationshipFetched} will include ${includedRecord}.`,
|
|
224
|
+
`Please update the response from the server or change your serializer to either ensure that the response for only includes ${quotedType} records that specify ${expectedModel} as their ${quotedInverse}, or omit the ${quotedInverse} relationship from the response.`,
|
|
225
|
+
].join('\n');
|
|
226
|
+
|
|
227
|
+
assert(message);
|
|
228
|
+
}
|
|
228
229
|
}
|
|
229
230
|
|
|
230
231
|
if (kind !== 'hasMany' || typeof relationshipData !== 'undefined') {
|
|
@@ -244,9 +245,11 @@ function inverseForRelationship(store, identifier, key) {
|
|
|
244
245
|
return null;
|
|
245
246
|
}
|
|
246
247
|
|
|
247
|
-
if (DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
if (DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE) {
|
|
249
|
+
if (metaIsRelationshipDefinition(definition)) {
|
|
250
|
+
const modelClass = store.modelFor(identifier.type);
|
|
251
|
+
return definition._inverseKey(store, modelClass);
|
|
252
|
+
}
|
|
250
253
|
}
|
|
251
254
|
assert(
|
|
252
255
|
`Expected the relationship defintion to specify the inverse type or null.`,
|
|
@@ -389,13 +389,15 @@ export class LegacySupport {
|
|
|
389
389
|
const graph = graphFor(this.store);
|
|
390
390
|
const relationship = graph.get(this.identifier, name);
|
|
391
391
|
|
|
392
|
-
if (DEBUG
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
392
|
+
if (DEBUG) {
|
|
393
|
+
if (kind) {
|
|
394
|
+
let modelName = this.identifier.type;
|
|
395
|
+
let actualRelationshipKind = relationship.definition.kind;
|
|
396
|
+
assert(
|
|
397
|
+
`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.`,
|
|
398
|
+
actualRelationshipKind === kind
|
|
399
|
+
);
|
|
400
|
+
}
|
|
399
401
|
}
|
|
400
402
|
|
|
401
403
|
let relationshipKind = relationship.definition.kind;
|
|
@@ -705,26 +707,28 @@ function extractIdentifierFromRecord(recordOrPromiseRecord: PromiseProxyRecord |
|
|
|
705
707
|
return null;
|
|
706
708
|
}
|
|
707
709
|
|
|
708
|
-
if (DEPRECATE_PROMISE_PROXIES
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
710
|
+
if (DEPRECATE_PROMISE_PROXIES) {
|
|
711
|
+
if (isPromiseRecord(recordOrPromiseRecord)) {
|
|
712
|
+
let content = recordOrPromiseRecord.content;
|
|
713
|
+
assert(
|
|
714
|
+
'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.',
|
|
715
|
+
content !== undefined
|
|
716
|
+
);
|
|
717
|
+
deprecate(
|
|
718
|
+
`You passed in a PromiseProxy to a Relationship API that now expects a resolved value. await the value before setting it.`,
|
|
719
|
+
false,
|
|
720
|
+
{
|
|
721
|
+
id: 'ember-data:deprecate-promise-proxies',
|
|
722
|
+
until: '5.0',
|
|
723
|
+
since: {
|
|
724
|
+
enabled: '4.7',
|
|
725
|
+
available: '4.7',
|
|
726
|
+
},
|
|
727
|
+
for: 'ember-data',
|
|
728
|
+
}
|
|
729
|
+
);
|
|
730
|
+
return content ? recordIdentifierFor(content) : null;
|
|
731
|
+
}
|
|
728
732
|
}
|
|
729
733
|
|
|
730
734
|
return recordIdentifierFor(recordOrPromiseRecord);
|
|
@@ -367,27 +367,29 @@ function extractIdentifiersFromRecords(records: RecordInstance[]): StableRecordI
|
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
function extractIdentifierFromRecord(recordOrPromiseRecord: PromiseProxyRecord | RecordInstance) {
|
|
370
|
-
if (DEPRECATE_PROMISE_PROXIES
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
370
|
+
if (DEPRECATE_PROMISE_PROXIES) {
|
|
371
|
+
if (isPromiseRecord(recordOrPromiseRecord)) {
|
|
372
|
+
let content = recordOrPromiseRecord.content;
|
|
373
|
+
assert(
|
|
374
|
+
'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo relationship.',
|
|
375
|
+
content !== undefined && content !== null
|
|
376
|
+
);
|
|
377
|
+
deprecate(
|
|
378
|
+
`You passed in a PromiseProxy to a Relationship API that now expects a resolved value. await the value before setting it.`,
|
|
379
|
+
false,
|
|
380
|
+
{
|
|
381
|
+
id: 'ember-data:deprecate-promise-proxies',
|
|
382
|
+
until: '5.0',
|
|
383
|
+
since: {
|
|
384
|
+
enabled: '4.7',
|
|
385
|
+
available: '4.7',
|
|
386
|
+
},
|
|
387
|
+
for: 'ember-data',
|
|
388
|
+
}
|
|
389
|
+
);
|
|
390
|
+
assertRecordPassedToHasMany(content);
|
|
391
|
+
return recordIdentifierFor(content);
|
|
392
|
+
}
|
|
391
393
|
}
|
|
392
394
|
|
|
393
395
|
assertRecordPassedToHasMany(recordOrPromiseRecord);
|