[db]MySQL系データベースのDDL管理ツールskeemaを使ってみた

Go言語でDBのスキーマをうまく管理してくれるツール無いの？というところで試したツールの一つ。
[skeema/skeema: Schema management CLI for MySQL](https://github.com/skeema/skeema)
ザックリ言うと、RailsでいうActiveRecord::Schemaみたいなスキーマダンプを作ってくれるやつ。

## 環境

- macOS Catalina
- go version 1.13.4

## 記事執筆時点で対応しているデータベース

MySQL系のプロダクトの模様。

- MySQL 5.5, 5.6, 5.7, 8.0
- Percona Server 5.5, 5.6, 5.7, 8.0
- MariaDB 10.1, 10.2, 10.3, 10.4

## 準備

```sh
go get -u github.com/skeema/skeema
```

## 使い方

### 現在のスキーマをダンプ

下記のコマンドを適宜編集して実行する。

```
skeema init -h my.db.hostname -u root -p -d schemas --schema dbname
```

すると`schemas`ディレクトリ以下にテーブルごとにDDLがファイルが出力される。
`-d`で指定したディレクトリにダンプされる。
`--schema`オプション無しの場合は、ユーザーが作ったすべてのデータベース毎のディレクトリが作られ、その中にそれぞれのデータベースにあるテーブル定義が出力される。
`--schema`ありの場合は、指定ディレクトリの直下にファイルが出力される。
`skeema init --help`で詳細なオプションを確認できる。
この時の接続情報は`.skeema`ファイルに記録されている。

### スキーマを変更して適用

例えば以下のように変更してみる。

```sql
CREATE TABLE `applications` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `ios_bundle_name` varchar(255) DEFAULT NULL,
  `android_bundle_name` varchar(255) DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  `deleted_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
```

↓

```sql
CREATE TABLE `applications` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(256) NOT NULL,
  `ios_bundle_name` varchar(255) DEFAULT '',
  `android_bundle_name` varchar(255) DEFAULT NULL,
  `created_at` datetime,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
```

これを適用してみる。

まず差分をチェックする。
`skeema diff`で実際にどのようなSQL文が発行されるかを確認できる。
今回は列の削除が含まれるので、`--allow-unsafe`オプションが必要。

```sh
$ skeema diff -p --allow-unsafe
:
-- instance: localhost:/tmp/mysql.sock
USE `testdb`;
ALTER TABLE `applications` DROP COLUMN `deleted_at`, MODIFY COLUMN `name` varchar(256) NOT NULL, MODIFY COLUMN `ios_bundle_name` varchar(255) DEFAULT '', MODIFY COLUMN `created_at` datetime DEFAULT NULL, ADD UNIQUE KEY `name` (`name`);
```

次に実際に適用してみる。

```sh
$ skeema push -p --allow-unsafe
:
-- instance: localhost:/tmp/mysql.sock
USE `testdb`;
ALTER TABLE `applications` DROP COLUMN `deleted_at`, MODIFY COLUMN `name` varchar(256) NOT NULL, MODIFY COLUMN `ios_bundle_name` varchar(255) DEFAULT '', MODIFY COLUMN `created_at` datetime DEFAULT NULL, ADD UNIQUE KEY `name` (`name`);
2020-03-15 14:44:46 [INFO]  localhost:/tmp/mysql.sock testdb: push complete
```

Sequel Proなどで軽く確認すると、適用されている事が分かる。
<img width="456" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9104/f91106c7-b980-6dc1-4796-4caff54782c5.png">

ここでは記載していないが、テーブルの追加や削除にも対応している。
削除時には`--allow-unsafe`が必要。

## スキーマの差分を反映する

直接本番で作業した、開発環境でテーブルをGUIで変更したなどの理由で差分をDDLに反映させたい場合などがあるだろう。
そういう場合には`skeema pull`を利用できる。

```sh
$ skeema pull -p               
Enter password: 
2020-03-15 14:59:13 [INFO]  Updating /path/to/schemas to reflect localhost:/tmp/mysql.sock testdb
2020-03-15 14:59:13 [INFO]  Wrote /path/to/schemas/applications.sql (425 bytes)

```

## フォーマット

`skeema format -p`でSQL文の整形ができる。

## lint

`skeema lint -p`でlintできる。こんな感じ。

```
2020-03-15 14:40:52 [INFO]  Linting /path/to/schemas
2020-03-15 14:40:53 [WARN]  /path/to/schemas/applications.sql:2: Column id of table applications is an auto_increment column
                            using data type int, which is not configured to be permitted. The following data types are listed in option
                            allow-auto-inc: int unsigned, bigint unsigned.
                            In general, auto_increment columns should be unsigned, since behavior of auto_increment is undefined with negative
                            numbers.
2020-03-15 14:40:53 [WARN]  Found 1 warnings
```

[GitHubにインストールして使えるCIサービス](https://www.skeema.io/ci/)もある。現在ベータ版で無料。

## 環境を分ける

最初に生成されるのは`production`の設定だが、`develop`や`staging`など環境を追加する事も可能。
残念な事に、データベース名(scheme)は共通となっており、本番と合わせる必要がある。

```sh
$ skeema add-environment development -h localhost -u root -p
2020-03-15 15:01:46 [INFO]  Added environment [development] to /path/to/schemas/.skeema
```

環境を指定する際は一番最後に付ける。
`skeema pull -p development`など。
お察しの通り、何も指定しない場合は`production`になる。
どちらかと言うと本番の時に指定させて欲しいところだが…