RemixでPrismaを使ってCloudFlareのD1を使ってマイグレーションをしたりする

## 概要

RemixにてPrismaを使いCloudFlareのD1のローカル用DBとデプロイ先DBにマイグレーションを行う方法を簡単にまとめる。
実際下記の内容の体験記

https://www.prisma.io/docs/orm/prisma-client/deployment/edge/deploy-to-cloudflare#cloudflare-d1

## 前提

- RemixがCloudFlareのテンプレートを使って作成済み
- CloudFlareにデプロイ済み
- 下記の記事を参考のPrismaに必要なパッケージが導入済み

https://qiita.com/miriwo/items/6c0837dcd12398acabdc

- CloudFlareにD1のデータベースが作成済み
- prisma/schema.prismaのファイルにテーブルスキーマの定義済み

## 準備

- CloudFlare上のD1データベースの「データベースID」を確認・メモしておく

## 流れ

D1は独自のマイグレーション処理？を用いてテーブル構造を反映する。
そのためPrismaオリジナルのマイグレーションコマンドを用いてD1の本番のテーブルの構造変更をする事はできない。
なので下記のように作業するようだ。

1. テーブルスキーマはPrisma側のschema.prismaに定義
1. CloudFlare側CLIコマンドを使ってマイグレーション処理を記載するファイル（器）を作成
1. Prismaを使ってスキーマ反映時に実行する素のSQLを2. の手順で作ったファイル（器）に追記
1. CloudFlare側CLIコマンドを使ってマイグレーション処理を実施（ローカル用のD1やデプロイ中のD1）
1. コード上でPrismaでテーブルにアクセスできるようにPrismaクライアントの作成


## 方法

### テーブルスキーマはPrisma側のschema.prismaに定義

今回すでにスキーマは記載されているものとする。
下記の記事を参考に`prisma/schema.prisma`のファイルにスキーマを記載しておく。

https://qiita.com/miriwo/items/6c0837dcd12398acabdc

### CloudFlare側CLIコマンドを使ってマイグレーション処理を記載するファイル（器）を作成

- 下記を実行してD1に接続するためのパッケージを取得する。

    ```shellscript
    npm install @prisma/adapter-d1
    ```

- schema.prismaを開き、clientの中を下記のように追記する。

    ```prisma/schema.prisma
    generator client {
      provider        = "prisma-client-js"
      previewFeatures = ["driverAdapters"]
    }
    ```

- プロジェクトルートにあるはずの`wrangler.toml`のファイルを開く。（CloudFlareのテンプレート指定してRemixを作成してればおそらく作られてる。めっちゃ記載されてるけどほとんどコメントアウトされているファイル。）`[[d1_databases]]`から`database_id`までの行のコメントアウトを解除する。
- それぞれの値を下記のように記載する。
    - `binding`： ソースコードからDBにアクセスするときの識別子、任意の値でOK
    - `database_name`： CloudFlare内部のDBの名前、任意の値NG、ちゃんと名前が一致している必要があり
    - `database_id`： CloudFlare内部のDBのデータベースID、任意の値NG、存在するデータベースIDである必要あり

    ![Shunokawa_gmail_com_s_Account___Cloudflare.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/c99c05bc-2e1e-d027-8b48-3ae034028d64.png)

- 下記を実行して「CloudFlare側CLIコマンドを使ってマイグレーション処理を記載するファイル（器）」を作成（〇〇には作るテーブル名をいれる）

    ```shellscript
    npx wrangler d1 migrations create wrangler.tomlに記載したdatabase_name create_〇〇_table
    ```

- 上記を実行すると、プロジェクトルートに`/migrations`というディレクトリが作られ、0001_create_〇〇_table.sqlみたいな空のファイルが作られる。これが「CloudFlare側CLIコマンドを使ってマイグレーション処理を記載するファイル（器）」

### Prismaを使ってスキーマ反映時に実行する素のSQLを2. の手順で作ったファイル（器）に追記

- 下記を実行して「Prismaを使ってスキーマ反映時に実行する素のSQLを2. の手順で作ったファイル（器）に追記」

    ```shellscript
    npx prisma migrate diff --from-empty --to-schema-datamodel ./prisma/schema.prisma --script --output migrations/0001_create_〇〇_table.sql
    ```

### CloudFlare側CLIコマンドを使ってマイグレーション処理を実施（ローカル用のD1やデプロイ中のD1）

- 下記を実行してローカル用のDBにマイグレーションを行う。（D1はSQLiteベースなのでローカルの場合は普通にプロジェクト内部に.sqliteのファイルができるっぽい。`.wrangler/state/v3/d1/miniflare-D1DatabaseObject`直下に.sqliteのファイルがあるので多分これがローカルのDBの実態だと思う。間違ってたらすみません。）

    ```shellscript
    npx wrangler d1 migrations apply wrangler.tomlに記載したdatabase_name --local
    ```

- 下記を実行してデプロイ中のD1にマイグレーションを行う。

    ```shellscript
    npx wrangler d1 migrations apply wrangler.tomlに記載したdatabase_name --remote
    ```

- 余談だけど、なんか下記みたいにしたらダミーデータも入れられるらしい。seedみたいな感じかな・・？？（このコードはガチでPrismaのドキュメントからパクっただけ。なのでテーブル名もUserで決め打ちになってる。このまま実行しても動かないので参考程度に。。）

    ```shellscript
    npx wrangler d1 execute wrangler.tomlに記載したdatabase_name --command "INSERT INTO  \"User\" (\"email\", \"name\") VALUES('jane@prisma.io', 'Jane Doe (Local)');" --local
    ```

### コード上でPrismaでテーブルにアクセスできるようにPrismaクライアントの作成

この内容は下記の内容を要約しているだけ。

https://www.prisma.io/docs/orm/prisma-client/deployment/edge/deploy-to-cloudflare#5-use-prisma-client-in-your-worker-to-send-a-query-to-the-database-2

- 下記を実行してPrismaのクライアントを作成する。

    ```shellscript
    npx prisma generate
    ```

- あくまで参考だが下記のようにすることでデータを取れるらしい。


    ```index.ts
    import { PrismaClient } from '@prisma/client'
    import { PrismaD1 } from '@prisma/adapter-d1'
    
    export interface Env {
      DB: D1Database
    }
    
    export default {
      async fetch(
        request: Request,
        env: Env,
        ctx: ExecutionContext
      ): Promise<Response> {
        const adapter = new PrismaD1(env.DB)
        const prisma = new PrismaClient({ adapter })
      
        const users = await prisma.user.findMany()
        const result = JSON.stringify(users)
        return new Response(result)
      },
    }
    ```

## 自分用メモ

自身がやろうとしていた「ローカル環境はSQLite、デプロイ環境はD1でそれぞれ.envを使って接続先を切り替える方法」はおそらく間違い。←これでかなり詰まった。
正しい方法は本方法で、最初からPrismaに用意されているD1にデプロイする方法を使い、その中に用意されているローカル用のD1を使う方法が正しい気がする。

## 参考文献

https://www.prisma.io/docs/orm/prisma-client/deployment/edge/deploy-to-cloudflare#5-use-prisma-client-in-your-worker-to-send-a-query-to-the-database-2

https://zenn.dev/chimame/articles/d3e7af9a612038