Skip to content

Commit

Permalink
rollbackInvalid & rollbackProperty functions (#179)
Browse files Browse the repository at this point in the history
  • Loading branch information
XaserAcheron authored and snewcomer committed Jul 30, 2018
1 parent 12b5e36 commit ad6d928
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 1 deletion.
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ Be sure to call `validate()` on the `changeset` before saving or committing chan
+ [`save`](#save)
+ [`merge`](#merge)
+ [`rollback`](#rollback)
+ [`rollbackInvalid`](#rollbackInvalid)
+ [`rollbackProperty`](#rollbackProperty)
+ [`validate`](#validate)
+ [`addError`](#adderror)
+ [`pushErrors`](#pusherrors)
Expand Down Expand Up @@ -521,14 +523,41 @@ Note that both changesets `A` and `B` are not destroyed by the merge, so you mig

#### `rollback`

Rollsback all unsaved changes and resets all errors.
Rolls back all unsaved changes and resets all errors.

```js
changeset.rollback(); // returns changeset
```

**[⬆️ back to top](#api)**

#### `rollbackInvalid`

Rolls back all invalid unsaved changes and resets all errors. Valid changes will be kept on the changeset.

```js
changeset.rollbackInvalid(); // returns changeset
```

**[⬆️ back to top](#api)**

#### `rollbackProperty`

Rolls back unsaved changes for the specified property only. All other changes will be kept on the changeset.

```js
// user = { firstName: "Jim", lastName: "Bob" };
let changeset = new Changeset(user);
changeset.set('firstName', 'Jimmy');
changeset.set('lastName', 'Fallon');
changeset.rollbackProperty('lastName'); // returns changeset
changeset.execute();
user.get('firstName'); // "Jimmy"
user.get('lastName'); // "Bob"
```

**[⬆️ back to top](#api)**

#### `validate`

Validates all or a single field on the changeset. This will also validate the property on the underlying object, and is a useful method if you require the changeset to validate immediately on render.
Expand Down
30 changes: 30 additions & 0 deletions addon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ export type ChangesetDef = {|
_notifyVirtualProperties: (?Array<string>) => void,
_rollbackKeys: () => Array<string>,
rollback: () => ChangesetDef,
rollbackInvalid: () => ChangesetDef,
rollbackProperty: () => ChangesetDef,
save: (Object) => Promise<ChangesetDef | mixed>,
merge: (ChangesetDef) => ChangesetDef,
validate: (string | void) => (Promise<null> | Promise<mixed | ErrLike<mixed>> | Promise<Array<mixed | ErrLike<mixed>>>),
Expand Down Expand Up @@ -404,6 +406,34 @@ export function changeset(
return this;
},

/**
* Discards any errors, keeping only valid changes.
*
* @public
* @chainable
* @return {Changeset}
*/
rollbackInvalid() {
this._notifyVirtualProperties();
set(this, ERRORS, {});

return this;
},

/**
* Discards changes/errors for the specified properly only.
*
* @public
* @chainable
* @return {Changeset}
*/
rollbackProperty(key) {
this._deleteKey(CHANGES, key);
this._deleteKey(ERRORS, key);

return this;
},

/**
* Validates the changeset immediately against the validationMap passed in.
* If no key is passed into this method, it will validate all fields on the
Expand Down
68 changes: 68 additions & 0 deletions tests/unit/changeset-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,74 @@ test('#rollback resets valid state', function(assert) {
assert.ok(get(dummyChangeset, 'isValid'), 'should be valid');
});

test('#rollbackInvalid clears errors and keeps valid values', function(assert) {
let dummyChangeset = new Changeset(dummyModel, dummyValidator);
let expectedChanges = [
{ key: 'firstName', value: 'foo' },
{ key: 'lastName', value: 'bar' }
];
let expectedErrors = [{ key: 'name', validation: 'too short', value: '' }];
dummyChangeset.set('firstName', 'foo');
dummyChangeset.set('lastName', 'bar');
dummyChangeset.set('name', '');

assert.deepEqual(get(dummyChangeset, 'changes'), expectedChanges, 'precondition');
assert.deepEqual(get(dummyChangeset, 'errors'), expectedErrors, 'precondition');
dummyChangeset.rollbackInvalid();
assert.deepEqual(get(dummyChangeset, 'changes'), expectedChanges, 'should not rollback');
assert.deepEqual(get(dummyChangeset, 'errors'), [], 'should rollback');
});

test('#rollbackInvalid resets valid state', function(assert) {
let dummyChangeset = new Changeset(dummyModel, dummyValidator);
dummyChangeset.set('name', 'a');

assert.ok(get(dummyChangeset, 'isInvalid'), 'should be invalid');
dummyChangeset.rollbackInvalid();
assert.ok(get(dummyChangeset, 'isValid'), 'should be valid');
});

test('#rollbackProperty restores old value for specified property only', function(assert) {
set(dummyModel, 'firstName', 'Jim');
set(dummyModel, 'lastName', 'Bob');
let dummyChangeset = new Changeset(dummyModel, dummyValidator);
let expectedChanges = [
{ key: 'lastName', value: 'bar' }
];
dummyChangeset.set('firstName', 'foo');
dummyChangeset.set('lastName', 'bar');

dummyChangeset.rollbackProperty('firstName');
assert.deepEqual(get(dummyChangeset, 'changes'), expectedChanges, 'should rollback single property');
});

test('#rollbackProperty clears errors for specified property', function(assert) {
let dummyChangeset = new Changeset(dummyModel, dummyValidator);
let expectedChanges = [
{ key: 'firstName', value: 'foo' },
{ key: 'lastName', value: 'bar' }
];
let expectedErrors = [{ key: 'name', validation: 'too short', value: '' }];
dummyChangeset.set('firstName', 'foo');
dummyChangeset.set('lastName', 'bar');
dummyChangeset.set('name', '');

assert.deepEqual(get(dummyChangeset, 'changes'), expectedChanges, 'precondition');
assert.deepEqual(get(dummyChangeset, 'errors'), expectedErrors, 'precondition');
dummyChangeset.rollbackProperty('name');
assert.deepEqual(get(dummyChangeset, 'changes'), expectedChanges, 'should not rollback');
assert.deepEqual(get(dummyChangeset, 'errors'), [], 'should rollback');
});

test('#rollbackProperty resets valid state', function(assert) {
let dummyChangeset = new Changeset(dummyModel, dummyValidator);
dummyChangeset.set('name', 'a');

assert.ok(get(dummyChangeset, 'isInvalid'), 'should be invalid');
dummyChangeset.rollbackProperty('name');
assert.ok(get(dummyChangeset, 'isValid'), 'should be valid');
});

test('observing #rollback values', function(assert) {
let res;
let changeset = new Changeset(dummyModel, dummyValidator);
Expand Down

0 comments on commit ad6d928

Please sign in to comment.