Skip to content

Commit

Permalink
Fix: @attr defaultValue() results should persist after initialization (
Browse files Browse the repository at this point in the history
…#9355)

* defaultValue function results should persist after initialization

* defaultValue function results should persist after initialization

* clear default values on patch changes

* defaultValue caching test

---------

Co-authored-by: christophersansone <chris@voltage.io>
  • Loading branch information
christophersansone and christophersansone committed May 10, 2024
1 parent 97b4331 commit b87ebd2
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 2 deletions.
23 changes: 21 additions & 2 deletions packages/json-api/src/-private/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ interface CachedResource {
id: string | null;
remoteAttrs: Record<string, Value | undefined> | null;
localAttrs: Record<string, Value | undefined> | null;
defaultAttrs: Record<string, Value | undefined> | null;
inflightAttrs: Record<string, Value | undefined> | null;
changes: Record<string, [Value | undefined, Value]> | null;
errors: JsonApiError[] | null;
Expand All @@ -90,6 +91,7 @@ function makeCache(): CachedResource {
id: null,
remoteAttrs: null,
localAttrs: null,
defaultAttrs: null,
inflightAttrs: null,
changes: null,
errors: null,
Expand Down Expand Up @@ -1036,6 +1038,7 @@ export default class JSONAPICache implements Cache {
// we report as `isEmpty` during teardown.
cached.localAttrs = null;
cached.remoteAttrs = null;
cached.defaultAttrs = null;
cached.inflightAttrs = null;

const relatedIdentifiers = _allRelatedIdentifiers(storeWrapper, identifier);
Expand Down Expand Up @@ -1096,11 +1099,18 @@ export default class JSONAPICache implements Cache {
return cached.inflightAttrs[attr];
} else if (cached.remoteAttrs && attr in cached.remoteAttrs) {
return cached.remoteAttrs[attr];
} else if (cached.defaultAttrs && attr in cached.defaultAttrs) {
return cached.defaultAttrs[attr];
} else {
const attrSchema = this._capabilities.schema.fields(identifier).get(attr);

upgradeCapabilities(this._capabilities);
return getDefaultValue(attrSchema, identifier, this._capabilities._store);
const defaultValue = getDefaultValue(attrSchema, identifier, this._capabilities._store);
if (typeof attrSchema?.options?.defaultValue === 'function') {
cached.defaultAttrs = cached.defaultAttrs || (Object.create(null) as Record<string, Value>);
cached.defaultAttrs[attr] = defaultValue;
}
return defaultValue;
}
}

Expand Down Expand Up @@ -1133,6 +1143,10 @@ export default class JSONAPICache implements Cache {
delete cached.changes![attr];
}

if (cached.defaultAttrs && attr in cached.defaultAttrs) {
delete cached.defaultAttrs[attr];
}

this._capabilities.notifyChange(identifier, 'attributes', attr);
}

Expand Down Expand Up @@ -1195,6 +1209,7 @@ export default class JSONAPICache implements Cache {
}

cached.inflightAttrs = null;
cached.defaultAttrs = null;

if (cached.errors) {
cached.errors = null;
Expand Down Expand Up @@ -1635,7 +1650,7 @@ function setupRelationships(
}

function patchLocalAttributes(cached: CachedResource): boolean {
const { localAttrs, remoteAttrs, inflightAttrs, changes } = cached;
const { localAttrs, remoteAttrs, inflightAttrs, defaultAttrs, changes } = cached;
if (!localAttrs) {
cached.changes = null;
return false;
Expand All @@ -1657,6 +1672,10 @@ function patchLocalAttributes(cached: CachedResource): boolean {
delete localAttrs[attr];
delete changes![attr];
}

if (defaultAttrs && attr in defaultAttrs) {
delete defaultAttrs[attr];
}
}
return hasAppliedPatch;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -491,4 +491,77 @@ module('Integration | @ember-data/json-api Cache.put(<ResourceDataDocument>)', f
'We can fetch more included data from the cache'
);
});

test('generated default values are retained', function (assert) {
const store = new TestStore();
let i = 0;

store.registerSchema(
new TestSchema<'user'>({
user: {
attributes: {
name: {
kind: 'attribute',
name: 'name',
type: null,
options: {
defaultValue: () => {
i++;
return `Name ${i}`;
},
},
},
},
relationships: {},
},
})
);

store._run(() => {
store.cache.put({
content: {
data: {
type: 'user',
id: '1',
attributes: {},
},
},
}) as SingleResourceDataDocument;
});
const identifier = store.identifierCache.getOrCreateRecordIdentifier({ type: 'user', id: '1' });

const name1 = store.cache.getAttr(identifier, 'name');
assert.equal(name1, 'Name 1', 'The default value was generated');
const name2 = store.cache.getAttr(identifier, 'name');
assert.equal(name2, 'Name 1', 'The default value was cached');

store.cache.setAttr(identifier, 'name', 'Chris');
const name3 = store.cache.getAttr(identifier, 'name');
assert.equal(name3, 'Chris', 'The value was updated');

store.cache.setAttr(identifier, 'name', null);
const name4 = store.cache.getAttr(identifier, 'name');
assert.equal(name4, null, 'Null was set and maintained');

store.cache.rollbackAttrs(identifier);
const name5 = store.cache.getAttr(identifier, 'name');
assert.equal(name5, 'Name 2', 'The default value was regenerated');

store._run(() => {
store.cache.put({
content: {
data: {
type: 'user',
id: '1',
attributes: {
name: 'Tomster',
},
},
},
}) as SingleResourceDataDocument;
});

const name6 = store.cache.getAttr(identifier, 'name');
assert.equal(name6, 'Tomster', 'The value was updated on put');
});
});

0 comments on commit b87ebd2

Please sign in to comment.