golang-migrateでマイグレーションをやってみる[Mac]

Goで`GORM`を使わずにDB設計を行っていたのですが、どうにかデータベースのカラムだけを変更することがしたいと考えた時に、Djangoで`マイグレーション`を行っていたことを思い出したので,今回どうやってGoでマイグレーションを行うか調べてみました。

# そもそもマイグレーションとは
`マイグレーション`とは、一般的に移行という意味を持っています。

今回行う｀データベースマイグレーション｀とは、データベースの定義を自動的に作成・管理することを指します。

従来の直接データベースに入って操作していたデータベース定義をスクリプトで操作することができます。

# `golang-migrate`でマイグレーションしてみる。

まず、golang-migrateのcliツールインストールします。

### インストール
```
brew install golang-migrate
```
>windowsのパッケージマネージャーとかは使ったことないのですいません

以下のコマンドで入っているかを確認します。
```
migrate --version
```

## マイグレーションファイルを作成してみる

### テーブル作成

実際にテーブル定義をしていこうと思います。

下の構造体のようにテーブル定義をしていこうと思います。

```go
type Music struct {
	ID        int
	MusicName string
	Composer  string
	CreatedAt time.Time
	UpdatedAt time.Time
}
```

下のコマンドで、マイグレーションファイルを生成します。
```
migrate create -ext sql -dir migrations -seq create_musics_table
```

すると、`000001_create_musics_table.up.sql`と`000001_create_musics_table.down.sql`が生成されます。

upは、マイグレーション実行用ファイル
downは、ロールバック(変更を元に戻す)ファイルになります。

`000001_create_musics_table.up.sql`には、作成するテーブルのクエリを書きます。

```sql:000001_create_musics_table.up.sql
CREATE TABLE IF NOT EXISTS musics (
    music_id INTEGER NOT NULL PRIMARY KEY,
    music_name TEXT NOT NULL,
    composer TEXT NOT NULL,
    createdAt TIMESTAMP NOT NULL,
    updatedAt TIMESTAMP NOT NULL
);
```

`000001_create_musics_table.down.sql`には、元に戻す時のクエリを書きます。

```sql:000001_create_musics_table.down.sql
DROP TABLE IF EXISTS musics;
```

そして、先ほど書いたファイルを定義するために下のコマンドを打ちます。

```
migrate -path migrations -database "mysql://user:password@tcp(127.0.0.1:3306)/db?parseTime=true&charset=utf8mb4" up
```

下のような表示が出てきたら成功です。

```
migrate -path migrations -database "mysql://user:password@tcp(127.0.0.1:3306)/db?parseTime=true&charset=utf8mb4" up
1/u create_musics_table (3.981542ms)
```

さてここで、実際にdbの中に入って、下のクエリで変わっていたか確認します。
```sql
SHOW COLUMNS FROM musics;
```

下みたいになったらおkです。

```
+------------+-----------+------+-----+---------+-------+
| Field      | Type      | Null | Key | Default | Extra |
+------------+-----------+------+-----+---------+-------+
| music_id   | int       | NO   | PRI | NULL    |       |
| music_name | text      | NO   |     | NULL    |       |
| composer   | text      | NO   |     | NULL    |       |
| createdAt  | timestamp | NO   |     | NULL    |       |
| updatedAt  | timestamp | NO   |     | NULL    |       |
+------------+-----------+------+-----+---------+-------+
```

### テーブルのカラム変更

テーブルに新しいカラムを加えたいとなった時には、先ほどと同じようにマイグレーションファイルを生成します。

```
migrate create -ext sql -dir migrations -seq rename_music_name_to_song_music
```

すると、`000002_rename_music_name_to_song_music.up.sql`と`000002_rename_music_name_to_song_music.down.sql`を生成します。


`000002_rename_music_name_to_song_music.up.sql`には、テーブルを変更させるためのクエリを書きます。

```sql:000002_rename_music_name_to_song_music.up.sql
ALTER TABLE musics
CHANGE COLUMN music_name song_name TEXT NOT NULL;
```

`000002_rename_music_name_to_song_music.down.sql`には、テーブルを変更戻すためのクエリを書きます。

```sql:000002_rename_music_name_to_song_music.down.sql
ALTER TABLE musics
CHANGE COLUMN song_name music_name TEXT NOT NULL;
```

また先ほどと同じようなコマンドを打ってマイグレーションを行います。

```
migrate -path migrations -database "mysql://user:password@tcp(127.0.0.1:3306)/db?parseTime=true&charset=utf8mb4" up
```

下のようになってたらokです。

```
migrate -path migrations -database "mysql://user:password@tcp(127.0.0.1:3306)/db?parseTime=true&charset=utf8mb4" up
2/u rename_music_name_to_song_music (29.513917ms)
```

また、同じようにdbの中に入って下のコマンドを打ちます。
```sql
SHOW COLUMNS FROM musics;
```

そして、今回でいうと`music_name`が`song_name`になっていたらマイグレーションが行えています。

```
+-----------+-----------+------+-----+---------+-------+
| Field     | Type      | Null | Key | Default | Extra |
+-----------+-----------+------+-----+---------+-------+
| music_id  | int       | NO   | PRI | NULL    |       |
| song_name | text      | NO   |     | NULL    |       |
| composer  | text      | NO   |     | NULL    |       |
| createdAt | timestamp | NO   |     | NULL    |       |
| updatedAt | timestamp | NO   |     | NULL    |       |
+-----------+-----------+------+-----+---------+-------+
```

### ロールバックする

逆にロールバックさせて、行ったマイグレーションによる変更を元に戻すには下のコマンドを打てば完了です。

```
migrate -path migrations -database "mysql://user:password@tcp(127.0.0.1:3306)/db?parseTime=true&charset=utf8mb4" down 1
```

下のような表示になっていたら成功です。

```
migrate -path migrations -database "mysql://user:password@tcp(127.0.0.1:3306)/db?parseTime=true&charset=utf8mb4" down 1
2/d rename_music_name_to_song_music (16.262625ms)
```