数据库管理
IAM 项目使用 Drizzle ORM 和 PostgreSQL 进行数据管理。
Drizzle ORM 使用
Section titled “Drizzle ORM 使用”数据库架构定义在 packages/db/src/schema/ 目录下。
使用 Drizzle 定义表结构:
import { pgTable, text, timestamp, boolean } from 'drizzle-orm/pg-core'
export const posts = pgTable('posts', { id: text('id').primaryKey(), title: text('title').notNull(), content: text('content'), authorId: text('author_id').references(() => user.id), published: boolean('published').default(false), createdAt: timestamp('created_at').defaultNow(), updatedAt: timestamp('updated_at') .defaultNow() .$onUpdate(() => new Date())})text(): 文本字段timestamp(): 时间戳字段boolean(): 布尔字段integer(): 整数字段numeric(): 数值字段
.primaryKey(): 主键.notNull(): 非空.default(): 默认值.unique(): 唯一约束.references(): 外键引用
使用 relations 定义表之间的关系:
import { relations } from 'drizzle-orm'
// 一对多关系export const userRelations = relations(user, ({ many }) => ({ posts: many(posts)}))
// 多对一关系export const postsRelations = relations(posts, ({ one }) => ({ author: one(user, { fields: [posts.authorId], references: [user.id] })}))one: 一对一或多对一many: 一对多或多对多
import { db } from '@IAM/db'import { posts } from '@IAM/db/schema'
// 查询所有记录const allPosts = await db.select().from(posts)
// 查询单条记录const [post] = await db.select().from(posts).where(eq(posts.id, postId))import { eq, and, or, like } from 'drizzle-orm'
// 等值查询const userPosts = await db.select().from(posts).where(eq(posts.authorId, userId))
// 多条件查询const publishedPosts = await db .select() .from(posts) .where(and(eq(posts.authorId, userId), eq(posts.published, true)))
// 模糊查询const searchResults = await db .select() .from(posts) .where(like(posts.title, `%${keyword}%`))// 插入单条记录await db.insert(posts).values({ id: generateId(), title: 'New Post', content: 'Content here', authorId: userId})
// 插入多条记录await db.insert(posts).values([ { id: '1', title: 'Post 1', authorId: userId }, { id: '2', title: 'Post 2', authorId: userId }])
// 插入并返回const [newPost] = await db .insert(posts) .values({ id: generateId(), title: 'New Post', authorId: userId }) .returning()import { eq } from 'drizzle-orm'
// 更新记录await db.update(posts).set({ title: 'Updated Title' }).where(eq(posts.id, postId))
// 更新并返回const [updatedPost] = await db .update(posts) .set({ title: 'Updated Title' }) .where(eq(posts.id, postId)) .returning()// 删除记录await db.delete(posts).where(eq(posts.id, postId))
// 删除并返回const [deletedPost] = await db.delete(posts).where(eq(posts.id, postId)).returning()import { db } from '@IAM/db'import { posts, user } from '@IAM/db/schema'
// 使用 join 查询const postsWithAuthor = await db .select({ post: posts, author: user }) .from(posts) .innerJoin(user, eq(posts.authorId, user.id))Schema 与迁移
Section titled “Schema 与迁移”开发、测试和生产环境都应优先使用可提交、可审查的 migration:
# 生成迁移文件pnpm run db:generate
# 应用迁移pnpm run db:migrate如果调整 Better Auth 插件或认证字段,先固定使用 1.7.1 生成认证 schema:
pnpm dlx auth@1.7.1 generate --yes \ --config packages/auth/src/index.ts \ --output packages/db/src/schema/auth.tspnpm db:generatepnpm db:migrateDATABASE_URL 用于运行时访问;DATABASE_URL_DIRECT 用于 migration/DDL,未配置时 Drizzle 会回退到 DATABASE_URL。
pnpm db:push 会直接修改数据库,可能造成 schema、migration 与真实数据库漂移,只允许在可丢弃的本地数据库临时验证。正式变更必须回到 migration 流程。
数据库管理界面
Section titled “数据库管理界面”使用 Drizzle Studio 可视化管理数据库:
pnpm run db:studio这将打开一个 Web 界面,可以:
- 查看表结构
- 浏览和编辑数据
- 执行 SQL 查询
- 使用迁移: 所有正式变更都生成并提交 migration
- 索引优化: 为常用查询字段添加索引
- 关系完整性: 使用外键确保数据完整性
- 类型安全: 利用 Drizzle 的类型推断
- 查询优化: 避免 N+1 查询问题