ember-data-model-fragments 7.0.1 → 7.0.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.
@@ -2,17 +2,17 @@
2
2
  "solution": {
3
3
  "ember-data-model-fragments": {
4
4
  "impact": "patch",
5
- "oldVersion": "7.0.0",
6
- "newVersion": "7.0.1",
5
+ "oldVersion": "7.0.2",
6
+ "newVersion": "7.0.3",
7
7
  "tagName": "latest",
8
8
  "constraints": [
9
9
  {
10
10
  "impact": "patch",
11
- "reason": "Appears in changelog section :house: Internal"
11
+ "reason": "Appears in changelog section :bug: Bug Fix"
12
12
  }
13
13
  ],
14
14
  "pkgJSONPath": "./package.json"
15
15
  }
16
16
  },
17
- "description": "## Release (2026-02-06)\n\n* ember-data-model-fragments 7.0.1 (patch)\n\n#### :house: Internal\n* `ember-data-model-fragments`\n * [#509](https://github.com/adopted-ember-addons/ember-data-model-fragments/pull/509) Update release-plan ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### Committers: 1\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n"
17
+ "description": "## Release (2026-02-27)\n\n* ember-data-model-fragments 7.0.3 (patch)\n\n#### :bug: Bug Fix\n* `ember-data-model-fragments`\n * [#514](https://github.com/adopted-ember-addons/ember-data-model-fragments/pull/514) Guard fragment access on destroyed/unloaded records ([@deanmarano](https://github.com/deanmarano))\n\n#### Committers: 1\n- Dean Marano ([@deanmarano](https://github.com/deanmarano))\n"
18
18
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## Release (2026-02-27)
4
+
5
+ * ember-data-model-fragments 7.0.3 (patch)
6
+
7
+ #### :bug: Bug Fix
8
+ * `ember-data-model-fragments`
9
+ * [#514](https://github.com/adopted-ember-addons/ember-data-model-fragments/pull/514) Guard fragment access on destroyed/unloaded records ([@deanmarano](https://github.com/deanmarano))
10
+
11
+ #### Committers: 1
12
+ - Dean Marano ([@deanmarano](https://github.com/deanmarano))
13
+
14
+ ## Release (2026-02-11)
15
+
16
+ * ember-data-model-fragments 7.0.2 (patch)
17
+
18
+ #### :bug: Bug Fix
19
+ * `ember-data-model-fragments`
20
+ * [#512](https://github.com/adopted-ember-addons/ember-data-model-fragments/pull/512) Prevent newly created fragments from being marked deleted after save ([@deanmarano](https://github.com/deanmarano))
21
+
22
+ #### Committers: 1
23
+ - Dean Marano ([@deanmarano](https://github.com/deanmarano))
24
+
3
25
  ## Release (2026-02-06)
4
26
 
5
27
  * ember-data-model-fragments 7.0.1 (patch)
@@ -55,6 +55,9 @@ export default function array(type, options) {
55
55
  // eslint-disable-next-line ember/require-computed-property-dependencies
56
56
  return computed({
57
57
  get(key) {
58
+ if (this.isDestroying || this.isDestroyed) {
59
+ return null;
60
+ }
58
61
  const identifier = recordIdentifierFor(this);
59
62
  const cache = this.store.cache;
60
63
  if (cache.getFragment(identifier, key) === null) {
@@ -64,6 +64,9 @@ export default function fragmentArray(type, options) {
64
64
  // eslint-disable-next-line ember/require-computed-property-dependencies
65
65
  return computed({
66
66
  get(key) {
67
+ if (this.isDestroying || this.isDestroyed) {
68
+ return null;
69
+ }
67
70
  const identifier = recordIdentifierFor(this);
68
71
  const cache = this.store.cache;
69
72
  if (cache.getFragment(identifier, key) === null) {
@@ -1,5 +1,6 @@
1
1
  import { assert } from '@ember/debug';
2
2
  import { computed } from '@ember/object';
3
+ import { isDestroying, isDestroyed } from '@ember/destroyable';
3
4
  import { isFragment } from '../fragment';
4
5
  import { recordIdentifierFor } from '@ember-data/store';
5
6
 
@@ -27,7 +28,15 @@ import { recordIdentifierFor } from '@ember-data/store';
27
28
  @return {Attribute}
28
29
  */
29
30
  export default function fragmentOwner() {
30
- return computed('store.{_instanceCache,cache}', function () {
31
+ // No dependent keys: the value is invalidated via notifyPropertyChange in
32
+ // setFragmentOwner(). Omitting dependent keys also avoids Ember's
33
+ // "Attempted to access the computed ... on a destroyed object" assertion
34
+ // when a fragment is torn down.
35
+ // eslint-disable-next-line ember/require-computed-property-dependencies
36
+ return computed(function () {
37
+ if (isDestroying(this) || isDestroyed(this)) {
38
+ return null;
39
+ }
31
40
  assert(
32
41
  'Fragment owner properties can only be used on fragments.',
33
42
  isFragment(this),
@@ -60,8 +60,12 @@ export default function fragment(type, options) {
60
60
  options,
61
61
  };
62
62
 
63
+ // eslint-disable-next-line ember/require-computed-property-dependencies -- isDestroying/isDestroyed are guards, not dependencies
63
64
  return computed('store.{_instanceCache,cache}', {
64
65
  get(key) {
66
+ if (this.isDestroying || this.isDestroyed) {
67
+ return null;
68
+ }
65
69
  const identifier = recordIdentifierFor(this);
66
70
  const cache = this.store.cache;
67
71
  const fragmentIdentifier = cache.getFragment(identifier, key);
@@ -1161,14 +1161,16 @@ export default class FragmentStateManager {
1161
1161
  }
1162
1162
  }
1163
1163
 
1164
+ // Upsert the committed values as new canonical state BEFORE rollback.
1165
+ // This clears isNew on the inner cache, which prevents rollbackAttrs
1166
+ // from incorrectly setting isDeleted=true for newly created fragments.
1167
+ // (rollbackAttrs treats isNew records as "discard new record" and marks
1168
+ // them deleted, but here we want to transition them to saved state.)
1169
+ innerCache.upsert(identifier, { attributes: commitAttrs }, false);
1170
+
1164
1171
  // Rollback the inner cache to clear dirty/in-flight tracking
1165
1172
  innerCache.rollbackAttrs(identifier);
1166
1173
 
1167
- // Push the committed values as the new canonical state
1168
- if (Object.keys(commitAttrs).length > 0) {
1169
- innerCache.upsert(identifier, { attributes: commitAttrs }, false);
1170
- }
1171
-
1172
1174
  // Re-apply any new dirty changes made during in-flight
1173
1175
  for (const [key, value] of Object.entries(newDirtyAttrs)) {
1174
1176
  innerCache.setAttr(identifier, key, value);
package/addon/fragment.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { get, computed } from '@ember/object';
2
2
  import Ember from 'ember';
3
+ import { isDestroying, isDestroyed } from '@ember/destroyable';
3
4
  // DS.Model gets munged to add fragment support, which must be included first
4
5
  import { Model } from './ext';
5
6
  import { copy } from './util/copy';
@@ -115,6 +116,9 @@ const Fragment = Model.extend(Ember.Comparable, {
115
116
  },
116
117
 
117
118
  toStringExtension() {
119
+ if (isDestroying(this) || isDestroyed(this)) {
120
+ return '';
121
+ }
118
122
  const identifier = recordIdentifierFor(this);
119
123
  const owner = this.store.cache.getFragmentOwner(identifier);
120
124
  return owner ? `owner(${owner.ownerIdentifier?.id})` : '';
@@ -125,6 +129,9 @@ const Fragment = Model.extend(Ember.Comparable, {
125
129
  ember-data 4.12+ doesn't call toStringExtension in Model.toString().
126
130
  */
127
131
  toString() {
132
+ if (isDestroying(this) || isDestroyed(this)) {
133
+ return `<fragment(destroyed)>`;
134
+ }
128
135
  const identifier = recordIdentifierFor(this);
129
136
  const extension = this.toStringExtension();
130
137
  const extensionStr = extension ? `:${extension}` : '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-data-model-fragments",
3
- "version": "7.0.1",
3
+ "version": "7.0.3",
4
4
  "description": "Ember Data addon to support nested JSON documents",
5
5
  "keywords": [
6
6
  "ember-addon",