app/modules/pipeline/validator/validator.js
// @flow
const Joi = require('joi');
const _ = require('lodash');
const utils = require('../../utils/utils');
const GCExp = require('../../exceptions/generic');
const Errors = require('../../exceptions/errors');
const no_subobject = path => async () => {
const e = Errors.InvalidSubobject;
e.path = path;
throw e;
};
/**
* Validator class
*/
class Validator {
_options: Object;
constructor() {
this._options = {
joi: {
allowUnknown: true,
abortEarly: false,
language: {
key: '{{!key}} ',
},
},
custom: {},
};
}
static _isJoi(validator: Joi | Object | Function): boolean {
return utils.hasProperty(validator, 'isJoi') && validator.isJoi;
}
static _compose_joi_errors(errors: Object,
joi_errors: Object, parent_key: ?string) {
if ('details' in joi_errors) {
if (errors === null) errors = {};
joi_errors.details.forEach((obj) => {
const path = parent_key ? `${parent_key}.${obj.path}` : obj.path;
obj.path = path;
if (path in errors) {
errors[path].push(obj);
} else {
errors[path] = [obj];
}
});
}
}
static _compose_custom_errors(errors: Object,
custom_errors: Array<GCExp>, parent_key: ?string) {
custom_errors.forEach((error) => {
const path = parent_key ? `${parent_key}.${error.path}` : error.path;
const e = {
message: error.message,
path,
};
if (path in errors) {
errors[path].push(e);
} else {
errors[path] = [e];
}
});
}
async _validate_with_validator(method: string, object: Object, errors: Object,
validator: Function, key: ?string): Object {
if (Validator._isJoi(validator)) {
const val = Joi.validate(object, validator, this._options.joi);
if (val.error) {
Validator._compose_joi_errors(errors, val.error, key);
}
} else {
try {
await validator(object, method);
} catch (err) {
Validator._compose_custom_errors(errors, [err], key);
}
}
return errors;
}
async validate(object: Object,
validators: Array<Object | Function>, method: string = 'post'): Promise<*> {
let errors = {};
for (const validator of validators) {
if (_.isPlainObject(validator)) {
for (const key in validator) {
const subvalidator = validator[key];
const information = utils.find_value_with_path(object, key.split('.'));
if (information) {
errors = await this._validate_with_validator(method, information, errors, subvalidator, key);
} else {
errors = await this._validate_with_validator(method, information, errors, no_subobject(key));
}
}
} else {
errors = await this._validate_with_validator(method, object,
errors, validator);
}
}
return errors;
}
}
module.exports = Validator;