@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/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 { S as SnapshotRecordArray } from "./snapshot-record-array-a4efeb60";
4
-
5
- /*!
6
- * @overview RSVP - a tiny implementation of Promises/A+.
7
- * @copyright Copyright (c) 2016 Yehuda Katz, Tom Dale, Stefan Penner and contributors
8
- * @license Licensed under MIT license
9
- * See https://raw.githubusercontent.com/tildeio/rsvp.js/master/LICENSE
10
- * @version 4.8.4+ff10049b
11
- */
12
-
13
- function callbacksFor(object) {
14
- var callbacks = object._promiseCallbacks;
15
- if (!callbacks) {
16
- callbacks = object._promiseCallbacks = {};
17
- }
18
- return callbacks;
19
- }
20
-
21
- /**
22
- @class EventTarget
23
- @for rsvp
24
- @public
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
- var queue = [];
186
- function scheduleFlush() {
187
- setTimeout(function () {
188
- for (var i = 0; i < queue.length; i++) {
189
- var entry = queue[i];
190
- var payload = entry.payload;
191
- payload.guid = payload.key + payload.id;
192
- payload.childGuid = payload.key + payload.childId;
193
- if (payload.error) {
194
- payload.stack = payload.error.stack;
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
- queue.length = 0;
199
- }, 50);
200
- }
201
- function instrument(eventName, promise, child) {
202
- if (1 === queue.push({
203
- name: eventName,
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
- scheduleFlush();
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
- `Promise.resolve` returns a promise that will become resolved with the
221
- passed `value`. It is shorthand for the following:
222
-
223
- ```javascript
224
- import Promise from 'rsvp';
225
-
226
- let promise = new Promise(function(resolve, reject){
227
- resolve(1);
228
- });
229
-
230
- promise.then(function(value){
231
- // value === 1
232
- });
233
- ```
234
-
235
- Instead of writing the above, your code now simply becomes the following:
236
-
237
- ```javascript
238
- import Promise from 'rsvp';
239
-
240
- let promise = RSVP.Promise.resolve(1);
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
- var promise = new Constructor(noop, label);
263
- resolve$1(promise, object);
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
- var tryCatchCallback = void 0;
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
- function tryCatch(fn) {
300
- tryCatchCallback = fn;
301
- return tryCatcher;
302
- }
303
- function handleForeignThenable(promise, thenable, then$$1) {
304
- config.async(function (promise) {
305
- var sealed = false;
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
- }, promise);
330
- }
331
- function handleOwnThenable(promise, thenable) {
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
- publish(promise);
127
+ payload.included.push(parentPayload);
128
+ return payload;
377
129
  }
378
- function fulfill(promise, value) {
379
- if (promise._state !== PENDING) {
380
- return;
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
- promise._result = value;
383
- promise._state = FULFILLED;
384
- if (promise._subscribers.length === 0) {
385
- if (config.instrument) {
386
- instrument('fulfilled', promise);
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 subscribe(parent, child, onFulfillment, onRejection) {
401
- var subscribers = parent._subscribers;
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 publish(promise) {
412
- var subscribers = promise._subscribers;
413
- var settled = promise._state;
414
- if (config.instrument) {
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 (subscribers.length === 0) {
418
- return;
419
- }
420
- var child = void 0,
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
- promise._subscribers.length = 0;
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 initializePromise(promise, resolver) {
457
- var resolved = false;
458
- try {
459
- resolver(function (value) {
460
- if (resolved) {
461
- return;
462
- }
463
- resolved = true;
464
- resolve$1(promise, value);
465
- }, function (reason) {
466
- if (resolved) {
467
- return;
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
- var Enumerator = function () {
498
- function Enumerator(Constructor, input, abortOnReject, label) {
499
- this._instanceConstructor = Constructor;
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
- Enumerator.prototype._init = function _init(Constructor, input) {
507
- var len = input.length || 0;
508
- this.length = len;
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
- Enumerator.prototype._settledAt = function _settledAt(state, i, value, firstPass) {
558
- var promise = this.promise;
559
- if (promise._state === PENDING) {
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
- this._result[i] = {
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 promise;
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 needsNew() {
799
- throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
800
- }
801
-
802
- /**
803
- Promise objects represent the eventual result of an asynchronous operation. The
804
- primary way of interacting with a promise is through its `then` method, which
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
- `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
932
- as the catch block of a try/catch statement.
933
-
934
- ```js
935
- function findAuthor(){
936
- throw new Error('couldn\'t find that author');
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
- return promise.then(callback, callback);
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
- // success
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
- if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
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 call && (typeof call === "object" || typeof call === "function") ? call : self;
263
+ return payload;
1263
264
  }
1264
- function _inherits$1(subClass, superClass) {
1265
- if (typeof superClass !== "function" && superClass !== null) {
1266
- throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
1267
- }
1268
- subClass.prototype = Object.create(superClass && superClass.prototype, {
1269
- constructor: {
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
- var PromiseHash = function (_Enumerator) {
1279
- _inherits$1(PromiseHash, _Enumerator);
1280
- function PromiseHash(Constructor, object) {
1281
- var abortOnReject = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
1282
- var label = arguments[3];
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
- this._checkFullfillment();
1302
- };
1303
- return PromiseHash;
1304
- }(Enumerator);
1305
- function _possibleConstructorReturn$2(self, call) {
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
- if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
1324
- }
1325
- var HashSettled = function (_PromiseHash) {
1326
- _inherits$2(HashSettled, _PromiseHash);
1327
- function HashSettled(Constructor, object, label) {
1328
- return _possibleConstructorReturn$2(this, _PromiseHash.call(this, Constructor, object, false, label));
1329
- }
1330
- return HashSettled;
1331
- }(PromiseHash);
1332
- HashSettled.prototype._setResultAt = setSettledResult;
1333
- function _possibleConstructorReturn$3(self, call) {
1334
- if (!self) {
1335
- throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
1336
- }
1337
- return call && (typeof call === "object" || typeof call === "function") ? call : self;
1338
- }
1339
- function _inherits$3(subClass, superClass) {
1340
- if (typeof superClass !== "function" && superClass !== null) {
1341
- throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
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
- MapEnumerator.prototype._init = function _init(Constructor, input, bool, label, mapFn) {
1359
- var len = input.length || 0;
1360
- this.length = len;
1361
- this._remaining = len;
1362
- this._result = new Array(len);
1363
- this._mapFn = mapFn;
1364
- this._enumerate(input);
1365
- };
1366
- MapEnumerator.prototype._setResultAt = function _setResultAt(state, i, value, firstPass) {
1367
- if (firstPass) {
1368
- var val = tryCatch(this._mapFn)(value, i);
1369
- if (val === TRY_CATCH_ERROR) {
1370
- this._settledAt(REJECTED, i, val.error, false);
1371
- } else {
1372
- this._eachEntry(val, i, false);
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
- @method resolve
1386
- @public
1387
- @static
1388
- @for rsvp
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
- return call && (typeof call === "object" || typeof call === "function") ? call : self;
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
- subClass.prototype = Object.create(superClass && superClass.prototype, {
1409
- constructor: {
1410
- value: subClass,
1411
- enumerable: false,
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
- var EMPTY_OBJECT = {};
1419
- (function (_MapEnumerator) {
1420
- _inherits$4(FilterEnumerator, _MapEnumerator);
1421
- function FilterEnumerator() {
1422
- return _possibleConstructorReturn$4(this, _MapEnumerator.apply(this, arguments));
1423
- }
1424
- FilterEnumerator.prototype._checkFullfillment = function _checkFullfillment() {
1425
- if (this._remaining === 0 && this._result !== null) {
1426
- var result = this._result.filter(function (val) {
1427
- return val !== EMPTY_OBJECT;
1428
- });
1429
- fulfill(this.promise, result);
1430
- this._result = null;
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
- FilterEnumerator.prototype._setResultAt = function _setResultAt(state, i, value, firstPass) {
1434
- if (firstPass) {
1435
- this._result[i] = value;
1436
- var val = tryCatch(this._mapFn)(value, i);
1437
- if (val === TRY_CATCH_ERROR) {
1438
- this._settledAt(REJECTED, i, val.error, false);
1439
- } else {
1440
- this._eachEntry(val, i, false);
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
- } else {
1443
- this._remaining--;
1444
- if (!value) {
1445
- this._result[i] = EMPTY_OBJECT;
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
- // web worker
1508
- function useMessageChannel() {
1509
- var channel = new MessageChannel();
1510
- channel.port1.onmessage = flush;
1511
- return function () {
1512
- return channel.port2.postMessage(0);
1513
- };
1514
- }
1515
- function useSetTimeout() {
1516
- return function () {
1517
- return setTimeout(flush, 1);
1518
- };
1519
- }
1520
- var queue$1 = new Array(1000);
1521
- function flush() {
1522
- for (var i = 0; i < len; i += 2) {
1523
- var callback = queue$1[i];
1524
- var arg = queue$1[i + 1];
1525
- callback(arg);
1526
- queue$1[i] = undefined;
1527
- queue$1[i + 1] = undefined;
1528
- }
1529
- len = 0;
1530
- }
1531
- function attemptVertex() {
1532
- try {
1533
- var vertx = Function('return this')().require('vertx');
1534
- vertxNext = vertx.runOnLoop || vertx.runOnContext;
1535
- return useVertxTimer();
1536
- } catch (e) {
1537
- return useSetTimeout();
1538
- }
1539
- }
1540
- var scheduleFlush$1 = void 0;
1541
- // Decide what async method to use to triggering processing of queued callbacks:
1542
- if (isNode) {
1543
- scheduleFlush$1 = useNextTick();
1544
- } else if (BrowserMutationObserver) {
1545
- scheduleFlush$1 = useMutationObserver();
1546
- } else if (isWorker) {
1547
- scheduleFlush$1 = useMessageChannel();
1548
- } else if (browserWindow === undefined && typeof require === 'function') {
1549
- scheduleFlush$1 = attemptVertex();
1550
- } else {
1551
- scheduleFlush$1 = useSetTimeout();
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
- return guarded;
1580
- }
1581
- function _objectIsAlive(object) {
1582
- return !(object.isDestroyed || object.isDestroying);
1583
- }
1584
- function guardDestroyedStore(promise, store, label) {
1585
- let wrapperPromise = resolve$2(promise, label).then(_v => {
1586
- if (!_objectIsAlive(store)) {
1587
- if (macroCondition(getOwnConfig().deprecations.DEPRECATE_RSVP_PROMISE)) {
1588
- deprecate(`A Promise did not resolve by the time the store was destroyed. This will error in a future release.`, false, {
1589
- id: 'ember-data:rsvp-unresolved-async',
1590
- until: '5.0',
1591
- for: '@ember-data/store',
1592
- since: {
1593
- available: '4.5',
1594
- enabled: '4.5'
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
- return promise;
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
- This is a helper method that validates a JSON API top-level document
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
- @internal
1613
- */
1614
- function validateDocumentStructure(doc) {
1615
- if (macroCondition(isDevelopingApp())) {
1616
- let errors = [];
1617
- if (!doc || typeof doc !== 'object') {
1618
- errors.push('Top level of a JSON API document must be an object');
1619
- } else {
1620
- if (!('data' in doc) && !('errors' in doc) && !('meta' in doc)) {
1621
- errors.push('One or more of the following keys must be present: "data", "errors", "meta".');
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
- if ('data' in doc && 'errors' in doc) {
1624
- errors.push('Top level keys "errors" and "data" cannot both be present in a JSON API document');
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
- if ('included' in doc) {
1653
- if (typeof doc.included !== 'object') {
1654
- errors.push('included must be an array');
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$1.resolve(store.peekAll(type));
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 payloadIsNotBlank(adapterPayload) {
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$1.resolve().then(() => adapter.findAll(store, schema, null, snapshotArray));
1724
- promise = guardDestroyedStore(promise, store, macroCondition(isDevelopingApp()) ? `DS: Handle Adapter#findAll of ${type}` : '');
1725
- return promise.then(adapterPayload => {
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(isDevelopingApp())) {
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$1.resolve().then(() => adapter.query(store, schema, query, recordArray, options));
1761
- promise = guardDestroyedStore(promise, store, macroCondition(isDevelopingApp()) ? `DS: Handle Adapter#query of ${type}` : ``);
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$1.resolve().then(() => adapter.queryRecord(store, schema, query, options));
1789
- promise = guardDestroyedStore(promise, store, macroCondition(isDevelopingApp()) ? `DS: Handle Adapter#queryRecord of ${type}` : ``);
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
- return store.push(payload);
674
+ const identifier = store._push(payload, true);
675
+ return identifier ? store.peekRecord(identifier) : null;
1795
676
  });
1796
677
  }
1797
678
  export { LegacyNetworkHandler };