@ember-data/model 5.3.0-alpha.4 → 5.3.0-alpha.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.
@@ -1,15 +1,14 @@
1
- import { macroCondition, getOwnConfig, importSync } from '@embroider/macros';
1
+ import { dasherize } from '@ember/string';
2
2
  import { assert, warn } from '@ember/debug';
3
3
  import EmberObject, { computed, get } from '@ember/object';
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
- import { dasherize } from '@ember/string';
7
- import { A } from '@ember/array';
8
- import { singularize } from 'ember-inflector';
9
4
  import { dependentKeyCompat } from '@ember/object/compat';
10
5
  import { run } from '@ember/runloop';
11
6
  import { cached, tracked } from '@glimmer/tracking';
12
7
  import Ember from 'ember';
8
+ import { macroCondition, getOwnConfig, importSync } from '@embroider/macros';
9
+ import { recordIdentifierFor as recordIdentifierFor$1, storeFor as storeFor$1 } from '@ember-data/store';
10
+ import { RecordArray, MUTATE, SOURCE, recordIdentifierFor, IDENTIFIER_ARRAY_TAG, notifyArray, isStableIdentifier, storeFor, peekCache, fastPush, coerceId } from '@ember-data/store/-private';
11
+ import { A } from '@ember/array';
13
12
  import ArrayProxy from '@ember/array/proxy';
14
13
  import { mapBy, not } from '@ember/object/computed';
15
14
  import PromiseProxyMixin from '@ember/object/promise-proxy-mixin';
@@ -34,152 +33,9 @@ function isElementDescriptor(args) {
34
33
  function computedMacroWithOptionalParams(fn) {
35
34
  return (...maybeDesc) => isElementDescriptor(maybeDesc) ? fn()(...maybeDesc) : fn(...maybeDesc);
36
35
  }
37
-
38
- /**
39
- @module @ember-data/model
40
- */
41
-
42
- /**
43
- `attr` defines an attribute on a [Model](/ember-data/release/classes/Model).
44
- By default, attributes are passed through as-is, however you can specify an
45
- optional type to have the value automatically transformed.
46
- Ember Data ships with four basic transform types: `string`, `number`,
47
- `boolean` and `date`. You can define your own transforms by subclassing
48
- [Transform](/ember-data/release/classes/Transform).
49
-
50
- Note that you cannot use `attr` to define an attribute of `id`.
51
-
52
- `attr` takes an optional hash as a second parameter, currently
53
- supported options are:
54
-
55
- - `defaultValue`: Pass a string or a function to be called to set the attribute
56
- to a default value if and only if the key is absent from the payload response.
57
-
58
- Example
59
-
60
- ```app/models/user.js
61
- import Model, { attr } from '@ember-data/model';
62
-
63
- export default class UserModel extends Model {
64
- @attr('string') username;
65
- @attr('string') email;
66
- @attr('boolean', { defaultValue: false }) verified;
67
- }
68
- ```
69
-
70
- Default value can also be a function. This is useful it you want to return
71
- a new object for each attribute.
72
-
73
- ```app/models/user.js
74
- import Model, { attr } from '@ember-data/model';
75
-
76
- export default class UserModel extends Model {
77
- @attr('string') username;
78
- @attr('string') email;
79
-
80
- @attr({
81
- defaultValue() {
82
- return {};
83
- }
84
- })
85
- settings;
86
- }
87
- ```
88
-
89
- The `options` hash is passed as second argument to a transforms'
90
- `serialize` and `deserialize` method. This allows to configure a
91
- transformation and adapt the corresponding value, based on the config:
92
-
93
- ```app/models/post.js
94
- import Model, { attr } from '@ember-data/model';
95
-
96
- export default class PostModel extends Model {
97
- @attr('text', {
98
- uppercase: true
99
- })
100
- text;
101
- }
102
- ```
103
-
104
- ```app/transforms/text.js
105
- export default class TextTransform {
106
- serialize(value, options) {
107
- if (options.uppercase) {
108
- return value.toUpperCase();
109
- }
110
-
111
- return value;
112
- }
113
-
114
- deserialize(value) {
115
- return value;
116
- }
117
-
118
- static create() {
119
- return new this();
120
- }
121
- }
122
- ```
123
-
124
- @method attr
125
- @public
126
- @static
127
- @for @ember-data/model
128
- @param {String|Object} type the attribute type
129
- @param {Object} options a hash of options
130
- @return {Attribute}
131
- */
132
- function attr(type, options) {
133
- if (typeof type === 'object') {
134
- options = type;
135
- type = undefined;
136
- } else {
137
- options = options || {};
138
- }
139
- let meta = {
140
- type: type,
141
- isAttribute: true,
142
- options: options
143
- };
144
- return computed({
145
- get(key) {
146
- if (macroCondition(getOwnConfig().env.DEBUG)) {
147
- if (['currentState'].indexOf(key) !== -1) {
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()}`);
149
- }
150
- }
151
- if (this.isDestroyed || this.isDestroying) {
152
- return;
153
- }
154
- return peekCache(this).getAttr(recordIdentifierFor(this), key);
155
- },
156
- set(key, value) {
157
- if (macroCondition(getOwnConfig().env.DEBUG)) {
158
- if (['currentState'].indexOf(key) !== -1) {
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()}`);
160
- }
161
- }
162
- assert(`Attempted to set '${key}' on the deleted record ${recordIdentifierFor(this)}`, !this.currentState.isDeleted);
163
- const identifier = recordIdentifierFor(this);
164
- const cache = peekCache(this);
165
- let currentValue = cache.getAttr(identifier, key);
166
- if (currentValue !== value) {
167
- cache.setAttr(identifier, key, value);
168
- if (!this.isValid) {
169
- const {
170
- errors
171
- } = this;
172
- if (errors.get(key)) {
173
- errors.remove(key);
174
- this.currentState.cleanErrorRequests();
175
- }
176
- }
177
- }
178
- return value;
179
- }
180
- }).meta(meta);
36
+ function normalizeModelName(modelName) {
37
+ return dasherize(modelName);
181
38
  }
182
- var attr$1 = computedMacroWithOptionalParams(attr);
183
39
  function _initializerDefineProperty(target, property, descriptor, context) {
184
40
  if (!descriptor) return;
185
41
  Object.defineProperty(target, property, {
@@ -728,7 +584,7 @@ class RelatedCollection extends RecordArray {
728
584
  op: 'removeFromRelatedRecords',
729
585
  record: this.identifier,
730
586
  field: this.key,
731
- value: recordIdentifierFor$1(result)
587
+ value: recordIdentifierFor(result)
732
588
  });
733
589
  }
734
590
  break;
@@ -747,7 +603,7 @@ class RelatedCollection extends RecordArray {
747
603
  op: 'removeFromRelatedRecords',
748
604
  record: this.identifier,
749
605
  field: this.key,
750
- value: recordIdentifierFor$1(result),
606
+ value: recordIdentifierFor(result),
751
607
  index: 0
752
608
  });
753
609
  }
@@ -757,7 +613,7 @@ class RelatedCollection extends RecordArray {
757
613
  op: 'sortRelatedRecords',
758
614
  record: this.identifier,
759
615
  field: this.key,
760
- value: result.map(recordIdentifierFor$1)
616
+ value: result.map(recordIdentifierFor)
761
617
  });
762
618
  break;
763
619
  case 'splice':
@@ -778,7 +634,7 @@ class RelatedCollection extends RecordArray {
778
634
  op: 'removeFromRelatedRecords',
779
635
  record: this.identifier,
780
636
  field: this.key,
781
- value: result.map(recordIdentifierFor$1),
637
+ value: result.map(recordIdentifierFor),
782
638
  index: start
783
639
  });
784
640
  }
@@ -869,7 +725,7 @@ RelatedCollection.prototype.DEPRECATED_CLASS_NAME = 'ManyArray';
869
725
  function assertRecordPassedToHasMany(record) {
870
726
  assert(`All elements of a hasMany relationship must be instances of Model, you passed $${typeof record}`, function () {
871
727
  try {
872
- recordIdentifierFor$1(record);
728
+ recordIdentifierFor(record);
873
729
  return true;
874
730
  } catch {
875
731
  return false;
@@ -881,7 +737,7 @@ function extractIdentifiersFromRecords(records) {
881
737
  }
882
738
  function extractIdentifierFromRecord$1(recordOrPromiseRecord) {
883
739
  assertRecordPassedToHasMany(recordOrPromiseRecord);
884
- return recordIdentifierFor$1(recordOrPromiseRecord);
740
+ return recordIdentifierFor(recordOrPromiseRecord);
885
741
  }
886
742
  const PromiseObject = ObjectProxy.extend(PromiseProxyMixin);
887
743
  var _dec, _class$5;
@@ -1511,7 +1367,7 @@ let BelongsToReference = (_class$3 = class BelongsToReference {
1511
1367
  let record = this.store.push(jsonApiDoc);
1512
1368
  if (macroCondition(getOwnConfig().env.DEBUG)) {
1513
1369
  // eslint-disable-next-line @typescript-eslint/no-unsafe-call
1514
- assertPolymorphicType(this.belongsToRelationship.identifier, this.belongsToRelationship.definition, recordIdentifierFor$1(record), this.store);
1370
+ assertPolymorphicType(this.belongsToRelationship.identifier, this.belongsToRelationship.definition, recordIdentifierFor(record), this.store);
1515
1371
  }
1516
1372
  const {
1517
1373
  identifier
@@ -1521,7 +1377,7 @@ let BelongsToReference = (_class$3 = class BelongsToReference {
1521
1377
  op: 'replaceRelatedRecord',
1522
1378
  record: identifier,
1523
1379
  field: this.key,
1524
- value: recordIdentifierFor$1(record)
1380
+ value: recordIdentifierFor(record)
1525
1381
  });
1526
1382
  });
1527
1383
  return Promise.resolve(record);
@@ -2008,9 +1864,9 @@ let HasManyReference = (_class$2 = class HasManyReference {
2008
1864
  let identifier = this.hasManyRelationship.identifier;
2009
1865
 
2010
1866
  // eslint-disable-next-line @typescript-eslint/no-unsafe-call
2011
- assertPolymorphicType(identifier, relationshipMeta, recordIdentifierFor(record), store);
1867
+ assertPolymorphicType(identifier, relationshipMeta, recordIdentifierFor$1(record), store);
2012
1868
  }
2013
- return recordIdentifierFor(record);
1869
+ return recordIdentifierFor$1(record);
2014
1870
  });
2015
1871
  const {
2016
1872
  identifier
@@ -2197,7 +2053,7 @@ class LegacySupport {
2197
2053
  constructor(record) {
2198
2054
  this.record = record;
2199
2055
  this.store = storeFor(record);
2200
- this.identifier = recordIdentifierFor$1(record);
2056
+ this.identifier = recordIdentifierFor(record);
2201
2057
  this.cache = peekCache(record);
2202
2058
  this._manyArrayCache = Object.create(null);
2203
2059
  this._relationshipPromisesCache = Object.create(null);
@@ -2697,7 +2553,7 @@ function extractIdentifierFromRecord(record) {
2697
2553
  if (!record) {
2698
2554
  return null;
2699
2555
  }
2700
- return recordIdentifierFor$1(record);
2556
+ return recordIdentifierFor(record);
2701
2557
  }
2702
2558
  function anyUnloaded(store, relationship) {
2703
2559
  let state = relationship.localState;
@@ -2917,7 +2773,7 @@ let RecordState = (_class3 = class RecordState {
2917
2773
  constructor(record) {
2918
2774
  _initializerDefineProperty(this, "isSaving", _descriptor2, this);
2919
2775
  const store = storeFor$1(record);
2920
- const identity = recordIdentifierFor$1(record);
2776
+ const identity = recordIdentifierFor(record);
2921
2777
  this.identifier = identity;
2922
2778
  this.record = record;
2923
2779
  this.cache = store.cache;
@@ -3188,7 +3044,7 @@ const {
3188
3044
  } = Ember;
3189
3045
  const LEGACY_SUPPORT = new Map();
3190
3046
  function lookupLegacySupport(record) {
3191
- const identifier = recordIdentifierFor(record);
3047
+ const identifier = recordIdentifierFor$1(record);
3192
3048
  let support = LEGACY_SUPPORT.get(identifier);
3193
3049
  if (!support) {
3194
3050
  assert(`Memory Leak Detected`, !record.isDestroyed && !record.isDestroying);
@@ -3305,7 +3161,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
3305
3161
  });
3306
3162
  }
3307
3163
  destroy() {
3308
- const identifier = recordIdentifierFor(this);
3164
+ const identifier = recordIdentifierFor$1(this);
3309
3165
  this.___recordState?.destroy();
3310
3166
  const store = storeFor$1(this);
3311
3167
  store.notifications.unsubscribe(this.___private_notifications);
@@ -3569,16 +3425,16 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
3569
3425
  // object is real.
3570
3426
  if (macroCondition(getOwnConfig().env.DEBUG)) {
3571
3427
  try {
3572
- return recordIdentifierFor(this).id;
3428
+ return recordIdentifierFor$1(this).id;
3573
3429
  } catch {
3574
3430
  return void 0;
3575
3431
  }
3576
3432
  }
3577
- return recordIdentifierFor(this).id;
3433
+ return recordIdentifierFor$1(this).id;
3578
3434
  }
3579
3435
  set id(id) {
3580
3436
  const normalizedId = coerceId(id);
3581
- const identifier = recordIdentifierFor(this);
3437
+ const identifier = recordIdentifierFor$1(this);
3582
3438
  let didChange = normalizedId !== identifier.id;
3583
3439
  assert(`Cannot set ${identifier.type} record's id to ${id}, because id is already ${identifier.id}`, !didChange || identifier.id === null);
3584
3440
  if (normalizedId !== null && didChange) {
@@ -3870,7 +3726,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
3870
3726
  and value is an [oldProp, newProp] array.
3871
3727
  */
3872
3728
  changedAttributes() {
3873
- return peekCache(this).changedAttrs(recordIdentifierFor(this));
3729
+ return peekCache(this).changedAttrs(recordIdentifierFor$1(this));
3874
3730
  }
3875
3731
 
3876
3732
  /**
@@ -3896,7 +3752,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
3896
3752
  isNew
3897
3753
  } = currentState;
3898
3754
  storeFor$1(this)._join(() => {
3899
- peekCache(this).rollbackAttrs(recordIdentifierFor(this));
3755
+ peekCache(this).rollbackAttrs(recordIdentifierFor$1(this));
3900
3756
  this.errors.clear();
3901
3757
  currentState.cleanErrorRequests();
3902
3758
  if (isNew) {
@@ -3916,7 +3772,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
3916
3772
  const FetchManager = importSync('@ember-data/legacy-compat/-private').FetchManager;
3917
3773
  store._fetchManager = new FetchManager(store);
3918
3774
  }
3919
- return store._fetchManager.createSnapshot(recordIdentifierFor(this));
3775
+ return store._fetchManager.createSnapshot(recordIdentifierFor$1(this));
3920
3776
  }
3921
3777
 
3922
3778
  /**
@@ -3958,6 +3814,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
3958
3814
  if (this.currentState.isNew && this.currentState.isDeleted) {
3959
3815
  promise = Promise.resolve(this);
3960
3816
  } else {
3817
+ this.errors.clear();
3961
3818
  promise = storeFor$1(this).saveRecord(this, options);
3962
3819
  }
3963
3820
  return promise;
@@ -3989,7 +3846,7 @@ let Model = (_class = (_class2 = class Model extends EmberObject {
3989
3846
  reload(options = {}) {
3990
3847
  options.isReloading = true;
3991
3848
  options.reload = true;
3992
- const identifier = recordIdentifierFor(this);
3849
+ const identifier = recordIdentifierFor$1(this);
3993
3850
  assert(`You cannot reload a record without an ID`, identifier.id);
3994
3851
  this.isReloading = true;
3995
3852
  const promise = storeFor$1(this).request({
@@ -4837,7 +4694,7 @@ if (macroCondition(getOwnConfig().includeDataAdapter)) {
4837
4694
  Model.prototype._debugInfo = function () {
4838
4695
  let relationships = {};
4839
4696
  let expensiveProperties = [];
4840
- const identifier = recordIdentifierFor(this);
4697
+ const identifier = recordIdentifierFor$1(this);
4841
4698
  const schema = this.store.getSchemaDefinitionService();
4842
4699
  const attrDefs = schema.attributesDefinitionFor(identifier);
4843
4700
  const relDefs = schema.relationshipsDefinitionFor(identifier);
@@ -4912,344 +4769,4 @@ if (macroCondition(getOwnConfig().env.DEBUG)) {
4912
4769
  assert(`Model.reopenClass is deprecated. Use Foo extends Model to add static methods and properties to your class instead.`);
4913
4770
  };
4914
4771
  }
4915
- function normalizeType$1(type) {
4916
- return dasherize(type);
4917
- }
4918
- /**
4919
- @module @ember-data/model
4920
- */
4921
-
4922
- /**
4923
- `belongsTo` is used to define One-To-One and One-To-Many
4924
- relationships on a [Model](/ember-data/release/classes/Model).
4925
-
4926
-
4927
- `belongsTo` takes an optional hash as a second parameter, currently
4928
- supported options are:
4929
-
4930
- - `async`: A boolean value used to explicitly declare this to be an async relationship. The default is true.
4931
- - `inverse`: A string used to identify the inverse property on a
4932
- related model in a One-To-Many relationship. See [Explicit Inverses](#explicit-inverses)
4933
- - `polymorphic` A boolean value to mark the relationship as polymorphic
4934
-
4935
- #### One-To-One
4936
- To declare a one-to-one relationship between two models, use
4937
- `belongsTo`:
4938
-
4939
- ```app/models/user.js
4940
- import Model, { belongsTo } from '@ember-data/model';
4941
-
4942
- export default class UserModel extends Model {
4943
- @belongsTo('profile') profile;
4944
- }
4945
- ```
4946
-
4947
- ```app/models/profile.js
4948
- import Model, { belongsTo } from '@ember-data/model';
4949
-
4950
- export default class ProfileModel extends Model {
4951
- @belongsTo('user') user;
4952
- }
4953
- ```
4954
-
4955
- #### One-To-Many
4956
-
4957
- To declare a one-to-many relationship between two models, use
4958
- `belongsTo` in combination with `hasMany`, like this:
4959
-
4960
- ```app/models/post.js
4961
- import Model, { hasMany } from '@ember-data/model';
4962
-
4963
- export default class PostModel extends Model {
4964
- @hasMany('comment', { async: false, inverse: 'post' }) comments;
4965
- }
4966
- ```
4967
-
4968
- ```app/models/comment.js
4969
- import Model, { belongsTo } from '@ember-data/model';
4970
-
4971
- export default class CommentModel extends Model {
4972
- @belongsTo('post', { async: false, inverse: 'comments' }) post;
4973
- }
4974
- ```
4975
-
4976
- #### Sync relationships
4977
-
4978
- Ember Data resolves sync relationships with the related resources
4979
- available in its local store, hence it is expected these resources
4980
- to be loaded before or along-side the primary resource.
4981
-
4982
- ```app/models/comment.js
4983
- import Model, { belongsTo } from '@ember-data/model';
4984
-
4985
- export default class CommentModel extends Model {
4986
- @belongsTo('post', {
4987
- async: false,
4988
- inverse: null
4989
- })
4990
- post;
4991
- }
4992
- ```
4993
-
4994
- In contrast to async relationship, accessing a sync relationship
4995
- will always return the record (Model instance) for the existing
4996
- local resource, or null. But it will error on access when
4997
- a related resource is known to exist and it has not been loaded.
4998
-
4999
- ```
5000
- let post = comment.post;
5001
-
5002
- ```
5003
-
5004
- @method belongsTo
5005
- @public
5006
- @static
5007
- @for @ember-data/model
5008
- @param {String} modelName (optional) type of the relationship
5009
- @param {Object} options (optional) a hash of options
5010
- @return {Ember.computed} relationship
5011
- */
5012
- function belongsTo(modelName, options) {
5013
- let opts = options;
5014
- let userEnteredModelName = modelName;
5015
- assert(`Expected belongsTo options.async to be a boolean`, opts && typeof opts.async === 'boolean');
5016
- assert(`Expected belongsTo options.inverse to be either null or the string type of the related resource.`, opts.inverse === null || typeof opts.inverse === 'string' && opts.inverse.length > 0);
5017
- let meta = {
5018
- type: normalizeType$1(userEnteredModelName),
5019
- isRelationship: true,
5020
- options: opts,
5021
- kind: 'belongsTo',
5022
- name: 'Belongs To',
5023
- key: null
5024
- };
5025
- return computed({
5026
- get(key) {
5027
- // this is a legacy behavior we may not carry into a new model setup
5028
- // it's better to error on disconnected records so users find errors
5029
- // in their logic.
5030
- if (this.isDestroying || this.isDestroyed) {
5031
- return null;
5032
- }
5033
- const support = lookupLegacySupport(this);
5034
- if (macroCondition(getOwnConfig().env.DEBUG)) {
5035
- if (['currentState'].indexOf(key) !== -1) {
5036
- 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()}`);
5037
- }
5038
- if (Object.prototype.hasOwnProperty.call(opts, 'serialize')) {
5039
- warn(`You provided a serialize option on the "${key}" property in the "${support.identifier.type}" class, this belongs in the serializer. See Serializer and it's implementations https://api.emberjs.com/ember-data/release/classes/Serializer`, false, {
5040
- id: 'ds.model.serialize-option-in-belongs-to'
5041
- });
5042
- }
5043
- if (Object.prototype.hasOwnProperty.call(opts, 'embedded')) {
5044
- warn(`You provided an embedded option on the "${key}" property in the "${support.identifier.type}" class, this belongs in the serializer. See EmbeddedRecordsMixin https://api.emberjs.com/ember-data/release/classes/EmbeddedRecordsMixin`, false, {
5045
- id: 'ds.model.embedded-option-in-belongs-to'
5046
- });
5047
- }
5048
- }
5049
- return support.getBelongsTo(key);
5050
- },
5051
- set(key, value) {
5052
- const support = lookupLegacySupport(this);
5053
- if (macroCondition(getOwnConfig().env.DEBUG)) {
5054
- if (['currentState'].indexOf(key) !== -1) {
5055
- 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()}`);
5056
- }
5057
- }
5058
- this.store._join(() => {
5059
- support.setDirtyBelongsTo(key, value);
5060
- });
5061
- return support.getBelongsTo(key);
5062
- }
5063
- }).meta(meta);
5064
- }
5065
- var belongsTo$1 = computedMacroWithOptionalParams(belongsTo);
5066
- function normalizeType(type) {
5067
- return singularize(dasherize(type));
5068
- }
5069
-
5070
- /**
5071
- `hasMany` is used to define One-To-Many and Many-To-Many
5072
- relationships on a [Model](/ember-data/release/classes/Model).
5073
-
5074
- `hasMany` takes an optional hash as a second parameter, currently
5075
- supported options are:
5076
-
5077
- - `async`: A boolean value used to explicitly declare this to be an async relationship. The default is true.
5078
- - `inverse`: A string used to identify the inverse property on a related model.
5079
- - `polymorphic` A boolean value to mark the relationship as polymorphic
5080
-
5081
- #### One-To-Many
5082
- To declare a one-to-many relationship between two models, use
5083
- `belongsTo` in combination with `hasMany`, like this:
5084
-
5085
- ```app/models/post.js
5086
- import Model, { hasMany } from '@ember-data/model';
5087
-
5088
- export default class PostModel extends Model {
5089
- @hasMany('comment') comments;
5090
- }
5091
- ```
5092
-
5093
- ```app/models/comment.js
5094
- import Model, { belongsTo } from '@ember-data/model';
5095
-
5096
- export default class CommentModel extends Model {
5097
- @belongsTo('post') post;
5098
- }
5099
- ```
5100
-
5101
- #### Many-To-Many
5102
- To declare a many-to-many relationship between two models, use
5103
- `hasMany`:
5104
-
5105
- ```app/models/post.js
5106
- import Model, { hasMany } from '@ember-data/model';
5107
-
5108
- export default class PostModel extends Model {
5109
- @hasMany('tag') tags;
5110
- }
5111
- ```
5112
-
5113
- ```app/models/tag.js
5114
- import Model, { hasMany } from '@ember-data/model';
5115
-
5116
- export default class TagModel extends Model {
5117
- @hasMany('post') posts;
5118
- }
5119
- ```
5120
-
5121
- You can avoid passing a string as the first parameter. In that case Ember Data
5122
- will infer the type from the singularized key name.
5123
-
5124
- ```app/models/post.js
5125
- import Model, { hasMany } from '@ember-data/model';
5126
-
5127
- export default class PostModel extends Model {
5128
- @hasMany tags;
5129
- }
5130
- ```
5131
-
5132
- will lookup for a Tag type.
5133
-
5134
- #### Explicit Inverses
5135
-
5136
- Ember Data will do its best to discover which relationships map to
5137
- one another. In the one-to-many code above, for example, Ember Data
5138
- can figure out that changing the `comments` relationship should update
5139
- the `post` relationship on the inverse because post is the only
5140
- relationship to that model.
5141
-
5142
- However, sometimes you may have multiple `belongsTo`/`hasMany` for the
5143
- same type. You can specify which property on the related model is
5144
- the inverse using `hasMany`'s `inverse` option:
5145
-
5146
- ```app/models/comment.js
5147
- import Model, { belongsTo } from '@ember-data/model';
5148
-
5149
- export default class CommentModel extends Model {
5150
- @belongsTo('post') onePost;
5151
- @belongsTo('post') twoPost
5152
- @belongsTo('post') redPost;
5153
- @belongsTo('post') bluePost;
5154
- }
5155
- ```
5156
-
5157
- ```app/models/post.js
5158
- import Model, { hasMany } from '@ember-data/model';
5159
-
5160
- export default class PostModel extends Model {
5161
- @hasMany('comment', {
5162
- inverse: 'redPost'
5163
- })
5164
- comments;
5165
- }
5166
- ```
5167
-
5168
- You can also specify an inverse on a `belongsTo`, which works how
5169
- you'd expect.
5170
-
5171
- #### Sync relationships
5172
-
5173
- Ember Data resolves sync relationships with the related resources
5174
- available in its local store, hence it is expected these resources
5175
- to be loaded before or along-side the primary resource.
5176
-
5177
- ```app/models/post.js
5178
- import Model, { hasMany } from '@ember-data/model';
5179
-
5180
- export default class PostModel extends Model {
5181
- @hasMany('comment', {
5182
- async: false
5183
- })
5184
- comments;
5185
- }
5186
- ```
5187
-
5188
- In contrast to async relationship, accessing a sync relationship
5189
- will always return a [ManyArray](/ember-data/release/classes/ManyArray) instance
5190
- containing the existing local resources. But it will error on access
5191
- when any of the known related resources have not been loaded.
5192
-
5193
- ```
5194
- post.comments.forEach((comment) => {
5195
-
5196
- });
5197
-
5198
- ```
5199
-
5200
- If you are using `links` with sync relationships, you have to use
5201
- `ref.reload` to fetch the resources.
5202
-
5203
- @method hasMany
5204
- @public
5205
- @static
5206
- @for @ember-data/model
5207
- @param {String} type (optional) type of the relationship
5208
- @param {Object} options (optional) a hash of options
5209
- @return {Ember.computed} relationship
5210
- */
5211
- function hasMany(type, options) {
5212
- assert(`Expected hasMany options.async to be a boolean`, options && typeof options.async === 'boolean');
5213
-
5214
- // Metadata about relationships is stored on the meta of
5215
- // the relationship. This is used for introspection and
5216
- // serialization. Note that `key` is populated lazily
5217
- // the first time the CP is called.
5218
- let meta = {
5219
- type: normalizeType(type),
5220
- options,
5221
- isRelationship: true,
5222
- kind: 'hasMany',
5223
- name: 'Has Many',
5224
- key: null
5225
- };
5226
- return computed({
5227
- get(key) {
5228
- if (macroCondition(getOwnConfig().env.DEBUG)) {
5229
- if (['currentState'].indexOf(key) !== -1) {
5230
- 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()}`);
5231
- }
5232
- }
5233
- if (this.isDestroying || this.isDestroyed) {
5234
- return A();
5235
- }
5236
- return lookupLegacySupport(this).getHasMany(key);
5237
- },
5238
- set(key, records) {
5239
- if (macroCondition(getOwnConfig().env.DEBUG)) {
5240
- if (['currentState'].indexOf(key) !== -1) {
5241
- 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()}`);
5242
- }
5243
- }
5244
- const support = lookupLegacySupport(this);
5245
- const manyArray = support.getManyArray(key);
5246
- assert(`You must pass an array of records to set a hasMany relationship`, Array.isArray(records));
5247
- this.store._join(() => {
5248
- manyArray.splice(0, manyArray.length, ...records);
5249
- });
5250
- return support.getHasMany(key);
5251
- }
5252
- }).meta(meta);
5253
- }
5254
- var hasMany$1 = computedMacroWithOptionalParams(hasMany);
5255
- export { Errors as E, LEGACY_SUPPORT as L, Model as M, PromiseBelongsTo as P, RelatedCollection as R, attr$1 as a, belongsTo$1 as b, PromiseManyArray as c, hasMany$1 as h };
4772
+ export { Errors as E, LEGACY_SUPPORT as L, Model as M, PromiseBelongsTo as P, RelatedCollection as R, PromiseManyArray as a, computedMacroWithOptionalParams as c, lookupLegacySupport as l, normalizeModelName as n };