はじめに
基本的なORMの利用方法としては、以下のようにモデル→データベースの順番で作成・構築していくと思う。
- モデルを定義
- データベースにそのモデルに合致するテーブルを構築
ただ、モデルの定義をしてからテーブルを構築だとどうしてもかゆい所に手が届かなかったりもするので、上記の逆の手順で、データベース→モデルという順番で作成・構築する事もあると思う。
- GUIツール(MySQL WorkbenchやNavicatなど)を利用してテーブルを設計
- テーブル定義からモデルを作成
ただこの場合、ORMライブラリに備わっている機能を使ってモデルの変更に合わせマイグレーションをするという事ができないので、dev, staging, productionと環境があった時には、手動でSQLを流してマイグレーションを行う必要がある(モデル→テーブルの変更の順であれば、Prismaの場合、prisma migrate deploy
で開発環境で作成したマイグレーションを環境ごとに適用するだけ(詳細はここを参照)。
そのマイグレーションのSQLとロールバックのSQLを、うまく簡単に作り、バージョン管理もできなかな~と思い、今回はPrismaを利用して、手動でマイグレーション・ロールバックのSQLを作成する手順を考えてみたいと思う。
データベースへの更新、モデルへの反映、マイグレーション用のSQL作成の流れ
まず、初期化と変更の2つがあると思うので、2つに分けてみていく。
- 初期化
一番最初にテーブルを作成するタイミングで、マイグレーションの初期ファイルを作る - 変更
テーブルの追加・変更など繰り返し行う手順で、今回で言うとこの変更時のマイグレーション・ロールバックのSQLを作成する部分が肝になる
初回
初回はIntrospectionにあるように、データベースからテーブルの定義を読み出し、モデルを作成したり、マイグレーションの初期ファイルを作成する。手順化すると以下のようになるだろう。
- GUI(MySQL WorkbenchやNavicat)でテーブルを設計・作成
-
npx prisma db pull
でモデルを作成 -
mkdir -p prisma/migrations/0_init
で初期状態を作るマイグレーションの格納先を作成 -
npx prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
で初期状態を作るマイグレーションのSQLを作成
実際にやってみた時のログは以下。
変更
続いて、今回やりたかったことの本題になる、テーブルの追加・変更を行った時に、各環境に反映するためのマイグレーションのSQLをどうやって作成するか、またロールバックのSQLをどうやって作成するか、を見ていきたいと思う。手順のサマリとしては以下のようになる。
- GUI(MySQL WorkbenchやNavicat)でテーブルを設計・作成
-
mkdir -p prisma/migrations/1_hogehoge
でマイグレーションの格納先を作成 -
npx prisma migrate diff --from-schema-datamodel prisma/schema.prisma --to-url mysql://root:@localhost:3306/prisma-express --script > prisma/migrations/1_hogehoge/migration.sql
でマイグレーションのSQLを作成する(詳細はのちほど) -
npx prisma migrate diff --from-url mysql://root:@localhost:3306/prisma-express --toschema-datamodel prisma/schema.prisma script > prisma/migrations/1_hogehoge/rollback.sql
でマイグレーションのSQLを作成する(詳細はのちほど) -
npx prisma db pull
でモデルを更新
少し補足する。
4,5の手順だが、それぞれ以下のように考えてマイグレーション・ロールバックのSQLを作成している。
- 4
データベースのテーブルが最新で、手元のモデルはそれを反映していないので、手元のモデル→データベースのテーブルに同期するために必要なSQLを出力すると、それが各環境に適用すべきマイグレーションのSQLになる
そのため、--from-schema-datamodel
でローカルのモデルを指定し、--to-url
でデータベース(のURL)を措定している - 5
こちらは4の逆の考えでロールバックのSQLを作成している
つまり、データベースのテーブルが最新なので、その最新の状態を手元のモデルに反映する(データベースのテーブル→モデル)をするために必要なSQLを出力すると、 それがロールバックのSQLになる
そのため、--from-url
でデータベース(のURL)を指定し、--to-schema-datamodel
でローカルのモデルを措定している
実際にやってみた時のログは以下。
※ただ、上記の方法で課題がある。prisma migrate diff
で--scriptオプションを付与して生成されるSQLのCOLLATEがutf8mb4_unicode_ci
になってしまい、データベースのテーブルの状態と乖離してしまう
現時点でissueを見る限り、この部分は手動で修正が必要になる。
※上記のPrismaの動きに関して、MySQL8のデフォルトのCOLLATEはutf8mb4_0900_as_ci
であるにもかかわらず、Prismaで作成したSQLのCOLLATEがなぜutf8mb4_unicode_ciになるのかは謎・・・。どこからきているのか?不明だった(MySQL8のデフォルトのCollationについてはここを参照)。
まとめとして
Prismaを活用する事で、データベース→モデルという逆の順番で開発を進めていても、効率よくマイグレーション・ロールバックのSQLを作成でき、またそれをGitの管理下に置く事でリリース時にはそれを流せばいいか?という事だけ気にすればよくなるのでいいのではと思った(マイグレーション・ロールバックのSQLをリリースの準備で作らないで良くなるし、そのSQLがどこにあるか分からないという事態にもならないので)。