数据库管理
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))使用 db:push 快速推送架构变更:
# 推送架构变更到数据库pnpm run db:push注意: db:push 会直接修改数据库,适合开发环境。
使用迁移文件管理数据库变更:
# 生成迁移文件pnpm run db:generate
# 应用迁移pnpm run db:migrate如果在 packages/auth/src/index.ts 中为 Better-Auth 新增了插件(例如 admin()),在执行以上命令之前,请先按照认证系统文档中的“启用插件后的数据库更新流程”重新生成认证相关的 Schema 并创建迁移文件,再在这里运行 db:generate / db:migrate 将这些变更应用到数据库。
数据库管理界面
Section titled “数据库管理界面”使用 Drizzle Studio 可视化管理数据库:
pnpm run db:studio这将打开一个 Web 界面,可以:
- 查看表结构
- 浏览和编辑数据
- 执行 SQL 查询
- 使用迁移: 生产环境使用迁移文件而不是
db:push - 索引优化: 为常用查询字段添加索引
- 关系完整性: 使用外键确保数据完整性
- 类型安全: 利用 Drizzle 的类型推断
- 查询优化: 避免 N+1 查询问题