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

Commit

Permalink
validation on scalar and customize validation and required
Browse files Browse the repository at this point in the history
  • Loading branch information
abz53378 committed Jul 26, 2018
1 parent 1029c1b commit 337aa79
Show file tree
Hide file tree
Showing 14 changed files with 192 additions and 25 deletions.
6 changes: 5 additions & 1 deletion docs/canner.schema.js
Expand Up @@ -80,7 +80,11 @@ export default <root connector={connector}>
<Posts columns={postColumns} />
<Users columns={userColumns} searchComponent={TabsFilter} />
<array keyName="test" title="array" uiParams={{columns: [{title: 'title', dataIndex: 'title'}]}}>
<string keyName="title" title="title"/>
<string keyName="title" title="title"
validation={{
maxLength: 2
}}
/>
<OnDeploy
keyName="test1"
title="OnDeploy Demo"
Expand Down
2 changes: 1 addition & 1 deletion docs/schema/realWorld/home.schema.js
Expand Up @@ -9,7 +9,7 @@ export default ({attributes}) => <object keyName="home" title="Home" description
</Block>
<Block title="Header">
<object keyName="header">
<string keyName="title" title="Title"/>
<string keyName="title" title="Title" validation={{maxLength: 4}}/>
<string keyName="subTitle" title="Subtitle"/>
<object keyName="desc" title="Description" ui="editor"/>
</object>
Expand Down
1 change: 1 addition & 0 deletions docs/schema/realWorld/posts.schema.js
Expand Up @@ -26,6 +26,7 @@ const Posts = ({attributes}) => <array keyName="posts" ui="tableRoute" title="po
}]
}}
ui="singleSelect"
required
/>
</array>

Expand Down
15 changes: 10 additions & 5 deletions docs/schema/realWorld/users.schema.js
Expand Up @@ -45,16 +45,21 @@ const Users = ({attributes}) => (
}]
}]} />
</toolbar>
<string keyName="name" title="name"/>
<string keyName="email" title="Email"/>
<number keyName="age" title="Age"/>
<string keyName="name" title="name" required validation={{
validator: {
validate: name => name === '123',
message: 'Should be 123'
}
}}/>
<string keyName="email" title="Email" required validation={{format: 'email'}}/>
<number keyName="age" title="Age" validation={{minimum: 18}}/>
<boolean keyName="isLogin" title="Logined" />
<array keyName="hobbies" title="Hobbies" ui="tag"/>
<array keyName="images" title="Images">
<array keyName="images" title="Images" validation={{minItems: 2}}>
<string keyName="url" title="Url" />
</array>
<object keyName="status" title="Status">
<boolean keyName="draft" title="Draft"/>
<boolean keyName="draft" title="Draft" required/>
<boolean keyName="stick" title="Stick"/>
</object>
<relation ui="multipleSelect" keyName="posts" relation={{to: 'posts', type: 'toMany'}} title="Posts" uiParams={{
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -78,6 +78,7 @@
"webpack-dev-server": "^3.1.0"
},
"dependencies": {
"ajv": "^6.5.2",
"apollo-boost": "^0.1.4",
"bson-objectid": "^1.2.2",
"canner-compiler": "^0.1.6",
Expand Down
2 changes: 1 addition & 1 deletion src/components/Generator.js
Expand Up @@ -157,7 +157,7 @@ export default class Generator extends React.PureComponent<Props, State> {
loading: Loading,
});
}
component = this.wrapByHOC(component, ['title', 'onDeploy', 'deploy', 'request', 'relation', 'query', 'cache', 'route', 'id', 'context', 'errorCatch'] || []);
component = this.wrapByHOC(component, ['title', 'onDeploy', 'validation', 'deploy', 'request', 'relation', 'query', 'cache', 'route', 'id', 'context', 'errorCatch'] || []);
}

if (!component) {
Expand Down
11 changes: 10 additions & 1 deletion src/components/Provider.js
Expand Up @@ -146,7 +146,16 @@ export default class Provider extends React.PureComponent<Props, State> {
actions = removeIdInCreateArray(actions);
const mutation = objectToQueries(actionToMutation(actions[0]), false);
const variables = actionsToVariables(actions, schema);
variables.payload = this.onDeploy(key, fromJS(variables.payload)).toJS();
const queryVariables = this.query.getVairables();
const query = gql`${this.query.toGQL(key)}`;
const cachedData = client.readQuery({query, variables: queryVariables});
const mutatedData = cachedData[key];
const {error} = this.onDeploy(key, fromJS(mutatedData));
if (error) {
return Promise.reject();
}

// variables.payload = data.toJS();
return client.mutate({
mutation: gql`${mutation}`,
variables
Expand Down
20 changes: 15 additions & 5 deletions src/hocs/cache.js
Expand Up @@ -177,12 +177,22 @@ export default function withCache(Com: React.ComponentType<*>, options: {
if (!this.actionManager) {
return deploy(key, id);
}
const originData = this.state[key];
let actions = this.actionManager.getActions(key, id);
actions = actions.map(action => {
const {key, value} = action.payload;
action.payload.value = this._executeOnDeployCallback(key, value);
return action;
})
const mutatedData = actions.reduce((result, action) => {
return mutate(result, action);
}, originData);
const {error} = this._executeOnDeployCallback(key, mutatedData.get(key));
if (error) {
return Promise.reject();
}
// actions = actions.map(action => {
// const {key, value} = action.payload;
// hasError = hasError || error;
// action.payload.value = data;
// return action;
// });

// $FlowFixMe
this.actionManager.removeActions(key, id);
request(actions);
Expand Down
4 changes: 3 additions & 1 deletion src/hocs/index.js
Expand Up @@ -10,6 +10,7 @@ import containerRouter from './containerRouter';
import onDeploy from './onDeploy';
import context from './connectContext';
import errorCatch from './errorCatch';
import validation from './validation';

export default {
errorCatch,
Expand All @@ -24,5 +25,6 @@ export default {
title,
containerRouter,
onDeploy,
context
context,
validation
};
17 changes: 10 additions & 7 deletions src/hocs/onDeploy.js
Expand Up @@ -46,16 +46,19 @@ export default function withOndeploy(Com: React.ComponentType<*>) {
return onDeploy(arg1, callback);
} else {
// first arguments is a function
return onDeploy(this.key, v => {
return onDeploy(this.key, result => {
let restPathArr = refId.getPathArr();
if (this.id) {
restPathArr = restPathArr.slice(2);
} else {
// if (this.id) {
// restPathArr = restPathArr.slice(2);
// } else {
restPathArr = restPathArr.slice(1);
// }
const {paths, value} = getValueAndPaths(result.data, restPathArr);
return {
...result,
// $FlowFixMe
data: result.data.setIn(paths, arg1(value))
}
const {paths, value} = getValueAndPaths(v, restPathArr);
// $FlowFixMe
return v.setIn(paths, arg1(value));
});
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/hocs/route.js
Expand Up @@ -52,6 +52,11 @@ export default function withRoute(Com: React.ComponentType<*>) {
deploying: false
});
goTo(routes[0]);
})
.catch(() => {
this.setState({
deploying: false
});
});
}

Expand Down
128 changes: 128 additions & 0 deletions src/hocs/validation.js
@@ -0,0 +1,128 @@
// @flow

import * as React from 'react';
import RefId from 'canner-ref-id';
import {Map, List} from 'immutable';
import Ajv from 'ajv';
import {isEmpty} from 'lodash';

type Props = {
refId: RefId,
keyName: string,
routes: Array<string>,
pattern: string,
onDeploy: (key: string, callback: any => any) => string,
removeOnDeploy: (key: string, id: ?string) => void,
rootValue: any,
validation: Object,
};

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

export default function withValidation(Com: React.ComponentType<*>) {
return class ComponentWithValition extends React.Component<Props, State> {
key: string;
id: ?string;
state = {
error: false,
errorInfo: []
}

componentDidMount() {
const {refId, validation = {}, onDeploy, required = false} = this.props;
const key = refId.getPathArr()[0];
const ajv = new Ajv();
const validate = ajv.compile(validation);
if (isEmpty(validation) && !required) {
// no validation
return;
}
let paths = refId.getPathArr();
const {validator = {validate: () => true, message: ''}} = validation;
paths = paths.slice(1);
onDeploy(key, result => {
const {value} = getValueAndPaths(result.data, paths);
const isRequiredValid = required ? Boolean(value) : true;
const customValid = validator.validate(value);
if (customValid && isRequiredValid && validate((value && value.toJS) ? value.toJS() : value)) {
this.setState({
error: false,
errorInfo: []
});
return result;
}
const errorInfo = [].concat(isRequiredValid ? []:{message: 'Required Field!'})
.concat(validate.errors || [])
.concat(customValid ? []:{message: validator.message});
this.setState({
error: true,
errorInfo: errorInfo
});
return {
...result,
error: true,
errorInfo: errorInfo
}
});
}

render() {
const {error, errorInfo} = this.state;
return <React.Fragment>
<Com {...this.props}/>
{
error && <span style={{color: 'red'}}>{errorInfo[0].message}</span>
}
</React.Fragment>
}
};
}

export function splitRefId({
refId,
rootValue,
pattern
}: {
refId: RefId,
rootValue: any,
pattern: string
}) {
const [key, index] = refId.getPathArr();
let id;
if (pattern.startsWith('array')) {
id = rootValue.getIn([key, index, 'id']);
}
return {
key,
id
}
}

export function getValueAndPaths(value: Map<string, *>, idPathArr: Array<string>) {
return idPathArr.reduce((result: any, key: string) => {
let v = result.value;
let paths = result.paths;
if (Map.isMap(v)) {
if (v.has('edges') && v.has('pageInfo')) {
v = v.getIn(['edges', key, 'node']);
paths = paths.concat(['edges', key, 'node']);
} else {
v = v.get(key);
paths = paths.concat(key);
}
} else if (List.isList(v)) {
v = v.get(key);
paths = paths.concat(key);
}
return {
value: v,
paths
}
}, {
value,
paths: []
});
}
3 changes: 1 addition & 2 deletions src/onDeployManager/index.js
Expand Up @@ -17,8 +17,7 @@ export class OnDeployManager {
value: any
}): any => {
const callbacks = this.findCallback(key);
// console.log(value, callbacks, callbacks.reduce((result, callback) => callback(result), value));
return callbacks.reduce((result, callback) => callback(result), value);
return callbacks.reduce((result, callback) => callback(result), {data: value});
}

findCallback = (key: string): Array<any> => {
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Expand Up @@ -1559,7 +1559,7 @@ ajv@^5.1.0, ajv@^5.2.3, ajv@^5.3.0:
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.3.0"

ajv@^6.1.0:
ajv@^6.1.0, ajv@^6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.2.tgz#678495f9b82f7cca6be248dd92f59bff5e1f4360"
dependencies:
Expand Down

0 comments on commit 337aa79

Please sign in to comment.