Skip to content

Commit

Permalink
Merge pull request #11 from rstgroup/addValidatorOnSchema
Browse files Browse the repository at this point in the history
Add validator on schema
  • Loading branch information
mprzodala authored Feb 19, 2018
2 parents e84cc8b + 68a66b8 commit e794158
Show file tree
Hide file tree
Showing 6 changed files with 514 additions and 113 deletions.
94 changes: 74 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,38 @@
# SCHEMA
# FORM SCHEMA VALIDATION

[![Build Status](https://travis-ci.org/rstgroup/form-schema-validation.svg?branch=master)](https://travis-ci.org/rstgroup/form-schema-validation)
[![Coverage Status](https://coveralls.io/repos/github/rstgroup/form-schema-validation/badge.svg?branch=master)](https://coveralls.io/github/rstgroup/form-schema-validation?branch=master)
[![npm](https://img.shields.io/npm/l/form-schema-validation.svg)](https://npmjs.org/package/form-schema-validation)
[![npm](https://img.shields.io/npm/v/form-schema-validation.svg)](https://npmjs.org/package/form-schema-validation)

[1. Installation](#installation)<br />
[2. How to use](#how-to-use)<br />
[3. Constructor](#constructor)<br />
[4. Methods](#methods)<br />
[5. Types](#types)<br />
[6. Example of custom validator](#example-of-custom-validator)<br />
[7. Schema definition Example](#schema-definition-example)<br />
[8. Example of schema in schema](#example-of-schema-in-schema)<br />
[9. Schema keys description](#schema-keys-description)<br />
[10. Custom validation messages](#custom-validation-messages)<br />
[11. Switch of keys validation](#switch-of-keys-validation)<br />

1. [Features](#features)
1. [Installation](#installation)
1. [How to use](#how-to-use)
1. [Constructor](#constructor)
1. [Methods](#methods)
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 in schema](#example-of-schema-in-schema)
1. [Schema keys description](#schema-keys-description)
1. [Custom validation messages](#custom-validation-messages)
1. [Switch of keys validation](#switch-of-keys-validation)

### Features

- sync validation
- async validation (Promise)
- validate object structure
- validate object keys
- validate required fields
- validate optional fields
- validate by type
- validate by custom type
- validate by one of type
- validate field by custom validators
- validate fields relations by custom validators
- validate whole object tree by custom additional validators

### Installation

Expand Down Expand Up @@ -84,23 +100,28 @@ results.then((errors) => {

| Name | Type | Description |
|---|---|---|
| schema | Object | schema will be used when you validate object |
| errorMessages | Object | errors messages that will be displayed on error |
| validateKeys | Boolean | this flag give you posibility to don't validate object keys not defined in schema |
| schema | Object | Schema will be used when you validate object |
| errorMessages | Object | Errors messages that will be displayed on error |
| validateKeys | Boolean | This flag give you posibility to don't validate object keys not defined in schema |

### Methods

| Name | Attributes | Description |
|---|---|---|
| validate | model: Object | Validate Object using defined schema |
| 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 |
| 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 |
| registerType | type: SchemaType | register new schema type |
| 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 |
| 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 |
| removeValidator | validatorName: String | Remove model validator |

### Types

Expand Down Expand Up @@ -132,6 +153,39 @@ const validateIfFieldTitleIsFilled = (minLength, message) => ({
});
```

#### Example of additional validator
Additional validator can set error deep in the objects tree.
```js
const fooSchema = new Schema({
fooStart: {
type: String,
},
fooEnd: {
type: String,
},
});
const modelSchema = new Schema({
foo: {
type: fooSchema,
required: true,
},
});
const dataModel = {
foo: {
fooStart: 'start',
fooEnd: 'end',
},
};

modelSchema.addValidator('fooValidator', (model, schema) => {
if(model.foo.fooStart === 'start') {
schema.setModelError('foo.fooStart', 'my foo error message');
}
});

modelSchema.validate(dataModel);
```

### Example of dynamic error messages

There can be a need for error messages generated based on the validation outcome. In that case a string or array of strings can be returned from the validator function. Error messages returned from validator function have higher priority that the errorMessage property.
Expand Down
34 changes: 17 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 35 additions & 2 deletions src/Schema.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import {
pick,
difference,
arraysDifference,
getFieldType,
getDefaultValueForType,
getDefaultValueFromOptions,
wrapToArray,
getFunctionName,
removeFirstKeyIfNumber,
getErrorIndexFromKeys,
} from './helpers';
import OneOfTypes from './OneOfTypes';
import SchemaType from './SchemaType';
Expand Down Expand Up @@ -50,6 +52,7 @@ class Schema {
this.schema = schema;
this.errors = {};
this.promises = [];
this.additionalValidators = new Set();
this.messages = messages || defaultMessages;
this.validateKeys = validateKeys;

Expand Down Expand Up @@ -148,6 +151,21 @@ class Schema {
this.errors[key].push(message);
}

setModelError(path, message) {
let error = message;
const pathKeys = path.split('.');
const [firstKey, ...keys] = pathKeys;
const errorIndex = getErrorIndexFromKeys(keys);
const field = this.getField(firstKey);
const fieldType = getFieldType(field);
if (fieldType instanceof Schema) {
const childPath = removeFirstKeyIfNumber(keys).join('.');
fieldType.setModelError(childPath, message);
error = fieldType.errors;
}
this.setError(firstKey, error, errorIndex);
}

checkModel(model) {
if (!model) {
this.setError('model', this.messages.modelIsUndefined());
Expand All @@ -160,7 +178,7 @@ class Schema {
if (!this.validateKeys) return;
const modelKeys = Object.keys(model);
const schemaKeys = Object.keys(this.schema);
const keysDiff = difference(modelKeys, schemaKeys);
const keysDiff = arraysDifference(modelKeys, schemaKeys);
if (keysDiff.length > 0) {
keysDiff.forEach((key) => {
this.setError(key, this.messages.notDefinedKey(key));
Expand Down Expand Up @@ -192,6 +210,7 @@ class Schema {
key,
});
});
this.validateAdditionalValidators(model);
}

resolveValidatorErrorsForKey(key, errorMessage, results) {
Expand Down Expand Up @@ -227,6 +246,10 @@ class Schema {
});
}

validateAdditionalValidators(model) {
this.additionalValidators.forEach(validator => validator(model, this));
}

validateRequired(fieldSchema, value, key) {
if (fieldSchema.required) {
const { name } = fieldSchema.type;
Expand Down Expand Up @@ -410,6 +433,16 @@ class Schema {
this.typesRequiredValidators[name] = requiredValidator.bind(this);
}
}

addValidator(validator) {
if (typeof validator === 'function') {
this.additionalValidators.add(validator);
}
}

removeValidator(validator) {
this.additionalValidators.delete(validator);
}
}

export default Schema;
Loading

0 comments on commit e794158

Please sign in to comment.