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

Commit 0d3dbe4

Browse files
committed
Implement asynchronous pipline of validation
1 parent 03ce0ff commit 0d3dbe4

File tree

1 file changed

+96
-39
lines changed

1 file changed

+96
-39
lines changed

packages/canner/src/hocs/validation.js

Lines changed: 96 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,70 @@
33
import * as React from 'react';
44
import RefId from 'canner-ref-id';
55
import Ajv from 'ajv';
6-
import {isEmpty, isArray, isPlainObject, isFunction, get} from 'lodash';
6+
import {isEmpty, isObject, isArray, isPlainObject, isFunction, get} from 'lodash';
77
import type {HOCProps} from './types';
88

99
type State = {
1010
error: boolean,
1111
errorInfo: Array<any>
1212
}
1313

14+
const _isRequiredValidation = async (value) => {
15+
const valid = Boolean(value)
16+
return {
17+
error: !valid,
18+
errorInfo: !valid ? [{message: 'should be required'}] :[]
19+
}
20+
}
21+
22+
const checkValidation = (validation) => {
23+
return (isObject(validation) && !isEmpty(validation))
24+
}
25+
26+
const checkSchema = (schema) => {
27+
return (isObject(schema) && !isEmpty(schema) )
28+
}
29+
const checkValidator = (validator) => {
30+
return (isFunction(validator))
31+
}
32+
33+
const _schemaValidation = (schema, errorMessage) => {
34+
const ajv = new Ajv();
35+
const validate = ajv.compile(schema);
36+
return async (value) => {
37+
try {
38+
const error = !validate(value)
39+
const errorInfo = error ? ( {message: errorMessage} || validate.error ) : []
40+
return {
41+
error,
42+
errorInfo
43+
}
44+
}
45+
catch(err){
46+
return {
47+
error: true,
48+
errorInfo: [{message: err}]
49+
}
50+
}
51+
52+
}
53+
}
54+
const _customizedValidator = (validator) => async (value) => {
55+
try {
56+
const errorMessage = await validator(value)
57+
return {
58+
error: Boolean(errorMessage),
59+
errorInfo: [{message: errorMessage}]
60+
}
61+
}
62+
catch(err) {
63+
return {
64+
error: true,
65+
errorInfo: [{message: err}]
66+
}
67+
}
68+
}
69+
1470
export default function withValidation(Com: React.ComponentType<*>) {
1571
return class ComponentWithValidation extends React.Component<HOCProps, State> {
1672
key: string;
@@ -35,52 +91,53 @@ export default function withValidation(Com: React.ComponentType<*>) {
3591
this.removeOnDeploy();
3692
}
3793

38-
validate = async (result: any) => {
39-
const {refId, validation = {}, required = false} = this.props;
40-
// required
41-
const paths = refId.getPathArr().slice(1);
42-
const {value} = getValueAndPaths(result.data, paths);
43-
const isRequiredValid = required ? Boolean(value) : true;
94+
handleValidationResult = (results) => {
4495

45-
const {schema, validator, errorMessage} = validation;
46-
let validate = null;
96+
let error = false;
97+
let errorInfo = [];
4798

48-
// Ajv validation
49-
if(schema && !isEmpty(schema)) {
50-
const ajv = new Ajv();
51-
validate = ajv.compile(schema);
52-
}
53-
// custom validator
54-
const reject = message => ({error: true, message});
55-
const validatorResult = (validator && isFunction(validator)) && validator(value, reject);
56-
57-
let customValid = !(validatorResult && validatorResult.error);
58-
59-
// if value is empty, should not validate with ajv
60-
if (customValid && isRequiredValid && (!(value && isFunction(validate)) || validate(value))) {
61-
this.setState({
62-
error: false,
63-
errorInfo: []
64-
});
65-
return result;
99+
for(let index = 0; index < results.length; index++) {
100+
error = error || results[index].error
101+
errorInfo = errorInfo.concat(results[index].errorInfo);
66102
}
67-
68-
69-
const errorInfo = []
70-
.concat(isRequiredValid ? [] : {
71-
message: 'should be required'
72-
})
73-
.concat(validate.errors ? (errorMessage ? {message: errorMessage} : validate.errors) : [])
74-
.concat(customValid ? [] : validatorResult);
75103

76104
this.setState({
77-
error: true,
78-
errorInfo: errorInfo
105+
error,
106+
errorInfo
79107
});
108+
109+
return {
110+
error,
111+
errorInfo
112+
}
113+
}
114+
115+
validate = async (result: any) => {
116+
const {refId, required = false, validation} = this.props;
117+
// required
118+
const paths = refId.getPathArr().slice(1);
119+
const {value} = getValueAndPaths(result.data, paths);
120+
const promiseQueue = [];
121+
122+
// check whether value is required in first step
123+
if(required) {
124+
promiseQueue.push(_isRequiredValidation);
125+
}
126+
127+
// skip validation if object validation is undefined or empty
128+
if(checkValidation(validation)) {
129+
const {schema, errorMessage, validator} = validation;
130+
if(checkSchema(schema)) {
131+
promiseQueue.pop(_schemaValidation(schema, errorMessage)(value));
132+
}
133+
if(checkValidator(validator)) {
134+
promiseQueue.pop(_customizedValidator(validator)(value));
135+
}
136+
}
137+
const ValidationResult = await Promise.all(promiseQueue);
80138
return {
81139
...result,
82-
error: true,
83-
errorInfo: errorInfo
140+
...this.handleValidationResult(ValidationResult)
84141
}
85142
}
86143

0 commit comments

Comments
 (0)