Skip to content

Commit

Permalink
Merge 59d7bc6 into 6032d15
Browse files Browse the repository at this point in the history
  • Loading branch information
mprzodala committed Oct 28, 2018
2 parents 6032d15 + 59d7bc6 commit a0dcf1c
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 12 deletions.
22 changes: 16 additions & 6 deletions README.md
Expand Up @@ -13,7 +13,7 @@
1. [Types](#types)
1. [Example of custom validator](#example-of-custom-validator)
1. [Example of additional validator](#example-of-additional-validator)
1. [Schema definition Example](#schema-definition-example)
1. [Example of Schema definition](#example-of-schema-definition)
1. [Example of schema in schema](#example-of-schema-in-schema)
1. [Schema keys description](#schema-keys-description)
1. [Custom validation messages](#custom-validation-messages)
Expand Down Expand Up @@ -112,12 +112,13 @@ results.then((errors) => {
| setError | key: String, message: String, index: Number | Set error on field |
| setModelError | path: String, message: String | Set error on model tree node |
| getDefaultValues | | Get default values for model using defined schema |
| getField | name: String | Get field schema |
| getField | | Get all fields schemas |
| getField | name: String | Get field properties extended by parent schema instance (`parentSchema`) |
| getFields | | Get all fields schemas |
| oneOfTypes | types: Array of types | Give posibility to validate one of type (Static method) |
| pick | fieldsToPick: [String] | Get fields from schema by keys |
| omit | fieldsToOmit: [String] | Get fields from schema and omit fieldsToOmit |
| extend | fieldsToExtend: [String] | Extend schema by new fields or overwrite them |
| extendFieldValidators | fieldName: String, validator: { validator: Function, errorMessage: String or Function } | Extend field validators |
| registerType | type: SchemaType | Register new schema type |
| isValidatorRegistred | validatorName: String | Check model validator exists in schema |
| addValidator | validatorName: String, validator: Function(model: Object, schema: instance of Schema) | Add model validator |
Expand All @@ -139,12 +140,21 @@ results.then((errors) => {
| SchemaType | You can register new schema type that has name, validator, validator when field is required (requiredValidator) and getDefaultValue |
| [OneOfTypesAbove] | This type check value is array of type |

### Custom validator attributes

| Name | Description |
|---|---|
| value | Field value |
| field | Field properties |
| model | Validated object |
| schema | Field parent schema instance |

#### Example of custom validator
This validator will check two fields. You can validate one field on base another field.
```js
const validateIfFieldTitleIsFilled = (minLength, message) => ({
validator: (value, fieldSchema, formData) => {
if(formData.title){
validator: (value, field, model, schema) => {
if (model.title) {
return !!value;
}
return true;
Expand Down Expand Up @@ -202,7 +212,7 @@ const validateIfOfAge = () => ({
});
```

### Schema definition Example
### Example of Schema definition

If You want create new schema You must put object to constructor with information about object keys names and type of value on key.

Expand Down
39 changes: 33 additions & 6 deletions src/Schema.js
Expand Up @@ -123,7 +123,7 @@ class Schema {
}

getField(name) {
return this.schema[name];
return { ...this.schema[name], parentSchema: this };
}

getFields() {
Expand Down Expand Up @@ -202,6 +202,7 @@ class Schema {
schemaKeys.forEach((key) => {
const value = validatedObject[key];
const fieldSchema = this.schema[key];
const validators = this.getFieldValidators(key);
const isArrayOfType = Array.isArray(fieldSchema.type);
const fieldType = isArrayOfType ? fieldSchema.type[0] : fieldSchema.type;
if (isArrayOfType && this.validateType(Array, value)) {
Expand All @@ -213,7 +214,7 @@ class Schema {
}
this.validateRequired(fieldSchema, value, key);
this.validateCustomValidators({
validators: fieldSchema.validators,
validators,
value,
fieldSchema,
validatedObject,
Expand All @@ -240,11 +241,8 @@ class Schema {
}

validateCustomValidators({ validators, value, fieldSchema, validatedObject, key }) {
if (!validators) {
return;
}
validators.forEach(({ validator, errorMessage }) => {
const results = validator(value, fieldSchema, validatedObject);
const results = validator(value, fieldSchema, validatedObject, this);
if (results instanceof Promise) {
const promise = results.then((result) => {
this.resolveValidatorErrorsForKey(key, errorMessage, result);
Expand Down Expand Up @@ -435,6 +433,35 @@ class Schema {
});
}

getFieldValidators(fieldName) {
return this.schema[fieldName].validators || [];
}

setFieldValidator(fieldName, validator) {
if (!Array.isArray(this.schema[fieldName].validators)) {
this.schema[fieldName].validators = [];
}
this.schema[fieldName].validators.push(validator);
}

extendFieldValidators(fieldName, validator) {
const validators = this.getFieldValidators(fieldName);
if (!validators.length) {
this.setFieldValidator(fieldName, validator);
return;
}
if (
validators.indexOf(validator) > -1 ||
(
validator.id &&
validators.findIndex(validatorItem => validatorItem.id === validator.id) > -1
)
) {
return;
}
this.setFieldValidator(fieldName, validator);
}

registerTypeIfNotExists(type, typeName) {
if (type instanceof SchemaType && typeof this.typesValidators[typeName] !== 'function') {
this.registerType(type);
Expand Down
82 changes: 82 additions & 0 deletions src/Schema.test.js
Expand Up @@ -1013,6 +1013,88 @@ describe('Schema', () => {
property: [customErrorMessage],
});
});

describe('Should extend validators on field', () => {
let fooValidator;
let customValidator;
let schema;
let schemaWithValidators;
beforeEach(() => {
const customErrorMessage = 'foo error';
fooValidator = {
validator: () => false,
errorMessage: () => customErrorMessage,
};
customValidator = {
validator: () => false,
errorMessage: () => customErrorMessage,
};
schema = new Schema({
property: {
type: String,
},
});
schemaWithValidators = new Schema({
property: {
type: String,
validators: [customValidator],
},
});
});

it('when validators property not exist on field', () => {
schema.extendFieldValidators('property', fooValidator);
expect(schema.getFieldValidators('property')).toEqual([fooValidator]);
});

it('when validators property exist on field', () => {
schemaWithValidators.extendFieldValidators('property', fooValidator);
expect(schemaWithValidators.getFieldValidators('property')).toEqual([customValidator, fooValidator]);
});

it('when validators property exist on field and validator has id', () => {
customValidator.id = 'customValidator';
fooValidator.id = 'fooValidator';
schemaWithValidators.extendFieldValidators('property', fooValidator);
expect(schemaWithValidators.getFieldValidators('property')).toEqual([customValidator, fooValidator]);
});
});
describe('Should not extend validators on field', () => {
let fooValidator;
let customValidator;
let schemaWithValidators;
beforeEach(() => {
const customErrorMessage = 'foo error';
fooValidator = {
validator: () => false,
errorMessage: () => customErrorMessage,
};
customValidator = {
validator: () => false,
errorMessage: () => customErrorMessage,
};
schemaWithValidators = new Schema({
property: {
type: String,
validators: [customValidator],
},
});
});

it('when validator exist in validators property', () => {
schemaWithValidators.setFieldValidator = jest.fn();
schemaWithValidators.extendFieldValidators('property', customValidator);
expect(schemaWithValidators.setFieldValidator).not.toBeCalled();
});

it('when validator with the same id exist in validators property', () => {
customValidator.id = 'customValidator';
fooValidator.id = 'customValidator';
schemaWithValidators.setFieldValidator = jest.fn();
schemaWithValidators.extendFieldValidators('property', fooValidator);
expect(schemaWithValidators.setFieldValidator).not.toBeCalled();
});
});
});

describe('Default value', () => {
Expand Down

0 comments on commit a0dcf1c

Please sign in to comment.