@ember-data/legacy-compat 4.12.0-alpha.9 → 4.12.0-beta.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/addon/-private.js +1 -1
- package/addon/fetch-manager-1067c70f.js +1128 -0
- package/addon/fetch-manager-1067c70f.js.map +1 -0
- package/addon/index.js +518 -1637
- package/addon/index.js.map +1 -1
- package/addon-main.js +18 -15
- package/package.json +17 -6
- package/addon/snapshot-record-array-a4efeb60.js +0 -169
- package/addon/snapshot-record-array-a4efeb60.js.map +0 -1
package/addon/index.js
CHANGED
|
@@ -1,1686 +1,560 @@
|
|
|
1
|
-
import { macroCondition, isDevelopingApp, getOwnConfig } from '@embroider/macros';
|
|
2
1
|
import { deprecate, assert } from '@ember/debug';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
var EventTarget = {
|
|
27
|
-
/**
|
|
28
|
-
`EventTarget.mixin` extends an object with EventTarget methods. For
|
|
29
|
-
Example:
|
|
30
|
-
```javascript
|
|
31
|
-
import EventTarget from 'rsvp';
|
|
32
|
-
let object = {};
|
|
33
|
-
EventTarget.mixin(object);
|
|
34
|
-
object.on('finished', function(event) {
|
|
35
|
-
// handle event
|
|
36
|
-
});
|
|
37
|
-
object.trigger('finished', { detail: value });
|
|
38
|
-
```
|
|
39
|
-
`EventTarget.mixin` also works with prototypes:
|
|
40
|
-
```javascript
|
|
41
|
-
import EventTarget from 'rsvp';
|
|
42
|
-
let Person = function() {};
|
|
43
|
-
EventTarget.mixin(Person.prototype);
|
|
44
|
-
let yehuda = new Person();
|
|
45
|
-
let tom = new Person();
|
|
46
|
-
yehuda.on('poke', function(event) {
|
|
47
|
-
console.log('Yehuda says OW');
|
|
48
|
-
});
|
|
49
|
-
tom.on('poke', function(event) {
|
|
50
|
-
console.log('Tom says OW');
|
|
51
|
-
});
|
|
52
|
-
yehuda.trigger('poke');
|
|
53
|
-
tom.trigger('poke');
|
|
54
|
-
```
|
|
55
|
-
@method mixin
|
|
56
|
-
@for rsvp
|
|
57
|
-
@private
|
|
58
|
-
@param {Object} object object to extend with EventTarget methods
|
|
59
|
-
*/
|
|
60
|
-
mixin: function (object) {
|
|
61
|
-
object.on = this.on;
|
|
62
|
-
object.off = this.off;
|
|
63
|
-
object.trigger = this.trigger;
|
|
64
|
-
object._promiseCallbacks = undefined;
|
|
65
|
-
return object;
|
|
66
|
-
},
|
|
67
|
-
/**
|
|
68
|
-
Registers a callback to be executed when `eventName` is triggered
|
|
69
|
-
```javascript
|
|
70
|
-
object.on('event', function(eventInfo){
|
|
71
|
-
// handle the event
|
|
72
|
-
});
|
|
73
|
-
object.trigger('event');
|
|
74
|
-
```
|
|
75
|
-
@method on
|
|
76
|
-
@for EventTarget
|
|
77
|
-
@private
|
|
78
|
-
@param {String} eventName name of the event to listen for
|
|
79
|
-
@param {Function} callback function to be called when the event is triggered.
|
|
80
|
-
*/
|
|
81
|
-
on: function (eventName, callback) {
|
|
82
|
-
if (typeof callback !== 'function') {
|
|
83
|
-
throw new TypeError('Callback must be a function');
|
|
84
|
-
}
|
|
85
|
-
var allCallbacks = callbacksFor(this);
|
|
86
|
-
var callbacks = allCallbacks[eventName];
|
|
87
|
-
if (!callbacks) {
|
|
88
|
-
callbacks = allCallbacks[eventName] = [];
|
|
89
|
-
}
|
|
90
|
-
if (callbacks.indexOf(callback) === -1) {
|
|
91
|
-
callbacks.push(callback);
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
/**
|
|
95
|
-
You can use `off` to stop firing a particular callback for an event:
|
|
96
|
-
```javascript
|
|
97
|
-
function doStuff() { // do stuff! }
|
|
98
|
-
object.on('stuff', doStuff);
|
|
99
|
-
object.trigger('stuff'); // doStuff will be called
|
|
100
|
-
// Unregister ONLY the doStuff callback
|
|
101
|
-
object.off('stuff', doStuff);
|
|
102
|
-
object.trigger('stuff'); // doStuff will NOT be called
|
|
103
|
-
```
|
|
104
|
-
If you don't pass a `callback` argument to `off`, ALL callbacks for the
|
|
105
|
-
event will not be executed when the event fires. For example:
|
|
106
|
-
```javascript
|
|
107
|
-
let callback1 = function(){};
|
|
108
|
-
let callback2 = function(){};
|
|
109
|
-
object.on('stuff', callback1);
|
|
110
|
-
object.on('stuff', callback2);
|
|
111
|
-
object.trigger('stuff'); // callback1 and callback2 will be executed.
|
|
112
|
-
object.off('stuff');
|
|
113
|
-
object.trigger('stuff'); // callback1 and callback2 will not be executed!
|
|
114
|
-
```
|
|
115
|
-
@method off
|
|
116
|
-
@for rsvp
|
|
117
|
-
@private
|
|
118
|
-
@param {String} eventName event to stop listening to
|
|
119
|
-
@param {Function} [callback] optional argument. If given, only the function
|
|
120
|
-
given will be removed from the event's callback queue. If no `callback`
|
|
121
|
-
argument is given, all callbacks will be removed from the event's callback
|
|
122
|
-
queue.
|
|
123
|
-
*/
|
|
124
|
-
off: function (eventName, callback) {
|
|
125
|
-
var allCallbacks = callbacksFor(this);
|
|
126
|
-
if (!callback) {
|
|
127
|
-
allCallbacks[eventName] = [];
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
var callbacks = allCallbacks[eventName];
|
|
131
|
-
var index = callbacks.indexOf(callback);
|
|
132
|
-
if (index !== -1) {
|
|
133
|
-
callbacks.splice(index, 1);
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
|
-
/**
|
|
137
|
-
Use `trigger` to fire custom events. For example:
|
|
138
|
-
```javascript
|
|
139
|
-
object.on('foo', function(){
|
|
140
|
-
console.log('foo event happened!');
|
|
141
|
-
});
|
|
142
|
-
object.trigger('foo');
|
|
143
|
-
// 'foo event happened!' logged to the console
|
|
144
|
-
```
|
|
145
|
-
You can also pass a value as a second argument to `trigger` that will be
|
|
146
|
-
passed as an argument to all event listeners for the event:
|
|
147
|
-
```javascript
|
|
148
|
-
object.on('foo', function(value){
|
|
149
|
-
console.log(value.name);
|
|
150
|
-
});
|
|
151
|
-
object.trigger('foo', { name: 'bar' });
|
|
152
|
-
// 'bar' logged to the console
|
|
153
|
-
```
|
|
154
|
-
@method trigger
|
|
155
|
-
@for rsvp
|
|
156
|
-
@private
|
|
157
|
-
@param {String} eventName name of the event to be triggered
|
|
158
|
-
@param {*} [options] optional value to be passed to any event handlers for
|
|
159
|
-
the given `eventName`
|
|
160
|
-
*/
|
|
161
|
-
trigger: function (eventName, options, label) {
|
|
162
|
-
var allCallbacks = callbacksFor(this);
|
|
163
|
-
var callbacks = allCallbacks[eventName];
|
|
164
|
-
if (callbacks) {
|
|
165
|
-
// Don't cache the callbacks.length since it may grow
|
|
166
|
-
var callback = void 0;
|
|
167
|
-
for (var i = 0; i < callbacks.length; i++) {
|
|
168
|
-
callback = callbacks[i];
|
|
169
|
-
callback(options, label);
|
|
2
|
+
import { macroCondition, getOwnConfig, importSync } from '@embroider/macros';
|
|
3
|
+
import { g as guardDestroyedStore, _ as _objectIsAlive, p as payloadIsNotBlank, n as normalizeResponseHelper, c as _guard, i as iterateData, d as _bind, F as FetchManager, e as assertIdentifierHasId, a as SaveOp, S as SnapshotRecordArray } from "./fetch-manager-1067c70f";
|
|
4
|
+
function _findHasMany(adapter, store, identifier, link, relationship, options) {
|
|
5
|
+
let promise = Promise.resolve().then(() => {
|
|
6
|
+
const snapshot = store._fetchManager.createSnapshot(identifier, options);
|
|
7
|
+
let useLink = !link || typeof link === 'string';
|
|
8
|
+
let relatedLink = useLink ? link : link.href;
|
|
9
|
+
return adapter.findHasMany(store, snapshot, relatedLink, relationship);
|
|
10
|
+
});
|
|
11
|
+
promise = guardDestroyedStore(promise, store);
|
|
12
|
+
promise = promise.then(adapterPayload => {
|
|
13
|
+
const record = store._instanceCache.getRecord(identifier);
|
|
14
|
+
if (!_objectIsAlive(record)) {
|
|
15
|
+
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_RSVP_PROMISE)) {
|
|
16
|
+
deprecate(`A Promise for fetching ${relationship.type} did not resolve by the time your model was destroyed. This will error in a future release.`, false, {
|
|
17
|
+
id: 'ember-data:rsvp-unresolved-async',
|
|
18
|
+
until: '5.0',
|
|
19
|
+
for: '@ember-data/store',
|
|
20
|
+
since: {
|
|
21
|
+
available: '4.5',
|
|
22
|
+
enabled: '4.5'
|
|
23
|
+
}
|
|
24
|
+
});
|
|
170
25
|
}
|
|
171
26
|
}
|
|
27
|
+
assert(`You made a 'findHasMany' request for a ${identifier.type}'s '${relationship.key}' relationship, using link '${link}' , but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload));
|
|
28
|
+
const modelClass = store.modelFor(relationship.type);
|
|
29
|
+
let serializer = store.serializerFor(relationship.type);
|
|
30
|
+
let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findHasMany');
|
|
31
|
+
assert(`fetched the hasMany relationship '${relationship.name}' for ${identifier.type}:${identifier.id} with link '${link}', but no data member is present in the response. If no data exists, the response should set { data: [] }`, 'data' in payload && Array.isArray(payload.data));
|
|
32
|
+
payload = syncRelationshipDataFromLink(store, payload, identifier, relationship);
|
|
33
|
+
return store._push(payload, true);
|
|
34
|
+
}, null, `DS: Extract payload of '${identifier.type}' : hasMany '${relationship.type}'`);
|
|
35
|
+
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_RSVP_PROMISE)) {
|
|
36
|
+
const record = store._instanceCache.getRecord(identifier);
|
|
37
|
+
promise = _guard(promise, _bind(_objectIsAlive, record));
|
|
172
38
|
}
|
|
173
|
-
|
|
174
|
-
var config = {
|
|
175
|
-
instrument: false
|
|
176
|
-
};
|
|
177
|
-
EventTarget['mixin'](config);
|
|
178
|
-
function configure(name, value) {
|
|
179
|
-
if (arguments.length === 2) {
|
|
180
|
-
config[name] = value;
|
|
181
|
-
} else {
|
|
182
|
-
return config[name];
|
|
183
|
-
}
|
|
39
|
+
return promise;
|
|
184
40
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
41
|
+
function _findBelongsTo(store, identifier, link, relationship, options) {
|
|
42
|
+
let promise = Promise.resolve().then(() => {
|
|
43
|
+
let adapter = store.adapterFor(identifier.type);
|
|
44
|
+
assert(`You tried to load a belongsTo relationship but you have no adapter (for ${identifier.type})`, adapter);
|
|
45
|
+
assert(`You tried to load a belongsTo relationship from a specified 'link' in the original payload but your adapter does not implement 'findBelongsTo'`, typeof adapter.findBelongsTo === 'function');
|
|
46
|
+
let snapshot = store._fetchManager.createSnapshot(identifier, options);
|
|
47
|
+
let useLink = !link || typeof link === 'string';
|
|
48
|
+
let relatedLink = useLink ? link : link.href;
|
|
49
|
+
return adapter.findBelongsTo(store, snapshot, relatedLink, relationship);
|
|
50
|
+
});
|
|
51
|
+
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_RSVP_PROMISE)) {
|
|
52
|
+
const record = store._instanceCache.getRecord(identifier);
|
|
53
|
+
promise = guardDestroyedStore(promise, store);
|
|
54
|
+
promise = _guard(promise, _bind(_objectIsAlive, record));
|
|
55
|
+
}
|
|
56
|
+
promise = promise.then(adapterPayload => {
|
|
57
|
+
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_RSVP_PROMISE)) {
|
|
58
|
+
const record = store._instanceCache.getRecord(identifier);
|
|
59
|
+
if (!_objectIsAlive(record)) {
|
|
60
|
+
deprecate(`A Promise for fetching ${relationship.type} did not resolve by the time your model was destroyed. This will error in a future release.`, false, {
|
|
61
|
+
id: 'ember-data:rsvp-unresolved-async',
|
|
62
|
+
until: '5.0',
|
|
63
|
+
for: '@ember-data/store',
|
|
64
|
+
since: {
|
|
65
|
+
available: '4.5',
|
|
66
|
+
enabled: '4.5'
|
|
67
|
+
}
|
|
68
|
+
});
|
|
195
69
|
}
|
|
196
|
-
config['trigger'](entry.name, entry.payload);
|
|
197
70
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
payload: {
|
|
205
|
-
key: promise._guidKey,
|
|
206
|
-
id: promise._id,
|
|
207
|
-
eventName: eventName,
|
|
208
|
-
detail: promise._result,
|
|
209
|
-
childId: child && child._id,
|
|
210
|
-
label: promise._label,
|
|
211
|
-
timeStamp: Date.now(),
|
|
212
|
-
error: config["instrument-with-stack"] ? new Error(promise._label) : null
|
|
71
|
+
let modelClass = store.modelFor(relationship.type);
|
|
72
|
+
let serializer = store.serializerFor(relationship.type);
|
|
73
|
+
let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findBelongsTo');
|
|
74
|
+
assert(`fetched the belongsTo relationship '${relationship.name}' for ${identifier.type}:${identifier.id} with link '${link}', but no data member is present in the response. If no data exists, the response should set { data: null }`, 'data' in payload && (payload.data === null || typeof payload.data === 'object' && !Array.isArray(payload.data)));
|
|
75
|
+
if (!payload.data && !payload.links && !payload.meta) {
|
|
76
|
+
return null;
|
|
213
77
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
78
|
+
payload = syncRelationshipDataFromLink(store, payload, identifier, relationship);
|
|
79
|
+
return store._push(payload, true);
|
|
80
|
+
}, null, `DS: Extract payload of ${identifier.type} : ${relationship.type}`);
|
|
81
|
+
return promise;
|
|
217
82
|
}
|
|
218
83
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
promise.then(function(value){
|
|
243
|
-
// value === 1
|
|
244
|
-
});
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
@method resolve
|
|
248
|
-
@for Promise
|
|
249
|
-
@static
|
|
250
|
-
@param {*} object value that the returned promise will be resolved with
|
|
251
|
-
@param {String} [label] optional string for identifying the returned promise.
|
|
252
|
-
Useful for tooling.
|
|
253
|
-
@return {Promise} a promise that will become fulfilled with the given
|
|
254
|
-
`value`
|
|
255
|
-
*/
|
|
256
|
-
function resolve$$1(object, label) {
|
|
257
|
-
/*jshint validthis:true */
|
|
258
|
-
var Constructor = this;
|
|
259
|
-
if (object && typeof object === 'object' && object.constructor === Constructor) {
|
|
260
|
-
return object;
|
|
84
|
+
// sync
|
|
85
|
+
// iterate over records in payload.data
|
|
86
|
+
// for each record
|
|
87
|
+
// assert that record.relationships[inverse] is either undefined (so we can fix it)
|
|
88
|
+
// or provide a data: {id, type} that matches the record that requested it
|
|
89
|
+
// return the relationship data for the parent
|
|
90
|
+
function syncRelationshipDataFromLink(store, payload, parentIdentifier, relationship) {
|
|
91
|
+
// ensure the right hand side (incoming payload) points to the parent record that
|
|
92
|
+
// requested this relationship
|
|
93
|
+
let relationshipData = payload.data ? iterateData(payload.data, (data, index) => {
|
|
94
|
+
const {
|
|
95
|
+
id,
|
|
96
|
+
type
|
|
97
|
+
} = data;
|
|
98
|
+
ensureRelationshipIsSetToParent(data, parentIdentifier, store, relationship, index);
|
|
99
|
+
return {
|
|
100
|
+
id,
|
|
101
|
+
type
|
|
102
|
+
};
|
|
103
|
+
}) : null;
|
|
104
|
+
const relatedDataHash = {};
|
|
105
|
+
if ('meta' in payload) {
|
|
106
|
+
relatedDataHash.meta = payload.meta;
|
|
261
107
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
return promise;
|
|
265
|
-
}
|
|
266
|
-
function withOwnPromise() {
|
|
267
|
-
return new TypeError('A promises callback cannot return that same promise.');
|
|
268
|
-
}
|
|
269
|
-
function objectOrFunction(x) {
|
|
270
|
-
var type = typeof x;
|
|
271
|
-
return x !== null && (type === 'object' || type === 'function');
|
|
272
|
-
}
|
|
273
|
-
function noop() {}
|
|
274
|
-
var PENDING = void 0;
|
|
275
|
-
var FULFILLED = 1;
|
|
276
|
-
var REJECTED = 2;
|
|
277
|
-
var TRY_CATCH_ERROR = {
|
|
278
|
-
error: null
|
|
279
|
-
};
|
|
280
|
-
function getThen(promise) {
|
|
281
|
-
try {
|
|
282
|
-
return promise.then;
|
|
283
|
-
} catch (error) {
|
|
284
|
-
TRY_CATCH_ERROR.error = error;
|
|
285
|
-
return TRY_CATCH_ERROR;
|
|
108
|
+
if ('links' in payload) {
|
|
109
|
+
relatedDataHash.links = payload.links;
|
|
286
110
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
function tryCatcher() {
|
|
290
|
-
try {
|
|
291
|
-
var target = tryCatchCallback;
|
|
292
|
-
tryCatchCallback = null;
|
|
293
|
-
return target.apply(this, arguments);
|
|
294
|
-
} catch (e) {
|
|
295
|
-
TRY_CATCH_ERROR.error = e;
|
|
296
|
-
return TRY_CATCH_ERROR;
|
|
111
|
+
if ('data' in payload) {
|
|
112
|
+
relatedDataHash.data = relationshipData;
|
|
297
113
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
var result = tryCatch(then$$1).call(thenable, function (value) {
|
|
307
|
-
if (sealed) {
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
sealed = true;
|
|
311
|
-
if (thenable === value) {
|
|
312
|
-
fulfill(promise, value);
|
|
313
|
-
} else {
|
|
314
|
-
resolve$1(promise, value);
|
|
315
|
-
}
|
|
316
|
-
}, function (reason) {
|
|
317
|
-
if (sealed) {
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
sealed = true;
|
|
321
|
-
reject(promise, reason);
|
|
322
|
-
}, 'Settle: ' + (promise._label || ' unknown promise'));
|
|
323
|
-
if (!sealed && result === TRY_CATCH_ERROR) {
|
|
324
|
-
sealed = true;
|
|
325
|
-
var error = TRY_CATCH_ERROR.error;
|
|
326
|
-
TRY_CATCH_ERROR.error = null;
|
|
327
|
-
reject(promise, error);
|
|
114
|
+
|
|
115
|
+
// now, push the left hand side (the parent record) to ensure things are in sync, since
|
|
116
|
+
// the payload will be pushed with store._push
|
|
117
|
+
const parentPayload = {
|
|
118
|
+
id: parentIdentifier.id,
|
|
119
|
+
type: parentIdentifier.type,
|
|
120
|
+
relationships: {
|
|
121
|
+
[relationship.key]: relatedDataHash
|
|
328
122
|
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
if (thenable._state === FULFILLED) {
|
|
333
|
-
fulfill(promise, thenable._result);
|
|
334
|
-
} else if (thenable._state === REJECTED) {
|
|
335
|
-
thenable._onError = null;
|
|
336
|
-
reject(promise, thenable._result);
|
|
337
|
-
} else {
|
|
338
|
-
subscribe(thenable, undefined, function (value) {
|
|
339
|
-
if (thenable === value) {
|
|
340
|
-
fulfill(promise, value);
|
|
341
|
-
} else {
|
|
342
|
-
resolve$1(promise, value);
|
|
343
|
-
}
|
|
344
|
-
}, function (reason) {
|
|
345
|
-
return reject(promise, reason);
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
function handleMaybeThenable(promise, maybeThenable, then$$1) {
|
|
350
|
-
var isOwnThenable = maybeThenable.constructor === promise.constructor && then$$1 === then && promise.constructor.resolve === resolve$$1;
|
|
351
|
-
if (isOwnThenable) {
|
|
352
|
-
handleOwnThenable(promise, maybeThenable);
|
|
353
|
-
} else if (then$$1 === TRY_CATCH_ERROR) {
|
|
354
|
-
var error = TRY_CATCH_ERROR.error;
|
|
355
|
-
TRY_CATCH_ERROR.error = null;
|
|
356
|
-
reject(promise, error);
|
|
357
|
-
} else if (typeof then$$1 === 'function') {
|
|
358
|
-
handleForeignThenable(promise, maybeThenable, then$$1);
|
|
359
|
-
} else {
|
|
360
|
-
fulfill(promise, maybeThenable);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
function resolve$1(promise, value) {
|
|
364
|
-
if (promise === value) {
|
|
365
|
-
fulfill(promise, value);
|
|
366
|
-
} else if (objectOrFunction(value)) {
|
|
367
|
-
handleMaybeThenable(promise, value, getThen(value));
|
|
368
|
-
} else {
|
|
369
|
-
fulfill(promise, value);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
function publishRejection(promise) {
|
|
373
|
-
if (promise._onError) {
|
|
374
|
-
promise._onError(promise._result);
|
|
123
|
+
};
|
|
124
|
+
if (!Array.isArray(payload.included)) {
|
|
125
|
+
payload.included = [];
|
|
375
126
|
}
|
|
376
|
-
|
|
127
|
+
payload.included.push(parentPayload);
|
|
128
|
+
return payload;
|
|
377
129
|
}
|
|
378
|
-
function
|
|
379
|
-
|
|
380
|
-
|
|
130
|
+
function ensureRelationshipIsSetToParent(payload, parentIdentifier, store, parentRelationship, index) {
|
|
131
|
+
let {
|
|
132
|
+
id,
|
|
133
|
+
type
|
|
134
|
+
} = payload;
|
|
135
|
+
if (!payload.relationships) {
|
|
136
|
+
payload.relationships = {};
|
|
381
137
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
138
|
+
let {
|
|
139
|
+
relationships
|
|
140
|
+
} = payload;
|
|
141
|
+
let inverse = getInverse(store, parentIdentifier, parentRelationship, type);
|
|
142
|
+
if (inverse) {
|
|
143
|
+
let {
|
|
144
|
+
inverseKey,
|
|
145
|
+
kind
|
|
146
|
+
} = inverse;
|
|
147
|
+
let relationshipData = relationships[inverseKey] && relationships[inverseKey].data;
|
|
148
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
149
|
+
if (typeof relationshipData !== 'undefined' && !relationshipDataPointsToParent(relationshipData, parentIdentifier)) {
|
|
150
|
+
let inspect = function inspect(thing) {
|
|
151
|
+
return `'${JSON.stringify(thing)}'`;
|
|
152
|
+
};
|
|
153
|
+
let quotedType = inspect(type);
|
|
154
|
+
let quotedInverse = inspect(inverseKey);
|
|
155
|
+
let expected = inspect({
|
|
156
|
+
id: parentIdentifier.id,
|
|
157
|
+
type: parentIdentifier.type
|
|
158
|
+
});
|
|
159
|
+
let expectedModel = `${parentIdentifier.type}:${parentIdentifier.id}`;
|
|
160
|
+
let got = inspect(relationshipData);
|
|
161
|
+
let prefix = typeof index === 'number' ? `data[${index}]` : `data`;
|
|
162
|
+
let path = `${prefix}.relationships.${inverseKey}.data`;
|
|
163
|
+
let other = relationshipData ? `<${relationshipData.type}:${relationshipData.id}>` : null;
|
|
164
|
+
let relationshipFetched = `${expectedModel}.${parentRelationship.kind}("${parentRelationship.name}")`;
|
|
165
|
+
let includedRecord = `<${type}:${id}>`;
|
|
166
|
+
let message = [`Encountered mismatched relationship: Ember Data expected ${path} in the payload from ${relationshipFetched} to include ${expected} but got ${got} instead.\n`, `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.`, `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.`, `Ember Data has corrected the ${includedRecord} record's ${quotedInverse} relationship to ${expectedModel} so that ${relationshipFetched} will include ${includedRecord}.`, `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.`].join('\n');
|
|
167
|
+
assert(message);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (kind !== 'hasMany' || typeof relationshipData !== 'undefined') {
|
|
171
|
+
relationships[inverseKey] = relationships[inverseKey] || {};
|
|
172
|
+
relationships[inverseKey].data = fixRelationshipData(relationshipData, kind, parentIdentifier);
|
|
387
173
|
}
|
|
388
|
-
} else {
|
|
389
|
-
config.async(publish, promise);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
function reject(promise, reason) {
|
|
393
|
-
if (promise._state !== PENDING) {
|
|
394
|
-
return;
|
|
395
174
|
}
|
|
396
|
-
promise._state = REJECTED;
|
|
397
|
-
promise._result = reason;
|
|
398
|
-
config.async(publishRejection, promise);
|
|
399
175
|
}
|
|
400
|
-
function
|
|
401
|
-
|
|
402
|
-
var length = subscribers.length;
|
|
403
|
-
parent._onError = null;
|
|
404
|
-
subscribers[length] = child;
|
|
405
|
-
subscribers[length + FULFILLED] = onFulfillment;
|
|
406
|
-
subscribers[length + REJECTED] = onRejection;
|
|
407
|
-
if (length === 0 && parent._state) {
|
|
408
|
-
config.async(publish, parent);
|
|
409
|
-
}
|
|
176
|
+
function metaIsRelationshipDefinition(meta) {
|
|
177
|
+
return typeof meta._inverseKey === 'function';
|
|
410
178
|
}
|
|
411
|
-
function
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise);
|
|
179
|
+
function inverseForRelationship(store, identifier, key) {
|
|
180
|
+
const definition = store.getSchemaDefinitionService().relationshipsDefinitionFor(identifier)[key];
|
|
181
|
+
if (!definition) {
|
|
182
|
+
return null;
|
|
416
183
|
}
|
|
417
|
-
if (
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
callback = void 0,
|
|
422
|
-
result = promise._result;
|
|
423
|
-
for (var i = 0; i < subscribers.length; i += 3) {
|
|
424
|
-
child = subscribers[i];
|
|
425
|
-
callback = subscribers[i + settled];
|
|
426
|
-
if (child) {
|
|
427
|
-
invokeCallback(settled, child, callback, result);
|
|
428
|
-
} else {
|
|
429
|
-
callback(result);
|
|
184
|
+
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE)) {
|
|
185
|
+
if (metaIsRelationshipDefinition(definition)) {
|
|
186
|
+
const modelClass = store.modelFor(identifier.type);
|
|
187
|
+
return definition._inverseKey(store, modelClass);
|
|
430
188
|
}
|
|
431
189
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
function invokeCallback(state, promise, callback, result) {
|
|
435
|
-
var hasCallback = typeof callback === 'function';
|
|
436
|
-
var value = void 0;
|
|
437
|
-
if (hasCallback) {
|
|
438
|
-
value = tryCatch(callback)(result);
|
|
439
|
-
} else {
|
|
440
|
-
value = result;
|
|
441
|
-
}
|
|
442
|
-
if (promise._state !== PENDING) ;else if (value === promise) {
|
|
443
|
-
reject(promise, withOwnPromise());
|
|
444
|
-
} else if (value === TRY_CATCH_ERROR) {
|
|
445
|
-
var error = TRY_CATCH_ERROR.error;
|
|
446
|
-
TRY_CATCH_ERROR.error = null; // release
|
|
447
|
-
reject(promise, error);
|
|
448
|
-
} else if (hasCallback) {
|
|
449
|
-
resolve$1(promise, value);
|
|
450
|
-
} else if (state === FULFILLED) {
|
|
451
|
-
fulfill(promise, value);
|
|
452
|
-
} else if (state === REJECTED) {
|
|
453
|
-
reject(promise, value);
|
|
454
|
-
}
|
|
190
|
+
assert(`Expected the relationship defintion to specify the inverse type or null.`, definition.options?.inverse === null || typeof definition.options?.inverse === 'string' && definition.options.inverse.length > 0);
|
|
191
|
+
return definition.options.inverse;
|
|
455
192
|
}
|
|
456
|
-
function
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
resolved = true;
|
|
470
|
-
reject(promise, reason);
|
|
471
|
-
});
|
|
472
|
-
} catch (e) {
|
|
473
|
-
reject(promise, e);
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
function then(onFulfillment, onRejection, label) {
|
|
477
|
-
var parent = this;
|
|
478
|
-
var state = parent._state;
|
|
479
|
-
if (state === FULFILLED && !onFulfillment || state === REJECTED && !onRejection) {
|
|
480
|
-
config.instrument && instrument('chained', parent, parent);
|
|
481
|
-
return parent;
|
|
482
|
-
}
|
|
483
|
-
parent._onError = null;
|
|
484
|
-
var child = new parent.constructor(noop, label);
|
|
485
|
-
var result = parent._result;
|
|
486
|
-
config.instrument && instrument('chained', parent, child);
|
|
487
|
-
if (state === PENDING) {
|
|
488
|
-
subscribe(parent, child, onFulfillment, onRejection);
|
|
489
|
-
} else {
|
|
490
|
-
var callback = state === FULFILLED ? onFulfillment : onRejection;
|
|
491
|
-
config.async(function () {
|
|
492
|
-
return invokeCallback(state, child, callback, result);
|
|
193
|
+
function getInverse(store, parentIdentifier, parentRelationship, type) {
|
|
194
|
+
let {
|
|
195
|
+
name: lhs_relationshipName
|
|
196
|
+
} = parentRelationship;
|
|
197
|
+
let {
|
|
198
|
+
type: parentType
|
|
199
|
+
} = parentIdentifier;
|
|
200
|
+
let inverseKey = inverseForRelationship(store, {
|
|
201
|
+
type: parentType
|
|
202
|
+
}, lhs_relationshipName);
|
|
203
|
+
if (inverseKey) {
|
|
204
|
+
const definition = store.getSchemaDefinitionService().relationshipsDefinitionFor({
|
|
205
|
+
type
|
|
493
206
|
});
|
|
207
|
+
let {
|
|
208
|
+
kind
|
|
209
|
+
} = definition[inverseKey];
|
|
210
|
+
return {
|
|
211
|
+
inverseKey,
|
|
212
|
+
kind
|
|
213
|
+
};
|
|
494
214
|
}
|
|
495
|
-
return child;
|
|
496
215
|
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
this.promise = new Constructor(noop, label);
|
|
501
|
-
this._abortOnReject = abortOnReject;
|
|
502
|
-
this._isUsingOwnPromise = Constructor === Promise$1;
|
|
503
|
-
this._isUsingOwnResolve = Constructor.resolve === resolve$$1;
|
|
504
|
-
this._init.apply(this, arguments);
|
|
216
|
+
function relationshipDataPointsToParent(relationshipData, identifier) {
|
|
217
|
+
if (relationshipData === null) {
|
|
218
|
+
return false;
|
|
505
219
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
this._remaining = len;
|
|
510
|
-
this._result = new Array(len);
|
|
511
|
-
this._enumerate(input);
|
|
512
|
-
};
|
|
513
|
-
Enumerator.prototype._enumerate = function _enumerate(input) {
|
|
514
|
-
var length = this.length;
|
|
515
|
-
var promise = this.promise;
|
|
516
|
-
for (var i = 0; promise._state === PENDING && i < length; i++) {
|
|
517
|
-
this._eachEntry(input[i], i, true);
|
|
518
|
-
}
|
|
519
|
-
this._checkFullfillment();
|
|
520
|
-
};
|
|
521
|
-
Enumerator.prototype._checkFullfillment = function _checkFullfillment() {
|
|
522
|
-
if (this._remaining === 0) {
|
|
523
|
-
var result = this._result;
|
|
524
|
-
fulfill(this.promise, result);
|
|
525
|
-
this._result = null;
|
|
526
|
-
}
|
|
527
|
-
};
|
|
528
|
-
Enumerator.prototype._settleMaybeThenable = function _settleMaybeThenable(entry, i, firstPass) {
|
|
529
|
-
var c = this._instanceConstructor;
|
|
530
|
-
if (this._isUsingOwnResolve) {
|
|
531
|
-
var then$$1 = getThen(entry);
|
|
532
|
-
if (then$$1 === then && entry._state !== PENDING) {
|
|
533
|
-
entry._onError = null;
|
|
534
|
-
this._settledAt(entry._state, i, entry._result, firstPass);
|
|
535
|
-
} else if (typeof then$$1 !== 'function') {
|
|
536
|
-
this._settledAt(FULFILLED, i, entry, firstPass);
|
|
537
|
-
} else if (this._isUsingOwnPromise) {
|
|
538
|
-
var promise = new c(noop);
|
|
539
|
-
handleMaybeThenable(promise, entry, then$$1);
|
|
540
|
-
this._willSettleAt(promise, i, firstPass);
|
|
541
|
-
} else {
|
|
542
|
-
this._willSettleAt(new c(function (resolve) {
|
|
543
|
-
return resolve(entry);
|
|
544
|
-
}), i, firstPass);
|
|
545
|
-
}
|
|
546
|
-
} else {
|
|
547
|
-
this._willSettleAt(c.resolve(entry), i, firstPass);
|
|
548
|
-
}
|
|
549
|
-
};
|
|
550
|
-
Enumerator.prototype._eachEntry = function _eachEntry(entry, i, firstPass) {
|
|
551
|
-
if (entry !== null && typeof entry === 'object') {
|
|
552
|
-
this._settleMaybeThenable(entry, i, firstPass);
|
|
553
|
-
} else {
|
|
554
|
-
this._setResultAt(FULFILLED, i, entry, firstPass);
|
|
220
|
+
if (Array.isArray(relationshipData)) {
|
|
221
|
+
if (relationshipData.length === 0) {
|
|
222
|
+
return false;
|
|
555
223
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
if (this._abortOnReject && state === REJECTED) {
|
|
561
|
-
reject(promise, value);
|
|
562
|
-
} else {
|
|
563
|
-
this._setResultAt(state, i, value, firstPass);
|
|
564
|
-
this._checkFullfillment();
|
|
224
|
+
for (let i = 0; i < relationshipData.length; i++) {
|
|
225
|
+
let entry = relationshipData[i];
|
|
226
|
+
if (validateRelationshipEntry(entry, identifier)) {
|
|
227
|
+
return true;
|
|
565
228
|
}
|
|
566
229
|
}
|
|
567
|
-
};
|
|
568
|
-
Enumerator.prototype._setResultAt = function _setResultAt(state, i, value, firstPass) {
|
|
569
|
-
this._remaining--;
|
|
570
|
-
this._result[i] = value;
|
|
571
|
-
};
|
|
572
|
-
Enumerator.prototype._willSettleAt = function _willSettleAt(promise, i, firstPass) {
|
|
573
|
-
var _this = this;
|
|
574
|
-
subscribe(promise, undefined, function (value) {
|
|
575
|
-
return _this._settledAt(FULFILLED, i, value, firstPass);
|
|
576
|
-
}, function (reason) {
|
|
577
|
-
return _this._settledAt(REJECTED, i, reason, firstPass);
|
|
578
|
-
});
|
|
579
|
-
};
|
|
580
|
-
return Enumerator;
|
|
581
|
-
}();
|
|
582
|
-
function setSettledResult(state, i, value) {
|
|
583
|
-
this._remaining--;
|
|
584
|
-
if (state === FULFILLED) {
|
|
585
|
-
this._result[i] = {
|
|
586
|
-
state: 'fulfilled',
|
|
587
|
-
value: value
|
|
588
|
-
};
|
|
589
230
|
} else {
|
|
590
|
-
|
|
591
|
-
state: 'rejected',
|
|
592
|
-
reason: value
|
|
593
|
-
};
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
/**
|
|
598
|
-
`Promise.all` accepts an array of promises, and returns a new promise which
|
|
599
|
-
is fulfilled with an array of fulfillment values for the passed promises, or
|
|
600
|
-
rejected with the reason of the first passed promise to be rejected. It casts all
|
|
601
|
-
elements of the passed iterable to promises as it runs this algorithm.
|
|
602
|
-
|
|
603
|
-
Example:
|
|
604
|
-
|
|
605
|
-
```javascript
|
|
606
|
-
import Promise, { resolve } from 'rsvp';
|
|
607
|
-
|
|
608
|
-
let promise1 = resolve(1);
|
|
609
|
-
let promise2 = resolve(2);
|
|
610
|
-
let promise3 = resolve(3);
|
|
611
|
-
let promises = [ promise1, promise2, promise3 ];
|
|
612
|
-
|
|
613
|
-
Promise.all(promises).then(function(array){
|
|
614
|
-
// The array here would be [ 1, 2, 3 ];
|
|
615
|
-
});
|
|
616
|
-
```
|
|
617
|
-
|
|
618
|
-
If any of the `promises` given to `RSVP.all` are rejected, the first promise
|
|
619
|
-
that is rejected will be given as an argument to the returned promises's
|
|
620
|
-
rejection handler. For example:
|
|
621
|
-
|
|
622
|
-
Example:
|
|
623
|
-
|
|
624
|
-
```javascript
|
|
625
|
-
import Promise, { resolve, reject } from 'rsvp';
|
|
626
|
-
|
|
627
|
-
let promise1 = resolve(1);
|
|
628
|
-
let promise2 = reject(new Error("2"));
|
|
629
|
-
let promise3 = reject(new Error("3"));
|
|
630
|
-
let promises = [ promise1, promise2, promise3 ];
|
|
631
|
-
|
|
632
|
-
Promise.all(promises).then(function(array){
|
|
633
|
-
// Code here never runs because there are rejected promises!
|
|
634
|
-
}, function(error) {
|
|
635
|
-
// error.message === "2"
|
|
636
|
-
});
|
|
637
|
-
```
|
|
638
|
-
|
|
639
|
-
@method all
|
|
640
|
-
@for Promise
|
|
641
|
-
@param {Array} entries array of promises
|
|
642
|
-
@param {String} [label] optional string for labeling the promise.
|
|
643
|
-
Useful for tooling.
|
|
644
|
-
@return {Promise} promise that is fulfilled when all `promises` have been
|
|
645
|
-
fulfilled, or rejected if any of them become rejected.
|
|
646
|
-
@static
|
|
647
|
-
*/
|
|
648
|
-
function all(entries, label) {
|
|
649
|
-
if (!Array.isArray(entries)) {
|
|
650
|
-
return this.reject(new TypeError("Promise.all must be called with an array"), label);
|
|
651
|
-
}
|
|
652
|
-
return new Enumerator(this, entries, true /* abort on reject */, label).promise;
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
/**
|
|
656
|
-
`Promise.race` returns a new promise which is settled in the same way as the
|
|
657
|
-
first passed promise to settle.
|
|
658
|
-
|
|
659
|
-
Example:
|
|
660
|
-
|
|
661
|
-
```javascript
|
|
662
|
-
import Promise from 'rsvp';
|
|
663
|
-
|
|
664
|
-
let promise1 = new Promise(function(resolve, reject){
|
|
665
|
-
setTimeout(function(){
|
|
666
|
-
resolve('promise 1');
|
|
667
|
-
}, 200);
|
|
668
|
-
});
|
|
669
|
-
|
|
670
|
-
let promise2 = new Promise(function(resolve, reject){
|
|
671
|
-
setTimeout(function(){
|
|
672
|
-
resolve('promise 2');
|
|
673
|
-
}, 100);
|
|
674
|
-
});
|
|
675
|
-
|
|
676
|
-
Promise.race([promise1, promise2]).then(function(result){
|
|
677
|
-
// result === 'promise 2' because it was resolved before promise1
|
|
678
|
-
// was resolved.
|
|
679
|
-
});
|
|
680
|
-
```
|
|
681
|
-
|
|
682
|
-
`Promise.race` is deterministic in that only the state of the first
|
|
683
|
-
settled promise matters. For example, even if other promises given to the
|
|
684
|
-
`promises` array argument are resolved, but the first settled promise has
|
|
685
|
-
become rejected before the other promises became fulfilled, the returned
|
|
686
|
-
promise will become rejected:
|
|
687
|
-
|
|
688
|
-
```javascript
|
|
689
|
-
import Promise from 'rsvp';
|
|
690
|
-
|
|
691
|
-
let promise1 = new Promise(function(resolve, reject){
|
|
692
|
-
setTimeout(function(){
|
|
693
|
-
resolve('promise 1');
|
|
694
|
-
}, 200);
|
|
695
|
-
});
|
|
696
|
-
|
|
697
|
-
let promise2 = new Promise(function(resolve, reject){
|
|
698
|
-
setTimeout(function(){
|
|
699
|
-
reject(new Error('promise 2'));
|
|
700
|
-
}, 100);
|
|
701
|
-
});
|
|
702
|
-
|
|
703
|
-
Promise.race([promise1, promise2]).then(function(result){
|
|
704
|
-
// Code here never runs
|
|
705
|
-
}, function(reason){
|
|
706
|
-
// reason.message === 'promise 2' because promise 2 became rejected before
|
|
707
|
-
// promise 1 became fulfilled
|
|
708
|
-
});
|
|
709
|
-
```
|
|
710
|
-
|
|
711
|
-
An example real-world use case is implementing timeouts:
|
|
712
|
-
|
|
713
|
-
```javascript
|
|
714
|
-
import Promise from 'rsvp';
|
|
715
|
-
|
|
716
|
-
Promise.race([ajax('foo.json'), timeout(5000)])
|
|
717
|
-
```
|
|
718
|
-
|
|
719
|
-
@method race
|
|
720
|
-
@for Promise
|
|
721
|
-
@static
|
|
722
|
-
@param {Array} entries array of promises to observe
|
|
723
|
-
@param {String} [label] optional string for describing the promise returned.
|
|
724
|
-
Useful for tooling.
|
|
725
|
-
@return {Promise} a promise which settles in the same way as the first passed
|
|
726
|
-
promise to settle.
|
|
727
|
-
*/
|
|
728
|
-
function race(entries, label) {
|
|
729
|
-
/*jshint validthis:true */
|
|
730
|
-
var Constructor = this;
|
|
731
|
-
var promise = new Constructor(noop, label);
|
|
732
|
-
if (!Array.isArray(entries)) {
|
|
733
|
-
reject(promise, new TypeError('Promise.race must be called with an array'));
|
|
734
|
-
return promise;
|
|
735
|
-
}
|
|
736
|
-
for (var i = 0; promise._state === PENDING && i < entries.length; i++) {
|
|
737
|
-
subscribe(Constructor.resolve(entries[i]), undefined, function (value) {
|
|
738
|
-
return resolve$1(promise, value);
|
|
739
|
-
}, function (reason) {
|
|
740
|
-
return reject(promise, reason);
|
|
741
|
-
});
|
|
231
|
+
return validateRelationshipEntry(relationshipData, identifier);
|
|
742
232
|
}
|
|
743
|
-
return
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
/**
|
|
747
|
-
`Promise.reject` returns a promise rejected with the passed `reason`.
|
|
748
|
-
It is shorthand for the following:
|
|
749
|
-
|
|
750
|
-
```javascript
|
|
751
|
-
import Promise from 'rsvp';
|
|
752
|
-
|
|
753
|
-
let promise = new Promise(function(resolve, reject){
|
|
754
|
-
reject(new Error('WHOOPS'));
|
|
755
|
-
});
|
|
756
|
-
|
|
757
|
-
promise.then(function(value){
|
|
758
|
-
// Code here doesn't run because the promise is rejected!
|
|
759
|
-
}, function(reason){
|
|
760
|
-
// reason.message === 'WHOOPS'
|
|
761
|
-
});
|
|
762
|
-
```
|
|
763
|
-
|
|
764
|
-
Instead of writing the above, your code now simply becomes the following:
|
|
765
|
-
|
|
766
|
-
```javascript
|
|
767
|
-
import Promise from 'rsvp';
|
|
768
|
-
|
|
769
|
-
let promise = Promise.reject(new Error('WHOOPS'));
|
|
770
|
-
|
|
771
|
-
promise.then(function(value){
|
|
772
|
-
// Code here doesn't run because the promise is rejected!
|
|
773
|
-
}, function(reason){
|
|
774
|
-
// reason.message === 'WHOOPS'
|
|
775
|
-
});
|
|
776
|
-
```
|
|
777
|
-
|
|
778
|
-
@method reject
|
|
779
|
-
@for Promise
|
|
780
|
-
@static
|
|
781
|
-
@param {*} reason value that the returned promise will be rejected with.
|
|
782
|
-
@param {String} [label] optional string for identifying the returned promise.
|
|
783
|
-
Useful for tooling.
|
|
784
|
-
@return {Promise} a promise rejected with the given `reason`.
|
|
785
|
-
*/
|
|
786
|
-
function reject$1(reason, label) {
|
|
787
|
-
/*jshint validthis:true */
|
|
788
|
-
var Constructor = this;
|
|
789
|
-
var promise = new Constructor(noop, label);
|
|
790
|
-
reject(promise, reason);
|
|
791
|
-
return promise;
|
|
792
|
-
}
|
|
793
|
-
var guidKey = 'rsvp_' + Date.now() + '-';
|
|
794
|
-
var counter = 0;
|
|
795
|
-
function needsResolver() {
|
|
796
|
-
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
|
|
233
|
+
return false;
|
|
797
234
|
}
|
|
798
|
-
function
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
registers callbacks to receive either a promise’s eventual value or the reason
|
|
806
|
-
why the promise cannot be fulfilled.
|
|
807
|
-
|
|
808
|
-
Terminology
|
|
809
|
-
-----------
|
|
810
|
-
|
|
811
|
-
- `promise` is an object or function with a `then` method whose behavior conforms to this specification.
|
|
812
|
-
- `thenable` is an object or function that defines a `then` method.
|
|
813
|
-
- `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
|
|
814
|
-
- `exception` is a value that is thrown using the throw statement.
|
|
815
|
-
- `reason` is a value that indicates why a promise was rejected.
|
|
816
|
-
- `settled` the final resting state of a promise, fulfilled or rejected.
|
|
817
|
-
|
|
818
|
-
A promise can be in one of three states: pending, fulfilled, or rejected.
|
|
819
|
-
|
|
820
|
-
Promises that are fulfilled have a fulfillment value and are in the fulfilled
|
|
821
|
-
state. Promises that are rejected have a rejection reason and are in the
|
|
822
|
-
rejected state. A fulfillment value is never a thenable.
|
|
823
|
-
|
|
824
|
-
Promises can also be said to *resolve* a value. If this value is also a
|
|
825
|
-
promise, then the original promise's settled state will match the value's
|
|
826
|
-
settled state. So a promise that *resolves* a promise that rejects will
|
|
827
|
-
itself reject, and a promise that *resolves* a promise that fulfills will
|
|
828
|
-
itself fulfill.
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
Basic Usage:
|
|
832
|
-
------------
|
|
833
|
-
|
|
834
|
-
```js
|
|
835
|
-
let promise = new Promise(function(resolve, reject) {
|
|
836
|
-
// on success
|
|
837
|
-
resolve(value);
|
|
838
|
-
|
|
839
|
-
// on failure
|
|
840
|
-
reject(reason);
|
|
841
|
-
});
|
|
842
|
-
|
|
843
|
-
promise.then(function(value) {
|
|
844
|
-
// on fulfillment
|
|
845
|
-
}, function(reason) {
|
|
846
|
-
// on rejection
|
|
847
|
-
});
|
|
848
|
-
```
|
|
849
|
-
|
|
850
|
-
Advanced Usage:
|
|
851
|
-
---------------
|
|
852
|
-
|
|
853
|
-
Promises shine when abstracting away asynchronous interactions such as
|
|
854
|
-
`XMLHttpRequest`s.
|
|
855
|
-
|
|
856
|
-
```js
|
|
857
|
-
function getJSON(url) {
|
|
858
|
-
return new Promise(function(resolve, reject){
|
|
859
|
-
let xhr = new XMLHttpRequest();
|
|
860
|
-
|
|
861
|
-
xhr.open('GET', url);
|
|
862
|
-
xhr.onreadystatechange = handler;
|
|
863
|
-
xhr.responseType = 'json';
|
|
864
|
-
xhr.setRequestHeader('Accept', 'application/json');
|
|
865
|
-
xhr.send();
|
|
866
|
-
|
|
867
|
-
function handler() {
|
|
868
|
-
if (this.readyState === this.DONE) {
|
|
869
|
-
if (this.status === 200) {
|
|
870
|
-
resolve(this.response);
|
|
871
|
-
} else {
|
|
872
|
-
reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
};
|
|
876
|
-
});
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
getJSON('/posts.json').then(function(json) {
|
|
880
|
-
// on fulfillment
|
|
881
|
-
}, function(reason) {
|
|
882
|
-
// on rejection
|
|
883
|
-
});
|
|
884
|
-
```
|
|
885
|
-
|
|
886
|
-
Unlike callbacks, promises are great composable primitives.
|
|
887
|
-
|
|
888
|
-
```js
|
|
889
|
-
Promise.all([
|
|
890
|
-
getJSON('/posts'),
|
|
891
|
-
getJSON('/comments')
|
|
892
|
-
]).then(function(values){
|
|
893
|
-
values[0] // => postsJSON
|
|
894
|
-
values[1] // => commentsJSON
|
|
895
|
-
|
|
896
|
-
return values;
|
|
897
|
-
});
|
|
898
|
-
```
|
|
899
|
-
|
|
900
|
-
@class Promise
|
|
901
|
-
@public
|
|
902
|
-
@param {function} resolver
|
|
903
|
-
@param {String} [label] optional string for labeling the promise.
|
|
904
|
-
Useful for tooling.
|
|
905
|
-
@constructor
|
|
906
|
-
*/
|
|
907
|
-
|
|
908
|
-
var Promise$1 = function () {
|
|
909
|
-
function Promise(resolver, label) {
|
|
910
|
-
this._id = counter++;
|
|
911
|
-
this._label = label;
|
|
912
|
-
this._state = undefined;
|
|
913
|
-
this._result = undefined;
|
|
914
|
-
this._subscribers = [];
|
|
915
|
-
config.instrument && instrument('created', this);
|
|
916
|
-
if (noop !== resolver) {
|
|
917
|
-
typeof resolver !== 'function' && needsResolver();
|
|
918
|
-
this instanceof Promise ? initializePromise(this, resolver) : needsNew();
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
Promise.prototype._onError = function _onError(reason) {
|
|
922
|
-
var _this = this;
|
|
923
|
-
config.after(function () {
|
|
924
|
-
if (_this._onError) {
|
|
925
|
-
config.trigger('error', reason, _this._label);
|
|
926
|
-
}
|
|
927
|
-
});
|
|
235
|
+
function fixRelationshipData(relationshipData, relationshipKind, {
|
|
236
|
+
id,
|
|
237
|
+
type
|
|
238
|
+
}) {
|
|
239
|
+
let parentRelationshipData = {
|
|
240
|
+
id,
|
|
241
|
+
type
|
|
928
242
|
};
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
// synchronous
|
|
940
|
-
try {
|
|
941
|
-
findAuthor();
|
|
942
|
-
} catch(reason) {
|
|
943
|
-
// something went wrong
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
// async with promises
|
|
947
|
-
findAuthor().catch(function(reason){
|
|
948
|
-
// something went wrong
|
|
949
|
-
});
|
|
950
|
-
```
|
|
951
|
-
|
|
952
|
-
@method catch
|
|
953
|
-
@param {Function} onRejection
|
|
954
|
-
@param {String} [label] optional string for labeling the promise.
|
|
955
|
-
Useful for tooling.
|
|
956
|
-
@return {Promise}
|
|
957
|
-
*/
|
|
958
|
-
|
|
959
|
-
Promise.prototype.catch = function _catch(onRejection, label) {
|
|
960
|
-
return this.then(undefined, onRejection, label);
|
|
961
|
-
};
|
|
962
|
-
|
|
963
|
-
/**
|
|
964
|
-
`finally` will be invoked regardless of the promise's fate just as native
|
|
965
|
-
try/catch/finally behaves
|
|
966
|
-
|
|
967
|
-
Synchronous example:
|
|
968
|
-
|
|
969
|
-
```js
|
|
970
|
-
findAuthor() {
|
|
971
|
-
if (Math.random() > 0.5) {
|
|
972
|
-
throw new Error();
|
|
973
|
-
}
|
|
974
|
-
return new Author();
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
try {
|
|
978
|
-
return findAuthor(); // succeed or fail
|
|
979
|
-
} catch(error) {
|
|
980
|
-
return findOtherAuthor();
|
|
981
|
-
} finally {
|
|
982
|
-
// always runs
|
|
983
|
-
// doesn't affect the return value
|
|
984
|
-
}
|
|
985
|
-
```
|
|
986
|
-
|
|
987
|
-
Asynchronous example:
|
|
988
|
-
|
|
989
|
-
```js
|
|
990
|
-
findAuthor().catch(function(reason){
|
|
991
|
-
return findOtherAuthor();
|
|
992
|
-
}).finally(function(){
|
|
993
|
-
// author was either found, or not
|
|
994
|
-
});
|
|
995
|
-
```
|
|
996
|
-
|
|
997
|
-
@method finally
|
|
998
|
-
@param {Function} callback
|
|
999
|
-
@param {String} [label] optional string for labeling the promise.
|
|
1000
|
-
Useful for tooling.
|
|
1001
|
-
@return {Promise}
|
|
1002
|
-
*/
|
|
1003
|
-
|
|
1004
|
-
Promise.prototype.finally = function _finally(callback, label) {
|
|
1005
|
-
var promise = this;
|
|
1006
|
-
var constructor = promise.constructor;
|
|
1007
|
-
if (typeof callback === 'function') {
|
|
1008
|
-
return promise.then(function (value) {
|
|
1009
|
-
return constructor.resolve(callback()).then(function () {
|
|
1010
|
-
return value;
|
|
1011
|
-
});
|
|
1012
|
-
}, function (reason) {
|
|
1013
|
-
return constructor.resolve(callback()).then(function () {
|
|
1014
|
-
throw reason;
|
|
1015
|
-
});
|
|
243
|
+
let payload;
|
|
244
|
+
if (relationshipKind === 'hasMany') {
|
|
245
|
+
payload = relationshipData || [];
|
|
246
|
+
if (relationshipData) {
|
|
247
|
+
// these arrays could be massive so this is better than filter
|
|
248
|
+
// Note: this is potentially problematic if type/id are not in the
|
|
249
|
+
// same state of normalization.
|
|
250
|
+
let found = relationshipData.find(v => {
|
|
251
|
+
return v.type === parentRelationshipData.type && v.id === parentRelationshipData.id;
|
|
1016
252
|
});
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
};
|
|
1020
|
-
return Promise;
|
|
1021
|
-
}();
|
|
1022
|
-
Promise$1.cast = resolve$$1; // deprecated
|
|
1023
|
-
Promise$1.all = all;
|
|
1024
|
-
Promise$1.race = race;
|
|
1025
|
-
Promise$1.resolve = resolve$$1;
|
|
1026
|
-
Promise$1.reject = reject$1;
|
|
1027
|
-
Promise$1.prototype._guidKey = guidKey;
|
|
1028
|
-
|
|
1029
|
-
/**
|
|
1030
|
-
The primary way of interacting with a promise is through its `then` method,
|
|
1031
|
-
which registers callbacks to receive either a promise's eventual value or the
|
|
1032
|
-
reason why the promise cannot be fulfilled.
|
|
1033
|
-
|
|
1034
|
-
```js
|
|
1035
|
-
findUser().then(function(user){
|
|
1036
|
-
// user is available
|
|
1037
|
-
}, function(reason){
|
|
1038
|
-
// user is unavailable, and you are given the reason why
|
|
1039
|
-
});
|
|
1040
|
-
```
|
|
1041
|
-
|
|
1042
|
-
Chaining
|
|
1043
|
-
--------
|
|
1044
|
-
|
|
1045
|
-
The return value of `then` is itself a promise. This second, 'downstream'
|
|
1046
|
-
promise is resolved with the return value of the first promise's fulfillment
|
|
1047
|
-
or rejection handler, or rejected if the handler throws an exception.
|
|
1048
|
-
|
|
1049
|
-
```js
|
|
1050
|
-
findUser().then(function (user) {
|
|
1051
|
-
return user.name;
|
|
1052
|
-
}, function (reason) {
|
|
1053
|
-
return 'default name';
|
|
1054
|
-
}).then(function (userName) {
|
|
1055
|
-
// If `findUser` fulfilled, `userName` will be the user's name, otherwise it
|
|
1056
|
-
// will be `'default name'`
|
|
1057
|
-
});
|
|
1058
|
-
|
|
1059
|
-
findUser().then(function (user) {
|
|
1060
|
-
throw new Error('Found user, but still unhappy');
|
|
1061
|
-
}, function (reason) {
|
|
1062
|
-
throw new Error('`findUser` rejected and we\'re unhappy');
|
|
1063
|
-
}).then(function (value) {
|
|
1064
|
-
// never reached
|
|
1065
|
-
}, function (reason) {
|
|
1066
|
-
// if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
|
|
1067
|
-
// If `findUser` rejected, `reason` will be '`findUser` rejected and we\'re unhappy'.
|
|
1068
|
-
});
|
|
1069
|
-
```
|
|
1070
|
-
If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
|
|
1071
|
-
|
|
1072
|
-
```js
|
|
1073
|
-
findUser().then(function (user) {
|
|
1074
|
-
throw new PedagogicalException('Upstream error');
|
|
1075
|
-
}).then(function (value) {
|
|
1076
|
-
// never reached
|
|
1077
|
-
}).then(function (value) {
|
|
1078
|
-
// never reached
|
|
1079
|
-
}, function (reason) {
|
|
1080
|
-
// The `PedgagocialException` is propagated all the way down to here
|
|
1081
|
-
});
|
|
1082
|
-
```
|
|
1083
|
-
|
|
1084
|
-
Assimilation
|
|
1085
|
-
------------
|
|
1086
|
-
|
|
1087
|
-
Sometimes the value you want to propagate to a downstream promise can only be
|
|
1088
|
-
retrieved asynchronously. This can be achieved by returning a promise in the
|
|
1089
|
-
fulfillment or rejection handler. The downstream promise will then be pending
|
|
1090
|
-
until the returned promise is settled. This is called *assimilation*.
|
|
1091
|
-
|
|
1092
|
-
```js
|
|
1093
|
-
findUser().then(function (user) {
|
|
1094
|
-
return findCommentsByAuthor(user);
|
|
1095
|
-
}).then(function (comments) {
|
|
1096
|
-
// The user's comments are now available
|
|
1097
|
-
});
|
|
1098
|
-
```
|
|
1099
|
-
|
|
1100
|
-
If the assimliated promise rejects, then the downstream promise will also reject.
|
|
1101
|
-
|
|
1102
|
-
```js
|
|
1103
|
-
findUser().then(function (user) {
|
|
1104
|
-
return findCommentsByAuthor(user);
|
|
1105
|
-
}).then(function (comments) {
|
|
1106
|
-
// If `findCommentsByAuthor` fulfills, we'll have the value here
|
|
1107
|
-
}, function (reason) {
|
|
1108
|
-
// If `findCommentsByAuthor` rejects, we'll have the reason here
|
|
1109
|
-
});
|
|
1110
|
-
```
|
|
1111
|
-
|
|
1112
|
-
Simple Example
|
|
1113
|
-
--------------
|
|
1114
|
-
|
|
1115
|
-
Synchronous Example
|
|
1116
|
-
|
|
1117
|
-
```javascript
|
|
1118
|
-
let result;
|
|
1119
|
-
|
|
1120
|
-
try {
|
|
1121
|
-
result = findResult();
|
|
1122
|
-
// success
|
|
1123
|
-
} catch(reason) {
|
|
1124
|
-
// failure
|
|
1125
|
-
}
|
|
1126
|
-
```
|
|
1127
|
-
|
|
1128
|
-
Errback Example
|
|
1129
|
-
|
|
1130
|
-
```js
|
|
1131
|
-
findResult(function(result, err){
|
|
1132
|
-
if (err) {
|
|
1133
|
-
// failure
|
|
1134
|
-
} else {
|
|
1135
|
-
// success
|
|
1136
|
-
}
|
|
1137
|
-
});
|
|
1138
|
-
```
|
|
1139
|
-
|
|
1140
|
-
Promise Example;
|
|
1141
|
-
|
|
1142
|
-
```javascript
|
|
1143
|
-
findResult().then(function(result){
|
|
1144
|
-
// success
|
|
1145
|
-
}, function(reason){
|
|
1146
|
-
// failure
|
|
1147
|
-
});
|
|
1148
|
-
```
|
|
1149
|
-
|
|
1150
|
-
Advanced Example
|
|
1151
|
-
--------------
|
|
1152
|
-
|
|
1153
|
-
Synchronous Example
|
|
1154
|
-
|
|
1155
|
-
```javascript
|
|
1156
|
-
let author, books;
|
|
1157
|
-
|
|
1158
|
-
try {
|
|
1159
|
-
author = findAuthor();
|
|
1160
|
-
books = findBooksByAuthor(author);
|
|
1161
|
-
// success
|
|
1162
|
-
} catch(reason) {
|
|
1163
|
-
// failure
|
|
1164
|
-
}
|
|
1165
|
-
```
|
|
1166
|
-
|
|
1167
|
-
Errback Example
|
|
1168
|
-
|
|
1169
|
-
```js
|
|
1170
|
-
|
|
1171
|
-
function foundBooks(books) {
|
|
1172
|
-
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
function failure(reason) {
|
|
1176
|
-
|
|
1177
|
-
}
|
|
1178
|
-
|
|
1179
|
-
findAuthor(function(author, err){
|
|
1180
|
-
if (err) {
|
|
1181
|
-
failure(err);
|
|
1182
|
-
// failure
|
|
1183
|
-
} else {
|
|
1184
|
-
try {
|
|
1185
|
-
findBoooksByAuthor(author, function(books, err) {
|
|
1186
|
-
if (err) {
|
|
1187
|
-
failure(err);
|
|
1188
|
-
} else {
|
|
1189
|
-
try {
|
|
1190
|
-
foundBooks(books);
|
|
1191
|
-
} catch(reason) {
|
|
1192
|
-
failure(reason);
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
});
|
|
1196
|
-
} catch(error) {
|
|
1197
|
-
failure(err);
|
|
253
|
+
if (!found) {
|
|
254
|
+
payload.push(parentRelationshipData);
|
|
1198
255
|
}
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
});
|
|
1202
|
-
```
|
|
1203
|
-
|
|
1204
|
-
Promise Example;
|
|
1205
|
-
|
|
1206
|
-
```javascript
|
|
1207
|
-
findAuthor().
|
|
1208
|
-
then(findBooksByAuthor).
|
|
1209
|
-
then(function(books){
|
|
1210
|
-
// found books
|
|
1211
|
-
}).catch(function(reason){
|
|
1212
|
-
// something went wrong
|
|
1213
|
-
});
|
|
1214
|
-
```
|
|
1215
|
-
|
|
1216
|
-
@method then
|
|
1217
|
-
@param {Function} onFulfillment
|
|
1218
|
-
@param {Function} onRejection
|
|
1219
|
-
@param {String} [label] optional string for labeling the promise.
|
|
1220
|
-
Useful for tooling.
|
|
1221
|
-
@return {Promise}
|
|
1222
|
-
*/
|
|
1223
|
-
Promise$1.prototype.then = then;
|
|
1224
|
-
function _possibleConstructorReturn(self, call) {
|
|
1225
|
-
if (!self) {
|
|
1226
|
-
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
|
1227
|
-
}
|
|
1228
|
-
return call && (typeof call === "object" || typeof call === "function") ? call : self;
|
|
1229
|
-
}
|
|
1230
|
-
function _inherits(subClass, superClass) {
|
|
1231
|
-
if (typeof superClass !== "function" && superClass !== null) {
|
|
1232
|
-
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
|
|
1233
|
-
}
|
|
1234
|
-
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
|
1235
|
-
constructor: {
|
|
1236
|
-
value: subClass,
|
|
1237
|
-
enumerable: false,
|
|
1238
|
-
writable: true,
|
|
1239
|
-
configurable: true
|
|
256
|
+
} else {
|
|
257
|
+
payload.push(parentRelationshipData);
|
|
1240
258
|
}
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
/**
|
|
1246
|
-
@module rsvp
|
|
1247
|
-
@public
|
|
1248
|
-
**/
|
|
1249
|
-
|
|
1250
|
-
var AllSettled = function (_Enumerator) {
|
|
1251
|
-
_inherits(AllSettled, _Enumerator);
|
|
1252
|
-
function AllSettled(Constructor, entries, label) {
|
|
1253
|
-
return _possibleConstructorReturn(this, _Enumerator.call(this, Constructor, entries, false /* don't abort on reject */, label));
|
|
1254
|
-
}
|
|
1255
|
-
return AllSettled;
|
|
1256
|
-
}(Enumerator);
|
|
1257
|
-
AllSettled.prototype._setResultAt = setSettledResult;
|
|
1258
|
-
function _possibleConstructorReturn$1(self, call) {
|
|
1259
|
-
if (!self) {
|
|
1260
|
-
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
|
259
|
+
} else {
|
|
260
|
+
payload = relationshipData || {};
|
|
261
|
+
Object.assign(payload, parentRelationshipData);
|
|
1261
262
|
}
|
|
1262
|
-
return
|
|
263
|
+
return payload;
|
|
1263
264
|
}
|
|
1264
|
-
function
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
value: subClass,
|
|
1271
|
-
enumerable: false,
|
|
1272
|
-
writable: true,
|
|
1273
|
-
configurable: true
|
|
1274
|
-
}
|
|
1275
|
-
});
|
|
1276
|
-
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
|
|
265
|
+
function validateRelationshipEntry({
|
|
266
|
+
id
|
|
267
|
+
}, {
|
|
268
|
+
id: parentModelID
|
|
269
|
+
}) {
|
|
270
|
+
return id && id.toString() === parentModelID;
|
|
1277
271
|
}
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
return _possibleConstructorReturn$1(this, _Enumerator.call(this, Constructor, object, abortOnReject, label));
|
|
1284
|
-
}
|
|
1285
|
-
PromiseHash.prototype._init = function _init(Constructor, object) {
|
|
1286
|
-
this._result = {};
|
|
1287
|
-
this._enumerate(object);
|
|
1288
|
-
};
|
|
1289
|
-
PromiseHash.prototype._enumerate = function _enumerate(input) {
|
|
1290
|
-
var keys = Object.keys(input);
|
|
1291
|
-
var length = keys.length;
|
|
1292
|
-
var promise = this.promise;
|
|
1293
|
-
this._remaining = length;
|
|
1294
|
-
var key = void 0,
|
|
1295
|
-
val = void 0;
|
|
1296
|
-
for (var i = 0; promise._state === PENDING && i < length; i++) {
|
|
1297
|
-
key = keys[i];
|
|
1298
|
-
val = input[key];
|
|
1299
|
-
this._eachEntry(val, key, true);
|
|
272
|
+
const LegacyNetworkHandler = {
|
|
273
|
+
request(context, next) {
|
|
274
|
+
// if we are not a legacy request, move on
|
|
275
|
+
if (context.request.url || !context.request.op) {
|
|
276
|
+
return next(context.request);
|
|
1300
277
|
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
if (!self) {
|
|
1307
|
-
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
|
1308
|
-
}
|
|
1309
|
-
return call && (typeof call === "object" || typeof call === "function") ? call : self;
|
|
1310
|
-
}
|
|
1311
|
-
function _inherits$2(subClass, superClass) {
|
|
1312
|
-
if (typeof superClass !== "function" && superClass !== null) {
|
|
1313
|
-
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
|
|
1314
|
-
}
|
|
1315
|
-
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
|
1316
|
-
constructor: {
|
|
1317
|
-
value: subClass,
|
|
1318
|
-
enumerable: false,
|
|
1319
|
-
writable: true,
|
|
1320
|
-
configurable: true
|
|
278
|
+
const {
|
|
279
|
+
store
|
|
280
|
+
} = context.request;
|
|
281
|
+
if (!store._fetchManager) {
|
|
282
|
+
store._fetchManager = new FetchManager(store);
|
|
1321
283
|
}
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
|
1344
|
-
constructor: {
|
|
1345
|
-
value: subClass,
|
|
1346
|
-
enumerable: false,
|
|
1347
|
-
writable: true,
|
|
1348
|
-
configurable: true
|
|
284
|
+
switch (context.request.op) {
|
|
285
|
+
case 'findRecord':
|
|
286
|
+
return findRecord(context);
|
|
287
|
+
case 'findAll':
|
|
288
|
+
return findAll(context);
|
|
289
|
+
case 'query':
|
|
290
|
+
return query(context);
|
|
291
|
+
case 'queryRecord':
|
|
292
|
+
return queryRecord(context);
|
|
293
|
+
case 'findBelongsTo':
|
|
294
|
+
return findBelongsTo(context);
|
|
295
|
+
case 'findHasMany':
|
|
296
|
+
return findHasMany(context);
|
|
297
|
+
case 'updateRecord':
|
|
298
|
+
return saveRecord(context);
|
|
299
|
+
case 'createRecord':
|
|
300
|
+
return saveRecord(context);
|
|
301
|
+
case 'deleteRecord':
|
|
302
|
+
return saveRecord(context);
|
|
303
|
+
default:
|
|
304
|
+
return next(context.request);
|
|
1349
305
|
}
|
|
1350
|
-
});
|
|
1351
|
-
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
|
|
1352
|
-
}
|
|
1353
|
-
var MapEnumerator = function (_Enumerator) {
|
|
1354
|
-
_inherits$3(MapEnumerator, _Enumerator);
|
|
1355
|
-
function MapEnumerator(Constructor, entries, mapFn, label) {
|
|
1356
|
-
return _possibleConstructorReturn$3(this, _Enumerator.call(this, Constructor, entries, true, label, mapFn));
|
|
1357
306
|
}
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
}
|
|
1374
|
-
} else {
|
|
1375
|
-
this._remaining--;
|
|
1376
|
-
this._result[i] = value;
|
|
1377
|
-
}
|
|
1378
|
-
};
|
|
1379
|
-
return MapEnumerator;
|
|
1380
|
-
}(Enumerator);
|
|
1381
|
-
|
|
1382
|
-
/**
|
|
1383
|
-
This is a convenient alias for `Promise.resolve`.
|
|
307
|
+
};
|
|
308
|
+
function findBelongsTo(context) {
|
|
309
|
+
const {
|
|
310
|
+
store,
|
|
311
|
+
data,
|
|
312
|
+
records: identifiers
|
|
313
|
+
} = context.request;
|
|
314
|
+
const {
|
|
315
|
+
options,
|
|
316
|
+
record,
|
|
317
|
+
links,
|
|
318
|
+
useLink,
|
|
319
|
+
field
|
|
320
|
+
} = data;
|
|
321
|
+
const identifier = identifiers?.[0];
|
|
1384
322
|
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
@param {*} value value that the returned promise will be resolved with
|
|
1390
|
-
@param {String} [label] optional string for identifying the returned promise.
|
|
1391
|
-
Useful for tooling.
|
|
1392
|
-
@return {Promise} a promise that will become fulfilled with the given
|
|
1393
|
-
`value`
|
|
1394
|
-
*/
|
|
1395
|
-
function resolve$2(value, label) {
|
|
1396
|
-
return Promise$1.resolve(value, label);
|
|
1397
|
-
}
|
|
1398
|
-
function _possibleConstructorReturn$4(self, call) {
|
|
1399
|
-
if (!self) {
|
|
1400
|
-
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
|
323
|
+
// short circuit if we are already loading
|
|
324
|
+
let pendingRequest = identifier && store._fetchManager.getPendingFetch(identifier, options);
|
|
325
|
+
if (pendingRequest) {
|
|
326
|
+
return pendingRequest;
|
|
1401
327
|
}
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
function _inherits$4(subClass, superClass) {
|
|
1405
|
-
if (typeof superClass !== "function" && superClass !== null) {
|
|
1406
|
-
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
|
|
328
|
+
if (useLink) {
|
|
329
|
+
return _findBelongsTo(store, record, links.related, field, options);
|
|
1407
330
|
}
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
writable: true,
|
|
1413
|
-
configurable: true
|
|
1414
|
-
}
|
|
1415
|
-
});
|
|
1416
|
-
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
|
|
331
|
+
assert(`Expected an identifier`, Array.isArray(identifiers) && identifiers.length === 1);
|
|
332
|
+
const manager = store._fetchManager;
|
|
333
|
+
assertIdentifierHasId(identifier);
|
|
334
|
+
return options.reload ? manager.scheduleFetch(identifier, options, context.request) : manager.fetchDataIfNeededForIdentifier(identifier, options, context.request);
|
|
1417
335
|
}
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
}
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
336
|
+
function findHasMany(context) {
|
|
337
|
+
const {
|
|
338
|
+
store,
|
|
339
|
+
data,
|
|
340
|
+
records: identifiers
|
|
341
|
+
} = context.request;
|
|
342
|
+
const {
|
|
343
|
+
options,
|
|
344
|
+
record,
|
|
345
|
+
links,
|
|
346
|
+
useLink,
|
|
347
|
+
field
|
|
348
|
+
} = data;
|
|
349
|
+
|
|
350
|
+
// link case
|
|
351
|
+
if (useLink) {
|
|
352
|
+
const adapter = store.adapterFor(record.type);
|
|
353
|
+
/*
|
|
354
|
+
If a relationship was originally populated by the adapter as a link
|
|
355
|
+
(as opposed to a list of IDs), this method is called when the
|
|
356
|
+
relationship is fetched.
|
|
357
|
+
The link (which is usually a URL) is passed through unchanged, so the
|
|
358
|
+
adapter can make whatever request it wants.
|
|
359
|
+
The usual use-case is for the server to register a URL as a link, and
|
|
360
|
+
then use that URL in the future to make a request for the relationship.
|
|
361
|
+
*/
|
|
362
|
+
assert(`You tried to load a hasMany relationship but you have no adapter (for ${record.type})`, adapter);
|
|
363
|
+
assert(`You tried to load a hasMany relationship from a specified 'link' in the original payload but your adapter does not implement 'findHasMany'`, typeof adapter.findHasMany === 'function');
|
|
364
|
+
return _findHasMany(adapter, store, record, links.related, field, options);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// identifiers case
|
|
368
|
+
|
|
369
|
+
const fetches = new Array(identifiers.length);
|
|
370
|
+
const manager = store._fetchManager;
|
|
371
|
+
for (let i = 0; i < identifiers.length; i++) {
|
|
372
|
+
let identifier = identifiers[i];
|
|
373
|
+
// TODO we probably can be lenient here and return from cache for the isNew case
|
|
374
|
+
assertIdentifierHasId(identifier);
|
|
375
|
+
fetches[i] = options.reload ? manager.scheduleFetch(identifier, options, context.request) : manager.fetchDataIfNeededForIdentifier(identifier, options, context.request);
|
|
376
|
+
}
|
|
377
|
+
return Promise.all(fetches);
|
|
378
|
+
}
|
|
379
|
+
function saveRecord(context) {
|
|
380
|
+
const {
|
|
381
|
+
store,
|
|
382
|
+
data,
|
|
383
|
+
op: operation
|
|
384
|
+
} = context.request;
|
|
385
|
+
const {
|
|
386
|
+
options,
|
|
387
|
+
record: identifier
|
|
388
|
+
} = data;
|
|
389
|
+
const saveOptions = Object.assign({
|
|
390
|
+
[SaveOp]: operation
|
|
391
|
+
}, options);
|
|
392
|
+
const fetchManagerPromise = store._fetchManager.scheduleSave(identifier, saveOptions);
|
|
393
|
+
return fetchManagerPromise.then(payload => {
|
|
394
|
+
if (macroCondition(getOwnConfig().debug.LOG_PAYLOADS)) {
|
|
395
|
+
try {
|
|
396
|
+
let data = payload ? JSON.parse(JSON.stringify(payload)) : payload;
|
|
397
|
+
// eslint-disable-next-line no-console
|
|
398
|
+
console.log(`EmberData | Payload - ${operation}`, data);
|
|
399
|
+
} catch (e) {
|
|
400
|
+
// eslint-disable-next-line no-console
|
|
401
|
+
console.log(`EmberData | Payload - ${operation}`, payload);
|
|
402
|
+
}
|
|
1431
403
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
404
|
+
/*
|
|
405
|
+
// TODO @runspired re-evaluate the below claim now that
|
|
406
|
+
// the save request pipeline is more streamlined.
|
|
407
|
+
Note to future spelunkers hoping to optimize.
|
|
408
|
+
We rely on this `run` to create a run loop if needed
|
|
409
|
+
that `store._push` and `store.saveRecord` will both share.
|
|
410
|
+
We use `join` because it is often the case that we
|
|
411
|
+
have an outer run loop available still from the first
|
|
412
|
+
call to `store._push`;
|
|
413
|
+
*/
|
|
414
|
+
store._join(() => {
|
|
415
|
+
let data = payload && payload.data;
|
|
416
|
+
if (!data) {
|
|
417
|
+
assert(`Your ${identifier.type} record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, identifier.id);
|
|
1441
418
|
}
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
if (
|
|
1445
|
-
|
|
419
|
+
const identifierCache = store.identifierCache;
|
|
420
|
+
let actualIdentifier = identifier;
|
|
421
|
+
if (operation !== 'deleteRecord' && data) {
|
|
422
|
+
actualIdentifier = identifierCache.updateRecordIdentifier(identifier, data);
|
|
1446
423
|
}
|
|
1447
|
-
}
|
|
1448
|
-
};
|
|
1449
|
-
return FilterEnumerator;
|
|
1450
|
-
})(MapEnumerator);
|
|
1451
|
-
var len = 0;
|
|
1452
|
-
var vertxNext = void 0;
|
|
1453
|
-
function asap(callback, arg) {
|
|
1454
|
-
queue$1[len] = callback;
|
|
1455
|
-
queue$1[len + 1] = arg;
|
|
1456
|
-
len += 2;
|
|
1457
|
-
if (len === 2) {
|
|
1458
|
-
// If len is 1, that means that we need to schedule an async flush.
|
|
1459
|
-
// If additional callbacks are queued before the queue is flushed, they
|
|
1460
|
-
// will be processed by this flush that we are scheduling.
|
|
1461
|
-
scheduleFlush$1();
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
var browserWindow = typeof window !== 'undefined' ? window : undefined;
|
|
1465
|
-
var browserGlobal = browserWindow || {};
|
|
1466
|
-
var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
|
|
1467
|
-
var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
|
|
1468
|
-
|
|
1469
|
-
// test for web worker but not in IE10
|
|
1470
|
-
var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
|
|
1471
|
-
|
|
1472
|
-
// node
|
|
1473
|
-
function useNextTick() {
|
|
1474
|
-
var nextTick = process.nextTick;
|
|
1475
|
-
// node version 0.10.x displays a deprecation warning when nextTick is used recursively
|
|
1476
|
-
// setImmediate should be used instead instead
|
|
1477
|
-
var version = process.versions.node.match(/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/);
|
|
1478
|
-
if (Array.isArray(version) && version[1] === '0' && version[2] === '10') {
|
|
1479
|
-
nextTick = setImmediate;
|
|
1480
|
-
}
|
|
1481
|
-
return function () {
|
|
1482
|
-
return nextTick(flush);
|
|
1483
|
-
};
|
|
1484
|
-
}
|
|
1485
|
-
|
|
1486
|
-
// vertx
|
|
1487
|
-
function useVertxTimer() {
|
|
1488
|
-
if (typeof vertxNext !== 'undefined') {
|
|
1489
|
-
return function () {
|
|
1490
|
-
vertxNext(flush);
|
|
1491
|
-
};
|
|
1492
|
-
}
|
|
1493
|
-
return useSetTimeout();
|
|
1494
|
-
}
|
|
1495
|
-
function useMutationObserver() {
|
|
1496
|
-
var iterations = 0;
|
|
1497
|
-
var observer = new BrowserMutationObserver(flush);
|
|
1498
|
-
var node = document.createTextNode('');
|
|
1499
|
-
observer.observe(node, {
|
|
1500
|
-
characterData: true
|
|
1501
|
-
});
|
|
1502
|
-
return function () {
|
|
1503
|
-
return node.data = iterations = ++iterations % 2;
|
|
1504
|
-
};
|
|
1505
|
-
}
|
|
1506
424
|
|
|
1507
|
-
//
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
return
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
}
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
}
|
|
1551
|
-
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1554
|
-
// defaults
|
|
1555
|
-
config.async = asap;
|
|
1556
|
-
config.after = function (cb) {
|
|
1557
|
-
return setTimeout(cb, 0);
|
|
1558
|
-
};
|
|
1559
|
-
function on() {
|
|
1560
|
-
config.on.apply(config, arguments);
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
// Set up instrumentation through `window.__PROMISE_INTRUMENTATION__`
|
|
1564
|
-
if (typeof window !== 'undefined' && typeof window['__PROMISE_INSTRUMENTATION__'] === 'object') {
|
|
1565
|
-
var callbacks = window['__PROMISE_INSTRUMENTATION__'];
|
|
1566
|
-
configure('instrument', true);
|
|
1567
|
-
for (var eventName in callbacks) {
|
|
1568
|
-
if (callbacks.hasOwnProperty(eventName)) {
|
|
1569
|
-
on(eventName, callbacks[eventName]);
|
|
1570
|
-
}
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
function _guard(promise, test) {
|
|
1574
|
-
let guarded = promise.finally(() => {
|
|
1575
|
-
if (!test()) {
|
|
1576
|
-
guarded._subscribers.length = 0;
|
|
425
|
+
//We first make sure the primary data has been updated
|
|
426
|
+
const cache = macroCondition(getOwnConfig().deprecations.DEPRECATE_V1_RECORD_DATA) ? store._instanceCache.getResourceCache(actualIdentifier) : store.cache;
|
|
427
|
+
cache.didCommit(identifier, data);
|
|
428
|
+
if (payload && payload.included) {
|
|
429
|
+
store._push({
|
|
430
|
+
data: null,
|
|
431
|
+
included: payload.included
|
|
432
|
+
}, true);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
return store.peekRecord(identifier);
|
|
436
|
+
}).catch(e => {
|
|
437
|
+
let err = e;
|
|
438
|
+
if (!e) {
|
|
439
|
+
err = new Error(`Unknown Error Occurred During Request`);
|
|
440
|
+
} else if (typeof e === 'string') {
|
|
441
|
+
err = new Error(e);
|
|
442
|
+
}
|
|
443
|
+
adapterDidInvalidate(store, identifier, err);
|
|
444
|
+
throw err;
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
function adapterDidInvalidate(store, identifier, error) {
|
|
448
|
+
if (error && error.isAdapterError === true && error.code === 'InvalidError') {
|
|
449
|
+
let serializer = store.serializerFor(identifier.type);
|
|
450
|
+
|
|
451
|
+
// TODO @deprecate extractErrors being called
|
|
452
|
+
// TODO remove extractErrors from the default serializers.
|
|
453
|
+
if (serializer && typeof serializer.extractErrors === 'function') {
|
|
454
|
+
let errorsHash = serializer.extractErrors(store, store.modelFor(identifier.type), error, identifier.id);
|
|
455
|
+
error.errors = errorsHashToArray(errorsHash);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
const cache = macroCondition(getOwnConfig().deprecations.DEPRECATE_V1_RECORD_DATA) ? store._instanceCache.getResourceCache(identifier) : store.cache;
|
|
459
|
+
if (error.errors) {
|
|
460
|
+
assert(`Expected the cache in use by resource ${String(identifier)} to have a getErrors(identifier) method for retreiving errors.`, typeof cache.getErrors === 'function');
|
|
461
|
+
let jsonApiErrors = error.errors;
|
|
462
|
+
if (jsonApiErrors.length === 0) {
|
|
463
|
+
jsonApiErrors = [{
|
|
464
|
+
title: 'Invalid Error',
|
|
465
|
+
detail: '',
|
|
466
|
+
source: {
|
|
467
|
+
pointer: '/data'
|
|
468
|
+
}
|
|
469
|
+
}];
|
|
1577
470
|
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
471
|
+
cache.commitWasRejected(identifier, jsonApiErrors);
|
|
472
|
+
} else {
|
|
473
|
+
cache.commitWasRejected(identifier);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
function makeArray(value) {
|
|
477
|
+
return Array.isArray(value) ? value : [value];
|
|
478
|
+
}
|
|
479
|
+
const PRIMARY_ATTRIBUTE_KEY = 'base';
|
|
480
|
+
function errorsHashToArray(errors) {
|
|
481
|
+
const out = [];
|
|
482
|
+
if (errors) {
|
|
483
|
+
Object.keys(errors).forEach(key => {
|
|
484
|
+
let messages = makeArray(errors[key]);
|
|
485
|
+
for (let i = 0; i < messages.length; i++) {
|
|
486
|
+
let title = 'Invalid Attribute';
|
|
487
|
+
let pointer = `/data/attributes/${key}`;
|
|
488
|
+
if (key === PRIMARY_ATTRIBUTE_KEY) {
|
|
489
|
+
title = 'Invalid Document';
|
|
490
|
+
pointer = `/data`;
|
|
491
|
+
}
|
|
492
|
+
out.push({
|
|
493
|
+
title: title,
|
|
494
|
+
detail: messages[i],
|
|
495
|
+
source: {
|
|
496
|
+
pointer: pointer
|
|
1595
497
|
}
|
|
1596
498
|
});
|
|
1597
499
|
}
|
|
1598
|
-
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
return _guard(wrapperPromise, () => {
|
|
1602
|
-
return _objectIsAlive(store);
|
|
1603
|
-
});
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
return out;
|
|
1604
503
|
}
|
|
504
|
+
function findRecord(context) {
|
|
505
|
+
const {
|
|
506
|
+
store,
|
|
507
|
+
data
|
|
508
|
+
} = context.request;
|
|
509
|
+
const {
|
|
510
|
+
record: identifier,
|
|
511
|
+
options
|
|
512
|
+
} = data;
|
|
513
|
+
let promise;
|
|
1605
514
|
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
The format of a document is described here:
|
|
1610
|
-
http://jsonapi.org/format/#document-top-level
|
|
515
|
+
// if not loaded start loading
|
|
516
|
+
if (!store._instanceCache.recordIsLoaded(identifier)) {
|
|
517
|
+
promise = store._fetchManager.fetchDataIfNeededForIdentifier(identifier, options, context.request);
|
|
1611
518
|
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
519
|
+
// Refetch if the reload option is passed
|
|
520
|
+
} else if (options.reload) {
|
|
521
|
+
assertIdentifierHasId(identifier);
|
|
522
|
+
promise = store._fetchManager.scheduleFetch(identifier, options, context.request);
|
|
523
|
+
} else {
|
|
524
|
+
let snapshot = null;
|
|
525
|
+
let adapter = store.adapterFor(identifier.type);
|
|
526
|
+
|
|
527
|
+
// Refetch the record if the adapter thinks the record is stale
|
|
528
|
+
if (typeof options.reload === 'undefined' && adapter.shouldReloadRecord && adapter.shouldReloadRecord(store, snapshot = store._fetchManager.createSnapshot(identifier, options))) {
|
|
529
|
+
assertIdentifierHasId(identifier);
|
|
530
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
531
|
+
promise = store._fetchManager.scheduleFetch(identifier, Object.assign({}, options, {
|
|
532
|
+
reload: true
|
|
533
|
+
}), context.request);
|
|
1622
534
|
} else {
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
}
|
|
1626
|
-
}
|
|
1627
|
-
if ('data' in doc) {
|
|
1628
|
-
if (!(doc.data === null || Array.isArray(doc.data) || typeof doc.data === 'object')) {
|
|
1629
|
-
errors.push('data must be null, an object, or an array');
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
|
-
if ('meta' in doc) {
|
|
1633
|
-
if (typeof doc.meta !== 'object') {
|
|
1634
|
-
errors.push('meta must be an object');
|
|
1635
|
-
}
|
|
1636
|
-
}
|
|
1637
|
-
if ('errors' in doc) {
|
|
1638
|
-
if (!Array.isArray(doc.errors)) {
|
|
1639
|
-
errors.push('errors must be an array');
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
if ('links' in doc) {
|
|
1643
|
-
if (typeof doc.links !== 'object') {
|
|
1644
|
-
errors.push('links must be an object');
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
|
-
if ('jsonapi' in doc) {
|
|
1648
|
-
if (typeof doc.jsonapi !== 'object') {
|
|
1649
|
-
errors.push('jsonapi must be an object');
|
|
1650
|
-
}
|
|
535
|
+
options.reload = true;
|
|
536
|
+
promise = store._fetchManager.scheduleFetch(identifier, options, context.request);
|
|
1651
537
|
}
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
538
|
+
} else {
|
|
539
|
+
// Trigger the background refetch if backgroundReload option is passed
|
|
540
|
+
if (options.backgroundReload !== false && (options.backgroundReload || !adapter.shouldBackgroundReloadRecord || adapter.shouldBackgroundReloadRecord(store, snapshot = snapshot || store._fetchManager.createSnapshot(identifier, options)))) {
|
|
541
|
+
assertIdentifierHasId(identifier);
|
|
542
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
543
|
+
void store._fetchManager.scheduleFetch(identifier, Object.assign({}, options, {
|
|
544
|
+
backgroundReload: true
|
|
545
|
+
}), context.request);
|
|
546
|
+
} else {
|
|
547
|
+
options.backgroundReload = true;
|
|
548
|
+
void store._fetchManager.scheduleFetch(identifier, options, context.request);
|
|
1655
549
|
}
|
|
1656
550
|
}
|
|
551
|
+
|
|
552
|
+
// Return the cached record
|
|
553
|
+
promise = Promise.resolve(identifier);
|
|
1657
554
|
}
|
|
1658
|
-
assert(`Response must be normalized to a valid JSON API document:\n\t* ${errors.join('\n\t* ')}`, errors.length === 0);
|
|
1659
555
|
}
|
|
556
|
+
return promise.then(identifier => store.peekRecord(identifier));
|
|
1660
557
|
}
|
|
1661
|
-
function normalizeResponseHelper(serializer, store, modelClass, payload, id, requestType) {
|
|
1662
|
-
let normalizedResponse = serializer ? serializer.normalizeResponse(store, modelClass, payload, id, requestType) : payload;
|
|
1663
|
-
validateDocumentStructure(normalizedResponse);
|
|
1664
|
-
return normalizedResponse;
|
|
1665
|
-
}
|
|
1666
|
-
const LegacyNetworkHandler = {
|
|
1667
|
-
request(context, next) {
|
|
1668
|
-
// if we are not a legacy request, move on
|
|
1669
|
-
if (context.request.url || !context.request.op) {
|
|
1670
|
-
return next(context.request);
|
|
1671
|
-
}
|
|
1672
|
-
switch (context.request.op) {
|
|
1673
|
-
case 'findAll':
|
|
1674
|
-
return findAll(context);
|
|
1675
|
-
case 'queryRecord':
|
|
1676
|
-
return queryRecord(context);
|
|
1677
|
-
case 'query':
|
|
1678
|
-
return query(context);
|
|
1679
|
-
default:
|
|
1680
|
-
return next(context.request);
|
|
1681
|
-
}
|
|
1682
|
-
}
|
|
1683
|
-
};
|
|
1684
558
|
function findAll(context) {
|
|
1685
559
|
const {
|
|
1686
560
|
store,
|
|
@@ -1701,35 +575,41 @@ function findAll(context) {
|
|
|
1701
575
|
let fetch;
|
|
1702
576
|
if (shouldReload) {
|
|
1703
577
|
maybeRecordArray && (maybeRecordArray.isUpdating = true);
|
|
1704
|
-
fetch = _findAll(adapter, store, type, snapshotArray);
|
|
578
|
+
fetch = _findAll(adapter, store, type, snapshotArray, context.request, true);
|
|
1705
579
|
} else {
|
|
1706
|
-
fetch = Promise
|
|
580
|
+
fetch = Promise.resolve(store.peekAll(type));
|
|
1707
581
|
if (options.backgroundReload || options.backgroundReload !== false && (!adapter.shouldBackgroundReloadAll || adapter.shouldBackgroundReloadAll(store, snapshotArray))) {
|
|
1708
582
|
maybeRecordArray && (maybeRecordArray.isUpdating = true);
|
|
1709
|
-
void _findAll(adapter, store, type, snapshotArray);
|
|
583
|
+
void _findAll(adapter, store, type, snapshotArray, context.request, false);
|
|
1710
584
|
}
|
|
1711
585
|
}
|
|
1712
586
|
return fetch;
|
|
1713
587
|
}
|
|
1714
|
-
function
|
|
1715
|
-
if (Array.isArray(adapterPayload)) {
|
|
1716
|
-
return true;
|
|
1717
|
-
} else {
|
|
1718
|
-
return Object.keys(adapterPayload || {}).length;
|
|
1719
|
-
}
|
|
1720
|
-
}
|
|
1721
|
-
function _findAll(adapter, store, type, snapshotArray) {
|
|
588
|
+
function _findAll(adapter, store, type, snapshotArray, request, isAsyncFlush) {
|
|
1722
589
|
const schema = store.modelFor(type);
|
|
1723
|
-
let promise = Promise
|
|
1724
|
-
promise = guardDestroyedStore(promise, store
|
|
1725
|
-
|
|
590
|
+
let promise = Promise.resolve().then(() => adapter.findAll(store, schema, null, snapshotArray));
|
|
591
|
+
promise = guardDestroyedStore(promise, store);
|
|
592
|
+
promise = promise.then(adapterPayload => {
|
|
1726
593
|
assert(`You made a 'findAll' request for '${type}' records, but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload));
|
|
1727
594
|
const serializer = store.serializerFor(type);
|
|
1728
595
|
const payload = normalizeResponseHelper(serializer, store, schema, adapterPayload, null, 'findAll');
|
|
1729
|
-
store._push(payload);
|
|
596
|
+
store._push(payload, isAsyncFlush);
|
|
1730
597
|
snapshotArray._recordArray.isUpdating = false;
|
|
598
|
+
if (macroCondition(getOwnConfig().debug.LOG_PAYLOADS)) {
|
|
599
|
+
// eslint-disable-next-line no-console
|
|
600
|
+
console.log(`request: findAll<${type}> background reload complete`);
|
|
601
|
+
}
|
|
1731
602
|
return snapshotArray._recordArray;
|
|
1732
603
|
});
|
|
604
|
+
if (macroCondition(getOwnConfig().env.TESTING)) {
|
|
605
|
+
if (!request.disableTestWaiter) {
|
|
606
|
+
const {
|
|
607
|
+
waitForPromise
|
|
608
|
+
} = importSync('@ember/test-waiters');
|
|
609
|
+
promise = waitForPromise(promise);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return promise;
|
|
1733
613
|
}
|
|
1734
614
|
function query(context) {
|
|
1735
615
|
const {
|
|
@@ -1750,19 +630,19 @@ function query(context) {
|
|
|
1750
630
|
type,
|
|
1751
631
|
query
|
|
1752
632
|
});
|
|
1753
|
-
if (macroCondition(
|
|
633
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
1754
634
|
options = Object.assign({}, options);
|
|
1755
635
|
delete options._recordArray;
|
|
1756
636
|
} else {
|
|
1757
637
|
delete options._recordArray;
|
|
1758
638
|
}
|
|
1759
639
|
const schema = store.modelFor(type);
|
|
1760
|
-
let promise = Promise
|
|
1761
|
-
promise = guardDestroyedStore(promise, store
|
|
640
|
+
let promise = Promise.resolve().then(() => adapter.query(store, schema, query, recordArray, options));
|
|
641
|
+
promise = guardDestroyedStore(promise, store);
|
|
1762
642
|
return promise.then(adapterPayload => {
|
|
1763
643
|
const serializer = store.serializerFor(type);
|
|
1764
644
|
const payload = normalizeResponseHelper(serializer, store, schema, adapterPayload, null, 'query');
|
|
1765
|
-
const identifiers = store._push(payload);
|
|
645
|
+
const identifiers = store._push(payload, true);
|
|
1766
646
|
assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Array.isArray(identifiers));
|
|
1767
647
|
store.recordArrayManager.populateManagedArray(recordArray, identifiers, payload);
|
|
1768
648
|
return recordArray;
|
|
@@ -1785,13 +665,14 @@ function queryRecord(context) {
|
|
|
1785
665
|
assert(`You tried to make a query but you have no adapter (for ${type})`, adapter);
|
|
1786
666
|
assert(`You tried to make a query but your adapter does not implement 'queryRecord'`, typeof adapter.queryRecord === 'function');
|
|
1787
667
|
const schema = store.modelFor(type);
|
|
1788
|
-
let promise = Promise
|
|
1789
|
-
promise = guardDestroyedStore(promise, store
|
|
668
|
+
let promise = Promise.resolve().then(() => adapter.queryRecord(store, schema, query, options));
|
|
669
|
+
promise = guardDestroyedStore(promise, store);
|
|
1790
670
|
return promise.then(adapterPayload => {
|
|
1791
671
|
const serializer = store.serializerFor(type);
|
|
1792
672
|
const payload = normalizeResponseHelper(serializer, store, schema, adapterPayload, null, 'queryRecord');
|
|
1793
673
|
assertSingleResourceDocument(payload);
|
|
1794
|
-
|
|
674
|
+
const identifier = store._push(payload, true);
|
|
675
|
+
return identifier ? store.peekRecord(identifier) : null;
|
|
1795
676
|
});
|
|
1796
677
|
}
|
|
1797
678
|
export { LegacyNetworkHandler };
|