yamlからER図を生成し、ER図とDBの実態を乖離させないgemを作った

# まずは見て欲しい こんなER図が作れる
![table.png](https://qiita-image-store.s3.amazonaws.com/0/236978/1075c84f-98f4-36e3-ce17-37b859f4f48b.png)

# 欲しかった
[いいから早く使い方教えろって方はこちら](#使い方)

- ER図書いたけどメンテされてない！！！！！
- カラムの論理名もつけたりテーブルごとにグルーピングしたい！！！
- 設計の段階で使えるものが欲しい！！！！
  - schemaからの自動生成じゃなくて
- 既存の生成ツールのER図は素朴すぎる
- ER図をコードで管理したい

そんな(自分の)悩みを解決するgemを作りました
[yaml2erd](https://rubygems.org/gems/yaml2erd)

rails寄りのテイストですが普通にrails関係なくER図生成はできます

# このgemのここがすごい
- yamlからER図を生成するから設計段階から使える
- **yamlとDBを比較するテストコード書くことで実態のDBとER図の乖離を防げる**
  - `ErYamlParser`クラスを使ってDBと比較するテストコードを書いてci回す
- グルーピングできる(背景色もつけられる)
- カラムの物理名や型だけでなく論理名/FK/PK/説明/初期値もある
- テーブルにもコメントつけられる

# 使い方
## 1. yaml2erdをインストールする
gemコマンド叩くなりGemfileに書くなり
この辺は割愛


## 2. graphvizとフォントをインストール
正直dockerの使用をオススメします

```shell-session
# apt-get install -y graphviz task-japanese fonts-noto-cjk
```

みたいな感じで
- `graphviz`(画像吐き出すためのツール)
- 日本語フォント
- `fonts-noto-cjk`
をインストールします

この辺は環境に合わせて適宜

フォントや文字サイズはお好みでカスタムできます　方法は後ほど

## 3. yamlでテーブル定義を書く
```yaml:etc/table.yaml
groups:
  - name: ユーザ
    bgcolor: '#9cf5b7'
  - name: 投稿
    bgcolor: '#bcdbf7'

models:
  User:
    columns:
      id:
        type: bigint(8)
        options:
          primary_key: true
          not_null: true
        logical_name: 主キー
      name:
        type: text
        options:
          not_null: true
          default: None Name
        logical_name: 名前
      created_at:
        type: datetime
        options:
          not_null: true
        logical_name: 作成日時
      updated_at:
        type: datetime
        options:
          not_null: true
        logical_name: 更新日時
    group: ユーザ
    relations:
      - has_many: Post
      - has_many: Favorite
    description: |-
      ユーザテーブル
  Post:
    columns:
      id:
        type: bigint(8)
        options:
          primary_key: true
          not_null: true
        logical_name: 主キー
      title:
        type: text
        options:
          not_null: true
        logical_name: タイトル
      body:
        type: text
        options:
          not_null: true
        logical_name: 本文
      created_at:
        type: datetime
        options:
          not_null: true
        logical_name: 作成日時
      updated_at:
        type: datetime
        options:
          not_null: true
        logical_name: 更新日時
    group: 投稿
    relations:
      - belongs_to: User
      - has_many: Comment
      - has_many: Favorite
    description: |-
      投稿テーブル
  Comment:
    columns:
      id:
        type: bigint(8)
        options:
          primary_key: true
          not_null: true
        logical_name: 主キー
      post_id:
        type: bigint(8)
        options:
          not_null: true
          foreign_key: true
        logical_name: 投稿id
      user_id:
        type: bigint(8)
        options:
          not_null: true
          foreign_key: true
        logical_name: ユーザid
      title:
        type: text
        options:
          not_null: true
        logical_name: タイトル
      body:
        type: text
        options:
          not_null: true
        logical_name: 本文
      created_at:
        type: datetime
        options:
          not_null: true
        logical_name: 作成日時
      updated_at:
        type: datetime
        options:
          not_null: true
        logical_name: 更新日時
    group: 投稿
    relations:
      - belongs_to: Post
      - belongs_to: User
    description: |-
      コメントテーブル
  Favorite:
    columns:
      id:
        type: bigint(8)
        options:
          primary_key: true
          not_null: true
        logical_name: 主キー
      post_id:
        type: bigint(8)
        options:
          not_null: true
          foreign_key: true
        logical_name: 投稿id
        description: |-
          user_idのユーザがお気に入りした投稿のid
      user_id:
        type: bigint(8)
        options:
          not_null: true
          foreign_key: true
        logical_name: ユーザid
      created_at:
        type: datetime
        options:
          not_null: true
        logical_name: 作成日時
      updated_at:
        type: datetime
        options:
          not_null: true
        logical_name: 更新日時
    relations:
      - belongs_to: Post
      - belongs_to: User
    description: |-
      お気に入りテーブル
```

rspecで扱いやすいように`models`になってますが
テーブル名を書いてもらってもER図生成には問題ないです

## 4. yaml2erdを実行してER図を吐き出す
```shell-session
$ yaml2erd etc/table.yaml -o etc/table.png
```

`-o`オプションは省略可能です
指定しない場合は`erd`ディレクトリの下にyamlと同じファイル名でpngを作ります
ディレクトリないとエラーになります

### フォントや文字サイズ変えたいとき
```yaml:etc/conf.yaml
entity_conf:
  fontname: Noto Sans CJK JP Black
  fontsize: 40

group_conf:
  fontname: Noto Sans CJK JP Black
  fontsize: 70
```
みたいなyamlで設定を書いて

```shell-session
$ yaml2erd etc/table.yaml -c etc/conf.yaml
```
`-c`オプションで指定してやるとお好みのフォント、文字サイズに変えることができます

`entity_conf`はテーブル名やカラム名などのフォントやサイズ
`group_conf`はグループ名のフォントやサイズ

## 5. rspecを書いてciで自動テストするようにしてやるとER図が取り残されなくなる
```ruby:sample
require 'yaml2erd'

RSpec.describe 'check schema for inventory' do
  parser = ErYamlParser.new('etc/table.yaml')

  describe 'check model\'s columns with yaml' do
    parser.models.each do |model_name, model|
      it "#{model_name} match to yaml" do
        # columnsメソッドでyamlに定義してるカラム情報のhashが取れる
        columns_hash = model.columns.map { |column, _detail| column.to_s }
        expect(columns_hash.sort).to match(model_name.to_s.constantize.column_names.sort)
      end
    end
  end
end
```

この辺はお好みで型やキーや制約のチェックもつけたり

# rubyなんて使ってない！！という方
https://github.com/rh-taro/dockerized_yaml2erd
rubyのプロジェクトにgemで入れずともスタンドアロンで使えるようにdocker化してます
ぜひ使ってみてください

# 今後
今ver0.2.0でまだまだ改善していく気なのでバグや改善点ありましたらコメントなどで教えていただけると助かります

設計から保守まで一貫して使えるものにするのが目標なので
yamlからmigration書き出したりとかも考えてます

フォントについては`fonts-noto-cjk`が個人的に一番見やすいと思ったんですが
他におすすめのフォントあれば教えてください