Goのコードからマイグレーションしてくれるツールないかなあと探していたところ、miguを見つけました。
開発も止まってなさそうなので、とりあえず使ってみることにしました。(2021/2/17時点)
サポートされているDBは「MariaDB / MySQL / Cloud Spanner」です。
開発者の方が基本的にMariaDB/MySQLしか使わないためメンテナンスできないことが理由だそうです。
プルリクをもらったらサポートを考えるそうです。
Dockerで環境構築
FROM golang:1.15.6-alpine
ENV GO111MODULE on
ADD . /migu_sample
WORKDIR /migu_sample
RUN apk update && apk add --no-cache git mariadb-dev mysql-client
RUN go get github.com/go-sql-driver/mysql && go get -u github.com/naoina/migu/cmd/migu
version: '3'
services:
app:
build:
context: .
container_name: app_migu_sample
volumes:
- '.:/migu_sample/'
ports:
- '8000:8000'
tty: true
db:
image: mariadb:latest
container_name: db_migu_sample
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
environment:
- MYSQL_ROOT_USER=root
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=db_migu_sample
- MYSQL_USER=user
- MYSQL_PASSWORD=user
volumes:
- db_data:/var/lib/mysql
ports:
- '3333:3306'
volumes:
db_data:
driver: local
スキーマを定義する
+migu
の記述のある構造体がマイグレーション対象として認識されます。
package model
// +migu
type User struct {
Username string
}
マイグレーション実行
コマンドは
migu sync -u ユーザー名 -h ホスト名 -p データベース名 スキーマファイル(または パッケージ)
docker-compose exec app migu sync -u root -h db -p db_migu_sample model/user.go
# docker-compose exec app migu sync -u root -h db -p db_migu_sample model とするとmodel直下のファイル全てがマイグレーション対象
================ 実行結果 ================
--------applying--------
CREATE TABLE `user` (
`username` VARCHAR(255) NOT NULL
)
もちろんテーブルが存在しない場合はテーブルを作成してくれます。
無事マイグレーション。
カラム追加
モデルに追加してマイグレーションを実行するだけです
package model
// +migu
type User struct {
Username string
Password string // 追加
}
docker-compose exec app migu sync -u root -h db -p db_migu_sample model/user.go
================ 実行結果 ================
--------applying--------
ALTER TABLE `user` ADD `password` VARCHAR(255) NOT NULL
--------done 0.005s--------
Primary Keyを定義
package model
// +migu
type User struct {
ID int64 `migu:"pk"`
Username string
Password string
}
docker-compose exec app migu sync -u root -h db -p db_migu_sample model/user.go
================ 実行結果 ================
--------applying--------
ALTER TABLE `user` ADD `id` BIGINT NOT NULL
--------done 0.006s--------
--------applying--------
ALTER TABLE `user` ADD PRIMARY KEY (`id`)
--------done 0.023s--------
--------done 0.005s--------
Primary Keyをオートインクリメントする
autoincrement
をつけるだけです
// +migu
type User struct {
...
_ int64 `migu:"pk,column:id,autoincrement"`
..
.
}
ベースモデル的なものを作る
ただ、BaseModelを実装し、Userモデルに埋め込んでもDDLに反映されません。
「_(アンダースコア)」を使用して対応するフィールドを記述することで、DDLに反映されるようになるようです。
package model
type BaseModel struct {
ID int64
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt time.Time
}
// +migu
type User struct {
Username string
Password string
BaseModel
_ int64 `migu:"pk,column:id"` // column:~~ がないとマイグレーションを実行しても無視される
_ time.Time `migu:"column:created_at"`
_ time.Time `migu:"column:updated_at"`
_ time.Time `migu:"column:deleted_at,null"`
}
docker-compose exec app migu sync -u root -h db -p db_migu_sample model/user.go
================ 実行結果 ================
--------applying--------
ALTER TABLE `user` ADD `id` BIGINT NOT NULL COMMENT 'column:~~ がないとマイグレーションを実行しても無視される'
--------done 0.008s--------
--------applying--------
ALTER TABLE `user` ADD `created_at` DATETIME NOT NULL
--------done 0.005s--------
--------applying--------
ALTER TABLE `user` ADD `updated_at` DATETIME NOT NULL
--------done 0.013s--------
--------applying--------
ALTER TABLE `user` ADD `deleted_at` DATETIME
--------done 0.016s--------
--------applying--------
ALTER TABLE `user` ADD PRIMARY KEY (`id`)
--------done 0.138s--------
文字列の最大長などを設定する
// +migu
type User struct {
Username string
Password string `migu:"type:varchar(128)"`
Weight float64 `migu:"type:decimal(2,1)"`
}
migu_sample % docker-compose exec app migu sync -u root -h db -p db_migu_sample model/user.go
================ 実行結果 ================
--------applying--------
ALTER TABLE `user` CHANGE `password` `password` VARCHAR(128) NOT NULL
--------done 0.048s--------
--------applying--------
ALTER TABLE `user` ADD `weight` DECIMAL(2,1) NOT NULL
--------done 0.003s--------
Nullを許容する
カラムはデフォルトでNotNullになってしまうっぽいので、Nullを許容したいフィールドは明示的に記述する必要があるみたいです。
// +migu
type User struct {
Username string
Password string `migu:"type:varchar(128)"`
Weight float64 `migu:"type:decimal(2,1),null"` // 明示的にnullを記述
}
docker-compose exec app migu sync -u root -h db -p db_migu_sample model/user.go
================ 実行結果 ================
--------applying--------
ALTER TABLE `user` CHANGE `weight` `weight` DECIMAL(2,1) // DDLからNOT NULLが消えた
--------done 0.025s--------
インデックスを張る
// +migu
type User struct {
Username string `migu:"index"` // index:user_index で任意のインデックス名にもできる
...
..
.
}
docker-compose exec app migu sync -u root -h db -p db_migu_sample model/user.go
================ 実行結果 ================
--------applying--------
ALTER TABLE `user` CHANGE `username` `username` VARCHAR(255) NOT NULL
--------done 0.002s--------
--------applying--------
ALTER TABLE `user` CHANGE `id` `id` BIGINT NOT NULL
--------done 0.003s--------
--------applying--------
CREATE INDEX `user_username` ON `user` (`username`)
--------done 0.010s--------
ユニーク制約を設定する
// +migu
type User struct {
Username string `migu:"unique"`
...
..
.
}
docker-compose exec app migu sync -u root -h db -p db_migu_sample model/user.go
================ 実行結果 ================
--------applying--------
ALTER TABLE `user` CHANGE `username` `username` VARCHAR(255) NOT NULL
--------done 0.001s--------
--------applying--------
DROP INDEX `user_username` ON `user`
--------done 0.018s--------
--------applying--------
CREATE UNIQUE INDEX `user_username` ON `user` (`username`)
--------done 0.009s--------
登録日時カラムに自動で値が入るようにしたい
// +migu
type User struct {
...
_ time.Time `migu:"column:created_at,default:current_timestamp"`
..
.
}
docker-compose exec app migu sync -u root -h db -p db_migu_sample model/user.go
================ 実行結果 ================
--------applying--------
ALTER TABLE `user` CHANGE `created_at` `created_at` DATETIME NOT NULL DEFAULT current_timestamp
--------done 0.002s--------
更新日時カラムに自動で値が入るようにしたい
初回登録時に「0000年0月0日」がはいってしまうので、Nullを許容してdefault:nullにしてます。
(default:current_timestampにしてしまっても良いと思います)
// +migu
type User struct {
...
_ time.Time `migu:"column:updated_at,null,default:null,extra:ON UPDATE CURRENT_TIMESTAMP"`
..
.
}
docker-compose exec app migu sync -u root -h db -p db_migu_sample model/user.go
================ 実行結果 ================
--------applying--------
ALTER TABLE `user` CHANGE `updated_at` `updated_at` DATETIME DEFAULT null ON UPDATE CURRENT_TIMESTAMP
--------done 0.046s--------
テーブル名を指定する
// +migu table:"auth_users"
type User struct {
...
..
.
}
docker-compose exec app migu sync -u root -h db -p db_migu_sample model/user.go
================ 実行結果 ================
--------applying--------
CREATE TABLE `auth_users` (
`username` VARCHAR(255) NOT NULL,
`password` VARCHAR(255) NOT NULL,
`id` BIGINT NOT NULL COMMENT 'column:~~ がないとマイグレーションを実行しても無視される',
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
`deleted_at` DATETIME NOT NULL,
PRIMARY KEY (`id`)
)
--------done 0.023s--------
フィールドにコメントを設定する
Goのコメント文を末尾にいれてるだけです。
// +migu
type User struct {
Username string `migu:"unique"` // ユーザー名
Password string `migu:"type:varchar(128)"` // パスワード
Weight float64 `migu:"type:decimal(2,1),null"` // 体重
Email string `migu:"type:varchar(254),null"` // メールアドレス
BaseModel
_ int64 `migu:"pk,column:id,autoincrement"` // 主キー
_ time.Time `migu:"column:created_at,default:current_timestamp"` // 登録日時
_ time.Time `migu:"column:updated_at,null,default:null,extra:ON UPDATE CURRENT_TIMESTAMP"` // 最終更新日時
_ time.Time `migu:"column:deleted_at,null"` // 削除日時
}
docker-compose exec app migu sync -u root -h db -p db_migu_sample model/user.go
================ 実行結果 ================
--------applying--------
ALTER TABLE `user` CHANGE `username` `username` VARCHAR(255) NOT NULL COMMENT 'ユーザー名'
--------done 0.002s--------
--------applying--------
ALTER TABLE `user` CHANGE `password` `password` VARCHAR(128) NOT NULL COMMENT 'パスワード'
--------done 0.013s--------
--------applying--------
ALTER TABLE `user` CHANGE `weight` `weight` DECIMAL(2,1) COMMENT '体重'
--------done 0.001s--------
--------applying--------
ALTER TABLE `user` CHANGE `email` `email` VARCHAR(254) COMMENT 'メールアドレス'
--------done 0.001s--------
--------applying--------
ALTER TABLE `user` CHANGE `id` `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主キー'
--------done 0.001s--------
--------applying--------
ALTER TABLE `user` CHANGE `created_at` `created_at` DATETIME NOT NULL DEFAULT current_timestamp COMMENT '登録日時'
--------done 0.002s--------
--------applying--------
ALTER TABLE `user` CHANGE `updated_at` `updated_at` DATETIME DEFAULT null ON UPDATE CURRENT_TIMESTAMP COMMENT '最終更新日時'
--------done 0.002s--------
--------applying--------
ALTER TABLE `user` CHANGE `deleted_at` `deleted_at` DATETIME COMMENT '削除日時'
--------done 0.002s--------
所感
コードで差分見てマイグレーションしてくれるし、マイグレーションファイルはいらないしで、個人的にはすごく使いやすく感じました。
(スター数が圧っっっっっっっっっっっっっっっっっっっっっっっっ倒的に少ないですが)
個人的にはもっと伸びてほしいマイグレーションツールだなと感じました・・・。