ember-data-model-fragments 4.0.0 → 5.0.0-beta.3

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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "workbench.colorCustomizations": {
3
+ "activityBar.background": "#24320F",
4
+ "titleBar.activeBackground": "#334615",
5
+ "titleBar.activeForeground": "#F8FCF3"
6
+ }
7
+ }
package/CHANGELOG.md CHANGED
@@ -1,6 +1,15 @@
1
1
  # Changelog
2
2
 
3
- ### v4.0.0 (January 25, 2018)
3
+ ### v5.0.0-beta.1 (November 12, 2020)
4
+
5
+ * [#381](https://github.com/adopted-ember-addons/ember-data-model-fragments/pull/381) Fix `hasDirtyAttributes` when resetting a property (@VincentMolinie)
6
+ * [#385](https://github.com/adopted-ember-addons/ember-data-model-fragments/pull/385) Upgrade to Ember 3.20 LTS (@patocallaghan)
7
+
8
+ ### v5.0.0-beta.0 (May 28, 2020)
9
+
10
+ * [#360](https://github.com/adopted-ember-addons/ember-data-model-fragments/pull/360) Upgrade to work with Ember Data 3.16 (@richgt, @igorT)
11
+
12
+ ### v4.0.0 (January 25, 2019)
4
13
 
5
14
  * Ember 3.5.0 compatibility with breaking changes related to `RecordData`. (@cohitre)
6
15
  * Fixed `changedAtributes` with fragments (@Gorzas)
package/LICENSE.md ADDED
@@ -0,0 +1,9 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ember Data Model Fragments
2
2
 
3
- [![Build Status](https://travis-ci.org/lytics/ember-data-model-fragments.svg)](https://travis-ci.org/lytics/ember-data-model-fragments)
3
+ [![CI](https://github.com/adopted-ember-addons/ember-data-model-fragments/actions/workflows/ci.yml/badge.svg)](https://github.com/adopted-ember-addons/ember-data-model-fragments/actions/workflows/ci.yml)
4
4
  [![NPM Version](https://badge.fury.io/js/ember-data-model-fragments.svg)](http://badge.fury.io/js/ember-data-model-fragments)
5
5
  [![Ember Observer Score](http://emberobserver.com/badges/ember-data-model-fragments.svg)](http://emberobserver.com/addons/ember-data-model-fragments)
6
6
 
@@ -27,7 +27,9 @@ Use the following table to decide which version of this project to use with your
27
27
  | >= v2.14.x < v3.0.x | v2.14.x |
28
28
  | >= v3.0.x < v3.2.x | v3.0.x-beta.1 |
29
29
  | >= v3.2.x < v3.4.x | v3.3.x |
30
- | >= v3.5.x | v4.0.x |
30
+ | >= v3.5.x < v3.12.x | v4.0.x |
31
+ | >= v3.13.x | v5.0.x |
32
+ | >= v3.28.x | Not fully compatible (See [issue](https://github.com/adopted-ember-addons/ember-data-model-fragments/issues/406)) |
31
33
 
32
34
  #### Notes
33
35
 
@@ -40,6 +42,7 @@ Use the following table to decide which version of this project to use with your
40
42
  - Ember Data 3.0 changed `ContainerInstanceCache` import paths. See [e4749c10](https://github.com/lytics/ember-data-model-fragments/pull/287/commits/e4749c107610a6d0dd6032a58c66356e6064562a).
41
43
  - Ember Data 3.2 changed `InternalModel#fields`. See: [#310](https://github.com/lytics/ember-data-model-fragments/pull/310).
42
44
  - Ember Data 3.5 added `RecordData` interfaces. See: [#324](https://github.com/lytics/ember-data-model-fragments/pull/324), [emberjs/rfcs#293](https://github.com/emberjs/rfcs/pull/293), and [emberjs/data#5616](https://github.com/emberjs/data/pull/5616).
45
+ - Ember Data 3.13 changed `InternalModel` Private APIs. See: [#360] (https://github.com/lytics/ember-data-model-fragments/pull/360)
43
46
 
44
47
  ## Installation
45
48
 
@@ -455,7 +458,7 @@ with `polymorphic` set to true. In addition the `typeKey` can be set, which defa
455
458
 
456
459
  The `typeKey`'s value must be the lowercase name of a class that is assignment-compatible to the declared type of the fragment attribute. That is, it must be the declared type itself or a subclass. Additionally, the `typeKey`'s value must be a field on the parent class.
457
460
 
458
- In the following example the declared type of `animals` is `animal`, which corresponds to the class `App.Animal`. `App.Animal` has two subclasses: `App.Elephant` and `App.Lion`,
461
+ In the following example the declared type of `animals` is `animal`, which corresponds to the class `Animal`. `Animal` has two subclasses: `Elephant` and `Lion`,
459
462
  so to `typeKey`'s value can be `'animal'`, `'elephant'` or `'lion'`.
460
463
 
461
464
  ```javascript
@@ -476,7 +479,7 @@ export default Model.extend({
476
479
  import Fragment from 'ember-data-model-fragments/fragment';
477
480
  import attr from 'ember-data/attr';
478
481
 
479
- App.Animal = Fragment.extend({
482
+ export default Fragment.extend({
480
483
  $type: attr('string'),
481
484
  name: attr('string'),
482
485
  });
@@ -540,14 +543,16 @@ Serializing the fragment type back to JSON is not currently supported out of the
540
543
  ```javascript
541
544
  // app/serializers/animal.js
542
545
  import JSONSerializer from 'ember-data/serializers/json';
546
+ import Elephant from 'app/models/elephant';
547
+ import Lion from 'app/models/elephant';
543
548
 
544
549
  export default JSONSerializer.extend({
545
550
  serialize(record, options) {
546
551
  let json = this._super(...arguments);
547
552
 
548
- if (record instanceof App.Elephant) {
553
+ if (record instanceof Elephant) {
549
554
  json.$type = 'elephant';
550
- } else if (record instanceof App.Lion) {
555
+ } else if (record instanceof Lion) {
551
556
  json.$type = 'lion';
552
557
  } else {
553
558
  json.$type = 'animal';
@@ -87,7 +87,7 @@ const FragmentArray = StatefulArray.extend({
87
87
  @param {Object} data
88
88
  */
89
89
  _normalizeData(data) {
90
- let content = get(this, 'content');
90
+ let content = this.content;
91
91
 
92
92
  return normalizeFragmentArray(this, content, data, true);
93
93
  },
@@ -113,16 +113,16 @@ const FragmentArray = StatefulArray.extend({
113
113
  },
114
114
 
115
115
  /**
116
- @method _adapterDidCommit
116
+ @method _didCommit
117
117
  @private
118
118
  */
119
- _adapterDidCommit(data) {
119
+ _didCommit(data) {
120
120
  this._super(...arguments);
121
121
 
122
122
  // Notify all records of commit; if the adapter update did not contain new
123
123
  // data, just notify each fragment so it can transition to a clean state
124
124
  this.forEach((fragment, index) => {
125
- fragment._adapterDidCommit(data && data[index]);
125
+ fragment._didCommit(data && data[index]);
126
126
  });
127
127
  },
128
128
 
@@ -200,7 +200,7 @@ const FragmentArray = StatefulArray.extend({
200
200
  @private
201
201
  */
202
202
  replaceContent(index, amount, objs) {
203
- let content = get(this, 'content');
203
+ let content = this.content;
204
204
  let replacedContent = content.slice(index, index + amount);
205
205
  let fragments = normalizeFragmentArray(this, replacedContent, objs);
206
206
 
@@ -239,9 +239,9 @@ const FragmentArray = StatefulArray.extend({
239
239
  @return {MF.Fragment} the newly added fragment
240
240
  */
241
241
  createFragment(props) {
242
- let record = get(this, 'owner');
242
+ let record = this.owner;
243
243
  let store = get(record, 'store');
244
- let type = get(this, 'type');
244
+ let type = this.type;
245
245
  let fragment = store.createFragment(type, props);
246
246
 
247
247
  return this.pushObject(fragment);
@@ -77,7 +77,6 @@ const StatefulArray = ArrayProxy.extend(Copyable, {
77
77
 
78
78
  // Completely replace the contents with the new data
79
79
  content.replace(0, get(content, 'length'), processedData);
80
-
81
80
  this._pendingData = undefined;
82
81
  },
83
82
 
@@ -105,10 +104,10 @@ const StatefulArray = ArrayProxy.extend(Copyable, {
105
104
  _flushChangedAttributes() {},
106
105
 
107
106
  /**
108
- @method _adapterDidCommit
107
+ @method _didCommit
109
108
  @private
110
109
  */
111
- _adapterDidCommit(data) {
110
+ _didCommit(data) {
112
111
  if (data) {
113
112
  this.setupData(data);
114
113
  } else {
@@ -140,6 +139,7 @@ const StatefulArray = ArrayProxy.extend(Copyable, {
140
139
  @readOnly
141
140
  */
142
141
  hasDirtyAttributes: computed('[]', '_originalState', function() {
142
+
143
143
  return compare(this.toArray(), get(this, '_originalState')) !== 0;
144
144
  }),
145
145
 
@@ -1,22 +1,9 @@
1
1
  import { assert } from '@ember/debug';
2
- import { copy } from 'ember-copy';
3
- import { typeOf } from '@ember/utils';
4
- import { isArray } from '@ember/array';
5
- import { get, setProperties, computed } from '@ember/object';
6
- import StatefulArray from './array/stateful';
7
- import FragmentArray from './array/fragment';
8
- import {
9
- fragmentDidDirty,
10
- fragmentDidReset
11
- } from './states';
2
+ import { computed } from '@ember/object';
12
3
  import {
13
4
  internalModelFor,
14
- setFragmentOwner,
15
- setFragmentData,
16
- createFragment,
17
5
  isFragment
18
6
  } from './fragment';
19
- import isInstanceOfType from './util/instance-of-type';
20
7
 
21
8
  /**
22
9
  @module ember-data-model-fragments
@@ -80,76 +67,7 @@ function fragment(declaredModelName, options) {
80
67
 
81
68
  let metaType = metaTypeFor('fragment', declaredModelName, options);
82
69
 
83
- function setupFragment(store, record, key) {
84
- let internalModel = internalModelFor(record);
85
- let data = getWithDefault(internalModel, key, options, 'object');
86
- let fragment = internalModel._recordData.getFragment(key);
87
-
88
- // Regardless of whether being called as a setter or getter, the fragment
89
- // may not be initialized yet, in which case the data will contain a
90
- // raw response or a stashed away fragment
91
-
92
- // If we already have a processed fragment in _data and our current fragment is
93
- // null simply reuse the one from data. We can be in this state after a rollback
94
- // for example
95
- if (!fragment && isFragment(data)) {
96
- fragment = data;
97
- // Else initialize the fragment
98
- } else if (data && data !== fragment) {
99
- if (fragment) {
100
- // It's important to update internal model data to fragment before calling
101
- // setFragmentData since updating the fragment can trigger calls to
102
- // notifyPropertyChange which can in turn call setupFragment again, creating
103
- // an infinite recursion loop. Since it's a reference anyway doing the
104
- // assignation sooner has no side effect
105
- internalModel._recordData._data[key] = fragment;
106
- setFragmentData(fragment, data);
107
- } else {
108
- fragment = createFragment(store, declaredModelName, record, key, options, data);
109
- internalModel._recordData._data[key] = fragment;
110
- }
111
-
112
- } else {
113
- // Handle the adapter setting the fragment to null
114
- fragment = data;
115
- }
116
-
117
- return fragment;
118
- }
119
-
120
- function setFragmentValue(record, key, fragment, value) {
121
- let store = record.store;
122
- let internalModel = internalModelFor(record);
123
-
124
- assert(`You can only assign \`null\`, an object literal or a '${declaredModelName}' fragment instance to this property`, value === null || typeOf(value) === 'object' || isInstanceOfType(store.modelFor(declaredModelName), value));
125
-
126
- if (!value) {
127
- fragment = null;
128
- } else if (isFragment(value)) {
129
- // A fragment instance was given, so just replace the existing value
130
- fragment = setFragmentOwner(value, record, key);
131
- } else if (!fragment) {
132
- // A property hash was given but the property was null, so create a new
133
- // fragment with the data
134
- fragment = createFragment(store, declaredModelName, record, key, options, value);
135
- } else {
136
- // The fragment already exists and a property hash is given, so just set
137
- // its values and let the state machine take care of the dirtiness
138
- setProperties(fragment, value);
139
-
140
- return fragment;
141
- }
142
-
143
- if (internalModel._recordData._data[key] !== fragment) {
144
- fragmentDidDirty(record, key, fragment);
145
- } else {
146
- fragmentDidReset(record, key);
147
- }
148
-
149
- return fragment;
150
- }
151
-
152
- return fragmentProperty(metaType, options, setupFragment, setFragmentValue);
70
+ return fragmentProperty(metaType, options, declaredModelName);
153
71
  }
154
72
 
155
73
  /**
@@ -197,14 +115,8 @@ function fragmentArray(modelName, options) {
197
115
 
198
116
  let metaType = metaTypeFor('fragment-array', modelName, options);
199
117
 
200
- return fragmentArrayProperty(metaType, options, function createFragmentArray(record, key) {
201
- return FragmentArray.create({
202
- type: modelName,
203
- options: options,
204
- name: key,
205
- owner: record
206
- });
207
- });
118
+ // fragmentArrayProperty takes type, options, modelName, isFragmentArray
119
+ return fragmentArrayProperty(metaType, options, modelName, true);
208
120
  }
209
121
 
210
122
  /**
@@ -245,16 +157,11 @@ function array(type, options) {
245
157
 
246
158
  let metaType = metaTypeFor('array', type);
247
159
 
248
- return fragmentArrayProperty(metaType, options, function createStatefulArray(record, key) {
249
- return StatefulArray.create({
250
- options: options,
251
- name: key,
252
- owner: record
253
- });
254
- });
160
+ // fragmentArrayProperty takes type, options, modelName, isArray, isFragmentArray
161
+ return fragmentArrayProperty(metaType, options, null, false);
255
162
  }
256
163
 
257
- function fragmentProperty(type, options, setupFragment, setFragmentValue) {
164
+ function fragmentProperty(type, options, declaredModelName, isArray = false, isFragmentArray = false) {
258
165
  options = options || {};
259
166
 
260
167
  let meta = {
@@ -266,68 +173,32 @@ function fragmentProperty(type, options, setupFragment, setFragmentValue) {
266
173
 
267
174
  return computed({
268
175
  get(key) {
176
+ let fragment;
269
177
  let internalModel = internalModelFor(this);
270
- let fragment = setupFragment(this.store, this, key);
271
-
272
- return internalModel._recordData.setFragment(key, fragment);
178
+ if (isArray) {
179
+ fragment = internalModel._recordData.getFragmentArray(key, options, declaredModelName, this, isFragmentArray);
180
+ } else {
181
+ fragment = internalModel._recordData.getFragment(key, options, declaredModelName, this);
182
+ }
183
+ return fragment;
273
184
  },
274
185
  set(key, value) {
186
+ let fragment;
275
187
  let internalModel = internalModelFor(this);
276
- let fragment = setupFragment(this.store, this, key);
277
-
278
- fragment = setFragmentValue(this, key, fragment, value);
279
-
280
- return internalModel._recordData.setFragment(key, fragment);
188
+ if (isArray) {
189
+ fragment = internalModel._recordData.getFragmentArray(key, options, declaredModelName, this, isFragmentArray);
190
+ fragment = internalModel._recordData.setFragmentArrayValue(key, fragment, value, this, declaredModelName, options, isFragmentArray);
191
+ } else {
192
+ fragment = internalModel._recordData.getFragment(key, options, declaredModelName, this);
193
+ fragment = internalModel._recordData.setFragmentValue(key, fragment, value, this, declaredModelName, options);
194
+ }
195
+ return internalModel._recordData.fragments[key] = fragment;
281
196
  }
282
197
  }).meta(meta);
283
198
  }
284
199
 
285
- function fragmentArrayProperty(metaType, options, createArray) {
286
- function setupFragmentArray(store, record, key) {
287
- let internalModel = internalModelFor(record);
288
- let data = getWithDefault(internalModel, key, options, 'array');
289
- let fragments = internalModel._recordData.getFragment(key) || null;
290
-
291
- // If we already have a processed fragment in _data and our current fragment is
292
- // null simply reuse the one from data. We can be in this state after a rollback
293
- // for example
294
- if (data instanceof StatefulArray && !fragments) {
295
- fragments = data;
296
- // Create a fragment array and initialize with data
297
- } else if (data && data !== fragments) {
298
- fragments || (fragments = createArray(record, key));
299
- internalModel._recordData._data[key] = fragments;
300
- fragments.setupData(data);
301
- } else {
302
- // Handle the adapter setting the fragment array to null
303
- fragments = data;
304
- }
305
-
306
- return fragments;
307
- }
308
-
309
- function setFragmentValue(record, key, fragments, value) {
310
- let internalModel = internalModelFor(record);
311
-
312
- if (isArray(value)) {
313
- fragments || (fragments = createArray(record, key));
314
- fragments.setObjects(value);
315
- } else if (value === null) {
316
- fragments = null;
317
- } else {
318
- assert('A fragment array property can only be assigned an array or null');
319
- }
320
-
321
- if (internalModel._recordData._data[key] !== fragments || (fragments && get(fragments, 'hasDirtyAttributes'))) {
322
- fragmentDidDirty(record, key, fragments);
323
- } else {
324
- fragmentDidReset(record, key);
325
- }
326
-
327
- return fragments;
328
- }
329
-
330
- return fragmentProperty(metaType, options, setupFragmentArray, setFragmentValue);
200
+ function fragmentArrayProperty(metaType, options, declaredModelName, isFragmentArray) {
201
+ return fragmentProperty(metaType, options, declaredModelName, true, isFragmentArray);
331
202
  }
332
203
 
333
204
  /**
@@ -357,47 +228,12 @@ function fragmentOwner() {
357
228
  return computed(function() {
358
229
  assert('Fragment owner properties can only be used on fragments.', isFragment(this));
359
230
 
360
- return internalModelFor(this)._recordData.getOwner();
231
+ return internalModelFor(this)._recordData._owner;
361
232
  }).meta({
362
233
  isFragmentOwner: true
363
234
  }).readOnly();
364
235
  }
365
236
 
366
- // The default value of a fragment is either an array or an object,
367
- // which should automatically get deep copied
368
- function getDefaultValue(record, options, type) {
369
- let value;
370
-
371
- if (typeof options.defaultValue === 'function') {
372
- value = options.defaultValue();
373
- } else if ('defaultValue' in options) {
374
- value = options.defaultValue;
375
- } else if (type === 'array') {
376
- value = [];
377
- } else {
378
- return null;
379
- }
380
-
381
- assert(`The fragment's default value must be an ${type}`, (typeOf(value) == type) || (value === null));
382
-
383
- // No need to copy value if it was a function
384
- if (typeof options.defaultValue === 'function') {
385
- return value;
386
- }
387
-
388
- // Create a deep copy of the resulting value to avoid shared reference errors
389
- return copy(value, true);
390
- }
391
-
392
- // Returns the value of the property or the default propery
393
- function getWithDefault(internalModel, key, options, type) {
394
- if (key in internalModel._recordData._data) {
395
- return internalModel._recordData._data[key];
396
- } else {
397
- return getDefaultValue(internalModel, options, type);
398
- }
399
- }
400
-
401
237
  export {
402
238
  fragment,
403
239
  fragmentArray,
package/addon/ext.js CHANGED
@@ -1,17 +1,20 @@
1
1
  import { assert } from '@ember/debug';
2
- import Store from 'ember-data/store';
3
- import Model from 'ember-data/model';
2
+ import Store from '@ember-data/store';
3
+ import Model from '@ember-data/model';
4
+ // eslint-disable-next-line ember/use-ember-data-rfc-395-imports
4
5
  import { coerceId, RecordData, InternalModel, normalizeModelName } from 'ember-data/-private';
5
- import JSONSerializer from 'ember-data/serializers/json';
6
+ import JSONSerializer from '@ember-data/serializer/json';
6
7
  import FragmentRootState from './states';
8
+ import FragmentRecordData from './record-data';
7
9
  import {
8
10
  internalModelFor,
9
11
  default as Fragment
10
12
  } from './fragment';
11
- import FragmentArray from './array/fragment';
12
13
  import { isPresent } from '@ember/utils';
13
14
  import { computed } from '@ember/object';
14
15
  import { getOwner } from '@ember/application';
16
+ import { assign } from '@ember/polyfills';
17
+ import { lte, gte } from 'ember-compatibility-helpers';
15
18
 
16
19
  function serializerForFragment(owner, normalizedModelName) {
17
20
  let serializer = owner.lookup(`serializer:${normalizedModelName}`);
@@ -39,7 +42,7 @@ function serializerForFragment(owner, normalizedModelName) {
39
42
  const InternalModelPrototype = InternalModel.prototype;
40
43
  const RecordDataPrototype = RecordData.prototype;
41
44
 
42
- Object.assign(RecordDataPrototype, {
45
+ assign(RecordDataPrototype, {
43
46
  eachFragmentKey(fn) {
44
47
  this._fragments = this._fragments || Object.create({});
45
48
  Object.keys(this._fragments).forEach(fn);
@@ -82,6 +85,11 @@ Object.assign(RecordDataPrototype, {
82
85
  },
83
86
 
84
87
  didCommit(data) {
88
+ if (this._attributes) {
89
+ // willCommit was never called
90
+ this._inFlightAttributes = this._attributes;
91
+ this._attributes = null;
92
+ }
85
93
  this._isNew = false;
86
94
  if (data) {
87
95
  if (data.relationships) {
@@ -95,15 +103,14 @@ Object.assign(RecordDataPrototype, {
95
103
  data = data.attributes;
96
104
 
97
105
  // Notify fragments that the record was committed
98
- this.eachFragmentKeyValue((key, fragment) => fragment._adapterDidCommit(data[key]));
106
+ this.eachFragmentKeyValue((key, fragment) => fragment._didCommit(data[key]));
99
107
  } else {
100
- this.eachFragmentKeyValue((key, fragment) => fragment._adapterDidCommit());
108
+ this.eachFragmentKeyValue((key, fragment) => fragment._didCommit());
101
109
  }
102
110
 
103
111
  const changedKeys = this._changedKeys(data);
104
112
 
105
- Object.assign(this._data, this.__inFlightAttributes, this._attributes, data);
106
- this._attributes = null;
113
+ assign(this._data, this._inFlightAttributes, data);
107
114
  this._inFlightAttributes = null;
108
115
  this._updateChangedAttributes();
109
116
 
@@ -116,6 +123,19 @@ Object.assign(RecordDataPrototype, {
116
123
  @namespace DS
117
124
  */
118
125
  Store.reopen({
126
+ createRecordDataFor(type, id, lid, storeWrapper) {
127
+ let identifier;
128
+ if (lte('ember-data', '3.13.0')) {
129
+ throw new Error('This version of Ember Data Model Fragments is incompatible with Ember Data Versions below 3.13. See matrix at https://github.com/lytics/ember-data-model-fragments#compatibility for details.');
130
+ }
131
+ if (gte('ember-data', '3.15.0')) {
132
+ identifier = this.identifierCache.getOrCreateRecordIdentifier({ type, id, lid });
133
+ } else {
134
+ identifier = { type, id, clientId: lid };
135
+ }
136
+ return new FragmentRecordData(identifier, storeWrapper);
137
+ },
138
+
119
139
  /**
120
140
  Create a new fragment that does not yet have an owner record.
121
141
  The properties passed to this method are set on the newly created
@@ -138,16 +158,22 @@ Store.reopen({
138
158
  */
139
159
  createFragment(modelName, props) {
140
160
  assert(`The '${modelName}' model must be a subclass of MF.Fragment`, this.isFragment(modelName));
141
-
142
- let internalModel = new InternalModel(modelName, null, this, getOwner(this).container);
161
+ let internalModel;
162
+ if (gte('ember-data', '3.15.0')) {
163
+ const identifier = this.identifierCache.createIdentifierForNewRecord({ type: modelName });
164
+ internalModel = this._internalModelForResource(identifier);
165
+ } else {
166
+ let identifier = { type: modelName, id: `${Math.random()}`, lid: `${Math.random()}` };
167
+ internalModel = this._internalModelForResource(identifier);
168
+ }
143
169
 
144
170
  // Re-wire the internal model to use the fragment state machine
145
171
  internalModel.currentState = FragmentRootState.empty;
146
172
 
147
173
  internalModel._recordData._name = null;
148
- internalModel._recordData.setOwner(null);
174
+ internalModel._recordData._owner = null;
149
175
 
150
- internalModel.loadedData();
176
+ internalModel.send('loadedData');
151
177
 
152
178
  let fragment = internalModel.getRecord();
153
179
 
@@ -191,7 +217,7 @@ Store.reopen({
191
217
 
192
218
  if (this.isFragment(normalizedModelName)) {
193
219
  return serializerForFragment(owner, normalizedModelName);
194
- } else {
220
+ } else {
195
221
  return this._super(...arguments);
196
222
  }
197
223
  }
@@ -202,29 +228,14 @@ Store.reopen({
202
228
  @namespace DS
203
229
  */
204
230
  Model.reopen({
231
+
205
232
  willDestroy() {
206
233
  this._super(...arguments);
207
234
 
208
235
  let internalModel = internalModelFor(this);
209
- let key, fragment;
210
236
 
211
237
  // destroy the current state
212
- for (key in internalModel._recordData._fragments) {
213
- fragment = internalModel._recordData._fragments[key];
214
- if (fragment) {
215
- fragment.destroy();
216
- delete internalModel._recordData._fragments[key];
217
- }
218
- }
219
-
220
- // destroy the original state
221
- for (key in internalModel._recordData._data) {
222
- fragment = internalModel._recordData._data[key];
223
- if (fragment instanceof Fragment || fragment instanceof FragmentArray) {
224
- fragment.destroy();
225
- delete internalModel._recordData._data[key];
226
- }
227
- }
238
+ internalModel._recordData.resetFragments();
228
239
  }
229
240
  });
230
241
 
@@ -259,14 +270,6 @@ function decorateMethod(obj, name, fn) {
259
270
  };
260
271
  }
261
272
 
262
- function decorateMethodBefore(obj, name, fn) {
263
- const originalFn = obj[name];
264
- obj[name] = function() {
265
- fn.apply(this, arguments);
266
- return originalFn.apply(this, arguments);
267
- };
268
- }
269
-
270
273
  /**
271
274
  Override parent method to snapshot fragment attributes before they are
272
275
  passed to the `DS.Model#serialize`.
@@ -281,6 +284,7 @@ decorateMethod(InternalModelPrototype, 'createSnapshot', function createFragment
281
284
  // If the attribute has a `_createSnapshot` method, invoke it before the
282
285
  // snapshot gets passed to the serializer
283
286
  if (attr && typeof attr._createSnapshot === 'function') {
287
+
284
288
  attrs[key] = attr._createSnapshot();
285
289
  }
286
290
  });
@@ -288,39 +292,6 @@ decorateMethod(InternalModelPrototype, 'createSnapshot', function createFragment
288
292
  return snapshot;
289
293
  });
290
294
 
291
- decorateMethod(InternalModelPrototype, 'adapterDidError', function adapterDidErrorFragments(returnValue, args) {
292
- const error = args[0] || Object.create(null);
293
- this._recordData.eachFragmentKeyValue((key, value) => {
294
- value._adapterDidError(error);
295
- });
296
- });
297
-
298
- decorateMethod(InternalModelPrototype, 'rollbackAttributes', function rollbackFragments() {
299
- this._recordData.eachFragmentKeyValue((key, value) => {
300
- value.rollbackAttributes();
301
- });
302
- });
303
-
304
- decorateMethod(RecordDataPrototype, 'changedAttributes', function changedAttributes(diffData) {
305
- this.eachFragmentKey((name) => {
306
- if (name in this._attributes) {
307
- diffData[name] = [
308
- diffData[name][0],
309
- diffData[name][1] ? diffData[name][1]._record : diffData[name][1]
310
- ];
311
- }
312
- });
313
- return diffData;
314
- });
315
-
316
- decorateMethodBefore(RecordDataPrototype, 'willCommit', function willCommit() {
317
- this.eachFragmentKeyValue((key, fragment) => fragment._flushChangedAttributes());
318
- });
319
-
320
- decorateMethodBefore(RecordDataPrototype, 'commitWasRejected', function commitWasRejected() {
321
- this.eachFragmentKeyValue((key, fragment) => fragment._adapterDidError());
322
- });
323
-
324
295
  /**
325
296
  @class JSONSerializer
326
297
  @namespace DS