添加ts从vo自动转换到dto
This commit is contained in:
parent
d69bdfea12
commit
e88210a9bc
229
typescripts/ts-transform-pojo.ts
Normal file
229
typescripts/ts-transform-pojo.ts
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
import Schema, { Rules } from 'async-validator';
|
||||||
|
|
||||||
|
// 定义字段元数据接口
|
||||||
|
interface FieldMetadata {
|
||||||
|
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
||||||
|
voField?: string;
|
||||||
|
rules?: Rules;
|
||||||
|
nestedSchema?: SchemaBuilder<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 链式API构建器类
|
||||||
|
class SchemaBuilder<T> {
|
||||||
|
private fields: Record<string, FieldMetadata> = {};
|
||||||
|
private currentField: string | null = null;
|
||||||
|
private currentMetadata: FieldMetadata | null = null;
|
||||||
|
|
||||||
|
constructor(private name: string) {}
|
||||||
|
|
||||||
|
// 添加字段
|
||||||
|
field<K extends string>(name: K): SchemaBuilder<T & { [P in K]: any }> {
|
||||||
|
this.currentField = name;
|
||||||
|
this.currentMetadata = { type: 'string' };
|
||||||
|
return this as unknown as SchemaBuilder<T & { [P in K]: any }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置字段类型
|
||||||
|
type(type: FieldMetadata['type']): this {
|
||||||
|
if (this.currentMetadata) {
|
||||||
|
this.currentMetadata.type = type;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置VO字段映射
|
||||||
|
voField(name: string): this {
|
||||||
|
if (this.currentMetadata) {
|
||||||
|
this.currentMetadata.voField = name;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加验证规则
|
||||||
|
validate(rules: Rules): this {
|
||||||
|
if (this.currentMetadata) {
|
||||||
|
this.currentMetadata.rules = rules;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置嵌套Schema
|
||||||
|
nested(schema: SchemaBuilder<any>): this {
|
||||||
|
if (this.currentMetadata) {
|
||||||
|
this.currentMetadata.nestedSchema = schema;
|
||||||
|
this.currentMetadata.type = 'object';
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 完成字段定义
|
||||||
|
end(): this {
|
||||||
|
if (this.currentField && this.currentMetadata) {
|
||||||
|
this.fields[this.currentField] = this.currentMetadata;
|
||||||
|
this.currentField = null;
|
||||||
|
this.currentMetadata = null;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成TypeScript类型
|
||||||
|
getType(): T {
|
||||||
|
return {} as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成验证规则
|
||||||
|
getValidationRules(): Rules {
|
||||||
|
const rules: Rules = {};
|
||||||
|
|
||||||
|
for (const [field, metadata] of Object.entries(this.fields)) {
|
||||||
|
if (metadata.rules) {
|
||||||
|
rules[field] = metadata.rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理嵌套对象
|
||||||
|
if (metadata.nestedSchema) {
|
||||||
|
rules[field] = { ...rules[field], fields: metadata.nestedSchema.getValidationRules() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取字段元数据
|
||||||
|
getFieldsMetadata(): Record<string, FieldMetadata> {
|
||||||
|
return { ...this.fields };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建Schema构建器的工厂函数
|
||||||
|
function createSchema<T = {}>(name: string): SchemaBuilder<T> {
|
||||||
|
return new SchemaBuilder<T>(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从Schema提取TypeScript类型的工具类型
|
||||||
|
type ExtractTypeFromSchema<T> = T extends SchemaBuilder<infer U> ? U : never;
|
||||||
|
|
||||||
|
// 生成验证规则
|
||||||
|
function createRules<T>(schema: SchemaBuilder<T>): Rules {
|
||||||
|
return schema.getValidationRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
// VO到DTO的转换函数
|
||||||
|
function transformVoToDto<T>(data: any, schema: SchemaBuilder<T>): T {
|
||||||
|
const fields = schema.getFieldsMetadata();
|
||||||
|
const result: any = {};
|
||||||
|
|
||||||
|
for (const [dtoField, metadata] of Object.entries(fields)) {
|
||||||
|
const voField = metadata.voField || dtoField;
|
||||||
|
const value = data[voField];
|
||||||
|
|
||||||
|
// 处理嵌套对象
|
||||||
|
if (metadata.nestedSchema && typeof value === 'object' && value !== null) {
|
||||||
|
result[dtoField] = transformVoToDto(value, metadata.nestedSchema);
|
||||||
|
} else {
|
||||||
|
// 根据类型转换值
|
||||||
|
switch (metadata.type) {
|
||||||
|
case 'number':
|
||||||
|
result[dtoField] = Number(value);
|
||||||
|
break;
|
||||||
|
case 'boolean':
|
||||||
|
result[dtoField] = Boolean(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result[dtoField] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 带转换功能的API请求函数
|
||||||
|
async function get<T>(url: string, schema: SchemaBuilder<T>): Promise<T> {
|
||||||
|
// 模拟API请求
|
||||||
|
const response = await fetch(url);
|
||||||
|
const voData = await response.json();
|
||||||
|
|
||||||
|
// 转换VO到DTO
|
||||||
|
const dtoData = transformVoToDto(voData, schema);
|
||||||
|
|
||||||
|
// 验证数据
|
||||||
|
const validator = new Schema(schema.getValidationRules());
|
||||||
|
try {
|
||||||
|
await validator.validate(dtoData);
|
||||||
|
} catch (errors) {
|
||||||
|
// 确保验证错误被正确抛出
|
||||||
|
throw new Error(`Validation failed: ${JSON.stringify(errors)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dtoData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix the export statement to ensure proper ESM exports
|
||||||
|
export { createSchema, createRules, get, transformVoToDto, ExtractTypeFromSchema };
|
||||||
|
|
||||||
|
// 创建地址Schema
|
||||||
|
const AddressSchema = createSchema('Address')
|
||||||
|
.field('street')
|
||||||
|
.type('string')
|
||||||
|
.voField('streetName')
|
||||||
|
.validate({ required: true, min: 2, max: 100 })
|
||||||
|
.end()
|
||||||
|
.field('city')
|
||||||
|
.type('string')
|
||||||
|
.validate({ required: true })
|
||||||
|
.end()
|
||||||
|
.field('zipCode')
|
||||||
|
.type('string')
|
||||||
|
.voField('postalCode')
|
||||||
|
.validate({ required: true, pattern: /^\d{5}$/ })
|
||||||
|
.end();
|
||||||
|
|
||||||
|
// 创建用户Schema
|
||||||
|
const UserSchema = createSchema('User')
|
||||||
|
.field('id')
|
||||||
|
.type('number')
|
||||||
|
.voField('userId')
|
||||||
|
.validate({ required: true, type: 'number' })
|
||||||
|
.end()
|
||||||
|
.field('name')
|
||||||
|
.type('string')
|
||||||
|
.validate({ required: true, min: 2, max: 50 })
|
||||||
|
.end()
|
||||||
|
.field('email')
|
||||||
|
.type('string')
|
||||||
|
.validate({
|
||||||
|
required: true,
|
||||||
|
type: 'string',
|
||||||
|
pattern: /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/,
|
||||||
|
})
|
||||||
|
.end()
|
||||||
|
.field('age')
|
||||||
|
.type('number')
|
||||||
|
.validate({ type: 'number', min: 0, max: 150 })
|
||||||
|
.end()
|
||||||
|
.field('address')
|
||||||
|
.type('object')
|
||||||
|
.nested(AddressSchema)
|
||||||
|
.validate({ type: 'object' })
|
||||||
|
.end();
|
||||||
|
|
||||||
|
// 提取用户类型
|
||||||
|
type User = ExtractTypeFromSchema<typeof UserSchema>;
|
||||||
|
|
||||||
|
// 获取验证规则
|
||||||
|
const userRules = createRules(UserSchema);
|
||||||
|
|
||||||
|
// 使用示例
|
||||||
|
async function fetchUser() {
|
||||||
|
try {
|
||||||
|
const user = await get<User>('/api/user/1', UserSchema);
|
||||||
|
console.log('用户数据:', user);
|
||||||
|
return user;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取用户失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行示例
|
||||||
|
fetchUser();
|
Loading…
x
Reference in New Issue
Block a user