02-Drizzle-Zod类型系统设计
分类:4-全栈/01-elysia
发布于:
阅读时间:36 分钟
1.1 基础 Schema 结构
所有文件都遵循相同的基础 Schema 模式: // =<mark> 基础 Schema </mark>= const Insert = createInsertSchema(table); const UpdateBase/Update = createUpdateSchema(table); // 有差异 const Select = createSelectSchema(table); 关键差异点: - category, product, ads, site-config, media: 使用 UpdateBase - auth: 直接使用 Update 1.2 业务 Schema 结构模式 标准模式(最完整): const Create = Insert.omit({ id: true, createdAt: true, updatedAt: true, }); const Update = UpdateBase.omit({ id: true, createdAt: true, updatedAt: true, }); const Patch = UpdateBase.omit({ id: true, createdAt: true, updatedAt: true, }).partial(); 查询 Schema 模式: const BusinessQuery = z.object({ // 业务特定的查询字段 }); const ListQuery = BusinessQuery.extend(PaginationParams.shape).extend(SortParams.shape); 1.3 特殊 Schema 命名规则 各文件中的特殊 Schema: | 文件 | 特殊 Schema | 用途 | |-------------|----------------------------------------------------------------------|-------------------| | category | FormUpsert, TreeQuery, Entityone | 表单upsert、树形查询、单实体 | | product | ProductTemplateModel, ProductImagesModel | 子模型扩展 | | auth | Login, ChangePassword | 认证相关操作 | | media | UploadFileDto, UploadFilesDto, BatchUpload, BatchDelete, BatchUpdate | 文件上传和批量操作 | | ads | BatchStatusUpdate | 批量状态更新 | | site-config | CategoryQuery, KeysQuery, BatchUpdate | 配置特定查询和批量更新 | 2. Update 和 UpdateBase 的区别分析 2.1 使用 UpdateBase 的文件(推荐模式): - category, product, ads, site-config, media const UpdateBase = createUpdateSchema(table); const Update = UpdateBase.omit({ id: true, createdAt: true, updatedAt: true, }); 2.2 直接使用 Update 的文件: - auth const Update = createUpdateSchema(usersTable); // 没有 UpdateBase,直接在 Patch 中使用 分析结论: UpdateBase 模式更规范,提供了更好的中间层抽象。 3. Create 和 Insert 的区别 所有文件都遵循相同的模式: const Create = Insert.omit({ id: true, createdAt: true, updatedAt: true, }); 部分文件有额外扩展: - product: 扩展了关联字段(templateId, categoryIds, imageIds) - media: 扩展了可选字段(url, key, fileSize等) 4. Patch 的定义方式 4.1 标准模式(推荐): const Patch = UpdateBase.omit({ id: true, createdAt: true, updatedAt: true, }).partial(); 4.2 特殊处理: - auth: 额外排除了 password 字段 - product: 使用了复杂的链式操作 5. 值聚合和类型聚合的导出结构 5.1 标准导出模式: // =<mark> 1. 运行时 Schema 集合(值)</mark>= export const ModelName = { Insert, Update, Select, Create, Patch, ListQuery, Entity, // ... 其他特殊 Schema } as const; // =<mark> 2. 编译时类型集合(类型)</mark>= export type ModelName = { Insert: z.infer<typeof Insert>; Update: z.infer<typeof Update>; Select: z.infer<typeof Select>; Create: z.infer<typeof Create>; Patch: z.infer<typeof Patch>; ListQuery: z.infer<typeof ListQuery>; Entity: z.infer<typeof Entity>; // ... 其他类型 }; 6. 最规范和完整的文件推荐 综合评分最高的文件: 🥇 第一名:media.model.ts 优点: - 结构最完整,包含所有标准 Schema - 枚举定义清晰(FileType, StorageProvider) - 批量操作 Schema 齐全(BatchUpload, BatchDelete, BatchUpdate) - 上传相关 Schema 专门定义(UploadFileDto, UploadFilesDto) - Entity 扩展合理(确保返回完整 URL) - 注释详细,代码可读性高 🥈 第二名:site-config.model.ts 优点: - 严格遵循 UpdateBase 模式 - 业务验证规则完善 - 特殊查询 Schema 定义合理(CategoryQuery, KeysQuery) - 结构清晰简洁 🥉 第三名:category.model.ts 优点: - 基础结构完整 - 特殊 Schema 有明确的业务用途 - 使用了 UpdateBase 模式 7. 标准化建议 7.1 推荐的标准模板: /** * [模块名称]模型定义 * [模块描述] */ import { createInsertSchema, createSelectSchema, createUpdateSchema, } from "drizzle-zod"; import { z } from "zod"; import { PaginationParams, SortParams } from "../helper/query-types"; import { [tableName] } from "./[module].schema"; // =<mark> 枚举定义(如果需要)</mark>= export const [EnumName] = z.enum([...]); export type [EnumName] = z.infer<typeof [EnumName]>; // =<mark> 基础 Schema </mark>= const Insert = createInsertSchema([tableName], { // 字段验证规则(可选) }); const UpdateBase = createUpdateSchema([tableName], { // 字段验证规则(可选) }); const Select = createSelectSchema([tableName]); // =<mark> 业务 Schema </mark>= const Create = Insert.omit({ id: true, createdAt: true, updatedAt: true, }).extend({ // 扩展字段(可选) }); const Update = UpdateBase.omit({ id: true, createdAt: true, updatedAt: true, }).extend({ // 扩展字段(可选) }); const Patch = UpdateBase.omit({ id: true, createdAt: true, updatedAt: true, }).partial(); const BusinessQuery = z.object({ // 业务查询字段 }); const ListQuery = BusinessQuery.extend(PaginationParams.shape).extend( SortParams.shape ); const Entity = Select.extend({ // 实体扩展字段(可选) }); // =<mark> 特殊业务 Schema(根据需要)</mark>= const [SpecialSchema] = z.object({ // 特殊业务逻辑 }); // =<mark> 值聚合导出 </mark>= export const [ModelName] = { // 基础 Schema Insert, Update, Select, // 业务 Schema Create, Patch, ListQuery, Entity, BusinessQuery, // 枚举(如果有) [EnumName], // 特殊 Schema(如果有) [SpecialSchema], } as const; // =<mark> 类型聚合导出 </mark>= export type [ModelName] = { Insert: z.infer<typeof Insert>; Update: z.infer<typeof Update>; Select: z.infer<typeof Select>; Create: z.infer<typeof Create>; Patch: z.infer<typeof Patch>; ListQuery: z.infer<typeof ListQuery>; Entity: z.infer<typeof Entity>; BusinessQuery: z.infer<typeof BusinessQuery>; // 枚举类型(如果有) [EnumName]: z.infer<typeof [EnumName]>; // 特殊类型(如果有) [SpecialSchema]: z.infer<typeof [SpecialSchema]>; }; 7.2 关键规范建议: 8. 始终使用 UpdateBase 模式 9. 保持 Create/Update/Patch 的一致性 10. 为复杂业务场景定义专门的 Schema 11. Entity 应该包含前端展示需要的所有字段 12. 批量操作使用标准的命名模式(BatchXxx) 13. 添加必要的注释和类型文档 这个分析为项目的类型系统标准化提供了明确的指导方向,建议以 media.model.ts 作为主要参考模板