Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ export class BufferedChangeset implements IChangeset {
*
* @method validate
*/
validate(...validationKeys: string[]): Promise<any> {
async validate(...validationKeys: string[]): Promise<any> {
if (keys(this.validationMap as object).length === 0 && !validationKeys.length) {
return Promise.resolve(null);
}
Expand Down
5 changes: 5 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ export type ValidatorMapFunc = {
| Promise<ValidationResult>;
};

export interface ValidatorClass {
validate: ValidatorMapFunc;
[s: string]: any;
};

export type ValidatorMap =
| { [s: string]: ValidatorMapFunc | ValidatorMapFunc[] | any }
| null
Expand Down
5 changes: 4 additions & 1 deletion src/utils/flatten-validations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ function flatten(
): object {
for (let key of keys) {
const value: any = validatorMap[key];
if (isObject(value)) {
if (typeof value.validate === 'function') {
// class with .validate function
obj[key] = value;
} else if (isObject(value)) {
flatten(value, obj, Object.keys(value), [...keysUpToFunction, key]);
} else if (typeof value === 'function') {
const dotSeparatedKeys = [...keysUpToFunction, key].join('.');
Expand Down
8 changes: 6 additions & 2 deletions src/utils/validator-lookup.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import handleMultipleValidations from './handle-multiple-validations';
import isPromise from './is-promise';
import isObject from './is-object';
import { ValidatorAction, ValidatorMapFunc, ValidationResult, ValidatorMap } from '../types';
import { ValidatorAction, ValidatorMapFunc, ValidatorClass, ValidationResult, ValidatorMap } from '../types';
import get from './get-deep';

/**
Expand All @@ -13,7 +13,11 @@ import get from './get-deep';
export default function lookupValidator(validationMap: ValidatorMap): ValidatorAction {
return ({ key, newValue, oldValue, changes, content }) => {
const validations = validationMap || {};
let validator: ValidatorMapFunc | ValidatorMapFunc[] = get(validations, key);
let validator: ValidatorMapFunc | ValidatorMapFunc[] | ValidatorClass = get(validations, key);
const isValidatorClass = (maybeClass: unknown): maybeClass is ValidatorClass => !!(maybeClass as Record<string, any>).validate;
if (validator && isValidatorClass(validator)) {
validator = validator.validate.bind(validator);
}

if (!validator || isObject(validator)) {
return true;
Expand Down
31 changes: 30 additions & 1 deletion test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Changeset, ValidatedChangeset } from '../src';
import { Changeset } from '../src';
import get from '../src/utils/get-deep';
import set from '../src/utils/set-deep';
import lookupValidator from '../src/utils/validator-lookup';
import { prependOnceListener } from 'process';

let dummyModel: any;
const exampleArray: Array<any> = [];
Expand Down Expand Up @@ -2172,6 +2173,34 @@ describe('Unit | Utility | changeset', () => {
expect(myChangeset.isInvalid).toEqual(false);
});

it('#validate/0 works with a class', async () => {
class PersonalValidator {
_validate() {
return 'oh no';
}
async validate(key: string, newValue: unknown) {
return this._validate();
}
}
const validationMap = {
name: new PersonalValidator()
};
dummyModel.name = 'J';
let dummyChangeset = Changeset(dummyModel, lookupValidator(validationMap), validationMap);
dummyChangeset.name = null;

await dummyChangeset.validate();

expect(get(dummyChangeset, 'errors.length')).toBe(1);
expect(get(dummyChangeset, 'error.name.validation')).toEqual('oh no');
expect(dummyChangeset.changes).toEqual([
{
key: 'name',
value: null,
}
]);
});

it('#isInvalid does not trigger validations without validate keys', async () => {
const model = { name: 'o' };
const dummyChangeset = Changeset(model, lookupValidator(dummyValidations));
Expand Down