Cloudflare D1でDrizzle ORMを使う
はじめに
Cloudflare D1でDrizzle ORMを利用するための手順をまとめました。以下の公式ドキュメントを参考に作業を進めます。
なお記事を投稿した時点でDrizzle公式ドキュメントに一部不備がありました。内容は適宜補足します。
環境
記事の投稿にあたり、以下の環境で動作確認しました。
- node: 23.5.0
- drizzle-orm: 0.38.3
- drizzle-kit: 0.30.1
動作確認はmacOSで行いましたが、Node.jsが動作する環境であればWindowsやLinuxなどOSに依存せず動作するはずです。
Step 1: Workersプロジェクトを作成する
まずはWorkersプロジェクトを作成します。以下のコマンドを実行してください。
$ npm create cloudflare@latest
各項目は以下のように回答しました。
├ In which directory do you want to create your application?
│ dir ./drizzle-test
│
├ What would you like to start with?
│ category Hello World example
│
├ Which template would you like to use?
│ type Hello World Worker
│
├ Which language do you want to use?
│ lang TypeScript
デプロイは後で行います。「Do you want to deploy your application?」はひとまずNoで進めてください。
Step 2: D1データベースを作成する
続いてD1データベースを作成します。以下のコマンドを実行してください。
cd ./drizzle-test
$ npx wrangler d1 create my-database
次の手順で利用するため、実行結果をメモしてください。
実行結果の例
⛅️ wrangler 3.100.0
--------------------
✅ Successfully created DB 'my-database' in region WNAM
Created your new D1 database.
[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Step 3: wrangler.tomlファイルを編集する
wrangler.tomlファイルを開き、末尾にD1データベースの項目を追加します。以下のように編集してください。
#:schema node_modules/wrangler/config-schema.json
name = "drizzle-test"
main = "src/index.ts"
compatibility_date = "2024-12-30"
compatibility_flags = ["nodejs_compat"]
# (省略)
[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
※database_id = "xxx..."
はStep 3でメモした内容で置き換えてください。
Step 4: バインディングの型定義を生成する
以下のコマンドを実行してください。
$ npx wrangler types
以下のように、worker-configuration.d.ts
ファイルにD1データベースの型定義が追加されていれば成功です。
$ cat ./worker-configuration.d.ts
// Generated by Wrangler by running `wrangler types`
interface Env {
DB: D1Database;
}
Step 5: Drizzleをインストールする
以下のコマンドを実行してください。
$ npm i drizzle-orm dotenv
$ npm i -D drizzle-kit tsx
Step 6: テーブルを定義する
src/db
ディレクトリを作成し、以下の内容でsrc/db/schema.ts
ファイルを作成してください。
import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core';
export const usersTable = sqliteTable('users', {
id: int().primaryKey({ autoIncrement: true }),
name: text().notNull(),
age: int().notNull(),
email: text().notNull().unique(),
});
補足情報を表示
(補足)名前のマッピングについて
Drizzleはテーブル名やカラム名をTypeScriptのコードにマッピングする設定が可能です。ただし、DrizzleのGet startedに定義されている実装ではusers
ではなくusers_table
テーブルが作成されてしまいます。
// 修正前
export const usersTable = sqliteTable("users_table", {
// 修正後
export const usersTable = sqliteTable("users", {
Step 7: drizzle.config.tsファイルを作成する
プロジェクトのルートディレクトリにdrizzle.config.ts
ファイルを作成します。以下の内容でファイルを作成してください。
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
out: './drizzle',
schema: './src/db/schema.ts',
dialect: 'sqlite',
driver: 'd1-http',
dbCredentials: {
accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
databaseId: process.env.CLOUDFLARE_DATABASE_ID!,
token: process.env.CLOUDFLARE_D1_TOKEN!,
},
});
補足情報を表示
(補足)driverプロパティについて
公式ドキュメントでは空欄になっていますが間違いです。
// 修正前
driver: '',
// 修正後
driver: 'd1-http',
なお空欄のままdrizzle-kit migrate
を実行するとバリデーションエラーが発生してコマンドの実行が中断します。
Step 8: 環境変数を設定する
プロジェクトのルートディレクトリに.env
ファイルを作成します。以下3つの環境変数を設定してください。
CLOUDFLARE_ACCOUNT_ID='CloudflareのアカウントID'
CLOUDFLARE_DATABASE_ID='wrangler.tomlファイルに設定したdatabase_idと同じ値'
CLOUDFLARE_D1_TOKEN='Cloudflareダッシュボードで発行したAPIトークン'
補足情報を表示
(補足)アカウントIDとAPIトークンの取得方法
CloudflareのアカウントIDはCloudflareのダッシュボードに表示されています。ダッシュボードにログイン→Workers & Pagesに移動→Account IDのコピーボタンをクリックすると取得できます。
APIトークンについては、Cloudflareのダッシュボードにログイン→Account Manage→Account API Tokens→Create Tokenから作成できます。
トークン作成画面に移動したら、Custom tokenのGet startedボタンをクリックします。項目は以下のように設定します。
- Resources: Accountを選択
- Permissions: D1を選択
- Permissions levels: Editを選択
トークンの名前や有効期間などは適当で構いません。入力が完了したらContinue to summaryボタンをクリックしてください。
権限として「D1:Edit」と表示されていることを確認したら、Create Tokenボタンをクリックしてください。D1データベースの操作権限のあるトークンが発行されます。
Step 9: マイグレーションファイルを生成する
以下のコマンドを実行してマイグレーションファイルを生成します。
$ npx drizzle-kit generate
以下のような結果が表示されたら成功です。
No config path provided, using default 'drizzle.config.ts'
Reading config file '/private/tmp/drizzle-test/drizzle.config.ts'
1 tables
users 4 columns 1 indexes 0 fks
[✓] Your SQL migration file ➜ drizzle/0000_daily_hardball.sql 🚀
Step 10: マイグレーションを適用する
以下のコマンドを実行してマイグレーションを適用します。
$ npx drizzle-kit migrate
結果は以下の2行しか表示されません。成功したか不安になりますが、エラーメッセージが表示されなければ成功です。
No config path provided, using default 'drizzle.config.ts'
Reading config file '/private/tmp/drizzle-test/drizzle.config.ts'
補足情報を表示
(補足)drizzle-kit pushコマンドについて
DrizzleのGet startedではdrizle-kit push
コマンドを実行してマイグレーションを適用する方法が示されています。しかし、このコマンドは失敗します。
$ npx drizzle-kit push
No config path provided, using default 'drizzle.config.ts'
Reading config file '/private/tmp/drizzle-test/drizzle.config.ts'
[✓] Pulling schema from database...
Error: 7500: not authorized: SQLITE_AUTH
なおエラーが発生するのはpushサブコマンドのみです。すでにGitHubにIssueが登録されているため、いずれ修正されるはずです。
push / pullサブコマンドは既存のデータベースからスキーマを読み取りコードを生成する場合に利用します。ただし、別のツールでマイグレーションに利用する.sql
ファイルを生成し、migrateサブコマンドを実行することでも同様の結果が得られます。
Step 11: レコードの読み書き処理を実装する
GETリクエストでレコードを取得、POSTリクエストでレコードを挿入する処理を実装しましょう。src/index.ts
を以下の内容で置き換えてください。
import { drizzle } from 'drizzle-orm/d1';
import { usersTable } from './db/schema';
export default {
async fetch(request, env, ctx): Promise<Response> {
switch (request.method) {
case 'POST': {
const db = drizzle(env.DB);
const record: typeof usersTable.$inferInsert = {
name: 'John',
age: 23,
email: crypto.randomUUID() + '@example.com',
};
await db.insert(usersTable).values(record);
return new Response(null, { status: 201 });
}
case 'GET': {
const db = drizzle(env.DB);
const result = await db.select().from(usersTable).all();
return Response.json({ count: result.length, values: result });
}
default: {
return new Response(null, { status: 405 });
}
}
},
} satisfies ExportedHandler<Env>;
Step 12: 動作確認
それでは動作確認してみましょう。まずはWorkerをデプロイします。以下のコマンドを実行してください。
$ npx wrangler deploy
バインディングが正しく設定されているか確認するには?
D1データベースのバインディングが正しく認識されているか確認しましょう。以下のように「db: my-database ...」がコマンドの実行結果に含まれていれば正常です。
⛅️ wrangler 3.100.0
--------------------
Total Upload: 188.87 KiB / gzip: 38.52 KiB
Worker Startup Time: 13 ms
Your worker has access to the following bindings:
- D1 Databases:
- DB: my-database (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
Uploaded drizzle-test (2.96 sec)
Deployed drizzle-test triggers (0.66 sec)
https://drizzle-test.<your_name>.workers.dev
Current Version ID: e27fe9b1-b79a-487b-a6c0-44356d180b1b
まずはGETリクエストを試しましょう。以下のコマンドを実行してください。
※URLの<your_name>
は各自の値に読み替えてください。
$ curl https://drizzle-test.<your_name>.workers.dev
この時点でテーブルは空なので以下のレスポンスが返されます。
{"count":0,"values":[]}
次はレコードを作成してみましょう。以下のようにPOSTリクエストを送信してください。
$ curl -i -X POST https://drizzle-test.<your_name>.workers.dev
リクエストが成功すると201 Createdレスポンスが返されます。
HTTP/2 201
date: Thu, 09 Jan 2025 04:58:22 GMT
content-length: 0
# 以下省略
これでテーブルに1つのレコードが挿入されました。改めてGETリクエストを送信して確認してみましょう。
$ curl https://drizzle-test.<your_name>.workers.dev
以下のような結果が得られます。
{"count":1,"values":[{"id":1,"name":"John","age":23,"email":"d73c45b2-ebd2-46e6-9afe-c5fb60204c9d@example.com"}]}%
作業は以上で完了です。Drizzle ORMをCloudflare D1データベースに対して利用できることが確認できました。
Discussion