diff --git a/packages/midway-decorator/package.json b/packages/midway-decorator/package.json index 1db6717bc20d..c80ccf7e39cf 100644 --- a/packages/midway-decorator/package.json +++ b/packages/midway-decorator/package.json @@ -16,9 +16,11 @@ "dependencies": { "camelcase": "^5.0.0", "debug": "^4.1.1", + "joi": "^14.3.1", "reflect-metadata": "^0.1.13" }, "devDependencies": { + "@types/joi": "^14.3.4", "midway-bin": "^2.0.15", "mm": "^2.5.0" }, diff --git a/packages/midway-decorator/src/annotation/check.ts b/packages/midway-decorator/src/annotation/check.ts new file mode 100644 index 000000000000..e2ddd67ef81f --- /dev/null +++ b/packages/midway-decorator/src/annotation/check.ts @@ -0,0 +1,22 @@ +import 'reflect-metadata'; +import * as joi from 'joi'; +export function Check(failValue?: any) { + return function (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) { + const origin = descriptor.value; + descriptor.value = function (...args: any[]) { + const paramTypes = Reflect.getMetadata('design:paramtypes', target, propertyKey); + for (let i = 0; i < paramTypes.length; i++) { + const item = paramTypes[i]; + const rules = Reflect.getMetadata('rules', item.prototype); + if (rules) { + const result = joi.validate(args[i], rules); + if (result.error) { + return failValue ? failValue : result; + } + } + } + const result = origin.call(this, ...arguments); + return result; + }; + }; +} diff --git a/packages/midway-decorator/src/annotation/index.ts b/packages/midway-decorator/src/annotation/index.ts index cbf4c0fc39d9..bff7a7095482 100644 --- a/packages/midway-decorator/src/annotation/index.ts +++ b/packages/midway-decorator/src/annotation/index.ts @@ -5,3 +5,5 @@ export * from './priority'; export * from './provide'; export * from './schedule'; export * from './pipeline'; +export * from './check'; +export * from './rule'; diff --git a/packages/midway-decorator/src/annotation/rule.ts b/packages/midway-decorator/src/annotation/rule.ts new file mode 100644 index 000000000000..04113b7254fc --- /dev/null +++ b/packages/midway-decorator/src/annotation/rule.ts @@ -0,0 +1,22 @@ +import * as joi from 'joi'; + +export function Rule(rule) { + return function (target: any, propertyKey: string) { + if (!rule.isJoi) { + rule = Reflect.getMetadata('rules', rule.prototype); + if (Reflect.getMetadata('design:type', target, propertyKey).name === 'Array') { + rule = joi.array().items(rule).required(); + } else { + rule = joi.object(rule).required(); + } + } + let rules = Reflect.getMetadata('rules', target); + if (!rules) { + rules = {}; + } + rules[propertyKey] = rule; + Reflect.defineMetadata('rules', rules, target); + }; +} + +export { joi as RuleType }; diff --git a/packages/midway-decorator/test/annotation/check.test.ts b/packages/midway-decorator/test/annotation/check.test.ts new file mode 100644 index 000000000000..334bc54980a3 --- /dev/null +++ b/packages/midway-decorator/test/annotation/check.test.ts @@ -0,0 +1,130 @@ +import { Check, Rule, RuleType } from '../../src'; +import * as assert from 'assert'; +describe('/test/annotation/check.test.ts', () => { + it('check with check', () => { + class UserDTO { + @Rule(RuleType.number().max(10)) + age: number; + } + + class Hello { + @Check() + school(a, data: UserDTO) { + return data; + } + } + const user = { + age: 8 + }; + const result = new Hello().school(1, user); + assert.deepEqual(result, user); + }); + + it('check with no check', () => { + class UserDTO { + @Rule(RuleType.number().max(10)) + age: number; + } + + class Hello { + school(a, data: UserDTO) { + return data; + } + } + const user = { + age: 18 + }; + const result = new Hello().school(1, user); + assert.deepEqual(result, user); + }); + + it('check with check when vo have two level', () => { + class WorldDTO { + @Rule(RuleType.number().max(20)) + age: number; + } + + class UserDTO { + @Rule(RuleType.number().max(10)) + age: number; + + @Rule(WorldDTO) + world: WorldDTO; + } + + class Hello { + @Check() + school(a, data: UserDTO) { + return data; + } + } + const user = { + age: 10, + world: { + age: 18 + } + }; + const result = new Hello().school(1, user); + assert.deepEqual(result, user); + }); + + it('check with check when vo have two level not equal', () => { + class WorldDTO { + @Rule(RuleType.number().max(20)) + age: number; + } + + class UserDTO { + @Rule(RuleType.number().max(10)) + age: number; + + @Rule(WorldDTO) + world: WorldDTO; + } + + class Hello { + @Check() + school(a, data: UserDTO) { + return data; + } + } + const user = { + age: 10, + world: { + age: 22 + } + }; + const result = new Hello().school(1, user); + assert.notDeepEqual(result, user); + }); + + it('check with check when two level and array and not equal', () => { + class WorldDTO { + @Rule(RuleType.number().max(20)) + age: number; + } + + class UserDTO { + @Rule(RuleType.number().max(10)) + age: number; + + @Rule(WorldDTO) + worlds: WorldDTO[]; + } + + class Hello { + @Check() + school(a, data: UserDTO) { + return data; + } + } + const user = { + age: 10, + worlds: [{ + age: 22 + }] + }; + const result = new Hello().school(1, user); + assert.notDeepEqual(result, user); + }); +}); diff --git a/packages/midway-decorator/tsconfig.json b/packages/midway-decorator/tsconfig.json index d6a141da4f32..0d422008bf3e 100644 --- a/packages/midway-decorator/tsconfig.json +++ b/packages/midway-decorator/tsconfig.json @@ -4,6 +4,7 @@ "module": "commonjs", "moduleResolution": "node", "experimentalDecorators": true, + "emitDecoratorMetadata": true, "noImplicitThis": true, "noUnusedLocals": true, "stripInternal": true, @@ -12,9 +13,5 @@ "outDir": "dist", "sourceMap": true }, - "exclude": [ - "dist", - "node_modules", - "test" - ] + "exclude": ["dist", "node_modules", "test"] }