十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Drizzle ORM 与 Kysely 集成指南:用 Kyselify 把 Drizzle 表定义无缝接入 Kysely 查询构建器

Drizzle ORM 与 Kysely 集成指南:用 Kyselify 把 Drizzle 表定义无缝接入 Kysely 查询构建器 Drizzle ORM 与 Kysely 集成指南用 Kyselify 把 Drizzle 表定义无缝接入 Kysely 查询构建器【免费下载链接】drizzle-ormORM项目地址: https://gitcode.com/gh_mirrors/dr/drizzle-orm本篇技术指南基于当前仓库drizzle-orm v0.45.3中 drizzle-orm/src/kysely/README.md 编写讲解如何在同一项目中同时使用 Drizzle 定义数据库 Schema、生成自动化迁移并用 Kysely 作为日常查询构建器。读完本文你将掌握Kyselify类型工具的核心用法、它如何把 Drizzle 表结构映射为 Kysely 的ColumnType三态类型select / insert / update以及如何从仓库源码与类型测试中验证映射结果的正确性。为什么要把 Drizzle 和 Kysely 组合使用Drizzle 与 Kysely 是两种定位不同的 TypeScript 数据库工具。本文所讲的集成方式核心思路是各取所长用 Drizzle 负责 Schema 定义与迁移通过pgTable、mysqlTable等 API 声明表结构配合 drizzle-kit 生成并执行 SQL 迁移保证数据库结构与代码定义始终一致用 Kysely 负责查询构建如果你已有 Kysely 项目或者更习惯 Kysely 的类型化链式查询 API如selectFrom(...).selectAll()可以继续用 Kysely 写查询。这种组合特别适合已有 Kysely 项目、希望引入 Drizzle 的表定义与自动化迁移能力的存量场景。它让 Drizzle 的 Schema 定义和自动化迁移成为项目事实的唯一来源single source of truth而查询层保留你熟悉的 Kysely 写法。快速上手最小可用示例以下示例完整引自关联文档展示了 Drizzle 定义表 Kysely 执行查询的完整链路import { Kysely, PostgresDialect } from kysely; import { Pool } from pg; import { Kyselify } from drizzle-orm/kysely; import { pgTable, serial, text } from drizzle-orm/pg-core; const test pgTable(test, { id: serial(id).primaryKey(), name: text(name).notNull(), }); interface Database { test: Kyselifytypeof test; } const db new KyselyDatabase({ dialect: new PostgresDialect({ pool: new Pool(), }), }); const result/*: { id: number, name: string }[] */ db.selectFrom(test).selectAll().execute();关键步骤拆解用 Drizzle 声明表pgTable(test, {...})定义表结构与列类型serial(...).primaryKey()、text(...).notNull()同时携带 DDL 约束信息用Kyselify桥接类型Kyselifytypeof test把 Drizzle 表类型转换为 Kysely 数据库接口Databaseinterface中可识别的表类型构造 Kysely 实例new KyselyDatabase({...})按 Kysely 惯用法配置方言与连接池此处为 PostgreSQL 的pg.Pool执行类型安全的查询selectFrom(test).selectAll()返回的结果数组类型即为 Drizzle 表推断出的 select 行类型{ id: number, name: string }[]。Kyselify 类型工具的实现原理Kyselify是本次集成的核心其完整实现位于 drizzle-orm/src/kysely/index.ts。它并非运行时工具而是一个纯类型层面的映射器源码总共只有一个导出类型export type KyselifyT extends Table Simplify { [Key in keyof T[_][columns] string as MapColumnNameKey, T[_][columns][Key], true]: ColumnType // select InferSelectModelT, { dbColumnNames: true }[MapColumnNameKey, T[_][columns][Key], true], // insert MapColumnNameKey, T[_][columns][Key], true extends keyof InferInsertModel T, { dbColumnNames: true } ? InferInsertModelT, { dbColumnNames: true }[MapColumnNameKey, T[_][columns][Key], true] : never, // update MapColumnNameKey, T[_][columns][Key], true extends keyof InferInsertModel T, { dbColumnNames: true } ? InferInsertModelT, { dbColumnNames: true }[MapColumnNameKey, T[_][columns][Key], true] : never ; } ;从源码结构看它做了三件事遍历列集合keyof T[_][columns]取出 Drizzle 表内部的列配置即Table类中_品牌类型所携带的columns见 drizzle-orm/src/table.ts映射列名通过MapColumnNameKey, T[_][columns][Key], true将 Drizzle 的列属性键如fileName转换为实际的数据库列名如file_name。第三个泛型参数固定为true表示始终使用dbColumnNames模式即优先取列定义中的数据库存储名TColumn[_][name]参见 drizzle-orm/src/table.ts生成 Kysely 的 ColumnType 三态Kysely 的ColumnTypeSelectType, InsertType, UpdateType区分查询返回类型 / 插入类型 / 更新类型。其中 select 类型来自InferSelectModelT, { dbColumnNames: true }insert 与 update 类型来自InferInsertModel且当某列不出现在 insert 模型例如带默认值或自增的列时映射为never。select / insert / update 三态映射的意义InferInsertModel基于RequiredKeyOnly/OptionalKeyOnly等工具类型区分必填列与可选列见 drizzle-orm/src/table.ts。映射到 Kysely 后insert 为never的列意味着 Kysely 在insertInto(...).values(...)时不会要求你提供该值——这正是serial自增主键、defaultNow()等带默认值列的行为update 类型同样取 insert 模型保证更新时不会把自增/默认列当作可写字段。因此Kysely 的写入约束与 Drizzle 表定义中的默认值、自增、notNull 等语义天然对齐。列名映射camelCase 属性名与 snake_case 数据库列名Kysely 的数据库接口默认以数据库列名作为键而 Drizzle 允许你使用任意 TS 属性名对应到不同数据库列名。Kyselify通过MapColumnName..., true保证了这种差异在桥接后依然成立。仓库中的类型测试 drizzle-orm/type-tests/kysely/index.ts 给出了真实场景一个uploads表使用 camelCase 属性名fileName、fileSize映射到 snake_case 数据库列名file_name、file_size在 Kysely 侧插入时必须以数据库列名书写const uploads pgTable(uploads, { id: varchar(id, { length: 100 }).primaryKey(), state: uploadStateEnum(state).notNull().default(uploading), type: uploadTypeEnum(type).notNull(), fileName: varchar(file_name, { length: 100 }).notNull(), fileType: varchar(file_type, { length: 100 }).notNull(), fileSize: integer(file_size).notNull(), createdAt: timestamp(created_at).notNull().defaultNow(), uploadedAt: timestamp(uploaded_at), }); interface Database { uploads: Kyselifytypeof uploads; } await db .insertInto(uploads) .values({ id: 1, file_name: fileName, file_type: contentType, type: image, file_size: 1, }) .returning(id) .executeTakeFirst();注意state列带default(uploading)插入时被Kyselify映射为可省略字段所以上例未提供而uploadedAt数据库列uploaded_at可为空同样无需提供。进阶场景PostgreSQL 枚举与 MySQL 表Kyselify作用于任意符合Table约束的 Drizzle 表因此不限于pg-core也支持mysql-core并且能正确处理 Drizzle 的 PostgreSQL 枚举类型。仓库类型测试 drizzle-orm/type-tests/kysely/index.ts 中的pgEnum示例表明const uploadStateEnum pgEnum(upload_state, [uploading, uploaded, failed]); const uploadTypeEnum pgEnum(upload_type, [image, video]); // 表内枚举列 state: uploadStateEnum(state).notNull().default(uploading), type: uploadTypeEnum(type).notNull(),经Kyselify映射后Kysely 侧的state/type字段类型即为枚举字面量联合uploading | uploaded | failed等写入时同样受枚举值约束。MySQL 场景同样有完整测试佐证drizzle-orm/type-tests/kysely/index.ts包括char定长字符串、varchar、带defaultNow()与onUpdateNow()的时间戳列const units mysqlTable(units, { id: char(id, { length: 16 }).primaryKey(), name: mysqlVarchar(name, { length: 255 }).notNull(), abbreviation: mysqlVarchar(abbreviation, { length: 10 }).notNull(), created_at: mysqlTimestamp(created_at).defaultNow().notNull(), updated_at: mysqlTimestamp(updated_at).defaultNow().notNull().onUpdateNow(), }); interface Database { units: KyselifyUnitModel; } await db .insertInto(units) .values({ id: my-unique-id, abbreviation: foo, name: bar, }) .execute();带默认值的created_at/updated_at被映射为可省略字段插入语句无需提供。用类型测试验证映射结果与 Drizzle 推断一致仓库不仅提供了功能示例还通过类型断言确保桥接后类型与 Drizzle 原生推断完全等价。见 drizzle-orm/type-tests/kysely/index.tsconst result db.selectFrom(test).selectAll().execute(); ExpectEqualPromiseOftypeof result, typeof test.$inferSelect[]();它用ExpectEqual...断言Kysely 查询返回的Promise解包后的元素类型与test.$inferSelectDrizzle 表自带的 select 行推断类型逐一相等。这从类型层面证明了Kyselify的映射没有丢失或改变任何列的类型信息。安装与依赖说明kysely在 drizzle-orm/package.json 中作为可选 peer dependency声明kysely: *且peerDependenciesMeta.kysely.optional true因此只有真正使用drizzle-orm/kysely子路径时才需要安装kysely包仓库开发环境使用的 Kysely 版本为^0.25.0devDependencies类型测试基于该版本编写建议你的项目选用兼容版本导入路径为drizzle-orm/kysely如文档示例中的import { Kyselify } from drizzle-orm/kysely它是独立子路径导出不会影响未使用此特性的项目体积。在项目中使用时直接安装所需驱动即可例如 PostgreSQL 场景需要kysely、pg与types/pg。适用边界与注意事项Kyselify是纯类型工具它只负责类型桥接不参与任何运行时行为实际的 SQL 生成与执行完全由 Kysely 及其方言如PostgresDialect负责因此查询性能、方言能力取决于 Kysely 本身数据库列名语义由于Kyselify固定以数据库列名dbColumnNames模式组织类型键Kysely 查询中一律使用 snake_case 数据库列名与 Drizzle 侧使用 camelCase 属性名不冲突但需注意区分Schema 演进表结构变更后Drizzle 表类型、Kyselify桥接类型与 Kysely 查询会同步获得类型反馈编译期即可发现字段增删导致的查询失效这也是本方案相对纯 Kysely 手写类型的主要收益之一。延伸阅读集成文档原文本指南的源头文档Kyselify 源码实现类型映射的完整定义Kysely 类型测试覆盖 PostgreSQL、MySQL、枚举与列名映射的可运行示例Drizzle 表与推断类型基础理解InferSelectModel、InferInsertModel、MapColumnName等底层类型工具drizzle-orm 包配置查看kyselypeer dependency 声明与版本约束。【免费下载链接】drizzle-ormORM项目地址: https://gitcode.com/gh_mirrors/dr/drizzle-orm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表