データベースマイグレーション
ひとつのアプリケーションが相手にするデータベースは、ひとつではありません。自分の
手元のファイル、同僚の手元のファイル、CI の実行ごとに作られる使い捨てのもの、
ステージング、本番 —— そのすべてを、誰も5か所で手作業の ALTER TABLE を打たずに
同じスキーマへ揃えなければなりません。
マイグレーションは、番号の付いた再実行可能なスキーマ変更の1ステップです。同じ 順序の集合をどのデータベースに再生しても同じ構造にたどり着きます。だからスキーマは、 各環境がそれぞれ覚えているものではなく、リポジトリが持つものになります。
| 用語 | 意味 |
|---|---|
| マイグレーション | 前進の変更と、その巻き戻しを1つにしたファイル |
| up / down | 前進の方向と、ロールバックの方向 |
| バージョン | 集合の順序を決める、マイグレーションの番号 |
| 適用済み / 未適用 | そのデータベースに記録済みか、まだ待っているか |
適用済みのバージョンはデータベース自身に、番号で記録されます。pw migrate up を
2回実行しても安全なのはこの記録があるからです。2回目は未適用のものを見つけません。
マイグレーションファイル
Section titled “マイグレーションファイル”マイグレーションは migrations/ に置き、goose の形式を使います。1つの .sql
ファイルに、注釈で区切られた2つのセクションを書きます。
-- +goose UpCREATE TABLE users ( id INTEGER PRIMARY KEY, name TEXT NOT NULL);
-- +goose DownDROP TABLE users;pw migrate create add_email実行するつもりがなくても Down は書いておきます。実行できないロールバックは、
失敗したデプロイの障害時間を、逆向きのマイグレーションを書き終えるまで引き延ばします。
pw dev は起動時に未適用のマイグレーションを適用するので、
普段の内側のループは「ファイルを作り、編集し、再起動する」だけです。開発中に
migrate コマンドを打つ場面はほとんどありません。
もう半分がデプロイとロールバックで、こちらは明示的に行います。
pw migrate statuspw migrate uppw migrate down自分で作ったのではないデータベースに対しては、up の前の status はその数秒を
かける価値があります。アクションの一覧は pw migrate に
あります。
どのデータベースに適用されるか
Section titled “どのデータベースに適用されるか”マイグレーションは middleware.rdb.write_group(設定されていれば、より狭い
middleware.rdb.migration_group)へ向かいます。readonly の接続が選ばれることは
なく、それをマイグレーション先に設定すると、最初の ALTER TABLE ではなく起動時に
失敗します。
pw は設定の優先順位を再実装せず、アプリケーション自身に解決済みの DSN を尋ねます。
つまりマイグレーションは APP_ENV の選択に従います。開発用でないデータベースへ
向けるときは、環境を確認してください。接続グループはリレーショナルデータベース、
キーそのものはアプリケーション設定一覧にあります。
テストでの扱い
Section titled “テストでの扱い”testutil.WithMigrations("../migrations") はテストサーバの起動前に集合を適用します。
スキーマの届き方は DSN のエンジンによって変わります。
- SQLite はキャッシュしたスナップショットをコピー先のデータベースへ再生します。
sqlite://:memory:が動くのはこのためです。プロセス内のデータベースには DSN で 到達できないので、接続文字列ではなく SQL のほうを転送します。 - PostgreSQL と MySQL はマイグレーションを直接適用します。同じデータベースに
対する2回目の
TestRunは何も適用せずスキーマを再利用します。1つのパッケージの テスト群が、用意済みのサーバを共有できるのはこの挙動によります。
サーバ系の DSN は、テストスイート専用のデータベースへ向けてください。適用済み バージョンは番号で記録されるため、別プロジェクトのバージョン 1 をすでに持つ データベースでは、最初のマイグレーションが適用済みに見え、スキーマは永遠に届きません —— しかもエラーは出ません。テストを参照してください。
スキーマだけでは、動かす相手としては物足りないのが普通です。それを使えるものにする 行はシードデータにあります。
