@ember-data/model 4.12.0-beta.3 → 4.12.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
- import { macroCondition, isDevelopingApp, getOwnConfig, importSync, dependencySatisfies } from '@embroider/macros';
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 { recordDataFor, RecordArray, MUTATE, SOURCE, recordIdentifierFor as recordIdentifierFor$1, IDENTIFIER_ARRAY_TAG, notifyArray, isStableIdentifier, storeFor as storeFor$1, fastPush, coerceId } from '@ember-data/store/-private';
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
- import Transform from '@ember-data/serializer/transform';
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(isDevelopingApp())) {
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 recordDataFor(this).getAttr(recordIdentifierFor(this), key);
154
+ return peekCache(this).getAttr(recordIdentifierFor(this), key);
154
155
  },
155
156
  set(key, value) {
156
- if (macroCondition(isDevelopingApp())) {
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 recordData = storeFor(this)._instanceCache.getRecordData(identifier);
164
- let currentValue = recordData.getAttr(identifier, key);
164
+ const cache = peekCache(this);
165
+ let currentValue = cache.getAttr(identifier, key);
165
166
  if (currentValue !== value) {
166
- recordData.setAttr(identifier, key, value);
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: resolve(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(!isDevelopingApp())) {
229
+ if (macroCondition(!getOwnConfig().env.DEBUG)) {
229
230
  return promiseObjectProxy;
230
231
  }
231
232
  const handler = {
@@ -632,384 +633,6 @@ let Errors = (_dec$1 = computed(), _dec2 = mapBy('content', 'message'), _dec3 =
632
633
  writable: true,
633
634
  initializer: null
634
635
  })), _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
636
 
1014
637
  /**
1015
638
  A `ManyArray` is a `MutableArray` that represents the contents of a has-many
@@ -1118,7 +741,7 @@ class RelatedCollection extends RecordArray {
1118
741
  switch (prop) {
1119
742
  case 'length 0':
1120
743
  {
1121
- this._manager.updateCache({
744
+ this._manager.mutate({
1122
745
  op: 'replaceRelatedRecords',
1123
746
  record: this.identifier,
1124
747
  field: this.key,
@@ -1129,7 +752,7 @@ class RelatedCollection extends RecordArray {
1129
752
  case 'replace cell':
1130
753
  {
1131
754
  const [index, prior, value] = args;
1132
- this._manager.updateCache({
755
+ this._manager.mutate({
1133
756
  op: 'replaceRelatedRecord',
1134
757
  record: this.identifier,
1135
758
  field: this.key,
@@ -1140,7 +763,7 @@ class RelatedCollection extends RecordArray {
1140
763
  break;
1141
764
  }
1142
765
  case 'push':
1143
- this._manager.updateCache({
766
+ this._manager.mutate({
1144
767
  op: 'addToRelatedRecords',
1145
768
  record: this.identifier,
1146
769
  field: this.key,
@@ -1149,7 +772,7 @@ class RelatedCollection extends RecordArray {
1149
772
  break;
1150
773
  case 'pop':
1151
774
  if (result) {
1152
- this._manager.updateCache({
775
+ this._manager.mutate({
1153
776
  op: 'removeFromRelatedRecords',
1154
777
  record: this.identifier,
1155
778
  field: this.key,
@@ -1158,7 +781,7 @@ class RelatedCollection extends RecordArray {
1158
781
  }
1159
782
  break;
1160
783
  case 'unshift':
1161
- this._manager.updateCache({
784
+ this._manager.mutate({
1162
785
  op: 'addToRelatedRecords',
1163
786
  record: this.identifier,
1164
787
  field: this.key,
@@ -1168,7 +791,7 @@ class RelatedCollection extends RecordArray {
1168
791
  break;
1169
792
  case 'shift':
1170
793
  if (result) {
1171
- this._manager.updateCache({
794
+ this._manager.mutate({
1172
795
  op: 'removeFromRelatedRecords',
1173
796
  record: this.identifier,
1174
797
  field: this.key,
@@ -1178,7 +801,7 @@ class RelatedCollection extends RecordArray {
1178
801
  }
1179
802
  break;
1180
803
  case 'sort':
1181
- this._manager.updateCache({
804
+ this._manager.mutate({
1182
805
  op: 'sortRelatedRecords',
1183
806
  record: this.identifier,
1184
807
  field: this.key,
@@ -1190,7 +813,7 @@ class RelatedCollection extends RecordArray {
1190
813
  const [start, removeCount, ...adds] = args;
1191
814
  // detect a full replace
1192
815
  if (removeCount > 0 && adds.length === this[SOURCE].length) {
1193
- this._manager.updateCache({
816
+ this._manager.mutate({
1194
817
  op: 'replaceRelatedRecords',
1195
818
  record: this.identifier,
1196
819
  field: this.key,
@@ -1199,7 +822,7 @@ class RelatedCollection extends RecordArray {
1199
822
  return;
1200
823
  }
1201
824
  if (removeCount > 0) {
1202
- this._manager.updateCache({
825
+ this._manager.mutate({
1203
826
  op: 'removeFromRelatedRecords',
1204
827
  record: this.identifier,
1205
828
  field: this.key,
@@ -1208,7 +831,7 @@ class RelatedCollection extends RecordArray {
1208
831
  });
1209
832
  }
1210
833
  if (adds?.length) {
1211
- this._manager.updateCache({
834
+ this._manager.mutate({
1212
835
  op: 'addToRelatedRecords',
1213
836
  record: this.identifier,
1214
837
  field: this.key,
@@ -1278,6 +901,7 @@ class RelatedCollection extends RecordArray {
1278
901
  const {
1279
902
  store
1280
903
  } = this;
904
+ assert(`Expected modelName to be set`, this.modelName);
1281
905
  const record = store.createRecord(this.modelName, hash);
1282
906
  this.push(record);
1283
907
  return record;
@@ -1286,7 +910,7 @@ class RelatedCollection extends RecordArray {
1286
910
  RelatedCollection.prototype.isAsync = false;
1287
911
  RelatedCollection.prototype.isPolymorphic = false;
1288
912
  RelatedCollection.prototype.identifier = null;
1289
- RelatedCollection.prototype.recordData = null;
913
+ RelatedCollection.prototype.cache = null;
1290
914
  RelatedCollection.prototype._inverseIsAsync = false;
1291
915
  RelatedCollection.prototype.key = '';
1292
916
  RelatedCollection.prototype.DEPRECATED_CLASS_NAME = 'ManyArray';
@@ -1430,7 +1054,7 @@ let PromiseManyArray = (_class$4 = class PromiseManyArray {
1430
1054
  }
1431
1055
  return false;
1432
1056
  };
1433
- } else if (macroCondition(isDevelopingApp())) {
1057
+ } else if (macroCondition(getOwnConfig().env.DEBUG)) {
1434
1058
  const meta = Ember.meta(this);
1435
1059
  meta.hasMixin = mixin => {
1436
1060
  assert(`Do not use A() on an EmberData PromiseManyArray`);
@@ -1652,7 +1276,7 @@ function tapPromise(proxy, promise) {
1652
1276
  proxy.isSettled = false;
1653
1277
  proxy.isFulfilled = false;
1654
1278
  proxy.isRejected = false;
1655
- return resolve(promise).then(content => {
1279
+ return Promise.resolve(promise).then(content => {
1656
1280
  proxy.isPending = false;
1657
1281
  proxy.isFulfilled = true;
1658
1282
  proxy.isSettled = true;
@@ -1715,7 +1339,7 @@ if (macroCondition(getOwnConfig().deprecations.DEPRECATE_PROMISE_MANY_ARRAY_BEHA
1715
1339
  `record.relationshipFor(key)`.
1716
1340
  */
1717
1341
  let assertPolymorphicType;
1718
- if (macroCondition(isDevelopingApp())) {
1342
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
1719
1343
  let checkPolymorphic = function checkPolymorphic(modelClass, addedModelClass) {
1720
1344
  if (modelClass.__isMixin) {
1721
1345
  return modelClass.__mixin.detect(addedModelClass.PrototypeMixin) ||
@@ -1967,7 +1591,8 @@ let BelongsToReference = (_class$3 = class BelongsToReference {
1967
1591
  }
1968
1592
  _resource() {
1969
1593
  this._ref; // subscribe
1970
- return this.store._instanceCache.getRecordData(this.___identifier).getRelationship(this.___identifier, this.key);
1594
+ const cache = macroCondition(getOwnConfig().deprecations.DEPRECATE_V1_RECORD_DATA) ? this.store._instanceCache.getResourceCache(this.___identifier) : this.store.cache;
1595
+ return cache.getRelationship(this.___identifier, this.key);
1971
1596
  }
1972
1597
 
1973
1598
  /**
@@ -2057,7 +1682,7 @@ let BelongsToReference = (_class$3 = class BelongsToReference {
2057
1682
  let jsonApiDoc = data;
2058
1683
  if (macroCondition(getOwnConfig().deprecations.DEPRECATE_PROMISE_PROXIES)) {
2059
1684
  if (data.then) {
2060
- jsonApiDoc = await resolve(data);
1685
+ jsonApiDoc = await data;
2061
1686
  if (jsonApiDoc !== data) {
2062
1687
  deprecate(`You passed in a Promise to a Reference API that now expects a resolved value. await the value before setting it.`, false, {
2063
1688
  id: 'ember-data:deprecate-promise-proxies',
@@ -2072,7 +1697,7 @@ let BelongsToReference = (_class$3 = class BelongsToReference {
2072
1697
  }
2073
1698
  }
2074
1699
  let record = this.store.push(jsonApiDoc);
2075
- if (macroCondition(isDevelopingApp())) {
1700
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
2076
1701
  // eslint-disable-next-line @typescript-eslint/no-unsafe-call
2077
1702
  assertPolymorphicType(this.belongsToRelationship.identifier, this.belongsToRelationship.definition, recordIdentifierFor$1(record), this.store);
2078
1703
  }
@@ -2332,7 +1957,8 @@ let HasManyReference = (_class$2 = class HasManyReference {
2332
1957
  return [];
2333
1958
  }
2334
1959
  _resource() {
2335
- return this.store._instanceCache.getRecordData(this.___identifier).getRelationship(this.___identifier, this.key);
1960
+ const cache = macroCondition(getOwnConfig().deprecations.DEPRECATE_V1_RECORD_DATA) ? this.store._instanceCache.getResourceCache(this.___identifier) : this.store.cache;
1961
+ return cache.getRelationship(this.___identifier, this.key);
2336
1962
  }
2337
1963
 
2338
1964
  /**
@@ -2549,7 +2175,7 @@ let HasManyReference = (_class$2 = class HasManyReference {
2549
2175
  let payload = objectOrPromise;
2550
2176
  if (macroCondition(getOwnConfig().deprecations.DEPRECATE_PROMISE_PROXIES)) {
2551
2177
  if (objectOrPromise.then) {
2552
- payload = await resolve(objectOrPromise);
2178
+ payload = await objectOrPromise;
2553
2179
  if (payload !== objectOrPromise) {
2554
2180
  deprecate(`You passed in a Promise to a Reference API that now expects a resolved value. await the value before setting it.`, false, {
2555
2181
  id: 'ember-data:deprecate-promise-proxies',
@@ -2582,7 +2208,7 @@ let HasManyReference = (_class$2 = class HasManyReference {
2582
2208
  data: obj
2583
2209
  });
2584
2210
  }
2585
- if (macroCondition(isDevelopingApp())) {
2211
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
2586
2212
  let relationshipMeta = this.hasManyRelationship.definition;
2587
2213
  let identifier = this.hasManyRelationship.identifier;
2588
2214
 
@@ -2775,9 +2401,9 @@ let HasManyReference = (_class$2 = class HasManyReference {
2775
2401
  class LegacySupport {
2776
2402
  constructor(record) {
2777
2403
  this.record = record;
2778
- this.store = storeFor$1(record);
2404
+ this.store = storeFor(record);
2779
2405
  this.identifier = recordIdentifierFor$1(record);
2780
- this.recordData = this.store._instanceCache.getRecordData(this.identifier);
2406
+ this.cache = peekCache(record);
2781
2407
  this._manyArrayCache = Object.create(null);
2782
2408
  this._relationshipPromisesCache = Object.create(null);
2783
2409
  this._relationshipProxyCache = Object.create(null);
@@ -2800,8 +2426,8 @@ class LegacySupport {
2800
2426
  currentState.length = 0;
2801
2427
  fastPush(currentState, identifiers);
2802
2428
  }
2803
- updateCache(operation) {
2804
- this.recordData.update(operation);
2429
+ mutate(mutation) {
2430
+ this.cache.mutate(mutation);
2805
2431
  }
2806
2432
  _findBelongsTo(key, resource, relationship, options) {
2807
2433
  // TODO @runspired follow up if parent isNew then we should not be attempting load here
@@ -2816,7 +2442,7 @@ class LegacySupport {
2816
2442
  const graphFor = importSync('@ember-data/graph/-private').graphFor;
2817
2443
  const relationship = graphFor(this.store).get(this.identifier, key);
2818
2444
  assert(`Expected ${key} to be a belongs-to relationship`, isBelongsTo(relationship));
2819
- let resource = this.recordData.getRelationship(this.identifier, key);
2445
+ let resource = this.cache.getRelationship(this.identifier, key);
2820
2446
  relationship.state.hasFailedLoadAttempt = false;
2821
2447
  relationship.state.shouldForceReload = true;
2822
2448
  let promise = this._findBelongsTo(key, resource, relationship, options);
@@ -2830,9 +2456,9 @@ class LegacySupport {
2830
2456
  getBelongsTo(key, options) {
2831
2457
  const {
2832
2458
  identifier,
2833
- recordData
2459
+ cache
2834
2460
  } = this;
2835
- let resource = recordData.getRelationship(this.identifier, key);
2461
+ let resource = cache.getRelationship(this.identifier, key);
2836
2462
  let relatedIdentifier = resource && resource.data ? resource.data : null;
2837
2463
  assert(`Expected a stable identifier`, !relatedIdentifier || isStableIdentifier(relatedIdentifier));
2838
2464
  const store = this.store;
@@ -2868,7 +2494,7 @@ class LegacySupport {
2868
2494
  }
2869
2495
  }
2870
2496
  setDirtyBelongsTo(key, value) {
2871
- return this.recordData.update({
2497
+ return this.cache.mutate({
2872
2498
  op: 'replaceRelatedRecord',
2873
2499
  record: this.identifier,
2874
2500
  field: key,
@@ -2878,7 +2504,7 @@ class LegacySupport {
2878
2504
  true);
2879
2505
  }
2880
2506
  _getCurrentState(identifier, field) {
2881
- let jsonApi = this.recordData.getRelationship(identifier, field, true);
2507
+ let jsonApi = this.cache.getRelationship(identifier, field, true);
2882
2508
  const cache = this.store._instanceCache;
2883
2509
  let identifiers = [];
2884
2510
  if (jsonApi.data) {
@@ -2893,7 +2519,7 @@ class LegacySupport {
2893
2519
  return [identifiers, jsonApi];
2894
2520
  }
2895
2521
  getManyArray(key, definition) {
2896
- if (macroCondition(dependencySatisfies("@ember-data/json-api", "*"))) {
2522
+ if (macroCondition(getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
2897
2523
  let manyArray = this._manyArrayCache[key];
2898
2524
  if (!definition) {
2899
2525
  const graphFor = importSync('@ember-data/graph/-private').graphFor;
@@ -2905,7 +2531,7 @@ class LegacySupport {
2905
2531
  store: this.store,
2906
2532
  type: definition.type,
2907
2533
  identifier: this.identifier,
2908
- recordData: this.recordData,
2534
+ cache: this.cache,
2909
2535
  identifiers,
2910
2536
  key,
2911
2537
  meta: doc.meta || null,
@@ -2924,16 +2550,16 @@ class LegacySupport {
2924
2550
  assert('hasMany only works with the @ember-data/json-api package');
2925
2551
  }
2926
2552
  fetchAsyncHasMany(key, relationship, manyArray, options) {
2927
- if (macroCondition(dependencySatisfies("@ember-data/json-api", "*"))) {
2553
+ if (macroCondition(getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
2928
2554
  let loadingPromise = this._relationshipPromisesCache[key];
2929
2555
  if (loadingPromise) {
2930
2556
  return loadingPromise;
2931
2557
  }
2932
- const jsonApi = this.recordData.getRelationship(this.identifier, key);
2558
+ const jsonApi = this.cache.getRelationship(this.identifier, key);
2933
2559
  const promise = this._findHasManyByJsonApiResource(jsonApi, this.identifier, relationship, options);
2934
2560
  if (!promise) {
2935
2561
  manyArray.isLoaded = true;
2936
- return resolve(manyArray);
2562
+ return Promise.resolve(manyArray);
2937
2563
  }
2938
2564
  loadingPromise = promise.then(() => handleCompletedRelationshipRequest(this, key, relationship, manyArray), e => handleCompletedRelationshipRequest(this, key, relationship, manyArray, e));
2939
2565
  this._relationshipPromisesCache[key] = loadingPromise;
@@ -2942,7 +2568,7 @@ class LegacySupport {
2942
2568
  assert('hasMany only works with the @ember-data/json-api package');
2943
2569
  }
2944
2570
  reloadHasMany(key, options) {
2945
- if (macroCondition(dependencySatisfies("@ember-data/json-api", "*"))) {
2571
+ if (macroCondition(getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
2946
2572
  let loadingPromise = this._relationshipPromisesCache[key];
2947
2573
  if (loadingPromise) {
2948
2574
  return loadingPromise;
@@ -2967,7 +2593,7 @@ class LegacySupport {
2967
2593
  assert(`hasMany only works with the @ember-data/json-api package`);
2968
2594
  }
2969
2595
  getHasMany(key, options) {
2970
- if (macroCondition(dependencySatisfies("@ember-data/json-api", "*"))) {
2596
+ if (macroCondition(getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
2971
2597
  const graphFor = importSync('@ember-data/graph/-private').graphFor;
2972
2598
  const relationship = graphFor(this.store).get(this.identifier, key);
2973
2599
  const {
@@ -3025,7 +2651,7 @@ class LegacySupport {
3025
2651
  referenceFor(kind, name) {
3026
2652
  let reference = this.references[name];
3027
2653
  if (!reference) {
3028
- if (macroCondition(!dependencySatisfies("@ember-data/json-api", "*"))) {
2654
+ if (macroCondition(!getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
3029
2655
  // TODO @runspired while this feels odd, it is not a regression in capability because we do
3030
2656
  // not today support references pulling from RecordDatas other than our own
3031
2657
  // because of the intimate API access involved. This is something we will need to redesign.
@@ -3034,7 +2660,7 @@ class LegacySupport {
3034
2660
  const graphFor = importSync('@ember-data/graph/-private').graphFor;
3035
2661
  const graph = graphFor(this.store);
3036
2662
  const relationship = graph.get(this.identifier, name);
3037
- if (macroCondition(isDevelopingApp())) {
2663
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
3038
2664
  if (kind) {
3039
2665
  let modelName = this.identifier.type;
3040
2666
  let actualRelationshipKind = relationship.definition.kind;
@@ -3052,7 +2678,7 @@ class LegacySupport {
3052
2678
  return reference;
3053
2679
  }
3054
2680
  _findHasManyByJsonApiResource(resource, parentIdentifier, relationship, options = {}) {
3055
- if (macroCondition(dependencySatisfies("@ember-data/json-api", "*"))) {
2681
+ if (macroCondition(getOwnConfig().packages.HAS_JSON_API_PACKAGE)) {
3056
2682
  if (!resource) {
3057
2683
  return;
3058
2684
  }
@@ -3069,66 +2695,46 @@ class LegacySupport {
3069
2695
  shouldForceReload
3070
2696
  } = state;
3071
2697
  const allInverseRecordsAreLoaded = areAllInverseRecordsLoaded(this.store, resource);
3072
- const shouldFindViaLink = resource.links && resource.links.related && (typeof adapter.findHasMany === 'function' || typeof resource.data === 'undefined') && (shouldForceReload || hasDematerializedInverse || isStale || !allInverseRecordsAreLoaded && !isEmpty);
2698
+ const identifiers = resource.data;
2699
+ const shouldFindViaLink = resource.links && resource.links.related && (typeof adapter.findHasMany === 'function' || typeof identifiers === 'undefined') && (shouldForceReload || hasDematerializedInverse || isStale || !allInverseRecordsAreLoaded && !isEmpty);
2700
+ const relationshipMeta = this.store.getSchemaDefinitionService().relationshipsDefinitionFor({
2701
+ type: definition.inverseType
2702
+ })[definition.key];
2703
+ const request = {
2704
+ useLink: shouldFindViaLink,
2705
+ field: relationshipMeta,
2706
+ links: resource.links,
2707
+ meta: resource.meta,
2708
+ options,
2709
+ record: parentIdentifier
2710
+ };
3073
2711
 
3074
2712
  // fetch via link
3075
2713
  if (shouldFindViaLink) {
3076
- // findHasMany, although not public, does not need to care about our upgrade relationship definitions
3077
- // and can stick with the public definition API for now.
3078
- const relationshipMeta = this.store.getSchemaDefinitionService().relationshipsDefinitionFor({
3079
- type: definition.inverseType
3080
- })[definition.key];
3081
- let adapter = this.store.adapterFor(parentIdentifier.type);
3082
-
3083
- /*
3084
- If a relationship was originally populated by the adapter as a link
3085
- (as opposed to a list of IDs), this method is called when the
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);
2714
+ assert(`Expected collection to be an array`, !identifiers || Array.isArray(identifiers));
2715
+ assert(`Expected stable identifiers`, !identifiers || identifiers.every(isStableIdentifier));
2716
+ return this.store.request({
2717
+ op: 'findHasMany',
2718
+ records: identifiers || [],
2719
+ data: request
2720
+ });
3095
2721
  }
3096
2722
  const preferLocalCache = hasReceivedData && !isEmpty;
3097
- const hasLocalPartialData = hasDematerializedInverse || isEmpty && Array.isArray(resource.data) && resource.data.length > 0;
3098
-
3099
- // fetch using data, pulling from local cache if possible
3100
- if (!shouldForceReload && !isStale && (preferLocalCache || hasLocalPartialData)) {
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);
2723
+ const hasLocalPartialData = hasDematerializedInverse || isEmpty && Array.isArray(identifiers) && identifiers.length > 0;
2724
+ const attemptLocalCache = !shouldForceReload && !isStale && (preferLocalCache || hasLocalPartialData);
2725
+ if (attemptLocalCache && allInverseRecordsAreLoaded) {
2726
+ return;
3116
2727
  }
3117
- let hasData = hasReceivedData && !isEmpty;
3118
-
3119
- // fetch by data
3120
- if (hasData || hasLocalPartialData) {
3121
- const identifiers = resource.data;
2728
+ const hasData = hasReceivedData && !isEmpty;
2729
+ if (attemptLocalCache || hasData || hasLocalPartialData) {
3122
2730
  assert(`Expected collection to be an array`, Array.isArray(identifiers));
3123
2731
  assert(`Expected stable identifiers`, identifiers.every(isStableIdentifier));
3124
- let fetches = new Array(identifiers.length);
3125
- const manager = this.store._fetchManager;
3126
- for (let i = 0; i < identifiers.length; i++) {
3127
- let identifier = identifiers[i];
3128
- assertIdentifierHasId(identifier);
3129
- fetches[i] = manager.scheduleFetch(identifier, options);
3130
- }
3131
- return all(fetches);
2732
+ options.reload = options.reload || !attemptLocalCache || undefined;
2733
+ return this.store.request({
2734
+ op: 'findHasMany',
2735
+ records: identifiers,
2736
+ data: request
2737
+ });
3132
2738
  }
3133
2739
 
3134
2740
  // we were explicitly told we have no data and no links.
@@ -3139,7 +2745,14 @@ class LegacySupport {
3139
2745
  }
3140
2746
  _findBelongsToByJsonApiResource(resource, parentIdentifier, relationship, options = {}) {
3141
2747
  if (!resource) {
3142
- return resolve(null);
2748
+ return Promise.resolve(null);
2749
+ }
2750
+
2751
+ // interleaved promises mean that we MUST cache this here
2752
+ // in order to prevent infinite re-render if the request
2753
+ // fails.
2754
+ if (this._pending) {
2755
+ return this._pending;
3143
2756
  }
3144
2757
  const identifier = resource.data ? resource.data : null;
3145
2758
  assert(`Expected a stable identifier`, !identifier || isStableIdentifier(identifier));
@@ -3150,53 +2763,65 @@ class LegacySupport {
3150
2763
  isEmpty,
3151
2764
  shouldForceReload
3152
2765
  } = 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
2766
  const allInverseRecordsAreLoaded = areAllInverseRecordsLoaded(this.store, resource);
3160
2767
  const shouldFindViaLink = resource.links?.related && (shouldForceReload || hasDematerializedInverse || isStale || !allInverseRecordsAreLoaded && !isEmpty);
2768
+ const relationshipMeta = this.store.getSchemaDefinitionService().relationshipsDefinitionFor(this.identifier)[relationship.definition.key];
2769
+ assert(`Attempted to access a belongsTo relationship but no definition exists for it`, relationshipMeta);
2770
+ const request = {
2771
+ useLink: shouldFindViaLink,
2772
+ field: relationshipMeta,
2773
+ links: resource.links,
2774
+ meta: resource.meta,
2775
+ options,
2776
+ record: parentIdentifier
2777
+ };
3161
2778
 
3162
2779
  // fetch via link
3163
2780
  if (shouldFindViaLink) {
3164
- const relationshipMeta = this.store.getSchemaDefinitionService().relationshipsDefinitionFor(this.identifier)[relationship.definition.key];
3165
- assert(`Attempted to access a belongsTo relationship but no definition exists for it`, relationshipMeta);
3166
- return _findBelongsTo(this.store, parentIdentifier, resource.links.related, relationshipMeta, options);
2781
+ const future = this.store.request({
2782
+ op: 'findBelongsTo',
2783
+ records: identifier ? [identifier] : [],
2784
+ data: request
2785
+ });
2786
+ this._pending = future.then(doc => doc.content).finally(() => {
2787
+ this._pending = null;
2788
+ });
2789
+ return this._pending;
3167
2790
  }
3168
- let preferLocalCache = hasReceivedData && allInverseRecordsAreLoaded && !isEmpty;
3169
- let hasLocalPartialData = hasDematerializedInverse || isEmpty && resource.data;
2791
+ const preferLocalCache = hasReceivedData && allInverseRecordsAreLoaded && !isEmpty;
2792
+ const hasLocalPartialData = hasDematerializedInverse || isEmpty && resource.data;
3170
2793
  // null is explicit empty, undefined is "we don't know anything"
3171
- const localDataIsEmpty = resource.data === undefined || resource.data === null;
3172
-
3173
- // fetch using data, pulling from local cache if possible
3174
- if (!shouldForceReload && !isStale && (preferLocalCache || hasLocalPartialData)) {
3175
- /*
3176
- We have canonical data, but our local state is empty
3177
- */
3178
- if (localDataIsEmpty) {
3179
- return resolve(null);
3180
- }
3181
- if (!identifier) {
3182
- assert(`No Information found for ${resource.data.lid}`, identifier);
3183
- }
3184
- return this.store._instanceCache._fetchDataIfNeededForIdentifier(identifier, options);
3185
- }
3186
- let resourceIsLocal = !localDataIsEmpty && resource.data.id === null;
3187
- if (identifier && resourceIsLocal) {
3188
- return resolve(identifier);
3189
- }
3190
-
3191
- // fetch by data
3192
- if (identifier && !localDataIsEmpty) {
3193
- assertIdentifierHasId(identifier);
3194
- return this.store._fetchManager.scheduleFetch(identifier, options);
2794
+ const localDataIsEmpty = !identifier;
2795
+ const attemptLocalCache = !shouldForceReload && !isStale && (preferLocalCache || hasLocalPartialData);
2796
+
2797
+ // we dont need to fetch and are empty
2798
+ if (attemptLocalCache && localDataIsEmpty) {
2799
+ return Promise.resolve(null);
2800
+ }
2801
+
2802
+ // we dont need to fetch because we are local state
2803
+ const resourceIsLocal = identifier?.id === null;
2804
+ if (attemptLocalCache && allInverseRecordsAreLoaded || resourceIsLocal) {
2805
+ return Promise.resolve(identifier);
2806
+ }
2807
+
2808
+ // we may need to fetch
2809
+ if (identifier) {
2810
+ assert(`Cannot fetch belongs-to relationship with no information`, identifier);
2811
+ options.reload = options.reload || !attemptLocalCache || undefined;
2812
+ this._pending = this.store.request({
2813
+ op: 'findBelongsTo',
2814
+ records: [identifier],
2815
+ data: request
2816
+ }).then(doc => doc.content).finally(() => {
2817
+ this._pending = null;
2818
+ });
2819
+ return this._pending;
3195
2820
  }
3196
2821
 
3197
2822
  // we were explicitly told we have no data and no links.
3198
2823
  // TODO if the relationshipIsStale, should we hit the adapter anyway?
3199
- return resolve(null);
2824
+ return Promise.resolve(null);
3200
2825
  }
3201
2826
  destroy() {
3202
2827
  this.isDestroying = true;
@@ -3245,11 +2870,14 @@ function handleCompletedRelationshipRequest(recordExt, key, relationship, value,
3245
2870
  if (proxy.content && proxy.content.isDestroying) {
3246
2871
  proxy.set('content', null);
3247
2872
  }
2873
+ recordExt.store.notifications._flush();
3248
2874
  }
3249
2875
  throw error;
3250
2876
  }
3251
2877
  if (isHasMany) {
3252
2878
  value.isLoaded = true;
2879
+ } else {
2880
+ recordExt.store.notifications._flush();
3253
2881
  }
3254
2882
  relationship.state.hasFailedLoadAttempt = false;
3255
2883
  // only set to not stale if no error is thrown
@@ -3356,7 +2984,8 @@ function notifyRelationship(identifier, key, record, meta) {
3356
2984
  }
3357
2985
  function notifyAttribute(store, identifier, key, record) {
3358
2986
  let currentValue = cacheFor(record, key);
3359
- if (currentValue !== store._instanceCache.getRecordData(identifier).getAttr(identifier, key)) {
2987
+ const cache = macroCondition(getOwnConfig().deprecations.DEPRECATE_V1_RECORD_DATA) ? peekCache(record) : store.cache;
2988
+ if (currentValue !== cache.getAttr(identifier, key)) {
3360
2989
  record.notifyPropertyChange(key);
3361
2990
  }
3362
2991
  }
@@ -3491,11 +3120,11 @@ root
3491
3120
  let RecordState = (_class3 = class RecordState {
3492
3121
  constructor(record) {
3493
3122
  _initializerDefineProperty(this, "isSaving", _descriptor2, this);
3494
- const store = storeFor(record);
3123
+ const store = storeFor$1(record);
3495
3124
  const identity = recordIdentifierFor$1(record);
3496
3125
  this.identifier = identity;
3497
3126
  this.record = record;
3498
- this.cache = store._instanceCache.getRecordData(identity);
3127
+ this.cache = macroCondition(getOwnConfig().deprecations.DEPRECATE_V1_RECORD_DATA) ? peekCache(record) : store.cache;
3499
3128
  this.pendingCount = 0;
3500
3129
  this.fulfilledCount = 0;
3501
3130
  this.rejectedCount = 0;
@@ -3555,7 +3184,7 @@ let RecordState = (_class3 = class RecordState {
3555
3184
 
3556
3185
  // we instantiate lazily
3557
3186
  // so we grab anything we don't have yet
3558
- if (macroCondition(!isDevelopingApp())) {
3187
+ if (macroCondition(!getOwnConfig().env.DEBUG)) {
3559
3188
  const lastRequest = requests.getLastRequestForRecord(identity);
3560
3189
  if (lastRequest) {
3561
3190
  handleRequest(lastRequest);
@@ -3580,7 +3209,7 @@ let RecordState = (_class3 = class RecordState {
3580
3209
  });
3581
3210
  }
3582
3211
  destroy() {
3583
- storeFor(this.record).notifications.unsubscribe(this.handler);
3212
+ storeFor$1(this.record).notifications.unsubscribe(this.handler);
3584
3213
  }
3585
3214
  notify(key) {
3586
3215
  getTag(this, key).notify();
@@ -3814,7 +3443,7 @@ class RelationshipDefinition {
3814
3443
  inverse = modelClass.inverseFor(this.key, store);
3815
3444
  }
3816
3445
  // TODO make this error again for the non-polymorphic case
3817
- if (macroCondition(isDevelopingApp())) {
3446
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
3818
3447
  if (!this.options.polymorphic) {
3819
3448
  modelClass.typeForRelationship(this.key, store);
3820
3449
  }
@@ -3932,7 +3561,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
3932
3561
  _initializerDefineProperty(this, "isReloading", _descriptor, this);
3933
3562
  }
3934
3563
  init(options = {}) {
3935
- if (macroCondition(isDevelopingApp())) {
3564
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
3936
3565
  if (!options._secretInit && !options._createProps) {
3937
3566
  throw new Error('You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.');
3938
3567
  }
@@ -3944,8 +3573,8 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
3944
3573
  let store = this.store = _secretInit.store;
3945
3574
  super.init(options);
3946
3575
  let identity = _secretInit.identifier;
3947
- _secretInit.cb(this, _secretInit.recordData, identity, _secretInit.store);
3948
- this.___recordState = macroCondition(isDevelopingApp()) ? new RecordState(this) : null;
3576
+ _secretInit.cb(this, _secretInit.cache, identity, _secretInit.store);
3577
+ this.___recordState = macroCondition(getOwnConfig().env.DEBUG) ? new RecordState(this) : null;
3949
3578
  this.setProperties(createProps);
3950
3579
  let notifications = store.notifications;
3951
3580
  this.___private_notifications = notifications.subscribe(identity, (identifier, type, key) => {
@@ -3955,7 +3584,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
3955
3584
  destroy() {
3956
3585
  const identifier = recordIdentifierFor(this);
3957
3586
  this.___recordState?.destroy();
3958
- const store = storeFor(this);
3587
+ const store = storeFor$1(this);
3959
3588
  store.notifications.unsubscribe(this.___private_notifications);
3960
3589
  // Legacy behavior is to notify the relationships on destroy
3961
3590
  // such that they "clear". It's uncertain this behavior would
@@ -4190,7 +3819,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4190
3819
  return this.currentState.isError;
4191
3820
  }
4192
3821
  set isError(v) {
4193
- if (macroCondition(isDevelopingApp())) {
3822
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
4194
3823
  throw new Error(`isError is not directly settable`);
4195
3824
  }
4196
3825
  }
@@ -4215,7 +3844,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4215
3844
  // this guard exists, because some dev-only deprecation code
4216
3845
  // (addListener via validatePropertyInjections) invokes toString before the
4217
3846
  // object is real.
4218
- if (macroCondition(isDevelopingApp())) {
3847
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
4219
3848
  try {
4220
3849
  return recordIdentifierFor(this).id;
4221
3850
  } catch {
@@ -4250,7 +3879,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4250
3879
  // when using legacy/classic ember classes. Basically: lazy in prod and eager in dev.
4251
3880
  // so we do this to try to steer folks to the nicer "dont user currentState"
4252
3881
  // error.
4253
- if (macroCondition(!isDevelopingApp())) {
3882
+ if (macroCondition(!getOwnConfig().env.DEBUG)) {
4254
3883
  if (!this.___recordState) {
4255
3884
  this.___recordState = new RecordState(this);
4256
3885
  }
@@ -4346,7 +3975,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4346
3975
  @return {Object} an object whose values are primitive JSON values only
4347
3976
  */
4348
3977
  serialize(options) {
4349
- return storeFor(this)._instanceCache.createSnapshot(recordIdentifierFor(this)).serialize(options);
3978
+ return storeFor$1(this).serializeRecord(this, options);
4350
3979
  }
4351
3980
 
4352
3981
  /*
@@ -4395,7 +4024,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4395
4024
  deleteRecord() {
4396
4025
  // ensure we've populated currentState prior to deleting a new record
4397
4026
  if (this.currentState) {
4398
- storeFor(this).deleteRecord(this);
4027
+ storeFor$1(this).deleteRecord(this);
4399
4028
  }
4400
4029
  }
4401
4030
 
@@ -4442,7 +4071,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4442
4071
  } = this.currentState;
4443
4072
  this.deleteRecord();
4444
4073
  if (isNew) {
4445
- return resolve(this);
4074
+ return Promise.resolve(this);
4446
4075
  }
4447
4076
  return this.save(options).then(_ => {
4448
4077
  run(() => {
@@ -4462,7 +4091,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4462
4091
  if (this.currentState.isNew && (this.isDestroyed || this.isDestroying)) {
4463
4092
  return;
4464
4093
  }
4465
- storeFor(this).unloadRecord(this);
4094
+ storeFor$1(this).unloadRecord(this);
4466
4095
  }
4467
4096
 
4468
4097
  /**
@@ -4518,7 +4147,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4518
4147
  and value is an [oldProp, newProp] array.
4519
4148
  */
4520
4149
  changedAttributes() {
4521
- return recordDataFor(this).changedAttrs(recordIdentifierFor(this));
4150
+ return peekCache(this).changedAttrs(recordIdentifierFor(this));
4522
4151
  }
4523
4152
 
4524
4153
  /**
@@ -4543,8 +4172,8 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4543
4172
  const {
4544
4173
  isNew
4545
4174
  } = currentState;
4546
- storeFor(this)._join(() => {
4547
- recordDataFor(this).rollbackAttrs(recordIdentifierFor(this));
4175
+ storeFor$1(this)._join(() => {
4176
+ peekCache(this).rollbackAttrs(recordIdentifierFor(this));
4548
4177
  this.errors.clear();
4549
4178
  currentState.cleanErrorRequests();
4550
4179
  if (isNew) {
@@ -4559,7 +4188,12 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4559
4188
  */
4560
4189
  // TODO @deprecate in favor of a public API or examples of how to test successfully
4561
4190
  _createSnapshot() {
4562
- return storeFor(this)._instanceCache.createSnapshot(recordIdentifierFor(this));
4191
+ const store = storeFor$1(this);
4192
+ if (!store._fetchManager) {
4193
+ const FetchManager = importSync('@ember-data/legacy-compat/-private').FetchManager;
4194
+ store._fetchManager = new FetchManager(store);
4195
+ }
4196
+ return store._fetchManager.createSnapshot(recordIdentifierFor(this));
4563
4197
  }
4564
4198
 
4565
4199
  /**
@@ -4599,9 +4233,9 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4599
4233
  save(options) {
4600
4234
  let promise;
4601
4235
  if (this.currentState.isNew && this.currentState.isDeleted) {
4602
- promise = resolve(this);
4236
+ promise = Promise.resolve(this);
4603
4237
  } else {
4604
- promise = storeFor(this).saveRecord(this, options);
4238
+ promise = storeFor$1(this).saveRecord(this, options);
4605
4239
  }
4606
4240
  if (macroCondition(getOwnConfig().deprecations.DEPRECATE_SAVE_PROMISE_ACCESS)) {
4607
4241
  return deprecatedPromiseObject(promise);
@@ -4632,16 +4266,19 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4632
4266
  adapter returns successfully or rejected if the adapter returns
4633
4267
  with an error.
4634
4268
  */
4635
- reload(_options) {
4636
- let options = {};
4637
- if (typeof _options === 'object' && _options !== null && _options.adapterOptions) {
4638
- options.adapterOptions = _options.adapterOptions;
4639
- }
4269
+ reload(options = {}) {
4640
4270
  options.isReloading = true;
4641
- let identifier = recordIdentifierFor(this);
4271
+ options.reload = true;
4272
+ const identifier = recordIdentifierFor(this);
4642
4273
  assert(`You cannot reload a record without an ID`, identifier.id);
4643
4274
  this.isReloading = true;
4644
- const promise = storeFor(this)._fetchManager.scheduleFetch(identifier, options).then(() => this).finally(() => {
4275
+ const promise = storeFor$1(this).request({
4276
+ op: 'findRecord',
4277
+ data: {
4278
+ options,
4279
+ record: identifier
4280
+ }
4281
+ }).then(() => this).finally(() => {
4645
4282
  this.isReloading = false;
4646
4283
  });
4647
4284
  if (macroCondition(getOwnConfig().deprecations.DEPRECATE_SAVE_PROMISE_ACCESS)) {
@@ -4809,7 +4446,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4809
4446
  return this.constructor.relationshipsByName.get(name);
4810
4447
  }
4811
4448
  inverseFor(key) {
4812
- return this.constructor.inverseFor(key, storeFor(this));
4449
+ return this.constructor.inverseFor(key, storeFor$1(this));
4813
4450
  }
4814
4451
  eachAttribute(callback, binding) {
4815
4452
  this.constructor.eachAttribute(callback, binding);
@@ -4981,7 +4618,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4981
4618
  if (possibleRelationships.length === 0) {
4982
4619
  return null;
4983
4620
  }
4984
- if (macroCondition(isDevelopingApp())) {
4621
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
4985
4622
  let filteredRelationships = possibleRelationships.filter(possibleRelationship => {
4986
4623
  let optionsForRelationship = possibleRelationship.options;
4987
4624
  return name === optionsForRelationship.inverse;
@@ -4999,7 +4636,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
4999
4636
  }
5000
4637
 
5001
4638
  // ensure inverse is properly configured
5002
- if (macroCondition(isDevelopingApp())) {
4639
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
5003
4640
  if (isPolymorphic) {
5004
4641
  if (macroCondition(getOwnConfig().deprecations.DEPRECATE_NON_EXPLICIT_POLYMORPHISM)) {
5005
4642
  if (!inverseOptions.as) {
@@ -5021,7 +4658,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
5021
4658
  }
5022
4659
 
5023
4660
  // ensure we are properly configured
5024
- if (macroCondition(isDevelopingApp())) {
4661
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
5025
4662
  if (inverseOptions.polymorphic) {
5026
4663
  if (macroCondition(getOwnConfig().deprecations.DEPRECATE_NON_EXPLICIT_POLYMORPHISM)) {
5027
4664
  if (!options.as) {
@@ -5187,7 +4824,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
5187
4824
  import { get } from '@ember/object';
5188
4825
  import Blog from 'app/models/blog';
5189
4826
  let relatedTypes = Blog.relatedTypes');
5190
- //=> [ User, Post ]
4827
+ //=> ['user', 'post']
5191
4828
  ```
5192
4829
  @property relatedTypes
5193
4830
  @public
@@ -5275,7 +4912,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
5275
4912
  for (let i = 0; i < relationships.length; i++) {
5276
4913
  let key = relationships[i];
5277
4914
  let value = rels[key];
5278
- map.set(value.key, value);
4915
+ map.set(value.name || value.key, value);
5279
4916
  }
5280
4917
  return map;
5281
4918
  }
@@ -5722,16 +5359,21 @@ if (macroCondition(getOwnConfig().includeDataAdapter)) {
5722
5359
  @private
5723
5360
  */
5724
5361
  Model.prototype._debugInfo = function () {
5725
- let attributes = ['id'];
5726
5362
  let relationships = {};
5727
5363
  let expensiveProperties = [];
5728
- this.eachAttribute((name, meta) => attributes.push(name));
5364
+ const identifier = recordIdentifierFor(this);
5365
+ const schema = this.store.getSchemaDefinitionService();
5366
+ const attrDefs = schema.attributesDefinitionFor(identifier);
5367
+ const relDefs = schema.relationshipsDefinitionFor(identifier);
5368
+ const attributes = Object.keys(attrDefs);
5369
+ attributes.unshift('id');
5729
5370
  let groups = [{
5730
5371
  name: 'Attributes',
5731
5372
  properties: attributes,
5732
5373
  expand: true
5733
5374
  }];
5734
- this.eachRelationship((name, relationship) => {
5375
+ Object.keys(relDefs).forEach(name => {
5376
+ const relationship = relDefs[name];
5735
5377
  let properties = relationships[relationship.kind];
5736
5378
  if (properties === undefined) {
5737
5379
  properties = relationships[relationship.kind] = [];
@@ -5759,7 +5401,7 @@ if (macroCondition(getOwnConfig().includeDataAdapter)) {
5759
5401
  };
5760
5402
  };
5761
5403
  }
5762
- if (macroCondition(isDevelopingApp())) {
5404
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
5763
5405
  let lookupDescriptor = function lookupDescriptor(obj, keyName) {
5764
5406
  let current = obj;
5765
5407
  do {
@@ -6008,7 +5650,7 @@ function belongsTo(modelName, options) {
6008
5650
  return null;
6009
5651
  }
6010
5652
  const support = lookupLegacySupport(this);
6011
- if (macroCondition(isDevelopingApp())) {
5653
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
6012
5654
  if (['currentState'].indexOf(key) !== -1) {
6013
5655
  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()}`);
6014
5656
  }
@@ -6027,7 +5669,7 @@ function belongsTo(modelName, options) {
6027
5669
  },
6028
5670
  set(key, value) {
6029
5671
  const support = lookupLegacySupport(this);
6030
- if (macroCondition(isDevelopingApp())) {
5672
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
6031
5673
  if (['currentState'].indexOf(key) !== -1) {
6032
5674
  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()}`);
6033
5675
  }
@@ -6258,7 +5900,7 @@ function hasMany(type, options) {
6258
5900
  };
6259
5901
  return computed({
6260
5902
  get(key) {
6261
- if (macroCondition(isDevelopingApp())) {
5903
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
6262
5904
  if (['currentState'].indexOf(key) !== -1) {
6263
5905
  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()}`);
6264
5906
  }
@@ -6269,7 +5911,7 @@ function hasMany(type, options) {
6269
5911
  return lookupLegacySupport(this).getHasMany(key);
6270
5912
  },
6271
5913
  set(key, records) {
6272
- if (macroCondition(isDevelopingApp())) {
5914
+ if (macroCondition(getOwnConfig().env.DEBUG)) {
6273
5915
  if (['currentState'].indexOf(key) !== -1) {
6274
5916
  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()}`);
6275
5917
  }