Prismaでレコードを保持したままテーブル名を変更する
EMのどんちゃんです。
HCCloudの開発では、DBにはPostgreSQLを使用しています。
ORMにはPrismaを採用しています。
ある時、機能名を変更することになり、実装との整合性を取るためにテーブル名を変更するという決断をしました。
GAされているサービスで、テーブル名を変更することはリスキーなので好ましくないですが、規模が小さいうちに、事前にバックアップを取った上で行うことにしました。
users
→ customer
テーブルに変更してみよう
今回は記事用に、いくつかのレコードがあるusers
テーブルを、単数系にしつつcustomer
テーブルに変更する場合を想定します。
Prismaでテーブル名を変更することは可能だが…
Prismaのスキーマファイルでは、@@map("テーブル名")
を使用することでDBに作成するテーブル名を指定することができます。
「じゃあここを変更したらええんちゃうの🧐」と思いますがそうはいきません。
yarn prisma migrate dev --create-only
コマンドを実行して生成されるSQLがこちら(yarnを使ってます)
/*
Warnings:
- You are about to drop the `users` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropForeignKey
ALTER TABLE "users" DROP CONSTRAINT "users_company_id_fkey";
-- DropTable
DROP TABLE "users";
-- CreateTable
CREATE TABLE "customer" (
"id" SERIAL NOT NULL,
"first_name" TEXT NOT NULL,
"last_name" TEXT NOT NULL,
"email" TEXT NOT NULL,
"company_id" INTEGER NOT NULL,
"role" TEXT,
"thumbnail_url" TEXT,
"last_login_at" TIMESTAMPTZ(6),
CONSTRAINT "customer_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "customer_email_key" ON "customer"("email");
-- AddForeignKey
ALTER TABLE "customer" ADD CONSTRAINT "customer_company_id_fkey" FOREIGN KEY ("company_id") REFERENCES "company"("id") ON DELETE CASCADE ON UPDATE CASCADE;
You are about to drop the
users
table. If the table is not empty, all the data it contains will be lost.
テーブルをdropしてからcreateするという挙動をします
これではレコードを維持したままリネームできないので工夫を加える必要があります。
Migrationファイルを加工
migrationファイルが生成されたら、それを下記のように書き換えます。
Dropされないように、制約や、シーケンスキー名、最後にテーブル名を変更するSQLにします。
なお、今回はPostgreSQLを前提としているので、他のRDBMSを利用している場合は読み替えてください。
ここを正確に行うようにしておきましょう。
-- RenamePrimaryKey
ALTER TABLE "users" RENAME CONSTRAINT "users_pkey" TO "customer_pkey";
-- RenameForeignKey
ALTER TABLE "users" RENAME CONSTRAINT "users_company_id_fkey" TO "customer_company_id_fkey";
-- Rename Sequence
ALTER SEQUENCE users_id_seq RENAME TO customer_id_seq;
-- RenameIndex
ALTER INDEX "users_email_key" RENAME TO "customer_email_key";
-- Rename Table
ALTER TABLE "users" RENAME TO "customer";
再度migrationを実行
yarn prisma migrate dev
これで、レコードを保持したままテーブル名の変更ができます。
余計なMigrationファイルを作りたくない場合
上記の方法の場合、--create-only
と、適用時に同じようなMigrationファイルが2つできてしまいます。
それを回避するには、次の方法を取れます(DBに直接SQLを実行できる場合に可能です)
SQLを実行
Migrationファイルを加工 で作成したSQLをRDBMSから実行します。
Migrationを解決
次に、Prismaと整合性を取るために prisma migrate dev --create-only
で作成したMigrationファイルを解決状態にします。
yarn prisma migrate resolve --applied {migrationディレクトリ名}
例:
yarn prisma migrate resolve --applied 20250909063523_rename_users_to_customer
本番環境への適用
ローカル環境では、上記の方法でテーブル名の変更、Migrationファイルの作成が完了します。
通常通り、CI/CDなどで下記のコマンドで本番環境もデータを保持したままリネームできます🚀
yarn prisma migrate deploy
FYI
Discussion