mcpField
D
drizzle

drizzle

github.com/bobmatnyc数据与数据库784.3k 次安装15 周前更新
代码仓库

关于 drizzle

drizzle 是面向数据库应用开发者的 TypeScript 优先 ORM 技能,涵盖类型安全的架构、类 SQL 查询、事务和迁移流程,支持 PostgreSQL、MySQL 与 SQLite。

主要功能

  1. 01类型安全的 TypeScript 架构
  2. 02类 SQL 查询与联接
  3. 03支持回滚的事务
  4. 04生成并应用迁移
  5. 05支持 PostgreSQL、MySQL 和 SQLite

适用场景

  1. 01设计关系型数据库架构
  2. 02编写筛选与分页查询
  3. 03安全执行多步更新
  4. 04管理数据库架构变更

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill drizzle-orm

安装后在 Claude Code 中输入/drizzle-orm确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

metadata.json
references/
advanced-schemas.md
performance.md
query-patterns.md
vs-prisma.md

详细介绍

Drizzle ORM

现代化、以 TypeScript 为先的 ORM,零依赖,具备编译时类型安全性,并采用类似 SQL 的语法。针对边缘运行时和无服务器环境进行了优化。

快速开始

安装
# Core ORM
npm install drizzle-orm

# Database driver (choose one)
npm install pg            # PostgreSQL
npm install mysql2        # MySQL
npm install better-sqlite3 # SQLite

# Drizzle Kit (migrations)
npm install -D drizzle-kit
基本设置
// db/schema.ts
import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  email: text('email').notNull().unique(),
  name: text('name').notNull(),
  createdAt: timestamp('created_at').defaultNow(),
});

// db/client.ts
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 });
第一个查询
import { db } from './db/client';
import { users } from './db/schema';
import { eq } from 'drizzle-orm';

// Insert
const newUser = await db.insert(users).values({
  email: '[email protected]',
  name: 'John Doe',
}).returning();

// Select
const allUsers = await db.select().from(users);

// Where
const user = await db.select().from(users).where(eq(users.id, 1));

// Update
await db.update(users).set({ name: 'Jane Doe' }).where(eq(users.id, 1));

// Delete
await db.delete(users).where(eq(users.id, 1));

Schema 定义

列类型参考
PostgreSQLMySQLSQLiteTypeScript
serial()serial()integer()number
text()text()text()string
integer()int()integer()number
boolean()boolean()integer()boolean
timestamp()datetime()integer()Date
json()json()text()unknown
uuid()varchar(36)text()string
常见 Schema 模式
import { pgTable, serial, text, varchar, integer, boolean, timestamp, json, unique } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  email: varchar('email', { length: 255 }).notNull().unique(),
  passwordHash: varchar('password_hash', { length: 255 }).notNull(),
  role: text('role', { enum: ['admin', 'user', 'guest'] }).default('user'),
  metadata: json('metadata').$type<{ theme: string; locale: string }>(),
  isActive: boolean('is_active').default(true),
  createdAt: timestamp('created_at').defaultNow().notNull(),
  updatedAt: timestamp('updated_at').defaultNow().notNull(),
}, (table) => ({
  emailIdx: unique('email_unique_idx').on(table.email),
}));

// Infer TypeScript types
type User = typeof users.$inferSelect;
type NewUser = typeof users.$inferInsert;

关系

一对多
import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';

export const authors = pgTable('authors', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
});

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  title: text('title').notNull(),
  authorId: integer('author_id').notNull().references(() => authors.id),
});

export const authorsRelations = relations(authors, ({ many }) => ({
  posts: many(posts),
}));

export const postsRelations = relations(posts, ({ one }) => ({
  author: one(authors, {
    fields: [posts.authorId],
    references: [authors.id],
  }),
}));

// Query with relations
const authorsWithPosts = await db.query.authors.findMany({
  with: { posts: true },
});
多对多
export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
});

export const groups = pgTable('groups', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
});

export const usersToGroups = pgTable('users_to_groups', {
  userId: integer('user_id').notNull().references(() => users.id),
  groupId: integer('group_id').notNull().references(() => groups.id),
}, (table) => ({
  pk: primaryKey({ columns: [table.userId, table.groupId] }),
}));

export const usersRelations = relations(users, ({ many }) => ({
  groups: many(usersToGroups),
}));

export const groupsRelations = relations(groups, ({ many }) => ({
  users: many(usersToGroups),
}));

export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({
  user: one(users, { fields: [usersToGroups.userId], references: [users.id] }),
  group: one(groups, { fields: [usersToGroups.groupId], references: [groups.id] }),
}));

查询

筛选
import { eq, ne, gt, gte, lt, lte, like, ilike, inArray, isNull, isNotNull, and, or, between } from 'drizzle-orm';

// Equality
await db.select().from(users).where(eq(users.email, '[email protected]'));

// Comparison
await db.select().from(users).where(gt(users.id, 10));

// Pattern matching
await db.select().from(users).where(like(users.name, '%John%'));

// Multiple conditions
await db.select().from(users).where(
  and(
    eq(users.role, 'admin'),
    gt(users.createdAt, new Date('2024-01-01'))
  )
);

// IN clause
await db.select().from(users).where(inArray(users.id, [1, 2, 3]));

// NULL checks
await db.select().from(users).where(isNull(users.deletedAt));
联接
import { eq } from 'drizzle-orm';

// Inner join
const result = await db
  .select({
    user: users,
    post: posts,
  })
  .from(users)
  .innerJoin(posts, eq(users.id, posts.authorId));

// Left join
const result = await db
  .select({
    user: users,
    post: posts,
  })
  .from(users)
  .leftJoin(posts, eq(users.id, posts.authorId));

// Multiple joins with aggregation
import { count, sql } from 'drizzle-orm';

const result = await db
  .select({
    authorName: authors.name,
    postCount: count(posts.id),
  })
  .from(authors)
  .leftJoin(posts, eq(authors.id, posts.authorId))
  .groupBy(authors.id);
分页与排序
import { desc, asc } from 'drizzle-orm';

// Order by
await db.select().from(users).orderBy(desc(users.createdAt));

// Limit & offset
await db.select().from(users).limit(10).offset(20);

// Pagination helper
function paginate(page: number, pageSize: number = 10) {
  return db.select().from(users)
    .limit(pageSize)
    .offset(page * pageSize);
}

事务

// Auto-rollback on error
await db.transaction(async (tx) => {
  await tx.insert(users).values({ email: '[email protected]', name: 'John' });
  await tx.insert(posts).values({ title: 'First Post', authorId: 1 });
  // If any query fails, entire transaction rolls back
});

// Manual control
const tx = db.transaction(async (tx) => {
  const user = await tx.insert(users).values({ ... }).returning();

  if (!user) {
    tx.rollback();
    return;
  }

  await tx.insert(posts).values({ authorId: user.id });
});

迁移

Drizzle Kit 配置
// drizzle.config.ts
import type { Config } from 'drizzle-kit';

export default {
  schema: './db/schema.ts',
  out: './drizzle',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
} satisfies Config;
迁移工作流
# Generate migration
npx drizzle-kit generate

# View SQL
cat drizzle/0000_migration.sql

# Apply migration
npx drizzle-kit migrate

# Introspect existing database
npx drizzle-kit introspect

# Drizzle Studio (database GUI)
npx drizzle-kit studio
迁移示例
-- drizzle/0000_initial.sql
CREATE TABLE IF NOT EXISTS "users" (
  "id" serial PRIMARY KEY NOT NULL,
  "email" varchar(255) NOT NULL,
  "name" text NOT NULL,
  "created_at" timestamp DEFAULT now() NOT NULL,
  CONSTRAINT "users_email_unique" UNIQUE("email")
);

导航

详细参考
  • 🏗️ 高级 Schema - 自定义类型、复合键、索引、约束、多租户模式。设计复杂数据库 Schema 时加载。

  • 🔍 查询模式 - 子查询、CTE、原始 SQL、预处理语句、批量操作。优化查询或处理复杂筛选时加载。

  • ⚡ 性能 - 连接池、查询优化、避免 N+1、预处理语句、边缘运行时集成。扩展或优化数据库性能时加载。

  • 🔄 与 Prisma 对比 - 功能对比、迁移指南、何时选择 Drizzle 而非 Prisma。评估 ORM 或从 Prisma 迁移时加载。

注意事项

遇到以下情况时请停下来重新考虑:

  • 对 JSON 列使用 any 或 unknown,但未进行类型标注
  • 未使用 sql 模板构建原始 SQL 字符串(存在 SQL 注入风险)
  • 多步骤数据修改未使用事务
  • 在生产查询中不分页地获取所有行
  • 外键或频繁查询的列缺少索引
  • 对大型表使用 select() 时未指定列

相较于 Prisma 的性能优势

指标DrizzlePrisma
包体积~35KB~230KB
冷启动~10ms~250ms
查询速度基准慢约 2-3 倍
内存~10MB~50MB
类型生成运行时推断构建时生成

集成

  • typescript-core:使用 satisfies 进行类型安全的 Schema 推断
  • nextjs-core:集成 Server Actions、Route Handlers、Middleware
  • 数据库迁移:安全的 Schema 演进模式

相关技能

使用 Drizzle 时,以下技能可改进你的工作流:

  • prisma:替代 ORM 对比:Drizzle 与 Prisma 的权衡
  • typescript:用于类型安全查询的高级 TypeScript 模式
  • nextjs:在 Next.js Server Actions 和 API 路由中使用 Drizzle
  • sqlalchemy:供学习 Drizzle 的 Python 开发者参考的 SQLAlchemy 模式

[如果这些技能已部署在你的资源包中,可查阅完整文档]

评论

支持 Markdown