关于 api-database-drizzle
面向使用 Drizzle ORM 和 Neon 构建 PostgreSQL 应用的 TypeScript 开发者,提供数据库实践指南。内容侧重类型安全的架构与查询、高效关联数据读取,以及事务和迁移。
主要功能
- 01以架构为先的类型安全设计
- 02Neon HTTP 与 WebSocket 连接指南
- 03使用 `.with()` 执行关联查询
- 04事务与迁移实践
- 05Drizzle Kit 数据填充指南
适用场景
- 01为无服务器应用编写类型安全查询
- 02读取关联记录并避免 N+1 查询
- 03执行原子数据库更新
- 04管理架构迁移与开发数据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ agents-inc/ skills --skill api-database-drizzle安装后在 Claude Code 中输入/api-database-drizzle确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
metadata.yamlreference.mdexamples/core.mdmigrations.mdqueries.mdrelations-v2.mdseeding.mdtransactions.md详细介绍
原文在翻译后有更新,译文可能不是最新。
使用 Drizzle ORM + Neon 的数据库
**快速指南:**使用 Drizzle ORM 执行类型安全的查询,使用 Neon 无服务器 Postgres 实现兼容边缘环境的连接。采用以架构为先的设计,自动生成 TypeScript 类型。使用 RQB v2、
defineRelations()和基于对象的where语法。使用.with()执行关联查询,避免 N+1 问题。使用事务确保操作的原子性。
<critical_requirements>
重要:使用此技能前
所有代码都必须遵循项目在 CLAUDE.md 中的约定(kebab-case、命名导出、导入顺序、
import type、命名常量)
(必须在 Drizzle 配置中设置 casing: 'snake_case',将 camelCase JS 映射为 snake_case SQL)
(事务回调中必须使用 tx 参数(而非 db),以确保原子性)
(关联查询必须使用 .with() 以避免 N+1 问题——它会在单个 SQL 查询中获取所有数据)
(RQB v2 必须使用 defineRelations()——旧的逐表 relations() 语法已弃用)
</critical_requirements>
详细资源:
- 代码示例请参阅 examples/ 文件夹:
- core.md - 连接设置和架构定义(始终加载)
- queries.md - 关联查询和查询构建器
- relations-v2.md - 使用 defineRelations() 的 RQB v2(新增)
- transactions.md - 原子操作
- migrations.md - Drizzle Kit 工作流
- seeding.md - 填充开发数据(包括 drizzle-seed)
- 决策框架和反模式请参阅 reference.md
自动检测: drizzle-orm、@neondatabase/serverless、neon-http、db.query、db.transaction、drizzle-kit、pgTable、defineRelations、drizzle-seed
适用场景:
- 需要执行类型安全数据库查询的无服务器函数
- 采用以架构为先的开发方式并使用迁移
- 构建带有 API 路由的服务端渲染应用
不适用场景:
- 直接使用框架服务端操作的简单应用(增加的开销不值得)
- 只需要传统 TCP 连接池的应用(请使用标准 Postgres 客户端)
- 非 TypeScript 项目(无法获得类型安全这一主要优势)
- 需要 WebSocket 连接的边缘函数(边缘运行时不支持)
核心模式
模式 1:数据库连接(Neon HTTP)
配置 Drizzle 与 Neon,以兼容无服务器和边缘环境。关键设置要求:
export const db = drizzle(sql, {
schema,
casing: "snake_case", // Maps camelCase JS to snake_case SQL
});
- 使用前验证
DATABASE_URL(缺失时抛出错误) - 始终设置
casing: "snake_case",以避免字段名称不匹配 - HTTP 使用
neon()(兼容边缘环境),WebSocket 使用Pool(用于长时间查询)
完整的连接设置、WebSocket 配置和 Drizzle Kit 配置请参阅 examples/core.md。
模式 2:架构定义
使用 Drizzle 的架构构建器定义表和 TypeScript 类型:
export const companies = pgTable("companies", {
id: uuid("id").primaryKey().defaultRandom(),
name: varchar("name", { length: 255 }).notNull(),
slug: varchar("slug", { length: 255 }).unique(),
deletedAt: timestamp("deleted_at"), // Soft delete
createdAt: timestamp("created_at").defaultNow(),
});
- 对受约束的值使用
pgEnum(),而非 varchar - 始终包含
createdAt/updatedAt时间戳 - 软删除时添加
deletedAt - 在外键上设置
onDelete: "cascade",以防止产生孤立记录 - 主键使用
uuid().defaultRandom()或integer().generatedAlwaysAsIdentity()
完整的架构示例(枚举、关联、联结表、自增列)请参阅 examples/core.md。
模式 3:使用 .with() 执行关联查询
使用 .with() 在单个 SQL 查询中高效获取关联数据:
const job = await db.query.jobs.findFirst({
where: and(eq(jobs.id, jobId), isNull(jobs.deletedAt)),
with: {
company: { with: { locations: true } },
jobSkills: { with: { skill: true } },
},
});
// Result is fully typed: job.company.name, job.jobSkills[0].skill.name
- 获取关联数据时,使用带有
.with()的db.query——只需单个 SQL 查询,不会产生 N+1 问题 - 自定义列选择、复杂 JOIN 和聚合时,使用查询构建器(
db.select()) - 对软删除表,WHERE 条件中始终包含
isNull(deletedAt)
完整的关联查询示例、N+1 反模式和动态筛选请参阅 examples/queries.md。
其他模式
以下模式均在 examples/ 中提供了完整示例:
- 查询构建器 - 复杂筛选器、动态条件、自定义 JOIN - 参见 queries.md
- 事务 - 原子操作、错误处理、回滚 - 参见 transactions.md
- 数据库迁移 - Drizzle Kit 工作流,
generate与push的区别 - 参见 migrations.md - 数据库填充 - 开发数据、安全清理 - 参见 seeding.md
性能优化(索引、预处理语句、分页)已记录在 reference.md 中。
<red_flags>
严重问题
- ❌ 在事务中使用
db而非tx- 会绕过事务上下文,破坏原子性 - ❌ 关联查询中的 N+1 查询 - 使用
.with()在一次查询中获取数据 - ❌ 未设置
casing: 'snake_case'- JS 与 SQL 之间的字段名称不匹配 - ❌ 使用 v1 的
relations()按表语法 - 已弃用,请使用defineRelations() - ❌ 使用基于回调的
where/orderBy- v1 语法已弃用,请使用基于对象的语法 - ⚠️ 查询未检查软删除(
isNull(deletedAt)) - ⚠️ 列表查询没有分页限制
注意事项与边缘情况:
- Neon HTTP 的查询超时时间为 30 秒——长时间运行的查询需要使用 WebSocket
- 在事务外创建的预处理语句不能在事务内使用
enableRLS()在 v1.0.0-beta.1 中已弃用——请改用pgTable.withRLS()- 验证器包已合并:
drizzle-zod现为drizzle-orm/zod(从 v1 beta 起)
完整的反模式和注意事项列表,请参见 reference.md。
</red_flags>
<critical_reminders>
重要提醒
所有代码都必须遵循 CLAUDE.md 中的项目约定
(必须在 Drizzle 配置中设置 casing: 'snake_case',以将 camelCase JS 映射为 snake_case SQL)
(必须在事务回调中使用 tx 参数(而非 db),以确保原子性)
(必须对关联查询使用 .with(),避免 N+1 问题——它会通过单条 SQL 查询获取所有数据)
(RQB v2 必须使用 defineRelations()——旧的 relations() 按表语法已弃用)
不遵循这些规则会导致字段名称不匹配、破坏事务原子性、造成 N+1 性能问题,并使用已弃用的 API。
</critical_reminders>