1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Golang用のマイグレーションツール「migu」使ってみた

Last updated at Posted at 2021-02-17

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

docker-compose.yml
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の記述のある構造体がマイグレーション対象として認識されます。

models/user.go
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
)

もちろんテーブルが存在しない場合はテーブルを作成してくれます。
無事マイグレーション。
image.png
image.png

カラム追加

モデルに追加してマイグレーションを実行するだけです

models/user.go
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を定義

model/user.go
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をつけるだけです

model/user.go
// +migu
type User struct {
	...
	_ int64     `migu:"pk,column:id,autoincrement"`
	..
	.
}

ベースモデル的なものを作る

ただ、BaseModelを実装し、Userモデルに埋め込んでもDDLに反映されません。
「_(アンダースコア)」を使用して対応するフィールドを記述することで、DDLに反映されるようになるようです。

model/user.go
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--------

文字列の最大長などを設定する

model/user.go
// +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を許容したいフィールドは明示的に記述する必要があるみたいです。

model/user.go
// +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--------

インデックスを張る

model/user.go
// +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--------

ユニーク制約を設定する

model/user.go
// +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--------

登録日時カラムに自動で値が入るようにしたい

model/user.go
// +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にしてしまっても良いと思います)

model/user.go
// +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--------

無事、登録日時/更新日時に値が入るようになりました。
image.png

テーブル名を指定する

model/user.go
// +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のコメント文を末尾にいれてるだけです。

model/user.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--------

所感

コードで差分見てマイグレーションしてくれるし、マイグレーションファイルはいらないしで、個人的にはすごく使いやすく感じました。
(スター数が圧っっっっっっっっっっっっっっっっっっっっっっっっ倒的に少ないですが)

個人的にはもっと伸びてほしいマイグレーションツールだなと感じました・・・。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?