Drizzle with Turso
이 튜토리얼은 Turso에서 Drizzle ORM을 사용하는 방법을 설명합니다.
- Drizzle ORM과 Drizzle kit이 설치되어 있어야 합니다. 다음 명령어로 설치할 수 있습니다:
npm i drizzle-orm
npm i -D drizzle-kit
- 환경 변수 관리를 위한
dotenv패키지가 설치되어 있어야 합니다. 이 패키지에 대한 자세한 내용은 여기를 참조하세요
npm i dotenv
@libsql/client패키지가 설치되어 있어야 합니다. 이 패키지에 대한 자세한 내용은 여기를 참조하세요.
npm i @libsql/client
- Turso CLI가 설치되어 있어야 합니다. 자세한 정보는 공식 문서를 확인하세요
Turso는 SQLite의 오픈 컨트리뷰션 포크인 libSQL을 기반으로 구축된 SQLite 호환 데이터베이스입니다. 조직당 수십만 개의 데이터베이스로 확장할 수 있으며, 자체 서버를 포함한 모든 위치로의 복제를 지원하여 마이크로초 단위의 지연 시간으로 액세스할 수 있습니다. Turso의 개념에 대한 자세한 내용은 여기에서 확인할 수 있습니다.
Drizzle ORM은 libSQL 드라이버를 기본적으로 지원합니다.
우리는 SQL 방언과 방언별 드라이버 및 구문을 채택하며, 가장 인기 있는 SQLite와 유사한 all, get, values, run 쿼리 메서드 구문을 반영합니다.
Turso 데이터베이스 설정은 공식 문서를 확인하세요.
Turso와 Drizzle ORM 설정
Turso 회원가입 또는 로그인
회원가입:
turso auth signup로그인:
turso auth login새 데이터베이스 생성
turso db create <DATABASE_NAME> 명령어를 실행하여 새 데이터베이스를 생성합니다:
turso db create drizzle-turso-db데이터베이스 정보를 확인하려면 다음 명령어를 실행하세요:
turso db show drizzle-turso-db인증 토큰 생성
데이터베이스의 인증 토큰을 생성하려면 다음 명령어를 실행하세요:
turso db tokens create drizzle-turso-db이 명령어와 옵션에 대한 자세한 내용은 공식 문서에서 확인할 수 있습니다.
환경 변수 업데이트
.env 또는 .env.local 파일에 연결 URL과 인증 토큰을 추가하세요.
TURSO_CONNECTION_URL=
TURSO_AUTH_TOKEN=Drizzle ORM을 데이터베이스에 연결
src/db 디렉토리에 index.ts 파일을 생성하고 데이터베이스 설정을 구성하세요:
import { config } from 'dotenv';
import { drizzle } from 'drizzle-orm/libsql';
config({ path: '.env' }); // or .env.local
export const db = drizzle({ connection: {
url: process.env.TURSO_CONNECTION_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!,
}});테이블 생성
src/db 디렉토리에 schema.ts 파일을 생성하고 테이블을 정의하세요:
import { sql } from 'drizzle-orm';
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
export const usersTable = sqliteTable('users', {
id: integer('id').primaryKey(),
name: text('name').notNull(),
age: integer('age').notNull(),
email: text('email').unique().notNull(),
});
export const postsTable = sqliteTable('posts', {
id: integer('id').primaryKey(),
title: text('title').notNull(),
content: text('content').notNull(),
userId: integer('user_id')
.notNull()
.references(() => usersTable.id, { onDelete: 'cascade' }),
createdAt: text('created_at')
.default(sql`(CURRENT_TIMESTAMP)`)
.notNull(),
updatedAt: integer('updated_at', { mode: 'timestamp' }).$onUpdate(() => new Date()),
});
export type InsertUser = typeof usersTable.$inferInsert;
export type SelectUser = typeof usersTable.$inferSelect;
export type InsertPost = typeof postsTable.$inferInsert;
export type SelectPost = typeof postsTable.$inferSelect;Drizzle 설정 파일 구성
Drizzle config - Drizzle Kit에서 사용되며, 데이터베이스 연결, 마이그레이션 폴더, 스키마 파일에 대한 모든 정보를 포함하는 설정 파일입니다.
프로젝트 루트에 drizzle.config.ts 파일을 생성하고 다음 내용을 추가하세요:
import { config } from 'dotenv';
import { defineConfig } from 'drizzle-kit';
config({ path: '.env' });
export default defineConfig({
schema: './src/db/schema.ts',
out: './migrations',
dialect: 'turso',
dbCredentials: {
url: process.env.TURSO_CONNECTION_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!,
},
});데이터베이스에 변경사항 적용
drizzle-kit generate 명령어를 사용하여 마이그레이션을 생성한 다음, drizzle-kit migrate 명령어를 사용하여 실행할 수 있습니다.
마이그레이션 생성:
npx drizzle-kit generate이러한 마이그레이션은 drizzle.config.ts에 지정된 대로 migrations 디렉토리에 저장됩니다. 이 디렉토리에는 데이터베이스 스키마를 업데이트하는 데 필요한 SQL 파일과 다양한 마이그레이션 단계에서 스키마의 스냅샷을 저장하기 위한 meta 폴더가 포함됩니다.
생성된 마이그레이션 예시:
CREATE TABLE `posts` (
`id` integer PRIMARY KEY NOT NULL,
`title` text NOT NULL,
`content` text NOT NULL,
`user_id` integer NOT NULL,
`created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
`updated_at` integer,
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `users` (
`id` integer PRIMARY KEY NOT NULL,
`name` text NOT NULL,
`age` integer NOT NULL,
`email` text NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);마이그레이션 실행:
npx drizzle-kit migrate또는 Drizzle kit push 명령을 사용하여 변경사항을 데이터베이스에 직접 푸시할 수 있습니다:
npx drizzle-kit push기본 파일 구조
프로젝트의 기본 파일 구조입니다. src/db 디렉토리에는 index.ts의 연결과 schema.ts의 스키마 정의를 포함한 데이터베이스 관련 파일이 있습니다.
📦 <project root>
├ 📂 src
│ ├ 📂 db
│ │ ├ 📜 index.ts
│ │ └ 📜 schema.ts
├ 📂 migrations
│ ├ 📂 meta
│ │ ├ 📜 _journal.json
│ │ └ 📜 0000_snapshot.json
│ └ 📜 0000_watery_spencer_smythe.sql
├ 📜 .env
├ 📜 drizzle.config.ts
├ 📜 package.json
└ 📜 tsconfig.json쿼리 예제
예를 들어, src/db/queries 폴더를 생성하고 각 작업(삽입, 조회, 업데이트, 삭제)에 대한 별도의 파일을 만듭니다.
데이터 삽입
삽입 쿼리에 대한 자세한 내용은 문서를 참조하세요.
import { db } from '../index';
import { InsertPost, InsertUser, postsTable, usersTable } from '../schema';
export async function createUser(data: InsertUser) {
await db.insert(usersTable).values(data);
}
export async function createPost(data: InsertPost) {
await db.insert(postsTable).values(data);
}데이터 조회
조회 쿼리에 대한 자세한 내용은 문서를 참조하세요.
getColumns는 drizzle-orm@1.0.0-beta.2부터 사용 가능합니다(자세히 보기)
버전 1 이전(0.45.1과 같은)을 사용하는 경우 getTableColumns를 사용하세요
import { asc, count, eq, getColumns, gt, sql } from 'drizzle-orm';
import { db } from '../index';
import { SelectUser, postsTable, usersTable } from '../schema';
export async function getUserById(id: SelectUser['id']): Promise<
Array<{
id: number;
name: string;
age: number;
email: string;
}>
> {
return db.select().from(usersTable).where(eq(usersTable.id, id));
}
export async function getUsersWithPostsCount(
page = 1,
pageSize = 5,
): Promise<
Array<{
postsCount: number;
id: number;
name: string;
age: number;
email: string;
}>
> {
return db
.select({
...getColumns(usersTable),
postsCount: count(postsTable.id),
})
.from(usersTable)
.leftJoin(postsTable, eq(usersTable.id, postsTable.userId))
.groupBy(usersTable.id)
.orderBy(asc(usersTable.id))
.limit(pageSize)
.offset((page - 1) * pageSize);
}
export async function getPostsForLast24Hours(
page = 1,
pageSize = 5,
): Promise<
Array<{
id: number;
title: string;
}>
> {
return db
.select({
id: postsTable.id,
title: postsTable.title,
})
.from(postsTable)
.where(gt(postsTable.createdAt, sql`(datetime('now','-24 hour'))`))
.orderBy(asc(postsTable.title), asc(postsTable.id))
.limit(pageSize)
.offset((page - 1) * pageSize);
}또는 관계형 쿼리 구문을 사용할 수 있습니다.
데이터 업데이트
업데이트 쿼리에 대한 자세한 내용은 문서를 참조하세요.
import { eq } from 'drizzle-orm';
import { db } from '../index';
import { SelectPost, postsTable } from '../schema';
export async function updatePost(id: SelectPost['id'], data: Partial<Omit<SelectPost, 'id'>>) {
await db.update(postsTable).set(data).where(eq(postsTable.id, id));
}데이터 삭제
삭제 쿼리에 대한 자세한 내용은 문서를 참조하세요.
import { eq } from 'drizzle-orm';
import { db } from '../index';
import { SelectUser, usersTable } from '../schema';
export async function deleteUser(id: SelectUser['id']) {
await db.delete(usersTable).where(eq(usersTable.id, id));
}