이 명령어의 출력 결과는 worker-configuration.d.ts 파일입니다.
Drizzle과 SQLite Durable Objects 시작하기
This guide assumes familiarity with:
Basic file structure
This is the basic file structure of the project. In the src/db directory, we have table definition in schema.ts. In drizzle folder there are sql migration file and snapshots.
📦 <project root>
├ 📂 drizzle
├ 📂 src
│ ├ 📂 db
│ │ └ 📜 schema.ts
│ └ 📜 index.ts
├ 📜 .env
├ 📜 drizzle.config.ts
├ 📜 package.json
└ 📜 tsconfig.json1단계 - 필수 패키지 설치
npm
yarn
pnpm
bun
npm i drizzle-orm wrangler dotenv
npm i -D drizzle-kit tsx
2단계 - wrangler.toml 설정
D1 데이터베이스를 위한 wrangler.toml 파일이 필요하며 다음과 같은 형태입니다:
#:schema node_modules/wrangler/config-schema.json
name = "sqlite-durable-objects"
main = "src/index.ts"
compatibility_date = "2024-11-12"
compatibility_flags = [ "nodejs_compat" ]
# Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model.
# Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps.
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#durable-objects
[[durable_objects.bindings]]
name = "MY_DURABLE_OBJECT"
class_name = "MyDurableObject"
# Durable Object migrations.
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#migrations
[[migrations]]
tag = "v1"
new_sqlite_classes = ["MyDurableObject"]
# We need rules so we can import migrations in the next steps
[[rules]]
type = "Text"
globs = ["**/*.sql"]
fallthrough = true3단계 - Drizzle ORM을 데이터베이스에 연결
import { drizzle, type DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite';
import { DurableObject } from 'cloudflare:workers'
export class MyDurableObject extends DurableObject {
storage: DurableObjectStorage;
db: DrizzleSqliteDODatabase;
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
this.storage = ctx.storage;
this.db = drizzle(this.storage, { logger: false });
}
}4단계 - wrangler 타입 생성
npm
yarn
pnpm
bun
npx wrangler types
5단계 - 테이블 생성
Create a schema.ts file in the src/db directory and declare your table:
import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";
export const usersTable = sqliteTable("users_table", {
id: int().primaryKey({ autoIncrement: true }),
name: text().notNull(),
age: int().notNull(),
email: text().notNull().unique(),
});6단계 - Drizzle 설정 파일 구성
Drizzle config - Drizzle Kit에서 사용하는 설정 파일이며, 데이터베이스 연결, 마이그레이션 폴더 및 스키마 파일에 대한 모든 정보를 포함합니다.
프로젝트 루트에 drizzle.config.ts 파일을 생성하고 다음 내용을 추가합니다:
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
out: './drizzle',
schema: './src/db/schema.ts',
dialect: 'sqlite',
driver: 'durable-sqlite',
});7단계 - 데이터베이스에 변경사항 적용
마이그레이션 생성:
npx drizzle-kit generate마이그레이션은 Cloudflare Workers에서만 적용할 수 있습니다. 이를 위해 MyDurableObject에 마이그레이션 기능을 정의합니다:
import { drizzle, type DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite';
import { DurableObject } from 'cloudflare:workers'
import { migrate } from 'drizzle-orm/durable-sqlite/migrator';
import migrations from '../drizzle/migrations';
export class MyDurableObject extends DurableObject {
storage: DurableObjectStorage;
db: DrizzleSqliteDODatabase;
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
this.storage = ctx.storage;
this.db = drizzle(this.storage, { logger: false });
}
async migrate() {
migrate(this.db, migrations);
}
}8단계 - 데이터베이스 마이그레이션 및 쿼리
import { drizzle, DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite';
import { DurableObject } from 'cloudflare:workers'
import { migrate } from 'drizzle-orm/durable-sqlite/migrator';
import migrations from '../drizzle/migrations';
import { usersTable } from './db/schema';
export class MyDurableObject extends DurableObject {
storage: DurableObjectStorage;
db: DrizzleSqliteDODatabase<any>;
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
this.storage = ctx.storage;
this.db = drizzle(this.storage, { logger: false });
// 쿼리를 수락하기 전에 모든 마이그레이션이 완료되었는지 확인합니다.
// 그렇지 않으면 Drizzle 데이터베이스 `this.db`에 접근하는 모든 함수에서
// `this.migrate()`를 실행해야 합니다.
ctx.blockConcurrencyWhile(async () => {
await this._migrate();
});
}
async insertAndList(user: typeof usersTable.$inferInsert) {
await this.insert(user);
return this.select();
}
async insert(user: typeof usersTable.$inferInsert) {
await this.db.insert(usersTable).values(user);
}
async select() {
return this.db.select().from(usersTable);
}
async _migrate() {
migrate(this.db, migrations);
}
}
export default {
/**
* Cloudflare Worker의 표준 fetch 핸들러
*
* @param request - 클라이언트에서 Worker로 제출된 요청
* @param env - wrangler.toml에 선언된 바인딩을 참조하는 인터페이스
* @param ctx - Worker의 실행 컨텍스트
* @returns 클라이언트에 전송될 응답
*/
async fetch(request: Request, env: Env): Promise<Response> {
const id: DurableObjectId = env.MY_DURABLE_OBJECT.idFromName('durable-object');
const stub = env.MY_DURABLE_OBJECT.get(id);
// 옵션 A - 최대 성능.
// DO 내에서 데이터베이스 접근이 빠르기 때문에,
// 모든 데이터베이스 상호작용을 하나의 Durable Object 호출로 묶는 것이 최대 성능을 위해 권장됩니다.
const usersAll = await stub.insertAndList({
name: 'John',
age: 30,
email: 'john@example.com',
});
console.log('New user created. Getting all users from the database: ', users);
// 옵션 B - 느리지만 디버깅에 유용할 수 있습니다.
// 노출된 개별 Drizzle 쿼리를 직접 호출할 수도 있지만,
// 모든 쿼리가 Durable Object 인스턴스로의 왕복임을 유의하세요.
await stub.insert({
name: 'John',
age: 30,
email: 'john@example.com',
});
console.log('New user created!');
const users = await stub.select();
console.log('Getting all users from the database: ', users);
return Response.json(users);
}
}