Skip to content

Commit

Permalink
feat: add dto helper
Browse files Browse the repository at this point in the history
  • Loading branch information
czy88840616 committed Mar 8, 2025
1 parent 59ec982 commit 4670339
Show file tree
Hide file tree
Showing 16 changed files with 1,626 additions and 385 deletions.
4 changes: 2 additions & 2 deletions packages/validation-class-validator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@
"@midwayjs/i18n": "workspace:^",
"@midwayjs/validation": "workspace:^",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"class-validator-multi-lang-lite": "^0.140.1"
},
"devDependencies": {
"class-validator": "^0.14.1",
"@midwayjs/core": "workspace:*",
"@midwayjs/mock": "workspace:*"
}
}
}
221 changes: 190 additions & 31 deletions packages/validation-class-validator/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,123 @@ import { plainToInstance } from 'class-transformer';
import {
validateSync,
ValidatorOptions,
getMetadataStorage,
ValidationMetadata,
ValidationTypes,
} from 'class-validator-multi-lang-lite';
import { MidwayI18nServiceSingleton } from '@midwayjs/i18n/dist';
import { MidwayI18nServiceSingleton } from '@midwayjs/i18n';

const EN_I18N_MESSAGES = require('../i18n/en.json');
const ZH_I18N_MESSAGES = require('../i18n/zh.json');
const localeMapping = new Map();

function isFieldOptional(target: any, propertyKey: string): boolean {
const metadataStorage = getMetadataStorage();

// 直接从存储中获取元数据
const allMetadatas = metadataStorage['validationMetadatas'].get(target) || [];

// 过滤出当前属性的元数据
const propertyMetadatas = allMetadatas.filter(
meta => meta.propertyName === propertyKey
);

// 如果没有任何验证规则,则认为是可选的
if (!propertyMetadatas || propertyMetadatas.length === 0) {
return true;
}

// 检查是否有必需的验证规则
const hasRequiredRule = propertyMetadatas.some(
meta =>
(meta.type === 'customValidation' && meta.name === 'isRequired') ||
meta.type === 'nestedValidation'
);

if (hasRequiredRule) {
return false;
}

// 检查是否有可选的验证规则
return propertyMetadatas.some(
meta =>
meta.type === 'isOptional' ||
meta.type === 'conditionalValidation' ||
(meta.type === 'customValidation' && meta.name === 'isOptional')
);
}

function setPropertyMetadata(
target: any,
propertyKey: string,
isOptional: boolean
): void {
const metadataStorage = getMetadataStorage();

// 获取现有的验证元数据
const existingMetadatas =
metadataStorage['validationMetadatas'].get(target) || [];

// 找到所有非 isOptional 和 conditionalValidation 的元数据
const validationMetadatas = existingMetadatas.filter(
meta =>
meta.propertyName === propertyKey &&
meta.type !== 'isOptional' &&
meta.type !== 'conditionalValidation'
);

// 清除该属性的所有现有元数据
const newMetadatas = existingMetadatas.filter(
meta => meta.propertyName !== propertyKey
);
metadataStorage['validationMetadatas'].set(target, newMetadatas);

// 添加基本验证规则
validationMetadatas.forEach(meta => {
const currentMetadatas =
metadataStorage['validationMetadatas'].get(target) || [];
currentMetadatas.push(meta);
metadataStorage['validationMetadatas'].set(target, currentMetadatas);
});

// 添加必需/可选的元数据
const validationMetadata = new ValidationMetadata({
target: target,
propertyName: propertyKey,
type: isOptional
? ValidationTypes.CONDITIONAL_VALIDATION
: ValidationTypes.CUSTOM_VALIDATION,
name: isOptional ? undefined : 'isRequired',
constraints: isOptional
? [(obj: any) => obj[propertyKey] !== undefined]
: [],
validationOptions: {
each: false,
always: !isOptional,
},
});

const currentMetadatas =
metadataStorage['validationMetadatas'].get(target) || [];
currentMetadatas.push(validationMetadata);
metadataStorage['validationMetadatas'].set(target, currentMetadatas);

// 如果是必需的,添加一个额外的验证规则
if (!isOptional) {
const requiredMetadata = new ValidationMetadata({
target: target,
propertyName: propertyKey,
type: ValidationTypes.NESTED_VALIDATION,
validationOptions: {
each: false,
always: true,
},
});
currentMetadatas.push(requiredMetadata);
metadataStorage['validationMetadatas'].set(target, currentMetadatas);
}
}

export class ClassValidatorService implements IValidationService<any> {
protected defaultClassValidatorOptions: ValidatorOptions;

Expand Down Expand Up @@ -79,41 +189,90 @@ export class ClassValidatorService implements IValidationService<any> {
value: instance,
};
}
}

getSchema(schema: any) {
return schema;
}
export default {
validateServiceHandler: (container: IMidwayContainer) => {
const configService = container.get(MidwayConfigService);
configService.addObject({
i18n: {
localeTable: {
en_US: {
classValidator: EN_I18N_MESSAGES,
},
zh_CN: {
classValidator: ZH_I18N_MESSAGES,
},
},
},
});
return new ClassValidatorService();
},
schemaHelper: {
isRequired: (ClzType: any, propertyName: string): boolean => {
return !isFieldOptional(ClzType, propertyName);
},

public getIntSchema(): any {
return Number;
}
isOptional: (ClzType: any, propertyName: string): boolean => {
return isFieldOptional(ClzType, propertyName);
},

public getBoolSchema(): any {
return Boolean;
}
setRequired: (ClzType: any, propertyName?: string): void => {
if (propertyName) {
// 处理单个属性
setPropertyMetadata(ClzType, propertyName, false);
} else {
// 处理所有属性
const metadataStorage = getMetadataStorage();
const properties = metadataStorage
.getTargetValidationMetadatas(ClzType, '', false, false)
.map(meta => meta.propertyName as string);

public getFloatSchema(): any {
return Number;
}
// 移除重复的属性名并保持字符串类型
const uniqueProperties = Array.from(new Set(properties)) as string[];
uniqueProperties.forEach(prop => {
setPropertyMetadata(ClzType, prop, false);
});
}
},

public getStringSchema(): any {
return String;
}
}
setOptional: (ClzType: any, propertyName?: string): void => {
if (propertyName) {
// 处理单个属性
setPropertyMetadata(ClzType, propertyName, true);
} else {
// 处理所有属性
const metadataStorage = getMetadataStorage();
const properties = metadataStorage
.getTargetValidationMetadatas(ClzType, '', false, false)
.map(meta => meta.propertyName as string);

export default async (container: IMidwayContainer) => {
const configService = container.get(MidwayConfigService);
configService.addObject({
i18n: {
localeTable: {
en_US: {
classValidator: EN_I18N_MESSAGES,
},
zh_CN: {
classValidator: ZH_I18N_MESSAGES,
},
},
// 移除重复的属性名并保持字符串类型
const uniqueProperties = Array.from(new Set(properties)) as string[];
uniqueProperties.forEach(prop => {
setPropertyMetadata(ClzType, prop, true);
});
}
},
});
return new ClassValidatorService();

getSchema(schema: any) {
return schema;
},

getIntSchema(): any {
return Number;
},

getBoolSchema(): any {
return Boolean;
},

getFloatSchema(): any {
return Number;
},

getStringSchema(): any {
return String;
},
},
};
Loading

0 comments on commit 4670339

Please sign in to comment.