From e88210a9bc279f464cb10ac9965f59ba40a32a61 Mon Sep 17 00:00:00 2001 From: LittleBoy Date: Sat, 19 Jul 2025 11:43:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0ts=E4=BB=8Evo=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=BD=AC=E6=8D=A2=E5=88=B0dto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- typescripts/ts-transform-pojo.ts | 229 +++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 typescripts/ts-transform-pojo.ts diff --git a/typescripts/ts-transform-pojo.ts b/typescripts/ts-transform-pojo.ts new file mode 100644 index 0000000..21cfc28 --- /dev/null +++ b/typescripts/ts-transform-pojo.ts @@ -0,0 +1,229 @@ +import Schema, { Rules } from 'async-validator'; + +// 定义字段元数据接口 +interface FieldMetadata { + type: 'string' | 'number' | 'boolean' | 'object' | 'array'; + voField?: string; + rules?: Rules; + nestedSchema?: SchemaBuilder; +} + +// 链式API构建器类 +class SchemaBuilder { + private fields: Record = {}; + private currentField: string | null = null; + private currentMetadata: FieldMetadata | null = null; + + constructor(private name: string) {} + + // 添加字段 + field(name: K): SchemaBuilder { + this.currentField = name; + this.currentMetadata = { type: 'string' }; + return this as unknown as SchemaBuilder; + } + + // 设置字段类型 + 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): 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 { + return { ...this.fields }; + } +} + +// 创建Schema构建器的工厂函数 +function createSchema(name: string): SchemaBuilder { + return new SchemaBuilder(name); +} + +// 从Schema提取TypeScript类型的工具类型 +type ExtractTypeFromSchema = T extends SchemaBuilder ? U : never; + +// 生成验证规则 +function createRules(schema: SchemaBuilder): Rules { + return schema.getValidationRules(); +} + +// VO到DTO的转换函数 +function transformVoToDto(data: any, schema: SchemaBuilder): 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(url: string, schema: SchemaBuilder): Promise { + // 模拟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; + +// 获取验证规则 +const userRules = createRules(UserSchema); + +// 使用示例 +async function fetchUser() { + try { + const user = await get('/api/user/1', UserSchema); + console.log('用户数据:', user); + return user; + } catch (error) { + console.error('获取用户失败:', error); + } +} + +// 执行示例 +fetchUser(); \ No newline at end of file