Prisma + MySQL でユニーク制約を削除する

2023/10/23に公開

概要

Prismaを使った開発中、DBのスキーマを変更する際、schema.prisma を変更して、migrationファイルを自動生成させるかと思います。
ただし、ユニークキーを取り除きたい場合は、MySQLをDBとして使用していると、自動でmigrationファイルが生成されません。
この記事では、Prisma + MySQLで、手動でmigrationファイルを作成することで、ユニーク制約を削除する方法について解説します。

  • 環境
    • MySQL (8.0)
    • Prisma (v4.14.0)

prisma migrate devでは、ユニーク制約を外せない

以下のモデルで、Profile.userIdのユニーク制約を外すことを考えます。

schema.prisma
model User {
  id      Int      @id @default(autoincrement())
  email   String   @unique
  name    String?
  role    Role     @default(USER)
  posts   Post[]
  profile Profile?
}

model Profile {
  id     Int    @id @default(autoincrement())
  bio    String
  user   User   @relation(fields: [userId], references: [id])
  userId Int    @unique
}

単純に、Profile.userId@unique を削除して、prisma migrate dev を実行してみると、スキーマの変更が検出されず、migrationファイルの生成もスキーマの変更も行われません。

schema.prisma の変更

schema.prisma
model Profile {
  id     Int    @id @default(autoincrement())
  bio    String
  user   User   @relation(fields: [userId], references: [id])
-  userId Int    @unique
+  userId Int
}

prisma migrate dev の実行結果

% npx prisma migrate dev --name remove_unique_constraint_on_profile_user_id

~~~ (出力抜粋)
Already in sync, no schema change or pending migration was found.

調べてみると、prismaのバグ?のようで、migrationファイルを自動生成してのschema変更はできないようです。
https://github.com/prisma/prisma/issues/12732

migrationファイルを手動で生成してスキーマを変更する

自動生成でのschema変更はできないようなので、上記のIssue にある通り、手動でmigrationファイルを作成してスキーマを変更します。

まずは、migrate dev --create-only を使って空のmigrationファイルを作成します。

% npx prisma migrate dev --name remove_unique_constraint_on_profile_user_id --create-only

~~~ (出力抜粋)
Prisma Migrate created the following migration without applying it 20231020092516_remove_unique_constraint_on_profile_user_id

You can now edit it and apply it by running yarn prisma migrate dev.

これで、migrations/ のフォルダに空のmigrationファイルが作成されます。

migration.sql
-- This is an empty migration.

続いて、こちらのSQLファイルに、ユニーク制約を削除するSQL文を書きます。
MySQLでは、外部キー制約のあるカラムのインデックスは削除できない仕様なので、一度外部キー制約を外してからユニーク制約を外し、外部キー制約を付け直します。
また、foreign key名やindex名は、MySQLでshow create table テーブル名 などで確認できます。

migration.sql
-- drop foreign key
ALTER TABLE `profiles`
    DROP FOREIGN KEY `profiles_userId_fkey`;

-- remove unique constraint
ALTER TABLE `profiles`
    DROP INDEX `profiles_userId_key`;
    
-- add foreign key
ALTER TABLE `profiles` 
  ADD CONSTRAINT `profiles_userId_fkey`
  FOREIGN KEY (`userId`) REFERENCES `users`(`id`);

最後に、migration deploy をすればschemaとmigrationの履歴が更新され、正しくユニーク制約が外れます。

% npx prisma migration deploy
株式会社Poksha

Discussion