A Practical Guide to Using Drizzle ORM with Claude Code
A practical guide to using drizzle orm using Claude Code with real-world code examples.
Drizzle ORM とは
Drizzle ORMはTypeScriptファーストの軽量ORMです。SQLに近い記法で型安全なクエリを書けるのが特徴です。Claude Codeと組み合わせれば、効率的にデータベース層を構築できます。
スキーマ定義
// db/schema.ts
import {
pgTable,
text,
timestamp,
boolean,
integer,
varchar,
index,
} from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
export const users = pgTable("users", {
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
email: varchar("email", { length: 255 }).notNull().unique(),
name: varchar("name", { length: 100 }).notNull(),
avatar: text("avatar"),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
}, (table) => ({
emailIdx: index("email_idx").on(table.email),
}));
export const posts = pgTable("posts", {
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
title: varchar("title", { length: 255 }).notNull(),
content: text("content").notNull(),
published: boolean("published").default(false).notNull(),
authorId: text("author_id").notNull().references(() => users.id),
viewCount: integer("view_count").default(0).notNull(),
publishedAt: timestamp("published_at"),
createdAt: timestamp("created_at").defaultNow().notNull(),
}, (table) => ({
authorIdx: index("author_idx").on(table.authorId),
publishedIdx: index("published_idx").on(table.published, table.publishedAt),
}));
export const comments = pgTable("comments", {
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
content: text("content").notNull(),
authorId: text("author_id").notNull().references(() => users.id),
postId: text("post_id").notNull().references(() => posts.id, { onDelete: "cascade" }),
createdAt: timestamp("created_at").defaultNow().notNull(),
});
リレーション定義
export const usersRelations = relations(users, ({ many, one }) => ({
posts: many(posts),
comments: many(comments),
}));
export const postsRelations = relations(posts, ({ one, many }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
comments: many(comments),
}));
export const commentsRelations = relations(comments, ({ one }) => ({
author: one(users, {
fields: [comments.authorId],
references: [users.id],
}),
post: one(posts, {
fields: [comments.postId],
references: [posts.id],
}),
}));
クエリ操作
import { drizzle } from "drizzle-orm/node-postgres";
import { eq, and, like, desc, sql, count } from "drizzle-orm";
import * as schema from "./schema";
const db = drizzle(pool, { schema });
// 挿入
async function createPost(data: {
title: string;
content: string;
authorId: string;
}) {
const [post] = await db
.insert(posts)
.values(data)
.returning();
return post;
}
// 検索(ページネーション付き)
async function getPosts(params: {
page?: number;
perPage?: number;
search?: string;
}) {
const { page = 1, perPage = 20, search } = params;
const conditions = [eq(posts.published, true)];
if (search) {
conditions.push(like(posts.title, `%${search}%`));
}
const [data, [{ total }]] = await Promise.all([
db
.select({
id: posts.id,
title: posts.title,
publishedAt: posts.publishedAt,
authorName: users.name,
commentCount: count(comments.id),
})
.from(posts)
.leftJoin(users, eq(posts.authorId, users.id))
.leftJoin(comments, eq(posts.id, comments.postId))
.where(and(...conditions))
.groupBy(posts.id, users.name)
.orderBy(desc(posts.publishedAt))
.limit(perPage)
.offset((page - 1) * perPage),
db
.select({ total: count() })
.from(posts)
.where(and(...conditions)),
]);
return { data, total, page, perPage };
}
// 更新
async function updatePost(id: string, data: Partial<typeof posts.$inferInsert>) {
const [updated] = await db
.update(posts)
.set({ ...data, updatedAt: new Date() })
.where(eq(posts.id, id))
.returning();
return updated;
}
Relational Queries API
// Prismaライクなクエリ
async function getPostWithRelations(id: string) {
return db.query.posts.findFirst({
where: eq(posts.id, id),
with: {
author: {
columns: { id: true, name: true, avatar: true },
},
comments: {
with: {
author: {
columns: { id: true, name: true },
},
},
orderBy: [desc(comments.createdAt)],
limit: 10,
},
},
});
}
マイグレーション
// 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;
# マイグレーション生成
npx drizzle-kit generate
# マイグレーション適用
npx drizzle-kit migrate
# Drizzle Studio(GUI)起動
npx drizzle-kit studio
Prisma との比較
| 特性 | Drizzle | Prisma |
|---|---|---|
| バンドルサイズ | 軽量 | やや大きい |
| クエリ記法 | SQL寄り | 独自API |
| エッジ対応 | 優秀 | 制限あり |
| スキーマ定義 | TypeScript | 独自DSL |
| マイグレーション | SQL生成 | 自動管理 |
Claude Codeでの活用
Drizzle ORMの実装をClaude Codeに依頼する例です。Prismaとの比較はPrisma ORM完全ガイド、データベース連携についてはSupabase統合開発も参照してください。
Drizzle ORMでデータベース層を構築して。
- PostgreSQLのスキーマ定義
- リレーション付きのCRUDクエリ
- ページネーションと検索
- マイグレーション設定
Drizzle ORMの詳細はDrizzle ORM公式ドキュメントを参照してください。Claude Codeの活用法は公式ドキュメントで確認できます。
Summary
Drizzle ORMはSQLに近い記法と軽量さが魅力のORMです。Claude Codeを使えば、型安全なクエリとスキーマ設計を効率的に実装できます。エッジ環境での利用にも適しています。
Related Posts
10 Tips to Triple Your Productivity with Claude Code
Learn about 10 tips to triple your productivity using Claude Code. Practical tips and code examples included.
Canvas/WebGL Optimization with Claude Code
Learn about canvas/webgl optimization using Claude Code. Practical tips and code examples included.
Markdown Implementation with Claude Code
Learn about markdown implementation using Claude Code. Practical tips and code examples included.