【Cloudflare】Workers から Prisma で D1 を操作する
Cloudflare Workers から D1 を操作する際に Prisma を使ってみたので、その手順をまとめます。
Worker セットアップ
C3 で Worker を作ります。
$ npm create cloudflare@latest
D1 セットアップ
Wrangler CLI で D1 Database を作ります。
$ npx wrangler d1 create example_database
wrangler.toml に D1 の設定を追加し、Worker に D1 をバインドします。
これにより Worker から D1 にアクセスできるようになります。
各プロパティの詳細は公式ドキュメントを参照してください。
<snip>
[[d1_databases]]
binding = "DB"
database_name = "example_database"
database_id = "xxx"
Prisma セットアップ
Prisma CLI、Driver をインストールします。
$ npm install @prisma/client @prisma/adapter-d1
$ npm install --save-dev prisma
Prisma スキーマ作成
./prisma/schema.prisma にスキーマを定義します。
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"]
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}
マイグレーション
マイグレーションファイルの作成とマイグレーションの適用は Wrangler CLI で行います。
SQL の生成は Prisma CLI の migrate diff
コマンドを使います。このコマンドはモデルとデータベースの差分を出力してくれるものです。オプション指定によりマイグレーション用 SQL の生成が可能です。
なお、上記は Prisma の公式ドキュメントに記載されている手順です。
Wrangler CLI でマイグレーションファイルを作成します。
$ npx wrangler d1 migrations create example_database create_user_table
Prisma CLI で SQL を生成し、マイグレーションファイルに書き出します。
$ npx prisma migrate diff \
--from-empty --to-schema-datamodel ./prisma/schema.prisma \
--script --output migrations/0001_create_user_table.sql
-- CreateTable
CREATE TABLE "User" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"email" TEXT NOT NULL,
"name" TEXT
);
-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
マイグレーションを適用し、テーブルを作成します。
--remote
オプションを指定しない場合は、ローカルのデータベースに適用されます。
$ npx wrangler d1 migrations apply example_database --remote
Prisma 操作
Prisma を使って D1 を操作してみます。
User モデルを操作できるように、Prisma Client を生成しておきます。
$ npx prisma generate
レコード追加
/insert にリクエストが来た場合に、create メソッドを使ってレコードを追加する実装をしてみます。
import { PrismaD1 } from '@prisma/adapter-d1';
import { PrismaClient } from '@prisma/client';
interface Env {
DB: D1Database;
}
async function insert(env: Env): Promise<Response> {
const adapter = new PrismaD1(env.DB);
const prisma = new PrismaClient({ adapter });
await prisma.user.create({
data: {
name: 'Alice',
email: 'test@example.com',
},
});
return new Response('Inserted', { status: 200 });
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
if (new URL(request.url).pathname === '/insert') {
return insert(env);
}
return new Response('Not Found', { status: 404 });
},
};
Worker をデプロイし、/insert にリクエストを送ると、レコードが追加されます。
$ npx wrangler deploy
$ curl ${Worker のエンドポイント}/insert
Inserted
レコード取得
/select にリクエストが来た場合に、findMany メソッドを使ってレコードを取得する実装をしてみます。
import { PrismaD1 } from '@prisma/adapter-d1';
import { PrismaClient } from '@prisma/client';
interface Env {
DB: D1Database;
}
async function insert(env: Env): Promise<Response> {
const adapter = new PrismaD1(env.DB);
const prisma = new PrismaClient({ adapter });
await prisma.user.create({
data: {
name: 'Alice',
email: 'test@example.com',
},
});
return new Response('Inserted', { status: 200 });
}
async function select(env: Env): Promise<Response> {
const adapter = new PrismaD1(env.DB);
const prisma = new PrismaClient({ adapter });
const users = await prisma.user.findMany();
return new Response(JSON.stringify(users), { status: 200 });
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
if (new URL(request.url).pathname === '/insert') {
return insert(env);
} else if (new URL(request.url).pathname === '/select') {
return select(env);
}
return new Response('Not Found', { status: 404 });
},
};
$ npx wrangler deploy
$ curl ${Worker のエンドポイント}/select
[{"id":1,"email":"test@example.com","name":"Alice"}]
所感
Prisma の API で D1 を扱えるのは嬉しいですね。
しかし @prisma/adapter-d1 は 2024/10/19 現在プレビュー版であるので、本番環境での利用には検討が必要かもしれないです。GA 版リリースを待ちましょう。
Discussion