@ember-data/model 4.12.4 → 4.12.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/addon/-private.js CHANGED
@@ -1,5 +1,5 @@
1
- import { M as Model } from "./has-many-c1bfdebf";
2
- export { E as Errors, L as LEGACY_SUPPORT, R as ManyArray, P as PromiseBelongsTo, c as PromiseManyArray, a as attr, b as belongsTo, h as hasMany } from "./has-many-c1bfdebf";
1
+ import { M as Model } from "./has-many-d45aa09e";
2
+ export { E as Errors, L as LEGACY_SUPPORT, R as ManyArray, P as PromiseBelongsTo, c as PromiseManyArray, a as attr, b as belongsTo, h as hasMany } from "./has-many-d45aa09e";
3
3
  import { getOwner } from '@ember/application';
4
4
 
5
5
  /*
@@ -14,8 +14,8 @@ import PromiseProxyMixin from '@ember/object/promise-proxy-mixin';
14
14
  import ObjectProxy from '@ember/object/proxy';
15
15
  import ArrayProxy from '@ember/array/proxy';
16
16
  import { mapBy, not } from '@ember/object/computed';
17
- import { cacheFor } from '@ember/object/internals';
18
17
  import { addToTransaction, subscribe } from '@ember-data/tracking/-private';
18
+ import { cacheFor } from '@ember/object/internals';
19
19
  function isElementDescriptor(args) {
20
20
  let [maybeTarget, maybeKey, maybeDesc] = args;
21
21
  return (
@@ -639,6 +639,28 @@ let Errors = (_dec$1 = computed(), _dec2 = mapBy('content', 'message'), _dec3 =
639
639
  initializer: null
640
640
  })), _class$6));
641
641
 
642
+ /*
643
+ NOTES ON MANY ARRAY DUPLICATION DEPRECATION APPROACH:
644
+
645
+ // 4.6 behavior
646
+
647
+ dedupe, no error and no deprecation
648
+
649
+ // 4.12 approach
650
+
651
+ DEPRECATE_MANY_ARRAY_DUPLICATES_4_12 === true => dedupe, no error
652
+ DEPRECATE_MANY_ARRAY_DUPLICATES_4_12 === false => no dedupe, error (same as 6.0)
653
+
654
+ // 5.3 approach
655
+
656
+ DEPRECATE_MANY_ARRAY_DUPLICATES === true => dedupe, deprecation
657
+ DEPRECATE_MANY_ARRAY_DUPLICATES === false => no dedupe, error (same as 6.0)
658
+
659
+ // 6.0 approach
660
+
661
+ no-dedupe, error
662
+ */
663
+
642
664
  /**
643
665
  A `ManyArray` is a `MutableArray` that represents the contents of a has-many
644
666
  relationship.
@@ -742,109 +764,192 @@ class RelatedCollection extends RecordArray {
742
764
  this.identifier = options.identifier;
743
765
  this.key = options.key;
744
766
  }
745
- [MUTATE](prop, args, result) {
767
+ [MUTATE](target, receiver, prop, args, _TAG) {
746
768
  switch (prop) {
747
769
  case 'length 0':
748
770
  {
749
- this._manager.mutate({
750
- op: 'replaceRelatedRecords',
751
- record: this.identifier,
752
- field: this.key,
753
- value: []
754
- });
755
- break;
771
+ Reflect.set(target, 'length', 0);
772
+ mutateReplaceRelatedRecords(this, [], _TAG);
773
+ return true;
756
774
  }
757
775
  case 'replace cell':
758
776
  {
759
777
  const [index, prior, value] = args;
760
- this._manager.mutate({
761
- op: 'replaceRelatedRecord',
762
- record: this.identifier,
763
- field: this.key,
778
+ target[index] = value;
779
+ mutateReplaceRelatedRecord(this, {
764
780
  value,
765
781
  prior,
766
782
  index
767
- });
768
- break;
783
+ }, _TAG);
784
+ return true;
769
785
  }
770
786
  case 'push':
771
- this._manager.mutate({
772
- op: 'addToRelatedRecords',
773
- record: this.identifier,
774
- field: this.key,
775
- value: extractIdentifiersFromRecords(args)
776
- });
777
- break;
787
+ {
788
+ if (macroCondition(getOwnConfig().deprecations.DEPRECATE_MANY_ARRAY_DUPLICATES_4_12)) {
789
+ // dedupe, no error
790
+ const seen = new Set(target);
791
+ const unique = new Set();
792
+ args.forEach(item => {
793
+ const identifier = recordIdentifierFor$1(item);
794
+ if (!seen.has(identifier)) {
795
+ seen.add(identifier);
796
+ unique.add(item);
797
+ }
798
+ });
799
+ const newArgs = Array.from(unique);
800
+ const result = Reflect.apply(target[prop], receiver, newArgs);
801
+ if (newArgs.length) {
802
+ mutateAddToRelatedRecords(this, {
803
+ value: extractIdentifiersFromRecords(newArgs)
804
+ }, _TAG);
805
+ }
806
+ return result;
807
+ }
808
+
809
+ // else, no dedupe, error on duplicates
810
+ const newValues = extractIdentifiersFromRecords(args);
811
+ assertNoDuplicates(this, target, currentState => currentState.push(...newValues), `Cannot push duplicates to a hasMany's state.`);
812
+ const result = Reflect.apply(target[prop], receiver, args);
813
+ if (newValues.length) {
814
+ mutateAddToRelatedRecords(this, {
815
+ value: newValues
816
+ }, _TAG);
817
+ }
818
+ return result;
819
+ }
778
820
  case 'pop':
779
- if (result) {
780
- this._manager.mutate({
781
- op: 'removeFromRelatedRecords',
782
- record: this.identifier,
783
- field: this.key,
784
- value: recordIdentifierFor$1(result)
785
- });
821
+ {
822
+ const result = Reflect.apply(target[prop], receiver, args);
823
+ if (result) {
824
+ mutateRemoveFromRelatedRecords(this, {
825
+ value: recordIdentifierFor$1(result)
826
+ }, _TAG);
827
+ }
828
+ return result;
786
829
  }
787
- break;
788
830
  case 'unshift':
789
- this._manager.mutate({
790
- op: 'addToRelatedRecords',
791
- record: this.identifier,
792
- field: this.key,
793
- value: extractIdentifiersFromRecords(args),
794
- index: 0
795
- });
796
- break;
831
+ {
832
+ if (macroCondition(getOwnConfig().deprecations.DEPRECATE_MANY_ARRAY_DUPLICATES_4_12)) {
833
+ // dedupe, no error
834
+ const seen = new Set(target);
835
+ const unique = new Set();
836
+ args.forEach(item => {
837
+ const identifier = recordIdentifierFor$1(item);
838
+ if (!seen.has(identifier)) {
839
+ seen.add(identifier);
840
+ unique.add(item);
841
+ }
842
+ });
843
+ const newArgs = Array.from(unique);
844
+ const result = Reflect.apply(target[prop], receiver, newArgs);
845
+ if (newArgs.length) {
846
+ mutateAddToRelatedRecords(this, {
847
+ value: extractIdentifiersFromRecords(newArgs),
848
+ index: 0
849
+ }, _TAG);
850
+ }
851
+ return result;
852
+ }
853
+
854
+ // else, no dedupe, error on duplicates
855
+ const newValues = extractIdentifiersFromRecords(args);
856
+ assertNoDuplicates(this, target, currentState => currentState.unshift(...newValues), `Cannot unshift duplicates to a hasMany's state.`);
857
+ const result = Reflect.apply(target[prop], receiver, args);
858
+ if (newValues.length) {
859
+ mutateAddToRelatedRecords(this, {
860
+ value: newValues,
861
+ index: 0
862
+ }, _TAG);
863
+ }
864
+ return result;
865
+ }
797
866
  case 'shift':
798
- if (result) {
799
- this._manager.mutate({
800
- op: 'removeFromRelatedRecords',
801
- record: this.identifier,
802
- field: this.key,
803
- value: recordIdentifierFor$1(result),
804
- index: 0
805
- });
867
+ {
868
+ const result = Reflect.apply(target[prop], receiver, args);
869
+ if (result) {
870
+ mutateRemoveFromRelatedRecords(this, {
871
+ value: recordIdentifierFor$1(result),
872
+ index: 0
873
+ }, _TAG);
874
+ }
875
+ return result;
806
876
  }
807
- break;
808
877
  case 'sort':
809
- this._manager.mutate({
810
- op: 'sortRelatedRecords',
811
- record: this.identifier,
812
- field: this.key,
813
- value: result.map(recordIdentifierFor$1)
814
- });
815
- break;
878
+ {
879
+ const result = Reflect.apply(target[prop], receiver, args);
880
+ mutateSortRelatedRecords(this, result.map(recordIdentifierFor$1), _TAG);
881
+ return result;
882
+ }
816
883
  case 'splice':
817
884
  {
818
- const [start, removeCount, ...adds] = args;
885
+ const [start, deleteCount, ...adds] = args;
886
+
819
887
  // detect a full replace
820
- if (removeCount > 0 && adds.length === this[SOURCE].length) {
821
- this._manager.mutate({
822
- op: 'replaceRelatedRecords',
823
- record: this.identifier,
824
- field: this.key,
825
- value: extractIdentifiersFromRecords(adds)
888
+ if (start === 0 && deleteCount === this[SOURCE].length) {
889
+ if (macroCondition(getOwnConfig().deprecations.DEPRECATE_MANY_ARRAY_DUPLICATES_4_12)) {
890
+ // dedupe, no error
891
+ const current = new Set(adds);
892
+ const unique = Array.from(current);
893
+ const newArgs = [start, deleteCount].concat(unique);
894
+ const result = Reflect.apply(target[prop], receiver, newArgs);
895
+ mutateReplaceRelatedRecords(this, extractIdentifiersFromRecords(unique), _TAG);
896
+ return result;
897
+ }
898
+
899
+ // else, no dedupe, error on duplicates
900
+ const newValues = extractIdentifiersFromRecords(adds);
901
+ assertNoDuplicates(this, target, currentState => currentState.splice(start, deleteCount, ...newValues), `Cannot replace a hasMany's state with a new state that contains duplicates.`);
902
+ const result = Reflect.apply(target[prop], receiver, args);
903
+ mutateReplaceRelatedRecords(this, newValues, _TAG);
904
+ return result;
905
+ }
906
+ if (macroCondition(getOwnConfig().deprecations.DEPRECATE_MANY_ARRAY_DUPLICATES_4_12)) {
907
+ // dedupe, no error
908
+ const currentState = target.slice();
909
+ currentState.splice(start, deleteCount);
910
+ const seen = new Set(currentState);
911
+ const unique = [];
912
+ adds.forEach(item => {
913
+ const identifier = recordIdentifierFor$1(item);
914
+ if (!seen.has(identifier)) {
915
+ seen.add(identifier);
916
+ unique.push(item);
917
+ }
826
918
  });
827
- return;
919
+ const newArgs = [start, deleteCount, ...unique];
920
+ const result = Reflect.apply(target[prop], receiver, newArgs);
921
+ if (deleteCount > 0) {
922
+ mutateRemoveFromRelatedRecords(this, {
923
+ value: result.map(recordIdentifierFor$1),
924
+ index: start
925
+ }, _TAG);
926
+ }
927
+ if (unique.length > 0) {
928
+ mutateAddToRelatedRecords(this, {
929
+ value: extractIdentifiersFromRecords(unique),
930
+ index: start
931
+ }, _TAG);
932
+ }
933
+ return result;
828
934
  }
829
- if (removeCount > 0) {
830
- this._manager.mutate({
831
- op: 'removeFromRelatedRecords',
832
- record: this.identifier,
833
- field: this.key,
935
+
936
+ // else, no dedupe, error on duplicates
937
+ const newValues = extractIdentifiersFromRecords(adds);
938
+ assertNoDuplicates(this, target, currentState => currentState.splice(start, deleteCount, ...newValues), `Cannot splice a hasMany's state with a new state that contains duplicates.`);
939
+ const result = Reflect.apply(target[prop], receiver, args);
940
+ if (deleteCount > 0) {
941
+ mutateRemoveFromRelatedRecords(this, {
834
942
  value: result.map(recordIdentifierFor$1),
835
943
  index: start
836
- });
944
+ }, _TAG);
837
945
  }
838
- if (adds?.length) {
839
- this._manager.mutate({
840
- op: 'addToRelatedRecords',
841
- record: this.identifier,
842
- field: this.key,
843
- value: extractIdentifiersFromRecords(adds),
946
+ if (newValues.length > 0) {
947
+ mutateAddToRelatedRecords(this, {
948
+ value: newValues,
844
949
  index: start
845
- });
950
+ }, _TAG);
846
951
  }
847
- break;
952
+ return result;
848
953
  }
849
954
  default:
850
955
  assert(`unable to convert ${prop} into a transaction that updates the cache state for this record array`);
@@ -959,6 +1064,58 @@ function extractIdentifierFromRecord$1(recordOrPromiseRecord) {
959
1064
  function isPromiseRecord$1(record) {
960
1065
  return !!record.then;
961
1066
  }
1067
+ function assertNoDuplicates(collection, target, callback, reason) {
1068
+ const state = target.slice();
1069
+ callback(state);
1070
+ if (state.length !== new Set(state).size) {
1071
+ const duplicates = state.filter((currentValue, currentIndex) => state.indexOf(currentValue) !== currentIndex);
1072
+ throw new Error(`${reason} Found duplicates for the following records within the new state provided to \`<${collection.identifier.type}:${collection.identifier.id || collection.identifier.lid}>.${collection.key}\`\n\t- ${Array.from(new Set(duplicates)).map(r => isStableIdentifier(r) ? r.lid : recordIdentifierFor$1(r).lid).sort((a, b) => a.localeCompare(b)).join('\n\t- ')}`);
1073
+ }
1074
+ }
1075
+ function mutateAddToRelatedRecords(collection, operationInfo, _TAG) {
1076
+ mutate(collection, {
1077
+ op: 'addToRelatedRecords',
1078
+ record: collection.identifier,
1079
+ field: collection.key,
1080
+ ...operationInfo
1081
+ }, _TAG);
1082
+ }
1083
+ function mutateRemoveFromRelatedRecords(collection, operationInfo, _TAG) {
1084
+ mutate(collection, {
1085
+ op: 'removeFromRelatedRecords',
1086
+ record: collection.identifier,
1087
+ field: collection.key,
1088
+ ...operationInfo
1089
+ }, _TAG);
1090
+ }
1091
+ function mutateReplaceRelatedRecord(collection, operationInfo, _TAG) {
1092
+ mutate(collection, {
1093
+ op: 'replaceRelatedRecord',
1094
+ record: collection.identifier,
1095
+ field: collection.key,
1096
+ ...operationInfo
1097
+ }, _TAG);
1098
+ }
1099
+ function mutateReplaceRelatedRecords(collection, value, _TAG) {
1100
+ mutate(collection, {
1101
+ op: 'replaceRelatedRecords',
1102
+ record: collection.identifier,
1103
+ field: collection.key,
1104
+ value
1105
+ }, _TAG);
1106
+ }
1107
+ function mutateSortRelatedRecords(collection, value, _TAG) {
1108
+ mutate(collection, {
1109
+ op: 'sortRelatedRecords',
1110
+ record: collection.identifier,
1111
+ field: collection.key,
1112
+ value
1113
+ }, _TAG);
1114
+ }
1115
+ function mutate(collection, mutation, _TAG) {
1116
+ collection._manager.mutate(mutation);
1117
+ addToTransaction(_TAG);
1118
+ }
962
1119
  var _dec, _class$5;
963
1120
 
964
1121
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -2521,9 +2678,8 @@ class LegacySupport {
2521
2678
  if (relatedIdentifier === null) {
2522
2679
  return null;
2523
2680
  } else {
2524
- let toReturn = store._instanceCache.getRecord(relatedIdentifier);
2525
- assert(`You looked up the '${key}' relationship on a '${identifier.type}' with id ${identifier.id || 'null'} but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (\`belongsTo(<type>, { async: true, inverse: <inverse> })\`)`, toReturn === null || store._instanceCache.recordIsLoaded(relatedIdentifier, true));
2526
- return toReturn;
2681
+ assert(`You looked up the '${key}' relationship on a '${identifier.type}' with id ${identifier.id || 'null'} but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (\`belongsTo(<type>, { async: true, inverse: <inverse> })\`)`, store._instanceCache.recordIsLoaded(relatedIdentifier, true));
2682
+ return store._instanceCache.getRecord(relatedIdentifier);
2527
2683
  }
2528
2684
  }
2529
2685
  }