drizzle
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDrizzle ORM Schema Style Guide
Drizzle ORM 架构风格指南
Configuration
配置
- Config:
drizzle.config.ts - Schemas:
src/database/schemas/ - Migrations:
src/database/migrations/ - Dialect: with
postgresqlstrict: true
- 配置文件:
drizzle.config.ts - 架构文件:
src/database/schemas/ - 迁移文件:
src/database/migrations/ - 数据库方言:启用的
strict: truepostgresql
Helper Functions
辅助函数
Location:
src/database/schemas/_helpers.ts- : Timestamp with timezone
timestamptz(name) - ,
createdAt(),updatedAt(): Standard timestamp columnsaccessedAt() - : Object with all three for easy spread
timestamps
位置:
src/database/schemas/_helpers.ts- :带时区的时间戳
timestamptz(name) - 、
createdAt()、updatedAt():标准时间戳列accessedAt() - :包含上述三个函数的对象,支持展开语法
timestamps
Naming Conventions
命名规范
- Tables: Plural snake_case (,
users)session_groups - Columns: snake_case (,
user_id)created_at
- 表名:复数蛇形命名法(、
users)session_groups - 列名:蛇形命名法(、
user_id)created_at
Column Definitions
列定义
Primary Keys
主键
typescript
id: text('id')
.primaryKey()
.$defaultFn(() => idGenerator('agents'))
.notNull(),ID prefixes make entity types distinguishable. For internal tables, use .
uuidtypescript
id: text('id')
.primaryKey()
.$defaultFn(() => idGenerator('agents'))
.notNull(),ID前缀可区分实体类型。对于内部表,使用。
uuidForeign Keys
外键
typescript
userId: text('user_id')
.references(() => users.id, { onDelete: 'cascade' })
.notNull(),typescript
userId: text('user_id')
.references(() => users.id, { onDelete: 'cascade' })
.notNull(),Timestamps
时间戳
typescript
...timestamps, // Spread from _helpers.tstypescript
...timestamps, // Spread from _helpers.tsIndexes
索引
typescript
// Return array (object style deprecated)
(t) => [uniqueIndex('client_id_user_id_unique').on(t.clientId, t.userId)],typescript
// Return array (object style deprecated)
(t) => [uniqueIndex('client_id_user_id_unique').on(t.clientId, t.userId)],Type Inference
类型推断
typescript
export const insertAgentSchema = createInsertSchema(agents);
export type NewAgent = typeof agents.$inferInsert;
export type AgentItem = typeof agents.$inferSelect;typescript
export const insertAgentSchema = createInsertSchema(agents);
export type NewAgent = typeof agents.$inferInsert;
export type AgentItem = typeof agents.$inferSelect;Example Pattern
示例模式
typescript
export const agents = pgTable(
'agents',
{
id: text('id').primaryKey().$defaultFn(() => idGenerator('agents')).notNull(),
slug: varchar('slug', { length: 100 }).$defaultFn(() => randomSlug(4)).unique(),
userId: text('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
clientId: text('client_id'),
chatConfig: jsonb('chat_config').$type<LobeAgentChatConfig>(),
...timestamps,
},
(t) => [uniqueIndex('client_id_user_id_unique').on(t.clientId, t.userId)],
);typescript
export const agents = pgTable(
'agents',
{
id: text('id').primaryKey().$defaultFn(() => idGenerator('agents')).notNull(),
slug: varchar('slug', { length: 100 }).$defaultFn(() => randomSlug(4)).unique(),
userId: text('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
clientId: text('client_id'),
chatConfig: jsonb('chat_config').$type<LobeAgentChatConfig>(),
...timestamps,
},
(t) => [uniqueIndex('client_id_user_id_unique').on(t.clientId, t.userId)],
);Common Patterns
常见模式
Junction Tables (Many-to-Many)
关联表(多对多)
typescript
export const agentsKnowledgeBases = pgTable(
'agents_knowledge_bases',
{
agentId: text('agent_id').references(() => agents.id, { onDelete: 'cascade' }).notNull(),
knowledgeBaseId: text('knowledge_base_id').references(() => knowledgeBases.id, { onDelete: 'cascade' }).notNull(),
userId: text('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
enabled: boolean('enabled').default(true),
...timestamps,
},
(t) => [primaryKey({ columns: [t.agentId, t.knowledgeBaseId] })],
);typescript
export const agentsKnowledgeBases = pgTable(
'agents_knowledge_bases',
{
agentId: text('agent_id').references(() => agents.id, { onDelete: 'cascade' }).notNull(),
knowledgeBaseId: text('knowledge_base_id').references(() => knowledgeBases.id, { onDelete: 'cascade' }).notNull(),
userId: text('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
enabled: boolean('enabled').default(true),
...timestamps,
},
(t) => [primaryKey({ columns: [t.agentId, t.knowledgeBaseId] })],
);Database Migrations
数据库迁移
See for detailed migration guide.
references/db-migrations.mdbash
undefined详细迁移指南请参考。
references/db-migrations.mdbash
undefinedGenerate migrations
生成迁移文件
bun run db:generate
bun run db:generate
After modifying SQL (e.g., adding IF NOT EXISTS)
修改SQL后(例如添加IF NOT EXISTS)
bun run db:generate:client
undefinedbun run db:generate:client
undefinedMigration Best Practices
迁移最佳实践
sql
-- ✅ Idempotent operations
ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "avatar" text;
DROP TABLE IF EXISTS "old_table";
CREATE INDEX IF NOT EXISTS "users_email_idx" ON "users" ("email");
-- ❌ Non-idempotent
ALTER TABLE "users" ADD COLUMN "avatar" text;Rename migration files meaningfully: →
0046_meaningless.sql0046_user_add_avatar.sqlsql
-- ✅ 幂等操作
ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "avatar" text;
DROP TABLE IF EXISTS "old_table";
CREATE INDEX IF NOT EXISTS "users_email_idx" ON "users" ("email");
-- ❌ 非幂等操作
ALTER TABLE "users" ADD COLUMN "avatar" text;为迁移文件赋予有意义的名称: →
0046_meaningless.sql0046_user_add_avatar.sql