@ember-data/model 4.12.0-alpha.2 → 4.12.0-alpha.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/README.md +42 -18
- package/addon/-private.js +2 -2
- package/addon/{has-many-26353d30.js → has-many-465843f4.js} +292 -583
- package/addon/has-many-465843f4.js.map +1 -0
- package/addon/index.js +1 -1
- package/addon-main.js +18 -15
- package/blueprints/model/HELP.md +26 -0
- package/blueprints/model/files/__root__/__path__/__name__.js +5 -0
- package/blueprints/model/index.js +150 -0
- package/blueprints/model/native-files/__root__/__path__/__name__.js +5 -0
- package/blueprints/model-test/index.js +33 -0
- package/blueprints/model-test/mocha-files/__root__/__path__/__test__.js +18 -0
- package/blueprints/model-test/mocha-rfc-232-files/__root__/__path__/__test__.js +15 -0
- package/blueprints/model-test/qunit-files/__root__/__path__/__test__.js +14 -0
- package/package.json +28 -22
- package/addon/has-many-26353d30.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { macroCondition,
|
|
1
|
+
import { macroCondition, getOwnConfig, importSync } from '@embroider/macros';
|
|
2
2
|
import { assert, deprecate, warn, inspect } from '@ember/debug';
|
|
3
3
|
import EmberObject, { computed, get } from '@ember/object';
|
|
4
|
-
import { recordIdentifierFor, storeFor } from '@ember-data/store';
|
|
5
|
-
import {
|
|
4
|
+
import { recordIdentifierFor, storeFor as storeFor$1 } from '@ember-data/store';
|
|
5
|
+
import { peekCache, RecordArray, MUTATE, SOURCE, recordIdentifierFor as recordIdentifierFor$1, IDENTIFIER_ARRAY_TAG, notifyArray, isStableIdentifier, storeFor, fastPush, coerceId } from '@ember-data/store/-private';
|
|
6
6
|
import { dasherize } from '@ember/string';
|
|
7
7
|
import ArrayMixin, { A, NativeArray } from '@ember/array';
|
|
8
8
|
import { singularize } from 'ember-inflector';
|
|
@@ -10,7 +10,6 @@ import { dependentKeyCompat } from '@ember/object/compat';
|
|
|
10
10
|
import { run } from '@ember/runloop';
|
|
11
11
|
import { cached, tracked } from '@glimmer/tracking';
|
|
12
12
|
import Ember from 'ember';
|
|
13
|
-
import { resolve, all } from 'rsvp';
|
|
14
13
|
import PromiseProxyMixin from '@ember/object/promise-proxy-mixin';
|
|
15
14
|
import ObjectProxy from '@ember/object/proxy';
|
|
16
15
|
import ArrayProxy from '@ember/array/proxy';
|
|
@@ -103,9 +102,7 @@ function computedMacroWithOptionalParams(fn) {
|
|
|
103
102
|
```
|
|
104
103
|
|
|
105
104
|
```app/transforms/text.js
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
export default class TextTransform extends Transform {
|
|
105
|
+
export default class TextTransform {
|
|
109
106
|
serialize(value, options) {
|
|
110
107
|
if (options.uppercase) {
|
|
111
108
|
return value.toUpperCase();
|
|
@@ -117,6 +114,10 @@ function computedMacroWithOptionalParams(fn) {
|
|
|
117
114
|
deserialize(value) {
|
|
118
115
|
return value;
|
|
119
116
|
}
|
|
117
|
+
|
|
118
|
+
static create() {
|
|
119
|
+
return new this();
|
|
120
|
+
}
|
|
120
121
|
}
|
|
121
122
|
```
|
|
122
123
|
|
|
@@ -142,7 +143,7 @@ function attr(type, options) {
|
|
|
142
143
|
};
|
|
143
144
|
return computed({
|
|
144
145
|
get(key) {
|
|
145
|
-
if (macroCondition(
|
|
146
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
146
147
|
if (['currentState'].indexOf(key) !== -1) {
|
|
147
148
|
throw new Error(`'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your attr on ${this.constructor.toString()}`);
|
|
148
149
|
}
|
|
@@ -150,20 +151,20 @@ function attr(type, options) {
|
|
|
150
151
|
if (this.isDestroyed || this.isDestroying) {
|
|
151
152
|
return;
|
|
152
153
|
}
|
|
153
|
-
return
|
|
154
|
+
return peekCache(this).getAttr(recordIdentifierFor(this), key);
|
|
154
155
|
},
|
|
155
156
|
set(key, value) {
|
|
156
|
-
if (macroCondition(
|
|
157
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
157
158
|
if (['currentState'].indexOf(key) !== -1) {
|
|
158
159
|
throw new Error(`'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your attr on ${this.constructor.toString()}`);
|
|
159
160
|
}
|
|
160
161
|
}
|
|
161
162
|
assert(`Attempted to set '${key}' on the deleted record ${recordIdentifierFor(this)}`, !this.currentState.isDeleted);
|
|
162
163
|
const identifier = recordIdentifierFor(this);
|
|
163
|
-
const
|
|
164
|
-
let currentValue =
|
|
164
|
+
const cache = peekCache(this);
|
|
165
|
+
let currentValue = cache.getAttr(identifier, key);
|
|
165
166
|
if (currentValue !== value) {
|
|
166
|
-
|
|
167
|
+
cache.setAttr(identifier, key, value);
|
|
167
168
|
if (!this.isValid) {
|
|
168
169
|
const {
|
|
169
170
|
errors
|
|
@@ -214,7 +215,7 @@ function _applyDecoratedDescriptor(target, property, decorators, descriptor, con
|
|
|
214
215
|
const PromiseObject = ObjectProxy.extend(PromiseProxyMixin);
|
|
215
216
|
function promiseObject(promise) {
|
|
216
217
|
return PromiseObject.create({
|
|
217
|
-
promise
|
|
218
|
+
promise
|
|
218
219
|
});
|
|
219
220
|
}
|
|
220
221
|
|
|
@@ -225,7 +226,7 @@ const PROXIED_OBJECT_PROPS = ['content', 'isPending', 'isSettled', 'isRejected',
|
|
|
225
226
|
const ProxySymbolString = String(Symbol.for('PROXY_CONTENT'));
|
|
226
227
|
function deprecatedPromiseObject(promise) {
|
|
227
228
|
const promiseObjectProxy = promiseObject(promise);
|
|
228
|
-
if (macroCondition(!
|
|
229
|
+
if (macroCondition(!getOwnConfig().env.DEBUG)) {
|
|
229
230
|
return promiseObjectProxy;
|
|
230
231
|
}
|
|
231
232
|
const handler = {
|
|
@@ -268,6 +269,11 @@ function deprecatedPromiseObject(promise) {
|
|
|
268
269
|
return new Proxy(promiseObjectProxy, handler);
|
|
269
270
|
}
|
|
270
271
|
var _dec$1, _dec2, _dec3, _dec4, _class$6, _descriptor$5, _descriptor2$2;
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
@module @ember-data/model
|
|
275
|
+
*/
|
|
276
|
+
|
|
271
277
|
// we force the type here to our own construct because mixin and extend patterns
|
|
272
278
|
// lose generic signatures. We also do this because we need to Omit `clear` from
|
|
273
279
|
// the type of ArrayProxy as we override it's signature.
|
|
@@ -632,384 +638,6 @@ let Errors = (_dec$1 = computed(), _dec2 = mapBy('content', 'message'), _dec3 =
|
|
|
632
638
|
writable: true,
|
|
633
639
|
initializer: null
|
|
634
640
|
})), _class$6));
|
|
635
|
-
function iterateData(data, fn) {
|
|
636
|
-
if (Array.isArray(data)) {
|
|
637
|
-
return data.map(fn);
|
|
638
|
-
} else {
|
|
639
|
-
return fn(data);
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
function assertIdentifierHasId(identifier) {
|
|
643
|
-
assert(`Attempted to schedule a fetch for a record without an id.`, identifier.id !== null);
|
|
644
|
-
}
|
|
645
|
-
function normalizeResponseHelper(serializer, store, modelClass, payload, id, requestType) {
|
|
646
|
-
let normalizedResponse = serializer ? serializer.normalizeResponse(store, modelClass, payload, id, requestType) : payload;
|
|
647
|
-
validateDocumentStructure(normalizedResponse);
|
|
648
|
-
return normalizedResponse;
|
|
649
|
-
}
|
|
650
|
-
function validateDocumentStructure(doc) {
|
|
651
|
-
if (macroCondition(isDevelopingApp())) {
|
|
652
|
-
let errors = [];
|
|
653
|
-
if (!doc || typeof doc !== 'object') {
|
|
654
|
-
errors.push('Top level of a JSON API document must be an object');
|
|
655
|
-
} else {
|
|
656
|
-
if (!('data' in doc) && !('errors' in doc) && !('meta' in doc)) {
|
|
657
|
-
errors.push('One or more of the following keys must be present: "data", "errors", "meta".');
|
|
658
|
-
} else {
|
|
659
|
-
if ('data' in doc && 'errors' in doc) {
|
|
660
|
-
errors.push('Top level keys "errors" and "data" cannot both be present in a JSON API document');
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
if ('data' in doc) {
|
|
664
|
-
if (!(doc.data === null || Array.isArray(doc.data) || typeof doc.data === 'object')) {
|
|
665
|
-
errors.push('data must be null, an object, or an array');
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
if ('meta' in doc) {
|
|
669
|
-
if (typeof doc.meta !== 'object') {
|
|
670
|
-
errors.push('meta must be an object');
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
if ('errors' in doc) {
|
|
674
|
-
if (!Array.isArray(doc.errors)) {
|
|
675
|
-
errors.push('errors must be an array');
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
if ('links' in doc) {
|
|
679
|
-
if (typeof doc.links !== 'object') {
|
|
680
|
-
errors.push('links must be an object');
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
if ('jsonapi' in doc) {
|
|
684
|
-
if (typeof doc.jsonapi !== 'object') {
|
|
685
|
-
errors.push('jsonapi must be an object');
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
if ('included' in doc) {
|
|
689
|
-
if (typeof doc.included !== 'object') {
|
|
690
|
-
errors.push('included must be an array');
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
assert(`Response must be normalized to a valid JSON API document:\n\t* ${errors.join('\n\t* ')}`, errors.length === 0);
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
function _findHasMany(adapter, store, identifier, link, relationship, options) {
|
|
698
|
-
const record = store._instanceCache.getRecord(identifier);
|
|
699
|
-
const snapshot = store._instanceCache.createSnapshot(identifier, options);
|
|
700
|
-
let modelClass = store.modelFor(relationship.type);
|
|
701
|
-
let useLink = !link || typeof link === 'string';
|
|
702
|
-
let relatedLink = useLink ? link : link.href;
|
|
703
|
-
let promise = adapter.findHasMany(store, snapshot, relatedLink, relationship);
|
|
704
|
-
let label = `DS: Handle Adapter#findHasMany of '${identifier.type}' : '${relationship.type}'`;
|
|
705
|
-
promise = guardDestroyedStore(promise, store, label);
|
|
706
|
-
promise = promise.then(adapterPayload => {
|
|
707
|
-
if (!_objectIsAlive(record)) {
|
|
708
|
-
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_RSVP_PROMISE)) {
|
|
709
|
-
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, {
|
|
710
|
-
id: 'ember-data:rsvp-unresolved-async',
|
|
711
|
-
until: '5.0',
|
|
712
|
-
for: '@ember-data/store',
|
|
713
|
-
since: {
|
|
714
|
-
available: '4.5',
|
|
715
|
-
enabled: '4.5'
|
|
716
|
-
}
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
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));
|
|
721
|
-
let serializer = store.serializerFor(relationship.type);
|
|
722
|
-
let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findHasMany');
|
|
723
|
-
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));
|
|
724
|
-
payload = syncRelationshipDataFromLink(store, payload, identifier, relationship);
|
|
725
|
-
return store._push(payload);
|
|
726
|
-
}, null, `DS: Extract payload of '${identifier.type}' : hasMany '${relationship.type}'`);
|
|
727
|
-
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_RSVP_PROMISE)) {
|
|
728
|
-
promise = _guard(promise, _bind(_objectIsAlive, record));
|
|
729
|
-
}
|
|
730
|
-
return promise;
|
|
731
|
-
}
|
|
732
|
-
function _findBelongsTo(store, identifier, link, relationship, options) {
|
|
733
|
-
const record = store._instanceCache.getRecord(identifier);
|
|
734
|
-
let adapter = store.adapterFor(identifier.type);
|
|
735
|
-
assert(`You tried to load a belongsTo relationship but you have no adapter (for ${identifier.type})`, adapter);
|
|
736
|
-
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');
|
|
737
|
-
let snapshot = store._instanceCache.createSnapshot(identifier, options);
|
|
738
|
-
let modelClass = store.modelFor(relationship.type);
|
|
739
|
-
let useLink = !link || typeof link === 'string';
|
|
740
|
-
let relatedLink = useLink ? link : link.href;
|
|
741
|
-
let promise = adapter.findBelongsTo(store, snapshot, relatedLink, relationship);
|
|
742
|
-
let label = `DS: Handle Adapter#findBelongsTo of ${identifier.type} : ${relationship.type}`;
|
|
743
|
-
promise = guardDestroyedStore(promise, store, label);
|
|
744
|
-
promise = _guard(promise, _bind(_objectIsAlive, record));
|
|
745
|
-
promise = promise.then(adapterPayload => {
|
|
746
|
-
if (!_objectIsAlive(record)) {
|
|
747
|
-
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_RSVP_PROMISE)) {
|
|
748
|
-
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, {
|
|
749
|
-
id: 'ember-data:rsvp-unresolved-async',
|
|
750
|
-
until: '5.0',
|
|
751
|
-
for: '@ember-data/store',
|
|
752
|
-
since: {
|
|
753
|
-
available: '4.5',
|
|
754
|
-
enabled: '4.5'
|
|
755
|
-
}
|
|
756
|
-
});
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
let serializer = store.serializerFor(relationship.type);
|
|
760
|
-
let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findBelongsTo');
|
|
761
|
-
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)));
|
|
762
|
-
if (!payload.data && !payload.links && !payload.meta) {
|
|
763
|
-
return null;
|
|
764
|
-
}
|
|
765
|
-
payload = syncRelationshipDataFromLink(store, payload, identifier, relationship);
|
|
766
|
-
return store._push(payload);
|
|
767
|
-
}, null, `DS: Extract payload of ${identifier.type} : ${relationship.type}`);
|
|
768
|
-
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_RSVP_PROMISE)) {
|
|
769
|
-
promise = _guard(promise, _bind(_objectIsAlive, record));
|
|
770
|
-
}
|
|
771
|
-
return promise;
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// sync
|
|
775
|
-
// iterate over records in payload.data
|
|
776
|
-
// for each record
|
|
777
|
-
// assert that record.relationships[inverse] is either undefined (so we can fix it)
|
|
778
|
-
// or provide a data: {id, type} that matches the record that requested it
|
|
779
|
-
// return the relationship data for the parent
|
|
780
|
-
function syncRelationshipDataFromLink(store, payload, parentIdentifier, relationship) {
|
|
781
|
-
// ensure the right hand side (incoming payload) points to the parent record that
|
|
782
|
-
// requested this relationship
|
|
783
|
-
let relationshipData = payload.data ? iterateData(payload.data, (data, index) => {
|
|
784
|
-
const {
|
|
785
|
-
id,
|
|
786
|
-
type
|
|
787
|
-
} = data;
|
|
788
|
-
ensureRelationshipIsSetToParent(data, parentIdentifier, store, relationship, index);
|
|
789
|
-
return {
|
|
790
|
-
id,
|
|
791
|
-
type
|
|
792
|
-
};
|
|
793
|
-
}) : null;
|
|
794
|
-
const relatedDataHash = {};
|
|
795
|
-
if ('meta' in payload) {
|
|
796
|
-
relatedDataHash.meta = payload.meta;
|
|
797
|
-
}
|
|
798
|
-
if ('links' in payload) {
|
|
799
|
-
relatedDataHash.links = payload.links;
|
|
800
|
-
}
|
|
801
|
-
if ('data' in payload) {
|
|
802
|
-
relatedDataHash.data = relationshipData;
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
// now, push the left hand side (the parent record) to ensure things are in sync, since
|
|
806
|
-
// the payload will be pushed with store._push
|
|
807
|
-
const parentPayload = {
|
|
808
|
-
id: parentIdentifier.id,
|
|
809
|
-
type: parentIdentifier.type,
|
|
810
|
-
relationships: {
|
|
811
|
-
[relationship.key]: relatedDataHash
|
|
812
|
-
}
|
|
813
|
-
};
|
|
814
|
-
if (!Array.isArray(payload.included)) {
|
|
815
|
-
payload.included = [];
|
|
816
|
-
}
|
|
817
|
-
payload.included.push(parentPayload);
|
|
818
|
-
return payload;
|
|
819
|
-
}
|
|
820
|
-
function ensureRelationshipIsSetToParent(payload, parentIdentifier, store, parentRelationship, index) {
|
|
821
|
-
let {
|
|
822
|
-
id,
|
|
823
|
-
type
|
|
824
|
-
} = payload;
|
|
825
|
-
if (!payload.relationships) {
|
|
826
|
-
payload.relationships = {};
|
|
827
|
-
}
|
|
828
|
-
let {
|
|
829
|
-
relationships
|
|
830
|
-
} = payload;
|
|
831
|
-
let inverse = getInverse(store, parentIdentifier, parentRelationship, type);
|
|
832
|
-
if (inverse) {
|
|
833
|
-
let {
|
|
834
|
-
inverseKey,
|
|
835
|
-
kind
|
|
836
|
-
} = inverse;
|
|
837
|
-
let relationshipData = relationships[inverseKey] && relationships[inverseKey].data;
|
|
838
|
-
if (macroCondition(isDevelopingApp())) {
|
|
839
|
-
if (typeof relationshipData !== 'undefined' && !relationshipDataPointsToParent(relationshipData, parentIdentifier)) {
|
|
840
|
-
let inspect = function inspect(thing) {
|
|
841
|
-
return `'${JSON.stringify(thing)}'`;
|
|
842
|
-
};
|
|
843
|
-
let quotedType = inspect(type);
|
|
844
|
-
let quotedInverse = inspect(inverseKey);
|
|
845
|
-
let expected = inspect({
|
|
846
|
-
id: parentIdentifier.id,
|
|
847
|
-
type: parentIdentifier.type
|
|
848
|
-
});
|
|
849
|
-
let expectedModel = `${parentIdentifier.type}:${parentIdentifier.id}`;
|
|
850
|
-
let got = inspect(relationshipData);
|
|
851
|
-
let prefix = typeof index === 'number' ? `data[${index}]` : `data`;
|
|
852
|
-
let path = `${prefix}.relationships.${inverseKey}.data`;
|
|
853
|
-
let other = relationshipData ? `<${relationshipData.type}:${relationshipData.id}>` : null;
|
|
854
|
-
let relationshipFetched = `${expectedModel}.${parentRelationship.kind}("${parentRelationship.name}")`;
|
|
855
|
-
let includedRecord = `<${type}:${id}>`;
|
|
856
|
-
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');
|
|
857
|
-
assert(message);
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
if (kind !== 'hasMany' || typeof relationshipData !== 'undefined') {
|
|
861
|
-
relationships[inverseKey] = relationships[inverseKey] || {};
|
|
862
|
-
relationships[inverseKey].data = fixRelationshipData(relationshipData, kind, parentIdentifier);
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
function metaIsRelationshipDefinition(meta) {
|
|
867
|
-
return typeof meta._inverseKey === 'function';
|
|
868
|
-
}
|
|
869
|
-
function inverseForRelationship(store, identifier, key) {
|
|
870
|
-
const definition = store.getSchemaDefinitionService().relationshipsDefinitionFor(identifier)[key];
|
|
871
|
-
if (!definition) {
|
|
872
|
-
return null;
|
|
873
|
-
}
|
|
874
|
-
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE)) {
|
|
875
|
-
if (metaIsRelationshipDefinition(definition)) {
|
|
876
|
-
const modelClass = store.modelFor(identifier.type);
|
|
877
|
-
return definition._inverseKey(store, modelClass);
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
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);
|
|
881
|
-
return definition.options.inverse;
|
|
882
|
-
}
|
|
883
|
-
function getInverse(store, parentIdentifier, parentRelationship, type) {
|
|
884
|
-
let {
|
|
885
|
-
name: lhs_relationshipName
|
|
886
|
-
} = parentRelationship;
|
|
887
|
-
let {
|
|
888
|
-
type: parentType
|
|
889
|
-
} = parentIdentifier;
|
|
890
|
-
let inverseKey = inverseForRelationship(store, {
|
|
891
|
-
type: parentType
|
|
892
|
-
}, lhs_relationshipName);
|
|
893
|
-
if (inverseKey) {
|
|
894
|
-
const definition = store.getSchemaDefinitionService().relationshipsDefinitionFor({
|
|
895
|
-
type
|
|
896
|
-
});
|
|
897
|
-
let {
|
|
898
|
-
kind
|
|
899
|
-
} = definition[inverseKey];
|
|
900
|
-
return {
|
|
901
|
-
inverseKey,
|
|
902
|
-
kind
|
|
903
|
-
};
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
function relationshipDataPointsToParent(relationshipData, identifier) {
|
|
907
|
-
if (relationshipData === null) {
|
|
908
|
-
return false;
|
|
909
|
-
}
|
|
910
|
-
if (Array.isArray(relationshipData)) {
|
|
911
|
-
if (relationshipData.length === 0) {
|
|
912
|
-
return false;
|
|
913
|
-
}
|
|
914
|
-
for (let i = 0; i < relationshipData.length; i++) {
|
|
915
|
-
let entry = relationshipData[i];
|
|
916
|
-
if (validateRelationshipEntry(entry, identifier)) {
|
|
917
|
-
return true;
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
} else {
|
|
921
|
-
return validateRelationshipEntry(relationshipData, identifier);
|
|
922
|
-
}
|
|
923
|
-
return false;
|
|
924
|
-
}
|
|
925
|
-
function fixRelationshipData(relationshipData, relationshipKind, {
|
|
926
|
-
id,
|
|
927
|
-
type
|
|
928
|
-
}) {
|
|
929
|
-
let parentRelationshipData = {
|
|
930
|
-
id,
|
|
931
|
-
type
|
|
932
|
-
};
|
|
933
|
-
let payload;
|
|
934
|
-
if (relationshipKind === 'hasMany') {
|
|
935
|
-
payload = relationshipData || [];
|
|
936
|
-
if (relationshipData) {
|
|
937
|
-
// these arrays could be massive so this is better than filter
|
|
938
|
-
// Note: this is potentially problematic if type/id are not in the
|
|
939
|
-
// same state of normalization.
|
|
940
|
-
let found = relationshipData.find(v => {
|
|
941
|
-
return v.type === parentRelationshipData.type && v.id === parentRelationshipData.id;
|
|
942
|
-
});
|
|
943
|
-
if (!found) {
|
|
944
|
-
payload.push(parentRelationshipData);
|
|
945
|
-
}
|
|
946
|
-
} else {
|
|
947
|
-
payload.push(parentRelationshipData);
|
|
948
|
-
}
|
|
949
|
-
} else {
|
|
950
|
-
payload = relationshipData || {};
|
|
951
|
-
Object.assign(payload, parentRelationshipData);
|
|
952
|
-
}
|
|
953
|
-
return payload;
|
|
954
|
-
}
|
|
955
|
-
function validateRelationshipEntry({
|
|
956
|
-
id
|
|
957
|
-
}, {
|
|
958
|
-
id: parentModelID
|
|
959
|
-
}) {
|
|
960
|
-
return id && id.toString() === parentModelID;
|
|
961
|
-
}
|
|
962
|
-
function _bind(fn, ...args) {
|
|
963
|
-
return function () {
|
|
964
|
-
return fn.apply(undefined, args);
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
function _guard(promise, test) {
|
|
968
|
-
let guarded = promise.finally(() => {
|
|
969
|
-
if (!test()) {
|
|
970
|
-
guarded._subscribers.length = 0;
|
|
971
|
-
}
|
|
972
|
-
});
|
|
973
|
-
return guarded;
|
|
974
|
-
}
|
|
975
|
-
function _objectIsAlive(object) {
|
|
976
|
-
return !(object.isDestroyed || object.isDestroying);
|
|
977
|
-
}
|
|
978
|
-
function payloadIsNotBlank(adapterPayload) {
|
|
979
|
-
if (Array.isArray(adapterPayload)) {
|
|
980
|
-
return true;
|
|
981
|
-
} else {
|
|
982
|
-
return Object.keys(adapterPayload || {}).length;
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
function guardDestroyedStore(promise, store, label) {
|
|
986
|
-
let token;
|
|
987
|
-
if (macroCondition(isDevelopingApp())) {
|
|
988
|
-
token = store._trackAsyncRequestStart(label);
|
|
989
|
-
}
|
|
990
|
-
let wrapperPromise = resolve(promise, label).then(_v => {
|
|
991
|
-
if (!_objectIsAlive(store)) {
|
|
992
|
-
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_RSVP_PROMISE)) {
|
|
993
|
-
deprecate(`A Promise did not resolve by the time the store was destroyed. This will error in a future release.`, false, {
|
|
994
|
-
id: 'ember-data:rsvp-unresolved-async',
|
|
995
|
-
until: '5.0',
|
|
996
|
-
for: '@ember-data/store',
|
|
997
|
-
since: {
|
|
998
|
-
available: '4.5',
|
|
999
|
-
enabled: '4.5'
|
|
1000
|
-
}
|
|
1001
|
-
});
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
return promise;
|
|
1005
|
-
});
|
|
1006
|
-
return _guard(wrapperPromise, () => {
|
|
1007
|
-
if (macroCondition(isDevelopingApp())) {
|
|
1008
|
-
store._trackAsyncRequestEnd(token);
|
|
1009
|
-
}
|
|
1010
|
-
return _objectIsAlive(store);
|
|
1011
|
-
});
|
|
1012
|
-
}
|
|
1013
641
|
|
|
1014
642
|
/**
|
|
1015
643
|
A `ManyArray` is a `MutableArray` that represents the contents of a has-many
|
|
@@ -1118,7 +746,7 @@ class RelatedCollection extends RecordArray {
|
|
|
1118
746
|
switch (prop) {
|
|
1119
747
|
case 'length 0':
|
|
1120
748
|
{
|
|
1121
|
-
this._manager.
|
|
749
|
+
this._manager.mutate({
|
|
1122
750
|
op: 'replaceRelatedRecords',
|
|
1123
751
|
record: this.identifier,
|
|
1124
752
|
field: this.key,
|
|
@@ -1129,7 +757,7 @@ class RelatedCollection extends RecordArray {
|
|
|
1129
757
|
case 'replace cell':
|
|
1130
758
|
{
|
|
1131
759
|
const [index, prior, value] = args;
|
|
1132
|
-
this._manager.
|
|
760
|
+
this._manager.mutate({
|
|
1133
761
|
op: 'replaceRelatedRecord',
|
|
1134
762
|
record: this.identifier,
|
|
1135
763
|
field: this.key,
|
|
@@ -1140,7 +768,7 @@ class RelatedCollection extends RecordArray {
|
|
|
1140
768
|
break;
|
|
1141
769
|
}
|
|
1142
770
|
case 'push':
|
|
1143
|
-
this._manager.
|
|
771
|
+
this._manager.mutate({
|
|
1144
772
|
op: 'addToRelatedRecords',
|
|
1145
773
|
record: this.identifier,
|
|
1146
774
|
field: this.key,
|
|
@@ -1149,7 +777,7 @@ class RelatedCollection extends RecordArray {
|
|
|
1149
777
|
break;
|
|
1150
778
|
case 'pop':
|
|
1151
779
|
if (result) {
|
|
1152
|
-
this._manager.
|
|
780
|
+
this._manager.mutate({
|
|
1153
781
|
op: 'removeFromRelatedRecords',
|
|
1154
782
|
record: this.identifier,
|
|
1155
783
|
field: this.key,
|
|
@@ -1158,7 +786,7 @@ class RelatedCollection extends RecordArray {
|
|
|
1158
786
|
}
|
|
1159
787
|
break;
|
|
1160
788
|
case 'unshift':
|
|
1161
|
-
this._manager.
|
|
789
|
+
this._manager.mutate({
|
|
1162
790
|
op: 'addToRelatedRecords',
|
|
1163
791
|
record: this.identifier,
|
|
1164
792
|
field: this.key,
|
|
@@ -1168,7 +796,7 @@ class RelatedCollection extends RecordArray {
|
|
|
1168
796
|
break;
|
|
1169
797
|
case 'shift':
|
|
1170
798
|
if (result) {
|
|
1171
|
-
this._manager.
|
|
799
|
+
this._manager.mutate({
|
|
1172
800
|
op: 'removeFromRelatedRecords',
|
|
1173
801
|
record: this.identifier,
|
|
1174
802
|
field: this.key,
|
|
@@ -1178,7 +806,7 @@ class RelatedCollection extends RecordArray {
|
|
|
1178
806
|
}
|
|
1179
807
|
break;
|
|
1180
808
|
case 'sort':
|
|
1181
|
-
this._manager.
|
|
809
|
+
this._manager.mutate({
|
|
1182
810
|
op: 'sortRelatedRecords',
|
|
1183
811
|
record: this.identifier,
|
|
1184
812
|
field: this.key,
|
|
@@ -1190,7 +818,7 @@ class RelatedCollection extends RecordArray {
|
|
|
1190
818
|
const [start, removeCount, ...adds] = args;
|
|
1191
819
|
// detect a full replace
|
|
1192
820
|
if (removeCount > 0 && adds.length === this[SOURCE].length) {
|
|
1193
|
-
this._manager.
|
|
821
|
+
this._manager.mutate({
|
|
1194
822
|
op: 'replaceRelatedRecords',
|
|
1195
823
|
record: this.identifier,
|
|
1196
824
|
field: this.key,
|
|
@@ -1199,7 +827,7 @@ class RelatedCollection extends RecordArray {
|
|
|
1199
827
|
return;
|
|
1200
828
|
}
|
|
1201
829
|
if (removeCount > 0) {
|
|
1202
|
-
this._manager.
|
|
830
|
+
this._manager.mutate({
|
|
1203
831
|
op: 'removeFromRelatedRecords',
|
|
1204
832
|
record: this.identifier,
|
|
1205
833
|
field: this.key,
|
|
@@ -1208,7 +836,7 @@ class RelatedCollection extends RecordArray {
|
|
|
1208
836
|
});
|
|
1209
837
|
}
|
|
1210
838
|
if (adds?.length) {
|
|
1211
|
-
this._manager.
|
|
839
|
+
this._manager.mutate({
|
|
1212
840
|
op: 'addToRelatedRecords',
|
|
1213
841
|
record: this.identifier,
|
|
1214
842
|
field: this.key,
|
|
@@ -1278,6 +906,7 @@ class RelatedCollection extends RecordArray {
|
|
|
1278
906
|
const {
|
|
1279
907
|
store
|
|
1280
908
|
} = this;
|
|
909
|
+
assert(`Expected modelName to be set`, this.modelName);
|
|
1281
910
|
const record = store.createRecord(this.modelName, hash);
|
|
1282
911
|
this.push(record);
|
|
1283
912
|
return record;
|
|
@@ -1286,7 +915,7 @@ class RelatedCollection extends RecordArray {
|
|
|
1286
915
|
RelatedCollection.prototype.isAsync = false;
|
|
1287
916
|
RelatedCollection.prototype.isPolymorphic = false;
|
|
1288
917
|
RelatedCollection.prototype.identifier = null;
|
|
1289
|
-
RelatedCollection.prototype.
|
|
918
|
+
RelatedCollection.prototype.cache = null;
|
|
1290
919
|
RelatedCollection.prototype._inverseIsAsync = false;
|
|
1291
920
|
RelatedCollection.prototype.key = '';
|
|
1292
921
|
RelatedCollection.prototype.DEPRECATED_CLASS_NAME = 'ManyArray';
|
|
@@ -1328,6 +957,9 @@ function isPromiseRecord$1(record) {
|
|
|
1328
957
|
return !!record.then;
|
|
1329
958
|
}
|
|
1330
959
|
var _dec, _class$5;
|
|
960
|
+
|
|
961
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
962
|
+
|
|
1331
963
|
const Extended = PromiseObject;
|
|
1332
964
|
|
|
1333
965
|
/**
|
|
@@ -1374,6 +1006,26 @@ let PromiseBelongsTo = (_dec = computed(), (_class$5 = class PromiseBelongsTo ex
|
|
|
1374
1006
|
}
|
|
1375
1007
|
}, (_applyDecoratedDescriptor(_class$5.prototype, "id", [cached], Object.getOwnPropertyDescriptor(_class$5.prototype, "id"), _class$5.prototype), _applyDecoratedDescriptor(_class$5.prototype, "meta", [_dec], Object.getOwnPropertyDescriptor(_class$5.prototype, "meta"), _class$5.prototype)), _class$5));
|
|
1376
1008
|
var _class$4, _descriptor$4, _descriptor2$1, _descriptor3, _descriptor4, _descriptor5;
|
|
1009
|
+
|
|
1010
|
+
/**
|
|
1011
|
+
@module @ember-data/model
|
|
1012
|
+
*/
|
|
1013
|
+
/**
|
|
1014
|
+
This class is returned as the result of accessing an async hasMany relationship
|
|
1015
|
+
on an instance of a Model extending from `@ember-data/model`.
|
|
1016
|
+
|
|
1017
|
+
A PromiseManyArray is an iterable proxy that allows templates to consume related
|
|
1018
|
+
ManyArrays and update once their contents are no longer pending.
|
|
1019
|
+
|
|
1020
|
+
In your JS code you should resolve the promise first.
|
|
1021
|
+
|
|
1022
|
+
```js
|
|
1023
|
+
const comments = await post.comments;
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
@class PromiseManyArray
|
|
1027
|
+
@public
|
|
1028
|
+
*/
|
|
1377
1029
|
let PromiseManyArray = (_class$4 = class PromiseManyArray {
|
|
1378
1030
|
// @deprecated (isDestroyed is not deprecated)
|
|
1379
1031
|
|
|
@@ -1430,7 +1082,7 @@ let PromiseManyArray = (_class$4 = class PromiseManyArray {
|
|
|
1430
1082
|
}
|
|
1431
1083
|
return false;
|
|
1432
1084
|
};
|
|
1433
|
-
} else if (macroCondition(
|
|
1085
|
+
} else if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
1434
1086
|
const meta = Ember.meta(this);
|
|
1435
1087
|
meta.hasMixin = mixin => {
|
|
1436
1088
|
assert(`Do not use A() on an EmberData PromiseManyArray`);
|
|
@@ -1652,7 +1304,7 @@ function tapPromise(proxy, promise) {
|
|
|
1652
1304
|
proxy.isSettled = false;
|
|
1653
1305
|
proxy.isFulfilled = false;
|
|
1654
1306
|
proxy.isRejected = false;
|
|
1655
|
-
return resolve(promise).then(content => {
|
|
1307
|
+
return Promise.resolve(promise).then(content => {
|
|
1656
1308
|
proxy.isPending = false;
|
|
1657
1309
|
proxy.isFulfilled = true;
|
|
1658
1310
|
proxy.isSettled = true;
|
|
@@ -1715,7 +1367,7 @@ if (macroCondition(getOwnConfig().deprecations.DEPRECATE_PROMISE_MANY_ARRAY_BEHA
|
|
|
1715
1367
|
`record.relationshipFor(key)`.
|
|
1716
1368
|
*/
|
|
1717
1369
|
let assertPolymorphicType;
|
|
1718
|
-
if (macroCondition(
|
|
1370
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
1719
1371
|
let checkPolymorphic = function checkPolymorphic(modelClass, addedModelClass) {
|
|
1720
1372
|
if (modelClass.__isMixin) {
|
|
1721
1373
|
return modelClass.__mixin.detect(addedModelClass.PrototypeMixin) ||
|
|
@@ -1967,7 +1619,8 @@ let BelongsToReference = (_class$3 = class BelongsToReference {
|
|
|
1967
1619
|
}
|
|
1968
1620
|
_resource() {
|
|
1969
1621
|
this._ref; // subscribe
|
|
1970
|
-
|
|
1622
|
+
const cache = macroCondition(getOwnConfig().deprecations.DEPRECATE_V1_RECORD_DATA) ? this.store._instanceCache.getResourceCache(this.___identifier) : this.store.cache;
|
|
1623
|
+
return cache.getRelationship(this.___identifier, this.key);
|
|
1971
1624
|
}
|
|
1972
1625
|
|
|
1973
1626
|
/**
|
|
@@ -2057,7 +1710,7 @@ let BelongsToReference = (_class$3 = class BelongsToReference {
|
|
|
2057
1710
|
let jsonApiDoc = data;
|
|
2058
1711
|
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_PROMISE_PROXIES)) {
|
|
2059
1712
|
if (data.then) {
|
|
2060
|
-
jsonApiDoc = await
|
|
1713
|
+
jsonApiDoc = await data;
|
|
2061
1714
|
if (jsonApiDoc !== data) {
|
|
2062
1715
|
deprecate(`You passed in a Promise to a Reference API that now expects a resolved value. await the value before setting it.`, false, {
|
|
2063
1716
|
id: 'ember-data:deprecate-promise-proxies',
|
|
@@ -2072,7 +1725,7 @@ let BelongsToReference = (_class$3 = class BelongsToReference {
|
|
|
2072
1725
|
}
|
|
2073
1726
|
}
|
|
2074
1727
|
let record = this.store.push(jsonApiDoc);
|
|
2075
|
-
if (macroCondition(
|
|
1728
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
2076
1729
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
2077
1730
|
assertPolymorphicType(this.belongsToRelationship.identifier, this.belongsToRelationship.definition, recordIdentifierFor$1(record), this.store);
|
|
2078
1731
|
}
|
|
@@ -2332,7 +1985,8 @@ let HasManyReference = (_class$2 = class HasManyReference {
|
|
|
2332
1985
|
return [];
|
|
2333
1986
|
}
|
|
2334
1987
|
_resource() {
|
|
2335
|
-
|
|
1988
|
+
const cache = macroCondition(getOwnConfig().deprecations.DEPRECATE_V1_RECORD_DATA) ? this.store._instanceCache.getResourceCache(this.___identifier) : this.store.cache;
|
|
1989
|
+
return cache.getRelationship(this.___identifier, this.key);
|
|
2336
1990
|
}
|
|
2337
1991
|
|
|
2338
1992
|
/**
|
|
@@ -2549,7 +2203,7 @@ let HasManyReference = (_class$2 = class HasManyReference {
|
|
|
2549
2203
|
let payload = objectOrPromise;
|
|
2550
2204
|
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_PROMISE_PROXIES)) {
|
|
2551
2205
|
if (objectOrPromise.then) {
|
|
2552
|
-
payload = await
|
|
2206
|
+
payload = await objectOrPromise;
|
|
2553
2207
|
if (payload !== objectOrPromise) {
|
|
2554
2208
|
deprecate(`You passed in a Promise to a Reference API that now expects a resolved value. await the value before setting it.`, false, {
|
|
2555
2209
|
id: 'ember-data:deprecate-promise-proxies',
|
|
@@ -2582,7 +2236,7 @@ let HasManyReference = (_class$2 = class HasManyReference {
|
|
|
2582
2236
|
data: obj
|
|
2583
2237
|
});
|
|
2584
2238
|
}
|
|
2585
|
-
if (macroCondition(
|
|
2239
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
2586
2240
|
let relationshipMeta = this.hasManyRelationship.definition;
|
|
2587
2241
|
let identifier = this.hasManyRelationship.identifier;
|
|
2588
2242
|
|
|
@@ -2775,9 +2429,9 @@ let HasManyReference = (_class$2 = class HasManyReference {
|
|
|
2775
2429
|
class LegacySupport {
|
|
2776
2430
|
constructor(record) {
|
|
2777
2431
|
this.record = record;
|
|
2778
|
-
this.store = storeFor
|
|
2432
|
+
this.store = storeFor(record);
|
|
2779
2433
|
this.identifier = recordIdentifierFor$1(record);
|
|
2780
|
-
this.
|
|
2434
|
+
this.cache = peekCache(record);
|
|
2781
2435
|
this._manyArrayCache = Object.create(null);
|
|
2782
2436
|
this._relationshipPromisesCache = Object.create(null);
|
|
2783
2437
|
this._relationshipProxyCache = Object.create(null);
|
|
@@ -2800,8 +2454,8 @@ class LegacySupport {
|
|
|
2800
2454
|
currentState.length = 0;
|
|
2801
2455
|
fastPush(currentState, identifiers);
|
|
2802
2456
|
}
|
|
2803
|
-
|
|
2804
|
-
this.
|
|
2457
|
+
mutate(mutation) {
|
|
2458
|
+
this.cache.mutate(mutation);
|
|
2805
2459
|
}
|
|
2806
2460
|
_findBelongsTo(key, resource, relationship, options) {
|
|
2807
2461
|
// TODO @runspired follow up if parent isNew then we should not be attempting load here
|
|
@@ -2816,7 +2470,7 @@ class LegacySupport {
|
|
|
2816
2470
|
const graphFor = importSync('@ember-data/graph/-private').graphFor;
|
|
2817
2471
|
const relationship = graphFor(this.store).get(this.identifier, key);
|
|
2818
2472
|
assert(`Expected ${key} to be a belongs-to relationship`, isBelongsTo(relationship));
|
|
2819
|
-
let resource = this.
|
|
2473
|
+
let resource = this.cache.getRelationship(this.identifier, key);
|
|
2820
2474
|
relationship.state.hasFailedLoadAttempt = false;
|
|
2821
2475
|
relationship.state.shouldForceReload = true;
|
|
2822
2476
|
let promise = this._findBelongsTo(key, resource, relationship, options);
|
|
@@ -2830,9 +2484,9 @@ class LegacySupport {
|
|
|
2830
2484
|
getBelongsTo(key, options) {
|
|
2831
2485
|
const {
|
|
2832
2486
|
identifier,
|
|
2833
|
-
|
|
2487
|
+
cache
|
|
2834
2488
|
} = this;
|
|
2835
|
-
let resource =
|
|
2489
|
+
let resource = cache.getRelationship(this.identifier, key);
|
|
2836
2490
|
let relatedIdentifier = resource && resource.data ? resource.data : null;
|
|
2837
2491
|
assert(`Expected a stable identifier`, !relatedIdentifier || isStableIdentifier(relatedIdentifier));
|
|
2838
2492
|
const store = this.store;
|
|
@@ -2868,7 +2522,7 @@ class LegacySupport {
|
|
|
2868
2522
|
}
|
|
2869
2523
|
}
|
|
2870
2524
|
setDirtyBelongsTo(key, value) {
|
|
2871
|
-
return this.
|
|
2525
|
+
return this.cache.mutate({
|
|
2872
2526
|
op: 'replaceRelatedRecord',
|
|
2873
2527
|
record: this.identifier,
|
|
2874
2528
|
field: key,
|
|
@@ -2878,7 +2532,7 @@ class LegacySupport {
|
|
|
2878
2532
|
true);
|
|
2879
2533
|
}
|
|
2880
2534
|
_getCurrentState(identifier, field) {
|
|
2881
|
-
let jsonApi = this.
|
|
2535
|
+
let jsonApi = this.cache.getRelationship(identifier, field, true);
|
|
2882
2536
|
const cache = this.store._instanceCache;
|
|
2883
2537
|
let identifiers = [];
|
|
2884
2538
|
if (jsonApi.data) {
|
|
@@ -2893,7 +2547,7 @@ class LegacySupport {
|
|
|
2893
2547
|
return [identifiers, jsonApi];
|
|
2894
2548
|
}
|
|
2895
2549
|
getManyArray(key, definition) {
|
|
2896
|
-
if (macroCondition(
|
|
2550
|
+
if (macroCondition(getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
|
|
2897
2551
|
let manyArray = this._manyArrayCache[key];
|
|
2898
2552
|
if (!definition) {
|
|
2899
2553
|
const graphFor = importSync('@ember-data/graph/-private').graphFor;
|
|
@@ -2905,7 +2559,7 @@ class LegacySupport {
|
|
|
2905
2559
|
store: this.store,
|
|
2906
2560
|
type: definition.type,
|
|
2907
2561
|
identifier: this.identifier,
|
|
2908
|
-
|
|
2562
|
+
cache: this.cache,
|
|
2909
2563
|
identifiers,
|
|
2910
2564
|
key,
|
|
2911
2565
|
meta: doc.meta || null,
|
|
@@ -2924,16 +2578,16 @@ class LegacySupport {
|
|
|
2924
2578
|
assert('hasMany only works with the @ember-data/json-api package');
|
|
2925
2579
|
}
|
|
2926
2580
|
fetchAsyncHasMany(key, relationship, manyArray, options) {
|
|
2927
|
-
if (macroCondition(
|
|
2581
|
+
if (macroCondition(getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
|
|
2928
2582
|
let loadingPromise = this._relationshipPromisesCache[key];
|
|
2929
2583
|
if (loadingPromise) {
|
|
2930
2584
|
return loadingPromise;
|
|
2931
2585
|
}
|
|
2932
|
-
const jsonApi = this.
|
|
2586
|
+
const jsonApi = this.cache.getRelationship(this.identifier, key);
|
|
2933
2587
|
const promise = this._findHasManyByJsonApiResource(jsonApi, this.identifier, relationship, options);
|
|
2934
2588
|
if (!promise) {
|
|
2935
2589
|
manyArray.isLoaded = true;
|
|
2936
|
-
return resolve(manyArray);
|
|
2590
|
+
return Promise.resolve(manyArray);
|
|
2937
2591
|
}
|
|
2938
2592
|
loadingPromise = promise.then(() => handleCompletedRelationshipRequest(this, key, relationship, manyArray), e => handleCompletedRelationshipRequest(this, key, relationship, manyArray, e));
|
|
2939
2593
|
this._relationshipPromisesCache[key] = loadingPromise;
|
|
@@ -2942,7 +2596,7 @@ class LegacySupport {
|
|
|
2942
2596
|
assert('hasMany only works with the @ember-data/json-api package');
|
|
2943
2597
|
}
|
|
2944
2598
|
reloadHasMany(key, options) {
|
|
2945
|
-
if (macroCondition(
|
|
2599
|
+
if (macroCondition(getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
|
|
2946
2600
|
let loadingPromise = this._relationshipPromisesCache[key];
|
|
2947
2601
|
if (loadingPromise) {
|
|
2948
2602
|
return loadingPromise;
|
|
@@ -2967,7 +2621,7 @@ class LegacySupport {
|
|
|
2967
2621
|
assert(`hasMany only works with the @ember-data/json-api package`);
|
|
2968
2622
|
}
|
|
2969
2623
|
getHasMany(key, options) {
|
|
2970
|
-
if (macroCondition(
|
|
2624
|
+
if (macroCondition(getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
|
|
2971
2625
|
const graphFor = importSync('@ember-data/graph/-private').graphFor;
|
|
2972
2626
|
const relationship = graphFor(this.store).get(this.identifier, key);
|
|
2973
2627
|
const {
|
|
@@ -3025,7 +2679,7 @@ class LegacySupport {
|
|
|
3025
2679
|
referenceFor(kind, name) {
|
|
3026
2680
|
let reference = this.references[name];
|
|
3027
2681
|
if (!reference) {
|
|
3028
|
-
if (macroCondition(!
|
|
2682
|
+
if (macroCondition(!getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
|
|
3029
2683
|
// TODO @runspired while this feels odd, it is not a regression in capability because we do
|
|
3030
2684
|
// not today support references pulling from RecordDatas other than our own
|
|
3031
2685
|
// because of the intimate API access involved. This is something we will need to redesign.
|
|
@@ -3034,7 +2688,7 @@ class LegacySupport {
|
|
|
3034
2688
|
const graphFor = importSync('@ember-data/graph/-private').graphFor;
|
|
3035
2689
|
const graph = graphFor(this.store);
|
|
3036
2690
|
const relationship = graph.get(this.identifier, name);
|
|
3037
|
-
if (macroCondition(
|
|
2691
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
3038
2692
|
if (kind) {
|
|
3039
2693
|
let modelName = this.identifier.type;
|
|
3040
2694
|
let actualRelationshipKind = relationship.definition.kind;
|
|
@@ -3052,7 +2706,7 @@ class LegacySupport {
|
|
|
3052
2706
|
return reference;
|
|
3053
2707
|
}
|
|
3054
2708
|
_findHasManyByJsonApiResource(resource, parentIdentifier, relationship, options = {}) {
|
|
3055
|
-
if (macroCondition(
|
|
2709
|
+
if (macroCondition(getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
|
|
3056
2710
|
if (!resource) {
|
|
3057
2711
|
return;
|
|
3058
2712
|
}
|
|
@@ -3069,66 +2723,52 @@ class LegacySupport {
|
|
|
3069
2723
|
shouldForceReload
|
|
3070
2724
|
} = state;
|
|
3071
2725
|
const allInverseRecordsAreLoaded = areAllInverseRecordsLoaded(this.store, resource);
|
|
3072
|
-
const
|
|
2726
|
+
const identifiers = resource.data;
|
|
2727
|
+
const shouldFindViaLink = resource.links && resource.links.related && (typeof adapter.findHasMany === 'function' || typeof identifiers === 'undefined') && (shouldForceReload || hasDematerializedInverse || isStale || !allInverseRecordsAreLoaded && !isEmpty);
|
|
2728
|
+
const relationshipMeta = this.store.getSchemaDefinitionService().relationshipsDefinitionFor({
|
|
2729
|
+
type: definition.inverseType
|
|
2730
|
+
})[definition.key];
|
|
2731
|
+
const request = {
|
|
2732
|
+
useLink: shouldFindViaLink,
|
|
2733
|
+
field: relationshipMeta,
|
|
2734
|
+
links: resource.links,
|
|
2735
|
+
meta: resource.meta,
|
|
2736
|
+
options,
|
|
2737
|
+
record: parentIdentifier
|
|
2738
|
+
};
|
|
3073
2739
|
|
|
3074
2740
|
// fetch via link
|
|
3075
2741
|
if (shouldFindViaLink) {
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
relationship is fetched.
|
|
3087
|
-
The link (which is usually a URL) is passed through unchanged, so the
|
|
3088
|
-
adapter can make whatever request it wants.
|
|
3089
|
-
The usual use-case is for the server to register a URL as a link, and
|
|
3090
|
-
then use that URL in the future to make a request for the relationship.
|
|
3091
|
-
*/
|
|
3092
|
-
assert(`You tried to load a hasMany relationship but you have no adapter (for ${parentIdentifier.type})`, adapter);
|
|
3093
|
-
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');
|
|
3094
|
-
return _findHasMany(adapter, this.store, parentIdentifier, resource.links.related, relationshipMeta, options);
|
|
2742
|
+
assert(`Expected collection to be an array`, !identifiers || Array.isArray(identifiers));
|
|
2743
|
+
assert(`Expected stable identifiers`, !identifiers || identifiers.every(isStableIdentifier));
|
|
2744
|
+
return this.store.request({
|
|
2745
|
+
op: 'findHasMany',
|
|
2746
|
+
records: identifiers || [],
|
|
2747
|
+
data: request,
|
|
2748
|
+
cacheOptions: {
|
|
2749
|
+
[Symbol.for('ember-data:skip-cache')]: true
|
|
2750
|
+
}
|
|
2751
|
+
});
|
|
3095
2752
|
}
|
|
3096
2753
|
const preferLocalCache = hasReceivedData && !isEmpty;
|
|
3097
|
-
const hasLocalPartialData = hasDematerializedInverse || isEmpty && Array.isArray(
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
if (allInverseRecordsAreLoaded) {
|
|
3102
|
-
return;
|
|
3103
|
-
}
|
|
3104
|
-
assert(`Expected collection to be an array`, Array.isArray(resource.data));
|
|
3105
|
-
if (allInverseRecordsAreLoaded) {
|
|
3106
|
-
return;
|
|
3107
|
-
}
|
|
3108
|
-
let finds = new Array(resource.data.length);
|
|
3109
|
-
let cache = this.store._instanceCache;
|
|
3110
|
-
for (let i = 0; i < resource.data.length; i++) {
|
|
3111
|
-
const identifier = resource.data[i];
|
|
3112
|
-
assert(`expected a stable identifier`, isStableIdentifier(identifier));
|
|
3113
|
-
finds[i] = cache._fetchDataIfNeededForIdentifier(identifier, options);
|
|
3114
|
-
}
|
|
3115
|
-
return all(finds);
|
|
2754
|
+
const hasLocalPartialData = hasDematerializedInverse || isEmpty && Array.isArray(identifiers) && identifiers.length > 0;
|
|
2755
|
+
const attemptLocalCache = !shouldForceReload && !isStale && (preferLocalCache || hasLocalPartialData);
|
|
2756
|
+
if (attemptLocalCache && allInverseRecordsAreLoaded) {
|
|
2757
|
+
return;
|
|
3116
2758
|
}
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
// fetch by data
|
|
3120
|
-
if (hasData || hasLocalPartialData) {
|
|
3121
|
-
const identifiers = resource.data;
|
|
2759
|
+
const hasData = hasReceivedData && !isEmpty;
|
|
2760
|
+
if (attemptLocalCache || hasData || hasLocalPartialData) {
|
|
3122
2761
|
assert(`Expected collection to be an array`, Array.isArray(identifiers));
|
|
3123
2762
|
assert(`Expected stable identifiers`, identifiers.every(isStableIdentifier));
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
2763
|
+
options.reload = options.reload || !attemptLocalCache || undefined;
|
|
2764
|
+
return this.store.request({
|
|
2765
|
+
op: 'findHasMany',
|
|
2766
|
+
records: identifiers,
|
|
2767
|
+
data: request,
|
|
2768
|
+
cacheOptions: {
|
|
2769
|
+
[Symbol.for('ember-data:skip-cache')]: true
|
|
2770
|
+
}
|
|
2771
|
+
});
|
|
3132
2772
|
}
|
|
3133
2773
|
|
|
3134
2774
|
// we were explicitly told we have no data and no links.
|
|
@@ -3139,7 +2779,14 @@ class LegacySupport {
|
|
|
3139
2779
|
}
|
|
3140
2780
|
_findBelongsToByJsonApiResource(resource, parentIdentifier, relationship, options = {}) {
|
|
3141
2781
|
if (!resource) {
|
|
3142
|
-
return resolve(null);
|
|
2782
|
+
return Promise.resolve(null);
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
// interleaved promises mean that we MUST cache this here
|
|
2786
|
+
// in order to prevent infinite re-render if the request
|
|
2787
|
+
// fails.
|
|
2788
|
+
if (this._pending) {
|
|
2789
|
+
return this._pending;
|
|
3143
2790
|
}
|
|
3144
2791
|
const identifier = resource.data ? resource.data : null;
|
|
3145
2792
|
assert(`Expected a stable identifier`, !identifier || isStableIdentifier(identifier));
|
|
@@ -3150,53 +2797,71 @@ class LegacySupport {
|
|
|
3150
2797
|
isEmpty,
|
|
3151
2798
|
shouldForceReload
|
|
3152
2799
|
} = relationship.state;
|
|
3153
|
-
|
|
3154
|
-
// short circuit if we are already loading
|
|
3155
|
-
let pendingRequest = identifier && this.store._fetchManager.getPendingFetch(identifier, options);
|
|
3156
|
-
if (pendingRequest) {
|
|
3157
|
-
return pendingRequest;
|
|
3158
|
-
}
|
|
3159
2800
|
const allInverseRecordsAreLoaded = areAllInverseRecordsLoaded(this.store, resource);
|
|
3160
2801
|
const shouldFindViaLink = resource.links?.related && (shouldForceReload || hasDematerializedInverse || isStale || !allInverseRecordsAreLoaded && !isEmpty);
|
|
2802
|
+
const relationshipMeta = this.store.getSchemaDefinitionService().relationshipsDefinitionFor(this.identifier)[relationship.definition.key];
|
|
2803
|
+
assert(`Attempted to access a belongsTo relationship but no definition exists for it`, relationshipMeta);
|
|
2804
|
+
const request = {
|
|
2805
|
+
useLink: shouldFindViaLink,
|
|
2806
|
+
field: relationshipMeta,
|
|
2807
|
+
links: resource.links,
|
|
2808
|
+
meta: resource.meta,
|
|
2809
|
+
options,
|
|
2810
|
+
record: parentIdentifier
|
|
2811
|
+
};
|
|
3161
2812
|
|
|
3162
2813
|
// fetch via link
|
|
3163
2814
|
if (shouldFindViaLink) {
|
|
3164
|
-
const
|
|
3165
|
-
|
|
3166
|
-
|
|
2815
|
+
const future = this.store.request({
|
|
2816
|
+
op: 'findBelongsTo',
|
|
2817
|
+
records: identifier ? [identifier] : [],
|
|
2818
|
+
data: request,
|
|
2819
|
+
cacheOptions: {
|
|
2820
|
+
[Symbol.for('ember-data:skip-cache')]: true
|
|
2821
|
+
}
|
|
2822
|
+
});
|
|
2823
|
+
this._pending = future.then(doc => doc.content).finally(() => {
|
|
2824
|
+
this._pending = null;
|
|
2825
|
+
});
|
|
2826
|
+
return this._pending;
|
|
3167
2827
|
}
|
|
3168
|
-
|
|
3169
|
-
|
|
2828
|
+
const preferLocalCache = hasReceivedData && allInverseRecordsAreLoaded && !isEmpty;
|
|
2829
|
+
const hasLocalPartialData = hasDematerializedInverse || isEmpty && resource.data;
|
|
3170
2830
|
// null is explicit empty, undefined is "we don't know anything"
|
|
3171
|
-
const localDataIsEmpty =
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
2831
|
+
const localDataIsEmpty = !identifier;
|
|
2832
|
+
const attemptLocalCache = !shouldForceReload && !isStale && (preferLocalCache || hasLocalPartialData);
|
|
2833
|
+
|
|
2834
|
+
// we dont need to fetch and are empty
|
|
2835
|
+
if (attemptLocalCache && localDataIsEmpty) {
|
|
2836
|
+
return Promise.resolve(null);
|
|
2837
|
+
}
|
|
2838
|
+
|
|
2839
|
+
// we dont need to fetch because we are local state
|
|
2840
|
+
const resourceIsLocal = identifier?.id === null;
|
|
2841
|
+
if (attemptLocalCache && allInverseRecordsAreLoaded || resourceIsLocal) {
|
|
2842
|
+
return Promise.resolve(identifier);
|
|
2843
|
+
}
|
|
2844
|
+
|
|
2845
|
+
// we may need to fetch
|
|
2846
|
+
if (identifier) {
|
|
2847
|
+
assert(`Cannot fetch belongs-to relationship with no information`, identifier);
|
|
2848
|
+
options.reload = options.reload || !attemptLocalCache || undefined;
|
|
2849
|
+
this._pending = this.store.request({
|
|
2850
|
+
op: 'findBelongsTo',
|
|
2851
|
+
records: [identifier],
|
|
2852
|
+
data: request,
|
|
2853
|
+
cacheOptions: {
|
|
2854
|
+
[Symbol.for('ember-data:skip-cache')]: true
|
|
2855
|
+
}
|
|
2856
|
+
}).then(doc => doc.content).finally(() => {
|
|
2857
|
+
this._pending = null;
|
|
2858
|
+
});
|
|
2859
|
+
return this._pending;
|
|
3195
2860
|
}
|
|
3196
2861
|
|
|
3197
2862
|
// we were explicitly told we have no data and no links.
|
|
3198
2863
|
// TODO if the relationshipIsStale, should we hit the adapter anyway?
|
|
3199
|
-
return resolve(null);
|
|
2864
|
+
return Promise.resolve(null);
|
|
3200
2865
|
}
|
|
3201
2866
|
destroy() {
|
|
3202
2867
|
this.isDestroying = true;
|
|
@@ -3245,11 +2910,14 @@ function handleCompletedRelationshipRequest(recordExt, key, relationship, value,
|
|
|
3245
2910
|
if (proxy.content && proxy.content.isDestroying) {
|
|
3246
2911
|
proxy.set('content', null);
|
|
3247
2912
|
}
|
|
2913
|
+
recordExt.store.notifications._flush();
|
|
3248
2914
|
}
|
|
3249
2915
|
throw error;
|
|
3250
2916
|
}
|
|
3251
2917
|
if (isHasMany) {
|
|
3252
2918
|
value.isLoaded = true;
|
|
2919
|
+
} else {
|
|
2920
|
+
recordExt.store.notifications._flush();
|
|
3253
2921
|
}
|
|
3254
2922
|
relationship.state.hasFailedLoadAttempt = false;
|
|
3255
2923
|
// only set to not stale if no error is thrown
|
|
@@ -3356,7 +3024,8 @@ function notifyRelationship(identifier, key, record, meta) {
|
|
|
3356
3024
|
}
|
|
3357
3025
|
function notifyAttribute(store, identifier, key, record) {
|
|
3358
3026
|
let currentValue = cacheFor(record, key);
|
|
3359
|
-
|
|
3027
|
+
const cache = macroCondition(getOwnConfig().deprecations.DEPRECATE_V1_RECORD_DATA) ? peekCache(record) : store.cache;
|
|
3028
|
+
if (currentValue !== cache.getAttr(identifier, key)) {
|
|
3360
3029
|
record.notifyPropertyChange(key);
|
|
3361
3030
|
}
|
|
3362
3031
|
}
|
|
@@ -3491,11 +3160,11 @@ root
|
|
|
3491
3160
|
let RecordState = (_class3 = class RecordState {
|
|
3492
3161
|
constructor(record) {
|
|
3493
3162
|
_initializerDefineProperty(this, "isSaving", _descriptor2, this);
|
|
3494
|
-
const store = storeFor(record);
|
|
3163
|
+
const store = storeFor$1(record);
|
|
3495
3164
|
const identity = recordIdentifierFor$1(record);
|
|
3496
3165
|
this.identifier = identity;
|
|
3497
3166
|
this.record = record;
|
|
3498
|
-
this.cache =
|
|
3167
|
+
this.cache = macroCondition(getOwnConfig().deprecations.DEPRECATE_V1_RECORD_DATA) ? peekCache(record) : store.cache;
|
|
3499
3168
|
this.pendingCount = 0;
|
|
3500
3169
|
this.fulfilledCount = 0;
|
|
3501
3170
|
this.rejectedCount = 0;
|
|
@@ -3555,7 +3224,7 @@ let RecordState = (_class3 = class RecordState {
|
|
|
3555
3224
|
|
|
3556
3225
|
// we instantiate lazily
|
|
3557
3226
|
// so we grab anything we don't have yet
|
|
3558
|
-
if (macroCondition(!
|
|
3227
|
+
if (macroCondition(!getOwnConfig().env.DEBUG)) {
|
|
3559
3228
|
const lastRequest = requests.getLastRequestForRecord(identity);
|
|
3560
3229
|
if (lastRequest) {
|
|
3561
3230
|
handleRequest(lastRequest);
|
|
@@ -3580,7 +3249,7 @@ let RecordState = (_class3 = class RecordState {
|
|
|
3580
3249
|
});
|
|
3581
3250
|
}
|
|
3582
3251
|
destroy() {
|
|
3583
|
-
storeFor(this.record).notifications.unsubscribe(this.handler);
|
|
3252
|
+
storeFor$1(this.record).notifications.unsubscribe(this.handler);
|
|
3584
3253
|
}
|
|
3585
3254
|
notify(key) {
|
|
3586
3255
|
getTag(this, key).notify();
|
|
@@ -3814,7 +3483,7 @@ class RelationshipDefinition {
|
|
|
3814
3483
|
inverse = modelClass.inverseFor(this.key, store);
|
|
3815
3484
|
}
|
|
3816
3485
|
// TODO make this error again for the non-polymorphic case
|
|
3817
|
-
if (macroCondition(
|
|
3486
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
3818
3487
|
if (!this.options.polymorphic) {
|
|
3819
3488
|
modelClass.typeForRelationship(this.key, store);
|
|
3820
3489
|
}
|
|
@@ -3839,6 +3508,7 @@ function lookupLegacySupport(record) {
|
|
|
3839
3508
|
const identifier = recordIdentifierFor(record);
|
|
3840
3509
|
let support = LEGACY_SUPPORT.get(identifier);
|
|
3841
3510
|
if (!support) {
|
|
3511
|
+
assert(`Memory Leak Detected`, !record.isDestroyed && !record.isDestroying);
|
|
3842
3512
|
support = new LegacySupport(record);
|
|
3843
3513
|
LEGACY_SUPPORT.set(identifier, support);
|
|
3844
3514
|
LEGACY_SUPPORT.set(record, support);
|
|
@@ -3897,7 +3567,7 @@ function computeOnce(target, key, desc) {
|
|
|
3897
3567
|
}
|
|
3898
3568
|
|
|
3899
3569
|
/**
|
|
3900
|
-
Base class from which Models can be
|
|
3570
|
+
Base class from which Models can be defined.
|
|
3901
3571
|
|
|
3902
3572
|
```js
|
|
3903
3573
|
import Model, { attr } from '@ember-data/model';
|
|
@@ -3931,7 +3601,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
3931
3601
|
_initializerDefineProperty(this, "isReloading", _descriptor, this);
|
|
3932
3602
|
}
|
|
3933
3603
|
init(options = {}) {
|
|
3934
|
-
if (macroCondition(
|
|
3604
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
3935
3605
|
if (!options._secretInit && !options._createProps) {
|
|
3936
3606
|
throw new Error('You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.');
|
|
3937
3607
|
}
|
|
@@ -3943,8 +3613,8 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
3943
3613
|
let store = this.store = _secretInit.store;
|
|
3944
3614
|
super.init(options);
|
|
3945
3615
|
let identity = _secretInit.identifier;
|
|
3946
|
-
_secretInit.cb(this, _secretInit.
|
|
3947
|
-
this.___recordState = macroCondition(
|
|
3616
|
+
_secretInit.cb(this, _secretInit.cache, identity, _secretInit.store);
|
|
3617
|
+
this.___recordState = macroCondition(getOwnConfig().env.DEBUG) ? new RecordState(this) : null;
|
|
3948
3618
|
this.setProperties(createProps);
|
|
3949
3619
|
let notifications = store.notifications;
|
|
3950
3620
|
this.___private_notifications = notifications.subscribe(identity, (identifier, type, key) => {
|
|
@@ -3954,7 +3624,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
3954
3624
|
destroy() {
|
|
3955
3625
|
const identifier = recordIdentifierFor(this);
|
|
3956
3626
|
this.___recordState?.destroy();
|
|
3957
|
-
const store = storeFor(this);
|
|
3627
|
+
const store = storeFor$1(this);
|
|
3958
3628
|
store.notifications.unsubscribe(this.___private_notifications);
|
|
3959
3629
|
// Legacy behavior is to notify the relationships on destroy
|
|
3960
3630
|
// such that they "clear". It's uncertain this behavior would
|
|
@@ -4189,7 +3859,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4189
3859
|
return this.currentState.isError;
|
|
4190
3860
|
}
|
|
4191
3861
|
set isError(v) {
|
|
4192
|
-
if (macroCondition(
|
|
3862
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
4193
3863
|
throw new Error(`isError is not directly settable`);
|
|
4194
3864
|
}
|
|
4195
3865
|
}
|
|
@@ -4214,7 +3884,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4214
3884
|
// this guard exists, because some dev-only deprecation code
|
|
4215
3885
|
// (addListener via validatePropertyInjections) invokes toString before the
|
|
4216
3886
|
// object is real.
|
|
4217
|
-
if (macroCondition(
|
|
3887
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
4218
3888
|
try {
|
|
4219
3889
|
return recordIdentifierFor(this).id;
|
|
4220
3890
|
} catch {
|
|
@@ -4249,7 +3919,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4249
3919
|
// when using legacy/classic ember classes. Basically: lazy in prod and eager in dev.
|
|
4250
3920
|
// so we do this to try to steer folks to the nicer "dont user currentState"
|
|
4251
3921
|
// error.
|
|
4252
|
-
if (macroCondition(!
|
|
3922
|
+
if (macroCondition(!getOwnConfig().env.DEBUG)) {
|
|
4253
3923
|
if (!this.___recordState) {
|
|
4254
3924
|
this.___recordState = new RecordState(this);
|
|
4255
3925
|
}
|
|
@@ -4345,7 +4015,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4345
4015
|
@return {Object} an object whose values are primitive JSON values only
|
|
4346
4016
|
*/
|
|
4347
4017
|
serialize(options) {
|
|
4348
|
-
return storeFor(this).
|
|
4018
|
+
return storeFor$1(this).serializeRecord(this, options);
|
|
4349
4019
|
}
|
|
4350
4020
|
|
|
4351
4021
|
/*
|
|
@@ -4394,7 +4064,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4394
4064
|
deleteRecord() {
|
|
4395
4065
|
// ensure we've populated currentState prior to deleting a new record
|
|
4396
4066
|
if (this.currentState) {
|
|
4397
|
-
storeFor(this).deleteRecord(this);
|
|
4067
|
+
storeFor$1(this).deleteRecord(this);
|
|
4398
4068
|
}
|
|
4399
4069
|
}
|
|
4400
4070
|
|
|
@@ -4441,7 +4111,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4441
4111
|
} = this.currentState;
|
|
4442
4112
|
this.deleteRecord();
|
|
4443
4113
|
if (isNew) {
|
|
4444
|
-
return resolve(this);
|
|
4114
|
+
return Promise.resolve(this);
|
|
4445
4115
|
}
|
|
4446
4116
|
return this.save(options).then(_ => {
|
|
4447
4117
|
run(() => {
|
|
@@ -4461,7 +4131,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4461
4131
|
if (this.currentState.isNew && (this.isDestroyed || this.isDestroying)) {
|
|
4462
4132
|
return;
|
|
4463
4133
|
}
|
|
4464
|
-
storeFor(this).unloadRecord(this);
|
|
4134
|
+
storeFor$1(this).unloadRecord(this);
|
|
4465
4135
|
}
|
|
4466
4136
|
|
|
4467
4137
|
/**
|
|
@@ -4517,7 +4187,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4517
4187
|
and value is an [oldProp, newProp] array.
|
|
4518
4188
|
*/
|
|
4519
4189
|
changedAttributes() {
|
|
4520
|
-
return
|
|
4190
|
+
return peekCache(this).changedAttrs(recordIdentifierFor(this));
|
|
4521
4191
|
}
|
|
4522
4192
|
|
|
4523
4193
|
/**
|
|
@@ -4542,8 +4212,8 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4542
4212
|
const {
|
|
4543
4213
|
isNew
|
|
4544
4214
|
} = currentState;
|
|
4545
|
-
storeFor(this)._join(() => {
|
|
4546
|
-
|
|
4215
|
+
storeFor$1(this)._join(() => {
|
|
4216
|
+
peekCache(this).rollbackAttrs(recordIdentifierFor(this));
|
|
4547
4217
|
this.errors.clear();
|
|
4548
4218
|
currentState.cleanErrorRequests();
|
|
4549
4219
|
if (isNew) {
|
|
@@ -4558,7 +4228,12 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4558
4228
|
*/
|
|
4559
4229
|
// TODO @deprecate in favor of a public API or examples of how to test successfully
|
|
4560
4230
|
_createSnapshot() {
|
|
4561
|
-
|
|
4231
|
+
const store = storeFor$1(this);
|
|
4232
|
+
if (!store._fetchManager) {
|
|
4233
|
+
const FetchManager = importSync('@ember-data/legacy-compat/-private').FetchManager;
|
|
4234
|
+
store._fetchManager = new FetchManager(store);
|
|
4235
|
+
}
|
|
4236
|
+
return store._fetchManager.createSnapshot(recordIdentifierFor(this));
|
|
4562
4237
|
}
|
|
4563
4238
|
|
|
4564
4239
|
/**
|
|
@@ -4598,9 +4273,9 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4598
4273
|
save(options) {
|
|
4599
4274
|
let promise;
|
|
4600
4275
|
if (this.currentState.isNew && this.currentState.isDeleted) {
|
|
4601
|
-
promise = resolve(this);
|
|
4276
|
+
promise = Promise.resolve(this);
|
|
4602
4277
|
} else {
|
|
4603
|
-
promise = storeFor(this).saveRecord(this, options);
|
|
4278
|
+
promise = storeFor$1(this).saveRecord(this, options);
|
|
4604
4279
|
}
|
|
4605
4280
|
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_SAVE_PROMISE_ACCESS)) {
|
|
4606
4281
|
return deprecatedPromiseObject(promise);
|
|
@@ -4631,16 +4306,22 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4631
4306
|
adapter returns successfully or rejected if the adapter returns
|
|
4632
4307
|
with an error.
|
|
4633
4308
|
*/
|
|
4634
|
-
reload(
|
|
4635
|
-
let options = {};
|
|
4636
|
-
if (typeof _options === 'object' && _options !== null && _options.adapterOptions) {
|
|
4637
|
-
options.adapterOptions = _options.adapterOptions;
|
|
4638
|
-
}
|
|
4309
|
+
reload(options = {}) {
|
|
4639
4310
|
options.isReloading = true;
|
|
4640
|
-
|
|
4311
|
+
options.reload = true;
|
|
4312
|
+
const identifier = recordIdentifierFor(this);
|
|
4641
4313
|
assert(`You cannot reload a record without an ID`, identifier.id);
|
|
4642
4314
|
this.isReloading = true;
|
|
4643
|
-
const promise = storeFor(this).
|
|
4315
|
+
const promise = storeFor$1(this).request({
|
|
4316
|
+
op: 'findRecord',
|
|
4317
|
+
data: {
|
|
4318
|
+
options,
|
|
4319
|
+
record: identifier
|
|
4320
|
+
},
|
|
4321
|
+
cacheOptions: {
|
|
4322
|
+
[Symbol.for('ember-data:skip-cache')]: true
|
|
4323
|
+
}
|
|
4324
|
+
}).then(() => this).finally(() => {
|
|
4644
4325
|
this.isReloading = false;
|
|
4645
4326
|
});
|
|
4646
4327
|
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_SAVE_PROMISE_ACCESS)) {
|
|
@@ -4808,11 +4489,46 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4808
4489
|
return this.constructor.relationshipsByName.get(name);
|
|
4809
4490
|
}
|
|
4810
4491
|
inverseFor(key) {
|
|
4811
|
-
return this.constructor.inverseFor(key, storeFor(this));
|
|
4492
|
+
return this.constructor.inverseFor(key, storeFor$1(this));
|
|
4812
4493
|
}
|
|
4813
4494
|
eachAttribute(callback, binding) {
|
|
4814
4495
|
this.constructor.eachAttribute(callback, binding);
|
|
4815
4496
|
}
|
|
4497
|
+
|
|
4498
|
+
/**
|
|
4499
|
+
Create should only ever be called by the store. To create an instance of a
|
|
4500
|
+
`Model` in a dirty state use `store.createRecord`.
|
|
4501
|
+
To create instances of `Model` in a clean state, use `store.push`
|
|
4502
|
+
@method create
|
|
4503
|
+
@private
|
|
4504
|
+
@static
|
|
4505
|
+
*/
|
|
4506
|
+
/**
|
|
4507
|
+
Represents the model's class name as a string. This can be used to look up the model's class name through
|
|
4508
|
+
`Store`'s modelFor method.
|
|
4509
|
+
`modelName` is generated for you by Ember Data. It will be a lowercased, dasherized string.
|
|
4510
|
+
For example:
|
|
4511
|
+
```javascript
|
|
4512
|
+
store.modelFor('post').modelName; // 'post'
|
|
4513
|
+
store.modelFor('blog-post').modelName; // 'blog-post'
|
|
4514
|
+
```
|
|
4515
|
+
The most common place you'll want to access `modelName` is in your serializer's `payloadKeyFromModelName` method. For example, to change payload
|
|
4516
|
+
keys to underscore (instead of dasherized), you might use the following code:
|
|
4517
|
+
```javascript
|
|
4518
|
+
import RESTSerializer from '@ember-data/serializer/rest';
|
|
4519
|
+
import { underscore } from '<app-name>/utils/string-utils';
|
|
4520
|
+
export default const PostSerializer = RESTSerializer.extend({
|
|
4521
|
+
payloadKeyFromModelName(modelName) {
|
|
4522
|
+
return underscore(modelName);
|
|
4523
|
+
}
|
|
4524
|
+
});
|
|
4525
|
+
```
|
|
4526
|
+
@property modelName
|
|
4527
|
+
@public
|
|
4528
|
+
@type String
|
|
4529
|
+
@readonly
|
|
4530
|
+
@static
|
|
4531
|
+
*/
|
|
4816
4532
|
/*
|
|
4817
4533
|
These class methods below provide relationship
|
|
4818
4534
|
introspection abilities about relationships.
|
|
@@ -4826,7 +4542,6 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4826
4542
|
do it before using your model with the store, which uses these properties
|
|
4827
4543
|
extensively.
|
|
4828
4544
|
*/
|
|
4829
|
-
|
|
4830
4545
|
/**
|
|
4831
4546
|
For a given relationship name, returns the model type of the relationship.
|
|
4832
4547
|
For example, if you define a model like this:
|
|
@@ -4980,7 +4695,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4980
4695
|
if (possibleRelationships.length === 0) {
|
|
4981
4696
|
return null;
|
|
4982
4697
|
}
|
|
4983
|
-
if (macroCondition(
|
|
4698
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
4984
4699
|
let filteredRelationships = possibleRelationships.filter(possibleRelationship => {
|
|
4985
4700
|
let optionsForRelationship = possibleRelationship.options;
|
|
4986
4701
|
return name === optionsForRelationship.inverse;
|
|
@@ -4998,7 +4713,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
4998
4713
|
}
|
|
4999
4714
|
|
|
5000
4715
|
// ensure inverse is properly configured
|
|
5001
|
-
if (macroCondition(
|
|
4716
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5002
4717
|
if (isPolymorphic) {
|
|
5003
4718
|
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_NON_EXPLICIT_POLYMORPHISM)) {
|
|
5004
4719
|
if (!inverseOptions.as) {
|
|
@@ -5020,7 +4735,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
5020
4735
|
}
|
|
5021
4736
|
|
|
5022
4737
|
// ensure we are properly configured
|
|
5023
|
-
if (macroCondition(
|
|
4738
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5024
4739
|
if (inverseOptions.polymorphic) {
|
|
5025
4740
|
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_NON_EXPLICIT_POLYMORPHISM)) {
|
|
5026
4741
|
if (!options.as) {
|
|
@@ -5186,7 +4901,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
5186
4901
|
import { get } from '@ember/object';
|
|
5187
4902
|
import Blog from 'app/models/blog';
|
|
5188
4903
|
let relatedTypes = Blog.relatedTypes');
|
|
5189
|
-
//=> [
|
|
4904
|
+
//=> ['user', 'post']
|
|
5190
4905
|
```
|
|
5191
4906
|
@property relatedTypes
|
|
5192
4907
|
@public
|
|
@@ -5274,7 +4989,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
|
|
|
5274
4989
|
for (let i = 0; i < relationships.length; i++) {
|
|
5275
4990
|
let key = relationships[i];
|
|
5276
4991
|
let value = rels[key];
|
|
5277
|
-
map.set(value.key, value);
|
|
4992
|
+
map.set(value.name || value.key, value);
|
|
5278
4993
|
}
|
|
5279
4994
|
return map;
|
|
5280
4995
|
}
|
|
@@ -5721,16 +5436,21 @@ if (macroCondition(getOwnConfig().includeDataAdapter)) {
|
|
|
5721
5436
|
@private
|
|
5722
5437
|
*/
|
|
5723
5438
|
Model.prototype._debugInfo = function () {
|
|
5724
|
-
let attributes = ['id'];
|
|
5725
5439
|
let relationships = {};
|
|
5726
5440
|
let expensiveProperties = [];
|
|
5727
|
-
|
|
5441
|
+
const identifier = recordIdentifierFor(this);
|
|
5442
|
+
const schema = this.store.getSchemaDefinitionService();
|
|
5443
|
+
const attrDefs = schema.attributesDefinitionFor(identifier);
|
|
5444
|
+
const relDefs = schema.relationshipsDefinitionFor(identifier);
|
|
5445
|
+
const attributes = Object.keys(attrDefs);
|
|
5446
|
+
attributes.unshift('id');
|
|
5728
5447
|
let groups = [{
|
|
5729
5448
|
name: 'Attributes',
|
|
5730
5449
|
properties: attributes,
|
|
5731
5450
|
expand: true
|
|
5732
5451
|
}];
|
|
5733
|
-
|
|
5452
|
+
Object.keys(relDefs).forEach(name => {
|
|
5453
|
+
const relationship = relDefs[name];
|
|
5734
5454
|
let properties = relationships[relationship.kind];
|
|
5735
5455
|
if (properties === undefined) {
|
|
5736
5456
|
properties = relationships[relationship.kind] = [];
|
|
@@ -5758,7 +5478,7 @@ if (macroCondition(getOwnConfig().includeDataAdapter)) {
|
|
|
5758
5478
|
};
|
|
5759
5479
|
};
|
|
5760
5480
|
}
|
|
5761
|
-
if (macroCondition(
|
|
5481
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5762
5482
|
let lookupDescriptor = function lookupDescriptor(obj, keyName) {
|
|
5763
5483
|
let current = obj;
|
|
5764
5484
|
do {
|
|
@@ -5861,6 +5581,7 @@ function normalizeType$1(type) {
|
|
|
5861
5581
|
```
|
|
5862
5582
|
|
|
5863
5583
|
#### One-To-Many
|
|
5584
|
+
|
|
5864
5585
|
To declare a one-to-many relationship between two models, use
|
|
5865
5586
|
`belongsTo` in combination with `hasMany`, like this:
|
|
5866
5587
|
|
|
@@ -5868,7 +5589,7 @@ function normalizeType$1(type) {
|
|
|
5868
5589
|
import Model, { hasMany } from '@ember-data/model';
|
|
5869
5590
|
|
|
5870
5591
|
export default class PostModel extends Model {
|
|
5871
|
-
@hasMany('comment') comments;
|
|
5592
|
+
@hasMany('comment', { async: false, inverse: 'post' }) comments;
|
|
5872
5593
|
}
|
|
5873
5594
|
```
|
|
5874
5595
|
|
|
@@ -5876,23 +5597,10 @@ function normalizeType$1(type) {
|
|
|
5876
5597
|
import Model, { belongsTo } from '@ember-data/model';
|
|
5877
5598
|
|
|
5878
5599
|
export default class CommentModel extends Model {
|
|
5879
|
-
@belongsTo('post') post;
|
|
5880
|
-
}
|
|
5881
|
-
```
|
|
5882
|
-
|
|
5883
|
-
You can avoid passing a string as the first parameter. In that case Ember Data
|
|
5884
|
-
will infer the type from the key name.
|
|
5885
|
-
|
|
5886
|
-
```app/models/comment.js
|
|
5887
|
-
import Model, { belongsTo } from '@ember-data/model';
|
|
5888
|
-
|
|
5889
|
-
export default class CommentModel extends Model {
|
|
5890
|
-
@belongsTo post;
|
|
5600
|
+
@belongsTo('post', { async: false, inverse: 'comments' }) post;
|
|
5891
5601
|
}
|
|
5892
5602
|
```
|
|
5893
5603
|
|
|
5894
|
-
will lookup for a Post type.
|
|
5895
|
-
|
|
5896
5604
|
#### Sync relationships
|
|
5897
5605
|
|
|
5898
5606
|
Ember Data resolves sync relationships with the related resources
|
|
@@ -5904,7 +5612,8 @@ function normalizeType$1(type) {
|
|
|
5904
5612
|
|
|
5905
5613
|
export default class CommentModel extends Model {
|
|
5906
5614
|
@belongsTo('post', {
|
|
5907
|
-
async: false
|
|
5615
|
+
async: false,
|
|
5616
|
+
inverse: null
|
|
5908
5617
|
})
|
|
5909
5618
|
post;
|
|
5910
5619
|
}
|
|
@@ -6007,7 +5716,7 @@ function belongsTo(modelName, options) {
|
|
|
6007
5716
|
return null;
|
|
6008
5717
|
}
|
|
6009
5718
|
const support = lookupLegacySupport(this);
|
|
6010
|
-
if (macroCondition(
|
|
5719
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
6011
5720
|
if (['currentState'].indexOf(key) !== -1) {
|
|
6012
5721
|
throw new Error(`'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your belongsTo on ${this.constructor.toString()}`);
|
|
6013
5722
|
}
|
|
@@ -6026,7 +5735,7 @@ function belongsTo(modelName, options) {
|
|
|
6026
5735
|
},
|
|
6027
5736
|
set(key, value) {
|
|
6028
5737
|
const support = lookupLegacySupport(this);
|
|
6029
|
-
if (macroCondition(
|
|
5738
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
6030
5739
|
if (['currentState'].indexOf(key) !== -1) {
|
|
6031
5740
|
throw new Error(`'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your belongsTo on ${this.constructor.toString()}`);
|
|
6032
5741
|
}
|
|
@@ -6257,7 +5966,7 @@ function hasMany(type, options) {
|
|
|
6257
5966
|
};
|
|
6258
5967
|
return computed({
|
|
6259
5968
|
get(key) {
|
|
6260
|
-
if (macroCondition(
|
|
5969
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
6261
5970
|
if (['currentState'].indexOf(key) !== -1) {
|
|
6262
5971
|
throw new Error(`'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your hasMany on ${this.constructor.toString()}`);
|
|
6263
5972
|
}
|
|
@@ -6268,7 +5977,7 @@ function hasMany(type, options) {
|
|
|
6268
5977
|
return lookupLegacySupport(this).getHasMany(key);
|
|
6269
5978
|
},
|
|
6270
5979
|
set(key, records) {
|
|
6271
|
-
if (macroCondition(
|
|
5980
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
6272
5981
|
if (['currentState'].indexOf(key) !== -1) {
|
|
6273
5982
|
throw new Error(`'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your hasMany on ${this.constructor.toString()}`);
|
|
6274
5983
|
}
|