Remix+CloudflareでWebサイトを作る 23
【2024-04-07】Prismaでデータが入っている既存のテーブルにカラムを追加する
We need to reset the SQLite database
All data will be lost.
まずは既存のDBの定義とPrismaのモデルと同期する。
- includeRelationFromFields = true
+ includeRelationFromFields = "true"
"true"
という文字列なんか嫌だな...。
--create-only
オプションをつけてマイグレーションファイルの作成だけをして適用はしないようにする。
$ npx prisma migrate dev --create-only --name your-migration-name
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": SQLite database "dev.db" at "file:./dev.db"
- Drift detected: Your database schema is not in sync with your migration history.
✖ We need to reset the SQLite database "dev.db" at "file:./dev.db"
Do you want to continue? All data will be lost. … no
All data will be lost.
....???
--create-only
するだけでなぜ消えるのか。
Prisma migrationを導入しようとすると、最初のタイミングでmigration用の管理テーブルが作られる。そして手動で定義していたものについてはその時点で既存のテーブルは一度削除されてしまうという仕様のようだ。テーブルが削除されるのでもちろんデータも消える。開発環境とは言えそれなりの量のデータが入っていること、本番適用時にデータが全部消えてしまうのは論外なこともあり色々と調べたり試したりしたものの良い解決策は見つからなかった。
--create-onlyをつけて実行すると実行日時のフォルダとともにマイグレーションファイルができあがり、マイグレーションの管理テーブルだけが作成された状態でマイグレーションファイルの内容は反映されていない状態となる。大事なことなので2回言うが、DB上は全部のテーブルが削除された上でマイグレーションの管理テーブルのみが存在しているという状態になる。
これに関してはどうしようもないので既存のものに導入する場合、かつデータも残したい場合は事前にバックアップするなり、テーブル単位でエクスポートしておくことは必須といえる。
ref: 既存のデータベースでPrisma migrateする。しかもPostGISを使う - Sweet Escape
ALTER TABLE tableName ADD COLUMN columnName BOOLEAN DEFAULT FALSE;
こんな感じでカラムだけ追加するSQL作成してほしいんだけどどこらへんがネックなんだろうか。
Refs
- Add a new field without losing data · prisma/prisma · Discussion #8724
- Baselining: prisma migrate dev --create-only asks for RESET DB · Issue #14746 · prisma/prisma
- npx prisma migrate dev --create-only · Issue #18236 · prisma/prisma
time-travelでバックアップ
マイグレーションファイル適当に作って中身のSQL書き換えようかなとも思ったけど、Prismaの思想に反するのもなんか良くない気もする。
ということで「バックアップ取って→マイグレーション→データ入れ直す」の一連の流れをちゃんとわかっておこう。
Backups (Legacy) · Cloudflare D1 docs
wrangler d1 backup
コマンドでバックアップできるっぽいけど、開発環境でのバックアップコマンドはなさそう。
Commands - Wrangler · Cloudflare Workers docs
wrangerコマンドのページを見ても--local
的なオプションがないのでなさそう。
Cloudflare Workers から D1 を操作する
今はwrangler d1 time-travel
の方か。そうでした。
結論
Development
カラムを追加するとDBのデータはすべて消えてしまうので諦める。
Staging/Production
以下でなんとかなりそうだけど全然スマートじゃない気がする。
bookmark取得
→テーブル初期化
→$ npm exec -- zx prisma/d1-migration.mjs --env=staging
でスキーマ更新
→restore
schema.prisma
に変更があった場合だけこの処理やってくれるGitHub Actionsとかあったら便利かな?
UserテーブルにOptionalなカラムであるtest
を追加した場合はAlterだけ
-- AlterTable
ALTER TABLE "User" ADD COLUMN "test" TEXT;
UserテーブルにRequiredなカラムであるhoge
を追加した場合は、tempとなるテーブルを作成してデータを移し替えて元のテーブルを削除して、tempとなるテーブルをリネームしている。
/*
Warnings:
- Added the required column `hoge` to the `User` table without a default value. This is not possible if the table is not empty.
*/
-- RedefineTables
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_User" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" TEXT,
"test" TEXT,
"hoge" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_User" ("createdAt", "email", "iconUrl", "id", "isArchived", "name", "role", "test", "updatedAt") SELECT "createdAt", "email", "iconUrl", "id", "isArchived", "name", "role", "test", "updatedAt" FROM "User";
DROP TABLE "User";
ALTER TABLE "new_User" RENAME TO "User";
CREATE UNIQUE INDEX "User_id_key" ON "User"("id");
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
PRAGMA foreign_key_check;
PRAGMA foreign_keys=ON;
このやり方でどうにかできそう。
後で試す。
【2024-04-10】Service Bindingのためにmonorepo構成にする
背景
こちらを参考にmonorepo構成にしてみている。
Service Binding自体についてこっちの記事も良かった。
エラー
Remix側とPrismaのWorkerがうまく連携できていないっぽい。
WARNING: Tried to access method or property 'fetchIdByEmail' on a Service Binding or Durable Object stub. Are you trying to use RPC? If so, please enable the 'rpc' compat flag or update your compat date to 2024-04-03 or later (see https://developers.cloudflare.com/workers/configuration/compatibility-dates/ ). If you are not trying to use RPC, please note that in the future, this property (and all other property names) will appear to be present as an RPC method.
指示通りにしても治らず。
compatibility_date = "2024-04-03"