Skip to content
This repository has been archived by the owner on Apr 24, 2023. It is now read-only.

Commit

Permalink
Implement asynchronous pipline of validation
Browse files Browse the repository at this point in the history
  • Loading branch information
Mosoc committed May 14, 2019
1 parent 03ce0ff commit 0d3dbe4
Showing 1 changed file with 96 additions and 39 deletions.
135 changes: 96 additions & 39 deletions packages/canner/src/hocs/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,70 @@
import * as React from 'react';
import RefId from 'canner-ref-id';
import Ajv from 'ajv';
import {isEmpty, isArray, isPlainObject, isFunction, get} from 'lodash';
import {isEmpty, isObject, isArray, isPlainObject, isFunction, get} from 'lodash';
import type {HOCProps} from './types';

type State = {
error: boolean,
errorInfo: Array<any>
}

const _isRequiredValidation = async (value) => {
const valid = Boolean(value)
return {
error: !valid,
errorInfo: !valid ? [{message: 'should be required'}] :[]
}
}

const checkValidation = (validation) => {
return (isObject(validation) && !isEmpty(validation))
}

const checkSchema = (schema) => {
return (isObject(schema) && !isEmpty(schema) )
}
const checkValidator = (validator) => {
return (isFunction(validator))
}

const _schemaValidation = (schema, errorMessage) => {
const ajv = new Ajv();
const validate = ajv.compile(schema);
return async (value) => {
try {
const error = !validate(value)
const errorInfo = error ? ( {message: errorMessage} || validate.error ) : []
return {
error,
errorInfo
}
}
catch(err){
return {
error: true,
errorInfo: [{message: err}]
}
}

}
}
const _customizedValidator = (validator) => async (value) => {
try {
const errorMessage = await validator(value)
return {
error: Boolean(errorMessage),
errorInfo: [{message: errorMessage}]
}
}
catch(err) {
return {
error: true,
errorInfo: [{message: err}]
}
}
}

export default function withValidation(Com: React.ComponentType<*>) {
return class ComponentWithValidation extends React.Component<HOCProps, State> {
key: string;
Expand All @@ -35,52 +91,53 @@ export default function withValidation(Com: React.ComponentType<*>) {
this.removeOnDeploy();
}

validate = async (result: any) => {
const {refId, validation = {}, required = false} = this.props;
// required
const paths = refId.getPathArr().slice(1);
const {value} = getValueAndPaths(result.data, paths);
const isRequiredValid = required ? Boolean(value) : true;
handleValidationResult = (results) => {

const {schema, validator, errorMessage} = validation;
let validate = null;
let error = false;
let errorInfo = [];

// Ajv validation
if(schema && !isEmpty(schema)) {
const ajv = new Ajv();
validate = ajv.compile(schema);
}
// custom validator
const reject = message => ({error: true, message});
const validatorResult = (validator && isFunction(validator)) && validator(value, reject);

let customValid = !(validatorResult && validatorResult.error);

// if value is empty, should not validate with ajv
if (customValid && isRequiredValid && (!(value && isFunction(validate)) || validate(value))) {
this.setState({
error: false,
errorInfo: []
});
return result;
for(let index = 0; index < results.length; index++) {
error = error || results[index].error
errorInfo = errorInfo.concat(results[index].errorInfo);
}


const errorInfo = []
.concat(isRequiredValid ? [] : {
message: 'should be required'
})
.concat(validate.errors ? (errorMessage ? {message: errorMessage} : validate.errors) : [])
.concat(customValid ? [] : validatorResult);

this.setState({
error: true,
errorInfo: errorInfo
error,
errorInfo
});

return {
error,
errorInfo
}
}

validate = async (result: any) => {
const {refId, required = false, validation} = this.props;
// required
const paths = refId.getPathArr().slice(1);
const {value} = getValueAndPaths(result.data, paths);
const promiseQueue = [];

// check whether value is required in first step
if(required) {
promiseQueue.push(_isRequiredValidation);
}

// skip validation if object validation is undefined or empty
if(checkValidation(validation)) {
const {schema, errorMessage, validator} = validation;
if(checkSchema(schema)) {
promiseQueue.pop(_schemaValidation(schema, errorMessage)(value));
}
if(checkValidator(validator)) {
promiseQueue.pop(_customizedValidator(validator)(value));
}
}
const ValidationResult = await Promise.all(promiseQueue);
return {
...result,
error: true,
errorInfo: errorInfo
...this.handleValidationResult(ValidationResult)
}
}

Expand Down

0 comments on commit 0d3dbe4

Please sign in to comment.