blow-validate
Version:
Validation for Blow entities.
109 lines (108 loc) • 4.21 kB
JavaScript
;
const Joi = require('joi');
const rxjs_1 = require('rxjs');
const ValidationResult_1 = require('./ValidationResult');
const ValidationError_1 = require('./ValidationError');
const JOIValidations = [
{ validation: 'valid' },
{ validation: 'invalid' },
{ validation: 'required' },
{ validation: 'optional' },
{ validation: 'forbidden' },
{ validation: 'min' },
{ validation: 'max' },
{ validation: 'length' },
{ validation: 'unique' },
{ validation: 'pattern' },
{ validation: 'email' },
{ validation: 'string' },
{ validation: 'number' },
{ validation: 'date' },
{ validation: 'array' },
{ validation: 'object' }
];
const JOI_VALIDATION_OPTIONS = {
abortEarly: false,
allowUnknown: true
};
function isJOIValidation(name) {
return JOIValidations.some(v => v['validation'] === name);
}
class Validator {
constructor(schema) {
this._schema = schema || {};
this._compile();
}
_compile() {
const properties = Object.keys(this._schema);
this._compiledJoiSchema = {};
this._compiledCustomSchema = {};
for (const property of properties) {
const validations = Object.keys(this._schema[property]);
let propertyJoiSchema;
let propertyCustomSchema;
for (const validation of validations) {
if (isJOIValidation(validation)) {
if (!propertyJoiSchema) {
propertyJoiSchema = Joi;
}
let options = this._schema[property][validation];
if (validation === 'email') {
options = undefined;
}
propertyJoiSchema = propertyJoiSchema[validation](options);
}
else {
if (!propertyCustomSchema) {
propertyCustomSchema = [];
}
propertyCustomSchema.push({ name: validation, fn: this._schema[property][validation] });
}
}
if (propertyJoiSchema) {
this._compiledJoiSchema[property] = propertyJoiSchema;
}
if (propertyCustomSchema) {
this._compiledCustomSchema[property] = propertyCustomSchema;
}
}
}
_validateJoi(data) {
if (!Object.keys(this._compiledJoiSchema).length) {
return rxjs_1.Observable.of(new ValidationResult_1.ValidationResult());
}
return rxjs_1.Observable.create(subscriber => {
Joi.validate(data, this._compiledJoiSchema, JOI_VALIDATION_OPTIONS, err => {
if (err) {
const createError = e => ValidationError_1.ValidationError.create({ property: e.path, type: e.type.split('.')[1], message: e.message });
subscriber.next(err.details.map(createError));
}
subscriber.complete();
});
})
.defaultIfEmpty()
.map(errors => new ValidationResult_1.ValidationResult(errors));
}
_validateCustom(data) {
const properties = Object.keys(this._compiledCustomSchema);
if (!properties.length) {
return rxjs_1.Observable.of(ValidationResult_1.ValidationResult.create());
}
return rxjs_1.Observable.from(properties)
.map(property => [property, this._compiledCustomSchema[property]])
.mergeMap(row => rxjs_1.Observable.from(row[1]).mergeMap((v) => v.fn.bind(data)(row[0])))
.filter(e => !!e)
.map(e => ValidationError_1.ValidationError.create({ property: e.path, type: e.type, message: e.message }))
.toArray()
.defaultIfEmpty()
.map(ValidationResult_1.ValidationResult.create);
}
validate(data) {
const mapResults = (joiResult, customResult) => joiResult.merge(customResult);
return rxjs_1.Observable.combineLatest(this._validateJoi(data), this._validateCustom(data), mapResults);
}
static create(schema) {
return new Validator(schema);
}
}
exports.Validator = Validator;