golang-migrateでのPostgreSQLマイグレーション備忘録
はじめに
最近 Go での WebAPI 制作に挑戦しはじめて、DB のマイグレーション周りをはじめて触ったので備忘録として書きました。
詳細
マイグレーションツールには golang-migrate を使用しました。
現在 ORM に使っている GORM にもマイグレーションの機能がありますが、機能が乏しそうだったので専用ツールの golang-migrate を使ってみました。
選定基準は検索して一番上に出てきたからです!!!!
DB 立ち上げ
PostgreSQL の公式 Docker イメージを使ってローカルで立ち上げました。
コンテナを一度消したあともデータを持ち越せるよう、名前付きボリュームを設定しています。(匿名でもバインドでもよい)
環境変数のとこはサンプルなので適当に...デフォルトではユーザー名がそのまま DB 名になります。
version: "3"
services:
db:
image: postgres:14.1-alpine
ports:
- 5432:5432
volumes:
- sample:/var/lib/postgresql/data
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: admin-password
LANG: ja_JP.utf8
TZ: Asia/Tokyo
volumes:
sample:
driver: local
起動しときましょう!
$ docker-compose up -d
CLI で試す
最終的にコード内に記述しますが、一旦ローカルにインストール
$ brew install golang-migrate
あとは公式チュートリアルの流れに従って...
$ migrate create -ext sql -dir db/migrations -seq create_bookmarks_table
すると、db/migrations
以下に 000001_create_bookmarks_table.up.sql
と 000001_create_bookmarks_table.down.sql
ファイルが生成されています!
数字の部分がバージョン、その後に-seq
で指定したファイル名が入り、up
と down
用がそれぞれ存在する感じですね。up
でバージョンを上げ、down
で落とすので、down
は up
で書いた内容をそのまま逆に行う SQL を書くってことですね(migration 初心者なのではじめて知りました)。
早速テーブルの作成(up)を書きます。(URL の最大文字数が 50 なのは気にしないでください...)
CREATE TABLE IF NOT EXISTS bookmarks(
id serial PRIMARY KEY,
url VARCHAR (50) UNIQUE
);
続いて down の方も書きます、up の逆なので DROP TABLE
ですね。
DROP TABLE IF EXISTS bookmarks;
一旦現時点の DB 構成を見ると...
$ export POSTGRESQL_URL=postgres://admin:admin-password@localhost:5432/admin?sslmode=disable
$ psql ${POSTGRESQL_URL}
psql (14.1)
Type "help" for help.
admin=# \d
List of relations
Schema | Name | Type | Owner
--------+-------------------+-------+-------
public | schema_migrations | table | admin
(1 row)
admin=#
schema_migrations
テーブルは、バージョン(version
)とそのバージョンへの変更が正常に行われているか(dirty
)を保存してるテーブルです。
ここで先程書いたバージョン 1 を適用してみましょう。
$ migrate -database ${POSTGRESQL_URL} -path tools/db/migration up 1
1/u create_bookmarks_table (23.938542ms)
もう一度 DB を確認すると...
$ psql ${POSTGRESQL_URL}
psql (14.1)
Type "help" for help.
admin=# \d
List of relations
Schema | Name | Type | Owner
--------+-------------------+----------+-------
public | bookmarks | table | admin
public | bookmarks_id_seq | sequence | admin
public | schema_migrations | table | admin
(3 rows)
admin=#
テーブルとシーケンスが作成されてます!
今度はバージョンを落として DB 構成を確認します。
$ migrate -database ${POSTGRESQL_URL} -path tools/db/migration down
Are you sure you want to apply all down migrations? [y/N]
y
Applying all down migrations
1/d create_bookmarks_table (35.738583ms)
$ psql $POSTGRESQL_URL
psql (14.1)
Type "help" for help.
admin=# \d
List of relations
Schema | Name | Type | Owner
--------+-------------------+-------+-------
public | schema_migrations | table | admin
(1 row)
admin=#
先ほど作成されたものが削除されていますね。
Go のコードから試す
実際のところは、go run
したときにマイグレーションも実行したいことが多いと思うので、コード内への記述をします。
migrate.New()
の引数に、プロジェクトのルートから見たマイグレーションファイルの path と、CLI でも使用した URL を渡します。
package config
import (
"github.com/golang-migrate/migrate/v4"
_ "github.com/golang-migrate/migrate/v4/database/postgres"
_ "github.com/golang-migrate/migrate/v4/source/file"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
)
--中略--
m, err := migrate.New(
"file://tools/db/migration",
"postgres://admin:admin-password@localhost:5432?sslmode=disable",
)
if err != nil {
panic(err)
}
if err := m.Up(); err != nil {
if err != migrate.ErrNoChange {
panic(err)
}
}
特にバージョンアップがなかった場合エラーが出てしまったので、自分は ErrNoChange だけ許容するようにしてます。
これでマイグレーションが完了します!
まとめ
仕事ではフロントエンドとインフラ周りしか触ったことがないのでマイグレーション自体はじめてでしたが、コマンドが直感的でわかりやすく、初心者に優しいパッケージでした 😄
他の有名なツールも触っていきたいと思います。
Discussion