diff --git a/addon/index.js b/addon/index.js index 77724e2d..40f592f4 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,6 +1,6 @@ import { assert } from '@ember/debug'; import { dependentKeyCompat } from '@ember/object/compat'; -import { BufferedChangeset } from 'validated-changeset'; +import { BufferedChangeset, Change, isChange } from 'validated-changeset'; import ArrayProxy from '@ember/array/proxy'; import ObjectProxy from '@ember/object/proxy'; import { notifyPropertyChange } from '@ember/object'; @@ -10,6 +10,7 @@ import { tracked } from '@glimmer/tracking'; import { get as safeGet, set as safeSet } from '@ember/object'; import { macroCondition, dependencySatisfies, importSync } from '@embroider/macros'; +const { keys, getOwnPropertySymbols } = Object; const CHANGES = '_changes'; const PREVIOUS_CONTENT = '_previousContent'; const CONTENT = '_content'; @@ -196,6 +197,38 @@ export class EmberChangeset extends BufferedChangeset { return this; } + + /** + * Gets the changes of the changeset to take a snapshot of them + * + * @override + * @see https://github.com/validated-changeset/validated-changeset/blob/main/src/index.ts#L673 + */ + getChangesForSnapshot(changes) { + return keys(changes).reduce((newObj, key) => { + newObj[key] = isChange(changes[key]) ? changes[key] : this.getChangesForSnapshot(changes[key]); + return newObj; + }, {}); + } + + /** + * Gets the changes of the changeset from the snapshot as well as + * takes nested keys and recursively makes their values into `Change` objects. + * + * @override + * @see https://github.com/validated-changeset/validated-changeset/blob/main/src/index.ts#L699 + */ + getChangesFromSnapshot(value) { + if (isChange(value)) { + const VALUE = getOwnPropertySymbols(value)[0]; + return new Change(value[VALUE]); + } + + return keys(value).reduce((newObj, key) => { + newObj[key] = this.getChangesFromSnapshot(value[key]); + return newObj; + }, {}); + } } /** diff --git a/tests/unit/changeset-test.js b/tests/unit/changeset-test.js index ac3ac24c..968fcf06 100644 --- a/tests/unit/changeset-test.js +++ b/tests/unit/changeset-test.js @@ -3,7 +3,7 @@ import { Changeset, EmberChangeset, Changeset as ChangesetFactory } from 'ember- import { settled } from '@ember/test-helpers'; import { module, test, todo } from 'qunit'; import { setupTest } from 'ember-qunit'; -import { lookupValidator } from 'validated-changeset'; +import { lookupValidator, Change } from 'validated-changeset'; import EmberObject, { get, set, setProperties } from '@ember/object'; @@ -2427,7 +2427,7 @@ module('Unit | Utility | changeset', function (hooks) { dummyChangeset.set('password', false); let snapshot = dummyChangeset.snapshot(); let expectedResult = { - changes: { name: 'Pokemon Go', password: false }, + changes: { name: new Change('Pokemon Go'), password: new Change(false) }, errors: { password: { validation: ['foo', 'bar'], value: false } }, }; @@ -2458,6 +2458,37 @@ module('Unit | Utility | changeset', function (hooks) { ); }); + test('#restore restores a snapshot of the changeset when nested value is object', function (assert) { + class Country { + constructor(id, name) { + this.id = id; + this.name = name; + } + } + + var us = new Country('US', 'United States'); + var prk = new Country('PRK', 'North Korea'); + var aus = new Country('AUS', 'Australia'); + + let user = { + name: 'Adam', + address: { country: us }, + }; + let dummyChangeset = Changeset(user); + + dummyChangeset.set('name', 'Jim Bob'); + dummyChangeset.set('address.country', prk); + let snapshot1 = dummyChangeset.snapshot(); + + dummyChangeset.set('name', 'Poteto'); + dummyChangeset.set('address.country', aus); + + dummyChangeset.restore(snapshot1); + + assert.strictEqual(get(dummyChangeset, 'change.name'), 'Jim Bob', 'should restore changes'); + assert.deepEqual(get(dummyChangeset, 'change.address.country'), prk, 'should restore nested changes'); + }); + /** * #cast */