Drizzle ORM
규칙
- 스키마 정의:
src/db/schema.ts에서 pgTable() / mysqlTable() / sqliteTable() 사용
- 개발: 빠른 반복을 위해
drizzle-kit push 사용 — 마이그레이션 파일 불필요
- 프로덕션: 추적 가능한 마이그레이션 이력을 위해
drizzle-kit generate + drizzle-kit migrate 사용
- 타입 안전 쿼리:
db.select().from(users).where(eq(users.email, email)) — 전체 TypeScript 추론
- 관계:
relations() 헬퍼로 정의 — one()과 many()를 사용하여 db.query로 관계형 쿼리
- 준비된 구문:
db.select().from(users).where(eq(users.id, sql.placeholder("id"))).prepare() — 자주 사용되는 경로에 재사용
- 트랜잭션:
db.transaction(async (tx) => { ... }) — 콜백 내부에서는 tx를 사용하고 db를 사용하지 않음
- 인덱스:
.index()로 인라인 정의하거나 테이블 설정에서 정의 — where 및 orderBy에 사용되는 열에 추가
- Drizzle Studio: 개발 중 시각적 데이터베이스 브라우저를 위해
npx drizzle-kit studio 실행
패턴
import { pgTable, text, timestamp, uuid, integer } from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
export const users = pgTable("users", {
id: uuid("id").primaryKey().defaultRandom(),
name: text("name").notNull(),
email: text("email").notNull().unique(),
createdAt: timestamp("created_at").defaultNow().notNull(),
});
export const posts = pgTable("posts", {
id: uuid("id").primaryKey().defaultRandom(),
title: text("title").notNull(),
authorId: uuid("author_id").references(() => users.id).notNull(),
});
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, { fields: [posts.authorId], references: [users.id] }),
}));
const result = await db.query.users.findFirst({
where: eq(users.id, userId),
with: { posts: true },
});
피해야 할 것
- 프로덕션에서
drizzle-kit push 사용 — 추적 가능한 마이그레이션을 위해 generate + migrate 사용
- Drizzle API가 처리할 수 있는 경우 원시 SQL 사용 — 복잡한 표현식에만
sql 템플릿 태그 사용
relations() 정의 누락 — 없으면 db.query 관계형 쿼리가 작동하지 않음
- N+1 쿼리 —
db.query에서 with를 사용하여 단일 쿼리로 관계 조인
- 외래 키 및 필터링된 열에 인덱스 누락 — Drizzle은 자동으로 생성하지 않음