@ember-data/model 4.5.0-beta.0 → 4.7.0-beta.0

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.
@@ -2,6 +2,7 @@ import { assert } from '@ember/debug';
2
2
  import { computed } from '@ember/object';
3
3
  import { DEBUG } from '@glimmer/env';
4
4
 
5
+ import { recordIdentifierFor, storeFor } from '@ember-data/store';
5
6
  import { recordDataFor } from '@ember-data/store/-private';
6
7
 
7
8
  import { computedMacroWithOptionalParams } from './util';
@@ -150,17 +151,25 @@ function attr(type, options) {
150
151
  );
151
152
  }
152
153
  }
153
- if (!this.isValid) {
154
- let oldValue = this._internalModel._recordData.getAttr(key);
155
- if (oldValue !== value) {
154
+ assert(
155
+ `Attempted to set '${key}' on the deleted record ${recordIdentifierFor(this)}`,
156
+ !this.currentState.isDeleted
157
+ );
158
+ const recordData = storeFor(this)._instanceCache.getRecordData(recordIdentifierFor(this));
159
+ let currentValue = recordData.getAttr(key);
160
+ if (currentValue !== value) {
161
+ recordData.setDirtyAttribute(key, value);
162
+
163
+ if (!this.isValid) {
156
164
  const { errors } = this;
157
165
  if (errors.get(key)) {
158
166
  errors.remove(key);
159
- this.___recordState.cleanErrorRequests();
167
+ this.currentState.cleanErrorRequests();
160
168
  }
161
169
  }
162
170
  }
163
- return this._internalModel.setDirtyAttribute(key, value);
171
+
172
+ return value;
164
173
  },
165
174
  }).meta(meta);
166
175
  }
@@ -2,6 +2,7 @@ import { assert, inspect, warn } from '@ember/debug';
2
2
  import { computed } from '@ember/object';
3
3
  import { DEBUG } from '@glimmer/env';
4
4
 
5
+ import { LEGACY_SUPPORT } from './model';
5
6
  import { computedMacroWithOptionalParams } from './util';
6
7
 
7
8
  /**
@@ -142,6 +143,8 @@ function belongsTo(modelName, options) {
142
143
 
143
144
  return computed({
144
145
  get(key) {
146
+ const support = LEGACY_SUPPORT.lookup(this);
147
+
145
148
  if (DEBUG) {
146
149
  if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) {
147
150
  throw new Error(
@@ -150,7 +153,7 @@ function belongsTo(modelName, options) {
150
153
  }
151
154
  if (Object.prototype.hasOwnProperty.call(opts, 'serialize')) {
152
155
  warn(
153
- `You provided a serialize option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See Serializer and it's implementations https://api.emberjs.com/ember-data/release/classes/Serializer`,
156
+ `You provided a serialize option on the "${key}" property in the "${support.identifier.type}" class, this belongs in the serializer. See Serializer and it's implementations https://api.emberjs.com/ember-data/release/classes/Serializer`,
154
157
  false,
155
158
  {
156
159
  id: 'ds.model.serialize-option-in-belongs-to',
@@ -160,7 +163,7 @@ function belongsTo(modelName, options) {
160
163
 
161
164
  if (Object.prototype.hasOwnProperty.call(opts, 'embedded')) {
162
165
  warn(
163
- `You provided an embedded option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See EmbeddedRecordsMixin https://api.emberjs.com/ember-data/release/classes/EmbeddedRecordsMixin`,
166
+ `You provided an embedded option on the "${key}" property in the "${support.identifier.type}" class, this belongs in the serializer. See EmbeddedRecordsMixin https://api.emberjs.com/ember-data/release/classes/EmbeddedRecordsMixin`,
164
167
  false,
165
168
  {
166
169
  id: 'ds.model.embedded-option-in-belongs-to',
@@ -169,9 +172,10 @@ function belongsTo(modelName, options) {
169
172
  }
170
173
  }
171
174
 
172
- return this._internalModel.getBelongsTo(key);
175
+ return support.getBelongsTo(key);
173
176
  },
174
177
  set(key, value) {
178
+ const support = LEGACY_SUPPORT.lookup(this);
175
179
  if (DEBUG) {
176
180
  if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) {
177
181
  throw new Error(
@@ -180,10 +184,10 @@ function belongsTo(modelName, options) {
180
184
  }
181
185
  }
182
186
  this.store._backburner.join(() => {
183
- this._internalModel.setDirtyBelongsTo(key, value);
187
+ support.setDirtyBelongsTo(key, value);
184
188
  });
185
189
 
186
- return this._internalModel.getBelongsTo(key);
190
+ return support.getBelongsTo(key);
187
191
  },
188
192
  }).meta(meta);
189
193
  }
@@ -4,6 +4,8 @@ import ArrayProxy from '@ember/array/proxy';
4
4
  import { computed, get } from '@ember/object';
5
5
  import { mapBy, not } from '@ember/object/computed';
6
6
 
7
+ import type RecordState from './record-state';
8
+
7
9
  type ValidationError = {
8
10
  attribute: string;
9
11
  message: string;
@@ -101,24 +103,7 @@ const ArrayProxyWithCustomOverrides = ArrayProxy as unknown as new <T, M = T>()
101
103
  @extends Ember.ArrayProxy
102
104
  */
103
105
  export default class Errors extends ArrayProxyWithCustomOverrides<ValidationError> {
104
- declare _registeredHandlers?: {
105
- becameInvalid: () => void;
106
- becameValid: () => void;
107
- };
108
-
109
- /**
110
- Register with target handler
111
-
112
- @method _registerHandlers
113
- @private
114
- */
115
- _registerHandlers(becameInvalid: () => void, becameValid: () => void): void {
116
- this._registeredHandlers = {
117
- becameInvalid,
118
- becameValid,
119
- };
120
- }
121
-
106
+ declare __record: { currentState: RecordState };
122
107
  /**
123
108
  @property errorsByAttributeName
124
109
  @type {MapWithDefault}
@@ -266,26 +251,11 @@ export default class Errors extends ArrayProxyWithCustomOverrides<ValidationErro
266
251
  @param {string[]|string} messages - an error message or array of error messages for the attribute
267
252
  */
268
253
  add(attribute: string, messages: string[] | string): void {
269
- let wasEmpty: boolean = this.isEmpty;
270
-
271
- this._add(attribute, messages);
272
-
273
- if (wasEmpty && !this.isEmpty) {
274
- this._registeredHandlers && this._registeredHandlers.becameInvalid();
275
- }
276
- }
277
-
278
- /**
279
- Adds error messages to a given attribute without sending event.
280
-
281
- @method _add
282
- @private
283
- */
284
- _add(attribute: string, messages: string[] | string) {
285
254
  const errors = this._findOrCreateMessages(attribute, messages);
286
255
  this.addObjects(errors);
287
256
 
288
257
  this.errorsFor(attribute).addObjects(errors);
258
+ this.__record.currentState.notify('isValid');
289
259
 
290
260
  this.notifyPropertyChange(attribute);
291
261
  }
@@ -347,24 +317,6 @@ export default class Errors extends ArrayProxyWithCustomOverrides<ValidationErro
347
317
  return;
348
318
  }
349
319
 
350
- this._remove(attribute);
351
-
352
- if (this.isEmpty) {
353
- this._registeredHandlers && this._registeredHandlers.becameValid();
354
- }
355
- }
356
-
357
- /**
358
- Removes all error messages from the given attribute without sending event.
359
-
360
- @method _remove
361
- @private
362
- */
363
- _remove(attribute: string) {
364
- if (this.isEmpty) {
365
- return;
366
- }
367
-
368
320
  let content = this.rejectBy('attribute', attribute);
369
321
  this.content.setObjects(content);
370
322
 
@@ -379,6 +331,7 @@ export default class Errors extends ArrayProxyWithCustomOverrides<ValidationErro
379
331
  }
380
332
  this.errorsByAttributeName.delete(attribute);
381
333
 
334
+ this.__record.currentState.notify('isValid');
382
335
  this.notifyPropertyChange(attribute);
383
336
  this.notifyPropertyChange('length');
384
337
  }
@@ -427,22 +380,6 @@ export default class Errors extends ArrayProxyWithCustomOverrides<ValidationErro
427
380
  return;
428
381
  }
429
382
 
430
- this._clear();
431
- this._registeredHandlers && this._registeredHandlers.becameValid();
432
- }
433
-
434
- /**
435
- Removes all error messages.
436
- to the record.
437
-
438
- @method _clear
439
- @private
440
- */
441
- _clear(): void {
442
- if (this.isEmpty) {
443
- return;
444
- }
445
-
446
383
  let errorsByAttributeName = this.errorsByAttributeName;
447
384
  let attributes: string[] = [];
448
385
 
@@ -455,7 +392,8 @@ export default class Errors extends ArrayProxyWithCustomOverrides<ValidationErro
455
392
  this.notifyPropertyChange(attribute);
456
393
  });
457
394
 
458
- ArrayProxy.prototype.clear.call(this);
395
+ this.__record.currentState.notify('isValid');
396
+ super.clear();
459
397
  }
460
398
 
461
399
  /**
@@ -5,6 +5,7 @@ import { assert, inspect } from '@ember/debug';
5
5
  import { computed } from '@ember/object';
6
6
  import { DEBUG } from '@glimmer/env';
7
7
 
8
+ import { LEGACY_SUPPORT } from './model';
8
9
  import { computedMacroWithOptionalParams } from './util';
9
10
 
10
11
  /**
@@ -182,28 +183,28 @@ function hasMany(type, options) {
182
183
  return computed({
183
184
  get(key) {
184
185
  if (DEBUG) {
185
- if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) {
186
+ if (['_internalModel', 'currentState'].indexOf(key) !== -1) {
186
187
  throw new Error(
187
188
  `'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your hasMany on ${this.constructor.toString()}`
188
189
  );
189
190
  }
190
191
  }
191
- return this._internalModel.getHasMany(key);
192
+ return LEGACY_SUPPORT.lookup(this).getHasMany(key);
192
193
  },
193
194
  set(key, records) {
194
195
  if (DEBUG) {
195
- if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) {
196
+ if (['_internalModel', 'currentState'].indexOf(key) !== -1) {
196
197
  throw new Error(
197
198
  `'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your hasMany on ${this.constructor.toString()}`
198
199
  );
199
200
  }
200
201
  }
201
- let internalModel = this._internalModel;
202
+ const support = LEGACY_SUPPORT.lookup(this);
202
203
  this.store._backburner.join(() => {
203
- internalModel.setDirtyHasMany(key, records);
204
+ support.setDirtyHasMany(key, records);
204
205
  });
205
206
 
206
- return internalModel.getHasMany(key);
207
+ return support.getHasMany(key);
207
208
  },
208
209
  }).meta(meta);
209
210
  }
@@ -4,10 +4,11 @@ export { default as hasMany } from './has-many';
4
4
  export { default as Model } from './model';
5
5
  export { default as Errors } from './errors';
6
6
 
7
- export { default as ManyArray } from './system/many-array';
8
- export { default as PromiseBelongsTo } from './system/promise-belongs-to';
9
- export { default as PromiseManyArray } from './system/promise-many-array';
10
- export { default as _modelForMixin } from './system/model-for-mixin';
7
+ export { default as ManyArray } from './many-array';
8
+ export { default as PromiseBelongsTo } from './promise-belongs-to';
9
+ export { default as PromiseManyArray } from './promise-many-array';
10
+ export { default as _modelForMixin } from './model-for-mixin';
11
11
 
12
12
  // // Used by tests
13
- export { default as diffArray } from './system/diff-array';
13
+ export { default as diffArray } from './diff-array';
14
+ export { LEGACY_SUPPORT } from './model';
@@ -0,0 +1,370 @@
1
+ import { assert, deprecate } from '@ember/debug';
2
+ import { DEBUG } from '@glimmer/env';
3
+
4
+ import { resolve } from 'rsvp';
5
+
6
+ import { DEPRECATE_RSVP_PROMISE } from '@ember-data/private-build-infra/deprecations';
7
+
8
+ import { iterateData, normalizeResponseHelper } from './legacy-data-utils';
9
+
10
+ export function _findHasMany(adapter, store, identifier, link, relationship, options) {
11
+ const snapshot = store._instanceCache.createSnapshot(identifier, options);
12
+ let modelClass = store.modelFor(relationship.type);
13
+ let useLink = !link || typeof link === 'string';
14
+ let relatedLink = useLink ? link : link.href;
15
+ let promise = adapter.findHasMany(store, snapshot, relatedLink, relationship);
16
+ let label = `DS: Handle Adapter#findHasMany of '${identifier.type}' : '${relationship.type}'`;
17
+
18
+ promise = guardDestroyedStore(promise, store, label);
19
+ promise = promise.then(
20
+ (adapterPayload) => {
21
+ if (!_objectIsAlive(store._instanceCache.getInternalModel(identifier))) {
22
+ if (DEPRECATE_RSVP_PROMISE) {
23
+ deprecate(
24
+ `A Promise for fetching ${relationship.type} did not resolve by the time your model was destroyed. This will error in a future release.`,
25
+ false,
26
+ {
27
+ id: 'ember-data:rsvp-unresolved-async',
28
+ until: '5.0',
29
+ for: '@ember-data/store',
30
+ since: {
31
+ available: '4.5',
32
+ enabled: '4.5',
33
+ },
34
+ }
35
+ );
36
+ }
37
+ }
38
+
39
+ assert(
40
+ `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`,
41
+ payloadIsNotBlank(adapterPayload)
42
+ );
43
+ let serializer = store.serializerFor(relationship.type);
44
+ let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findHasMany');
45
+
46
+ assert(
47
+ `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: [] }`,
48
+ 'data' in payload && Array.isArray(payload.data)
49
+ );
50
+
51
+ payload = syncRelationshipDataFromLink(store, payload, identifier, relationship);
52
+
53
+ return store._push(payload);
54
+ },
55
+ null,
56
+ `DS: Extract payload of '${identifier.type}' : hasMany '${relationship.type}'`
57
+ );
58
+
59
+ if (DEPRECATE_RSVP_PROMISE) {
60
+ promise = _guard(promise, _bind(_objectIsAlive, store._instanceCache.getInternalModel(identifier)));
61
+ }
62
+
63
+ return promise;
64
+ }
65
+
66
+ export function _findBelongsTo(store, identifier, link, relationship, options) {
67
+ let adapter = store.adapterFor(identifier.type);
68
+
69
+ assert(`You tried to load a belongsTo relationship but you have no adapter (for ${identifier.type})`, adapter);
70
+ assert(
71
+ `You tried to load a belongsTo relationship from a specified 'link' in the original payload but your adapter does not implement 'findBelongsTo'`,
72
+ typeof adapter.findBelongsTo === 'function'
73
+ );
74
+ let snapshot = store._instanceCache.createSnapshot(identifier, options);
75
+ let modelClass = store.modelFor(relationship.type);
76
+ let useLink = !link || typeof link === 'string';
77
+ let relatedLink = useLink ? link : link.href;
78
+ let promise = adapter.findBelongsTo(store, snapshot, relatedLink, relationship);
79
+ let label = `DS: Handle Adapter#findBelongsTo of ${identifier.type} : ${relationship.type}`;
80
+
81
+ promise = guardDestroyedStore(promise, store, label);
82
+ promise = _guard(promise, _bind(_objectIsAlive, store._instanceCache.getInternalModel(identifier)));
83
+
84
+ promise = promise.then(
85
+ (adapterPayload) => {
86
+ if (!_objectIsAlive(store._instanceCache.getInternalModel(identifier))) {
87
+ if (DEPRECATE_RSVP_PROMISE) {
88
+ deprecate(
89
+ `A Promise for fetching ${relationship.type} did not resolve by the time your model was destroyed. This will error in a future release.`,
90
+ false,
91
+ {
92
+ id: 'ember-data:rsvp-unresolved-async',
93
+ until: '5.0',
94
+ for: '@ember-data/store',
95
+ since: {
96
+ available: '4.5',
97
+ enabled: '4.5',
98
+ },
99
+ }
100
+ );
101
+ }
102
+ }
103
+
104
+ let serializer = store.serializerFor(relationship.type);
105
+ let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findBelongsTo');
106
+
107
+ assert(
108
+ `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 }`,
109
+ 'data' in payload &&
110
+ (payload.data === null || (typeof payload.data === 'object' && !Array.isArray(payload.data)))
111
+ );
112
+
113
+ if (!payload.data && !payload.links && !payload.meta) {
114
+ return null;
115
+ }
116
+
117
+ payload = syncRelationshipDataFromLink(store, payload, identifier, relationship);
118
+
119
+ return store._push(payload);
120
+ },
121
+ null,
122
+ `DS: Extract payload of ${identifier.type} : ${relationship.type}`
123
+ );
124
+
125
+ if (DEPRECATE_RSVP_PROMISE) {
126
+ promise = _guard(promise, _bind(_objectIsAlive, store._instanceCache.getInternalModel(identifier)));
127
+ }
128
+
129
+ return promise;
130
+ }
131
+
132
+ // sync
133
+ // iterate over records in payload.data
134
+ // for each record
135
+ // assert that record.relationships[inverse] is either undefined (so we can fix it)
136
+ // or provide a data: {id, type} that matches the record that requested it
137
+ // return the relationship data for the parent
138
+ function syncRelationshipDataFromLink(store, payload, parentIdentifier, relationship) {
139
+ // ensure the right hand side (incoming payload) points to the parent record that
140
+ // requested this relationship
141
+ let relationshipData = payload.data
142
+ ? iterateData(payload.data, (data, index) => {
143
+ const { id, type } = data;
144
+ ensureRelationshipIsSetToParent(data, parentIdentifier, store, relationship, index);
145
+ return { id, type };
146
+ })
147
+ : null;
148
+
149
+ const relatedDataHash = {};
150
+
151
+ if ('meta' in payload) {
152
+ relatedDataHash.meta = payload.meta;
153
+ }
154
+ if ('links' in payload) {
155
+ relatedDataHash.links = payload.links;
156
+ }
157
+ if ('data' in payload) {
158
+ relatedDataHash.data = relationshipData;
159
+ }
160
+
161
+ // now, push the left hand side (the parent record) to ensure things are in sync, since
162
+ // the payload will be pushed with store._push
163
+ const parentPayload = {
164
+ id: parentIdentifier.id,
165
+ type: parentIdentifier.type,
166
+ relationships: {
167
+ [relationship.key]: relatedDataHash,
168
+ },
169
+ };
170
+
171
+ if (!Array.isArray(payload.included)) {
172
+ payload.included = [];
173
+ }
174
+ payload.included.push(parentPayload);
175
+
176
+ return payload;
177
+ }
178
+
179
+ function ensureRelationshipIsSetToParent(payload, parentIdentifier, store, parentRelationship, index) {
180
+ let { id, type } = payload;
181
+
182
+ if (!payload.relationships) {
183
+ payload.relationships = {};
184
+ }
185
+ let { relationships } = payload;
186
+
187
+ let inverse = getInverse(store, parentIdentifier, parentRelationship, type);
188
+ if (inverse) {
189
+ let { inverseKey, kind } = inverse;
190
+
191
+ let relationshipData = relationships[inverseKey] && relationships[inverseKey].data;
192
+
193
+ if (
194
+ DEBUG &&
195
+ typeof relationshipData !== 'undefined' &&
196
+ !relationshipDataPointsToParent(relationshipData, parentIdentifier)
197
+ ) {
198
+ let inspect = function inspect(thing) {
199
+ return `'${JSON.stringify(thing)}'`;
200
+ };
201
+ let quotedType = inspect(type);
202
+ let quotedInverse = inspect(inverseKey);
203
+ let expected = inspect({
204
+ id: parentIdentifier.id,
205
+ type: parentIdentifier.type,
206
+ });
207
+ let expectedModel = `${parentIdentifier.type}:${parentIdentifier.id}`;
208
+ let got = inspect(relationshipData);
209
+ let prefix = typeof index === 'number' ? `data[${index}]` : `data`;
210
+ let path = `${prefix}.relationships.${inverseKey}.data`;
211
+ let other = relationshipData ? `<${relationshipData.type}:${relationshipData.id}>` : null;
212
+ let relationshipFetched = `${expectedModel}.${parentRelationship.kind}("${parentRelationship.name}")`;
213
+ let includedRecord = `<${type}:${id}>`;
214
+ let message = [
215
+ `Encountered mismatched relationship: Ember Data expected ${path} in the payload from ${relationshipFetched} to include ${expected} but got ${got} instead.\n`,
216
+ `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.`,
217
+ `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.`,
218
+ `Ember Data has corrected the ${includedRecord} record's ${quotedInverse} relationship to ${expectedModel} so that ${relationshipFetched} will include ${includedRecord}.`,
219
+ `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.`,
220
+ ].join('\n');
221
+
222
+ assert(message);
223
+ }
224
+
225
+ if (kind !== 'hasMany' || typeof relationshipData !== 'undefined') {
226
+ relationships[inverseKey] = relationships[inverseKey] || {};
227
+ relationships[inverseKey].data = fixRelationshipData(relationshipData, kind, parentIdentifier);
228
+ }
229
+ }
230
+ }
231
+
232
+ function getInverse(store, parentInternalModel, parentRelationship, type) {
233
+ return recordDataFindInverseRelationshipInfo(store, parentInternalModel, parentRelationship, type);
234
+ }
235
+
236
+ function recordDataFindInverseRelationshipInfo(store, parentIdentifier, parentRelationship, type) {
237
+ let { name: lhs_relationshipName } = parentRelationship;
238
+ let { type: parentType } = parentIdentifier;
239
+ let inverseKey = store._instanceCache._storeWrapper.inverseForRelationship(parentType, lhs_relationshipName);
240
+
241
+ if (inverseKey) {
242
+ let {
243
+ meta: { kind },
244
+ } = store._instanceCache._storeWrapper.relationshipsDefinitionFor(type)[inverseKey];
245
+ return {
246
+ inverseKey,
247
+ kind,
248
+ };
249
+ }
250
+ }
251
+
252
+ function relationshipDataPointsToParent(relationshipData, identifier) {
253
+ if (relationshipData === null) {
254
+ return false;
255
+ }
256
+
257
+ if (Array.isArray(relationshipData)) {
258
+ if (relationshipData.length === 0) {
259
+ return false;
260
+ }
261
+ for (let i = 0; i < relationshipData.length; i++) {
262
+ let entry = relationshipData[i];
263
+ if (validateRelationshipEntry(entry, identifier)) {
264
+ return true;
265
+ }
266
+ }
267
+ } else {
268
+ return validateRelationshipEntry(relationshipData, identifier);
269
+ }
270
+
271
+ return false;
272
+ }
273
+
274
+ function fixRelationshipData(relationshipData, relationshipKind, { id, type }) {
275
+ let parentRelationshipData = {
276
+ id,
277
+ type,
278
+ };
279
+
280
+ let payload;
281
+
282
+ if (relationshipKind === 'hasMany') {
283
+ payload = relationshipData || [];
284
+ if (relationshipData) {
285
+ // these arrays could be massive so this is better than filter
286
+ // Note: this is potentially problematic if type/id are not in the
287
+ // same state of normalization.
288
+ let found = relationshipData.find((v) => {
289
+ return v.type === parentRelationshipData.type && v.id === parentRelationshipData.id;
290
+ });
291
+ if (!found) {
292
+ payload.push(parentRelationshipData);
293
+ }
294
+ } else {
295
+ payload.push(parentRelationshipData);
296
+ }
297
+ } else {
298
+ payload = relationshipData || {};
299
+ Object.assign(payload, parentRelationshipData);
300
+ }
301
+
302
+ return payload;
303
+ }
304
+
305
+ function validateRelationshipEntry({ id }, { id: parentModelID }) {
306
+ return id && id.toString() === parentModelID;
307
+ }
308
+
309
+ function _bind(fn, ...args) {
310
+ return function () {
311
+ return fn.apply(undefined, args);
312
+ };
313
+ }
314
+
315
+ function _guard(promise, test) {
316
+ let guarded = promise.finally(() => {
317
+ if (!test()) {
318
+ guarded._subscribers.length = 0;
319
+ }
320
+ });
321
+
322
+ return guarded;
323
+ }
324
+
325
+ function _objectIsAlive(object) {
326
+ return !(object.isDestroyed || object.isDestroying);
327
+ }
328
+
329
+ function payloadIsNotBlank(adapterPayload) {
330
+ if (Array.isArray(adapterPayload)) {
331
+ return true;
332
+ } else {
333
+ return Object.keys(adapterPayload || {}).length;
334
+ }
335
+ }
336
+
337
+ function guardDestroyedStore(promise, store, label) {
338
+ let token;
339
+ if (DEBUG) {
340
+ token = store._trackAsyncRequestStart(label);
341
+ }
342
+ let wrapperPromise = resolve(promise, label).then((_v) => {
343
+ if (!_objectIsAlive(store)) {
344
+ if (DEPRECATE_RSVP_PROMISE) {
345
+ deprecate(
346
+ `A Promise did not resolve by the time the store was destroyed. This will error in a future release.`,
347
+ false,
348
+ {
349
+ id: 'ember-data:rsvp-unresolved-async',
350
+ until: '5.0',
351
+ for: '@ember-data/store',
352
+ since: {
353
+ available: '4.5',
354
+ enabled: '4.5',
355
+ },
356
+ }
357
+ );
358
+ }
359
+ }
360
+
361
+ return promise;
362
+ });
363
+
364
+ return _guard(wrapperPromise, () => {
365
+ if (DEBUG) {
366
+ store._trackAsyncRequestEnd(token);
367
+ }
368
+ return _objectIsAlive(store);
369
+ });
370
+ }