Skip to content

Commit

Permalink
Collect errors correctly (#399)
Browse files Browse the repository at this point in the history
  • Loading branch information
snewcomer authored Jan 11, 2020
1 parent cf2c4eb commit 41f0ef0
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 14 deletions.
19 changes: 7 additions & 12 deletions addon/-private/validated-changeset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
isEqual
} from '@ember/utils';
import Change from 'ember-changeset/-private/change';
import { getKeyValues } from 'ember-changeset/utils/get-key-values';
import { getKeyValues, getKeyErrorValues } from 'ember-changeset/utils/get-key-values';
import { notifierForEvent } from 'ember-changeset/-private/evented';
import Err from 'ember-changeset/-private/err';
import normalizeObject from 'ember-changeset/utils/normalize-object';
Expand Down Expand Up @@ -147,20 +147,15 @@ export class BufferedChangeset implements IChangeset {
return getKeyValues(obj);
}

// TODO: iterate and find all leaf errors
// can only provide leaf key
/**
* @property errors
* @type {Array}
*/
get errors() {
let obj = this[ERRORS];

function transform(e: Err) {
return { value: e.value, validation: e.validation };
}

return keys(obj).map(key => {
let { value, validation } = transform(obj[key]);

return { key, value, validation };
});
// [{ key, validation, value }, ...]
return getKeyErrorValues(obj);
}

get change() {
Expand Down
4 changes: 2 additions & 2 deletions addon/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ export interface ChangesetDef {
_runningValidations: RunningValidations,
_bareChanges: { [s: string]: any },

changes: any, // { key: string; value: any; }[], //ComputedProperty<object[], object[]>,
errors: { key: string; value: any; validation: ValidationErr | ValidationErr[] }[], //ComputedProperty<object[], object[]>,
changes: object[],
errors: object[],
error: object,
change: object,
data: object,
Expand Down
30 changes: 30 additions & 0 deletions addon/utils/get-key-values.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import isObject from './is-object';
import Err from '../-private/err';

/**
* traverse through target and return leaf nodes with `value` property and key as 'person.name'
Expand All @@ -25,3 +26,32 @@ export function getKeyValues<T extends Record<string, any>>(obj: T, keysUpToValu

return map;
}

/**
* traverse through target and return leaf nodes with `value` property and key as 'person.name'
*
* @method getKeyErrorValues
* @return {Array} [{ key: 'person.name', validation: '', value: '' }]
*/
export function getKeyErrorValues<T extends Record<string, any>>(
obj: T,
keysUpToValue: string[] = []
): object[] {
let map = [];

for (let key in obj) {
keysUpToValue.push(key);

if (obj[key] && isObject(obj[key])) {
if (Object.prototype.hasOwnProperty.call(obj[key], 'value') && obj[key] as any instanceof Err) {
map.push({ key: keysUpToValue.join('.'), validation: obj[key].validation, value: obj[key].value });
// stop collecting keys
keysUpToValue = [];
} else if (key !== 'value') {
map.push(...getKeyErrorValues(obj[key], keysUpToValue));
}
}
}

return map;
}
20 changes: 20 additions & 0 deletions tests/unit/changeset-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,26 @@ module('Unit | Utility | changeset', function(hooks) {
/**
* #errors
*/
test('#errors returns the error object and keeps changes', async function(assert) {
let dummyChangeset = new Changeset(dummyModel, dummyValidator);
let expectedResult = [{ key: 'name', validation: 'too short', value: 'a' }];
dummyChangeset.set('name', 'a');

assert.deepEqual(dummyChangeset.errors, expectedResult, 'should return errors object');
assert.deepEqual(dummyChangeset.get('errors'), expectedResult, 'should return nested errors');
assert.deepEqual(dummyChangeset.get('errors.name'), expectedResult.name, 'should return nested errors');
assert.deepEqual(dummyChangeset.change, { name: 'a' }, 'should return change object');
assert.deepEqual(dummyChangeset.get('change.name'), 'a', 'should return nested change');
assert.deepEqual(dummyChangeset.get('change').name, 'a', 'should return nested change');
});

test('can get nested values in the errors object', function(assert) {
let dummyChangeset = new Changeset(dummyModel, dummyValidator);
dummyChangeset.set('org.usa.ny', '');

let expectedErrors = [{ key: 'org.usa.ny', validation: 'must be present', value: '' }];
assert.deepEqual(dummyChangeset.get('errors'), expectedErrors, 'should return errors object for `org.usa.ny` key');
});

/**
* #changes
Expand Down

0 comments on commit 41f0ef0

Please sign in to comment.