🗄️

Rails エンジニアが Prisma に入門する:開発フロー編

2022/07/28に公開

前回

https://zenn.dev/gabu/articles/f9ce106d626984

の続きです。

はじめに

前回チュートリアルをやりながら Prisma を一通り触ってみたわけですが、実際の開発(普通の Web アプリケーションを想像してください)となると、目的の機能を作るためにデータストアのレイヤーでは以下のようなことをよく行います。

  • 新しいモデル(テーブル)を追加
  • カラムを追加
  • 関連を追加
  • NULL/NOT NULLなど制約を変更

などなど。変更や削除は、運用を考えると取り回しを別途考えなければいけないので一旦触れません🙇‍♂️

いきなりつまづいた

チュートリアルでは prisma migrate dev を使ってマイグレーションファイルを作り、DBに反映することを学びましたし、Rails でも同様の思想で開発するのでこれが当たり前かと思ってしまいましたが、素振りをしている中でいきなり課題にぶつかりました。

https://twitter.com/gabu/status/1552464735991279616

Rails ではマイグレーションファイルを作って試し、開発を進める中でちょっとマイグレーションの内容を変えたくなった時に rails db:rollback で1つ戻して、マイグレーションファイルを変更して rails db:migrate で流して、いい感じになったらコミットするということをやっていました。本番環境では行いません。開発環境での試行錯誤中に限っての話です。

ちなみに、Ridgepole はもちろん知っているんですが、運用しているシステムでえいやで Ridgepole に切り替えるタイミングがなく今に至っています。。

で、Prisma では db:rollback に相当する機能はなく、このあたりの話の流れに興味がある方は以下のスレッドを見ていただくとして、

https://twitter.com/gabu/status/1552469815058526210

Prisma での開発フロー

開発中の試行錯誤を気持ちよくやりたいなーと社内 Slack でぼやいていると同僚がヒントをくれました(神!)

Schema prototyping with db push | Prisma Docs

またしても公式ドキュメントに答えはありました。結論的には、開発中の試行錯誤は prisma db push で DB への反映と Prisma Client の更新を行い(内部的に generate が実行されるので実際に実行するコマンドは prisma db push だけでOKです)、いい感じになったら migrate dev でマイグレーションファイルを生成するというワークフローです。

例えば、ざっくり以下のようなイメージです。

  • schema.prisma のモデル定義にフィールド(カラム) jobTitle を追加
  • prisma db push
  • schema.prismaname フィールドの型を String? から String に変更
    • Nullable から Required になるので NOT NULL 制約が付くはずです
  • prisma db push
  • 開発を進めていい感じになった
  • prisma migrate dev --name add-job-title-and-more
    • すみません名前は適当です。。
$ yarn prisma migrate dev --name add-job-title-and-more
yarn run v1.22.19
$ /Users/gabu/dev/src/github.com/gabu/hello-prisma/node_modules/.bin/prisma migrate dev --name add-job-title-and-more
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "hello_prisma", schema "public" at "localhost:5432"

Drift detected: Your database schema is not in sync with your migration history.

The following is a summary of the differences between the expected database schema given your migrations files, and the actual schema of the database.

It should be understood as the set of changes to get from the expected schema to the actual schema.

[*] Changed the `User` table
  [+] Added column `jobTitle`
  [*] Altered column `name` (changed from Nullable to Required)

✔ We need to reset the PostgreSQL database "hello_prisma" at "localhost:5432".
Do you want to continue? All data will be lost.

最後に migrate した状態から db push によって DB のスキーマが変わっているので、マイグレーションの履歴と DB が同期できていないと判定されます。 結果、migrate reset が必要になります。migrate reset するということはデータが全て消えます。やむなし。

yes

Applying migration `20220720022636_init`

The following migration(s) have been applied:

migrations/
  └─ 20220720022636_init/
    └─ migration.sql
Applying migration `20220728024844_add_job_title_and_more`


The following migration(s) have been created and applied from new schema changes:

migrations/
  └─ 20220728024844_add_job_title_and_more/
    └─ migration.sql

Your database is now in sync with your schema.

✔ Generated Prisma Client (4.1.0 | library) to ./node_modules/@prisma/client in 39ms


✨  Done in 22.57s.

試行錯誤した結果は、以下の1つのマイグレーションファイルに書き出されました。まる。

prisma/migrations/20220728024844_add_job_title_and_more/migration.sql
ALTER TABLE "User" ADD COLUMN     "jobTitle" TEXT NOT NULL,
ALTER COLUMN "name" SET NOT NULL;

これをコミットしておいて、デプロイ時に反映されるようにすれば良さそうですね!

ちなみに、Ridgepole っぽくて一見便利そうな db push ですが、本番環境には使わないことが推奨されています。

Choosing db push or Prisma Migrate

データを保ちながらあらゆるスキーマの変更の反映を自動化することは難しいので、本番環境ではマイグレーション方式を使うようにということです。テーブルやカラムを純粋に追加する場合は特に問題ないですが、変更や削除(削除はまぁあまりやりませんが)は、データのケアが必要になることが多いですよね(冒頭でも本編では触れないと謳ったのはそういう理由です)。

おわり

これで Prisma を使っての開発フローが決められましたし、開発時のキリのよい粒度でマイグレーションファイルを生成してコミットするということでOKそうです!

次は、デプロイと組み合わせた本番反映の仕組みの確認をしていきたいと思います。それでは!

株式会社モニクル

Discussion