关于 drizzle-orm-v0
面向使用 Drizzle ORM v0.45+ 的 TypeScript 开发者,提供 PostgreSQL、MySQL 和 SQLite 的模式、类型安全查询与迁移实践。重点涵盖类型推导、Drizzle Kit 迁移和事务。
主要功能
- 01定义带类型的数据库表和列
- 02构建类型安全查询
- 03通过 Drizzle Kit 管理迁移
- 04使用类型推导生成记录类型
- 05以事务执行多步操作
适用场景
- 01为 PostgreSQL、MySQL 或 SQLite 建立模式
- 02编写类型安全的 CRUD 查询
- 03生成并应用数据库迁移
- 04确保多步数据库操作保持原子性
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ blockmatic/ basilic-skills --skill drizzle-orm-v0安装后在 Claude Code 中输入/drizzle-orm-v0确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/postgresql-patterns.mdqueries.mdtemplates/db.tsschema.ts详细介绍
技能:drizzle-orm
适用范围
- 适用于:Drizzle ORM v0.45+,用于 PostgreSQL、MySQL、SQLite,包括模式定义、类型安全查询和迁移
- 不涵盖:数据库驱动设置、连接池配置、其他 ORM
前提条件
- Drizzle ORM v0.45+
- Drizzle Kit v0.31+(开发依赖),用于迁移
- PostgreSQL、MySQL 或 SQLite 数据库
- TypeScript v5+,启用严格模式
- ESM 模块系统
原则
- 使用表构建器(
pgTable、mysqlTable、sqliteTable)定义模式,并为列指定类型 - 列类型与数据库约束相匹配(例如,
varchar指定长度,timestamp指定模式) - 在表定义的第二个参数中使用
index()辅助函数定义索引 - 带有
.references()外键的文本主键是有效的默认选择 - 查询辅助函数(
eq、and、or、like)可用于构建类型安全的 SQL - 使用
$inferSelect和$inferInsert推导类型,避免手动定义类型 - 使用
drizzle-kit generate生成迁移(生产环境中不要使用push) - 使用预处理语句优化频繁执行的查询
- 按领域组织模式(每个实体/表一个文件)
- 使用事务(
db.transaction)确保多步操作的原子性
约束
必须
- 使用 Drizzle Kit 执行迁移(
drizzle-kit generate、drizzle-kit migrate) - 定义与数据库约束相匹配的列类型
- 使用查询辅助函数,而非原始 SQL
应当
- 对多步操作使用事务
- 对频繁执行的查询使用预处理语句
- 使用
$inferSelect和$inferInsert导出类型 - 通过
DrizzleQueryError进行结构化错误处理 - 按领域组织模式(每个实体一个文件)
- 选择性加载字段(而非完整行)
- 为
varchar列指定长度 - 在表定义中使用
index()辅助函数 - 使用 PGLite 测试 PostgreSQL 模式
- 如果项目已在使用
relations(),则使用它和关系查询构建器
可选
- 在 PostgreSQL 中使用标识列(
generatedAlwaysAsIdentity)代替serial - 定义了关系时,可对复杂联接使用关系查询构建器(
db.query.*)
避免
- 除非必要,否则避免使用原始 SQL
- 避免手动进行类型断言(使用推导类型)
- 避免跳过迁移生成
- 避免在新的 PostgreSQL 表中使用
serial(改用标识列) - 避免过度创建索引(仅在查询有需要时创建)
- 仅需少数几列时,避免获取完整行
- 避免在生产环境中使用
push(使用generate+migrate) - 数据库支持日期/时间类型时,避免使用基于字符串的时间戳模式
交互
模式
模式定义
import { index, pgTable, text, timestamp, varchar } from 'drizzle-orm/pg-core'
export const users = pgTable(
'users',
{
id: text('id').primaryKey(),
email: varchar('email', { length: 255 }).notNull().unique(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull(),
},
table => [index('users_email_idx').on(table.email)],
)
export type User = typeof users.$inferSelect
export type NewUser = typeof users.$inferInsert
标识列
import { pgTable, integer, generatedAlwaysAsIdentity } from 'drizzle-orm/pg-core'
export const posts = pgTable('posts', {
id: integer('id').primaryKey().generatedAlwaysAsIdentity(),
})
查询构建器
import { eq } from 'drizzle-orm'
const user = await db
.select()
.from(users)
.where(eq(users.id, userId))
.limit(1)
const userWithPosts = await db.query.users.findFirst({
where: eq(users.id, userId),
with: { posts: true },
})
const userEmail = await db
.select({ email: users.email })
.from(users)
.where(eq(users.id, userId))
事务
await db.transaction(async (tx) => {
const [user] = await tx.insert(users).values(userData).returning()
await tx.insert(profiles).values({ userId: user.id, ...profileData })
})
预处理语句
import { placeholder } from 'drizzle-orm'
const getUserByEmail = db
.select()
.from(users)
.where(eq(users.email, placeholder('email')))
.prepare('get_user_by_email')
const user = await getUserByEmail.execute({ email: '[email protected]' })
错误处理
import { DrizzleQueryError } from 'drizzle-orm'
try {
const user = await db.select().from(users).where(eq(users.id, userId))
} catch (error) {
if (error instanceof DrizzleQueryError) {
if (error.cause?.code === '23505') {
throw new Error('User already exists')
}
}
throw error
}
关系
import { relations } from 'drizzle-orm'
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}))
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
}))
数据库连接
import { drizzle } from 'drizzle-orm/node-postgres'
import { Pool } from 'pg'
import * as schema from './schema'
const pool = new Pool({ connectionString: process.env.DATABASE_URL })
export const db = drizzle(pool, { schema })
Drizzle Kit 配置
import { defineConfig } from 'drizzle-kit'
export default defineConfig({
dialect: 'postgresql',
schema: './src/db/schema/index.ts',
out: './src/db/migrations',
dbCredentials: { url: process.env.DATABASE_URL! },
migrations: {
table: '__drizzle_migrations',
schema: 'public',
},
verbose: true,
strict: true,
})
参考资料
- 查询模式 - CRUD 操作、联接、聚合
- PostgreSQL 模式 - PostgreSQL 专属模式
评论
支持 Markdown