CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: ERAlchemy を使って ER 図を描く

今回は ERAlchemy という ER 図を描くツールを使ってみる。 このツールは erd という Haskell で書かれた同様のツールにインスパイアされて作られたものらしい。 ただ、機能的にできることは ERAlchemy の方が多いみたいだ。

ERAlchemy が提供する基本的な機能は次の通り。

  • ER フォーマットのテキストファイルから ER 図を生成する
  • SQLAlchemy 経由で既存のデータベースから ER 図を生成する

後者の既存データベースから ER 図を生成するところなんかは、これまでだと MySQL Workbench を使ったりしてた。 ただ、このやり方だと文字通り MySQL でしか使えないのに対して ERAlchemy はそれ以外のデータベースにも対応している。 今回も試しに SQLite3 のデータベースから ER 図を生成してみている。 ただ、この機能が出力する図は、ちょっと直感には反する図になってしまった。

使った環境は次の通り。

$ sw_vers 
ProductName:    Mac OS X
ProductVersion: 10.12.6
BuildVersion:   16G1114
$ python --version
Python 3.6.3

インストール

まずは Homebrew を使って Graphviz を Pango と一緒にインストールしておく。

$ brew reinstall graphviz --with-pango

続いて ERAlchemy 本体をインストールする。

$ brew install eralchemy

ちなみに ERAlchemy 自体は Python で書かれているので pip 経由でインストールしても構わない。

$ pip install eralchemy

ER ファイルから ER 図を生成する

まず、基本となる使い方として ER フォーマットというテキストファイルから ER 図を生成してみる。 ER フォーマットの詳細については erd で詳しく説明されている。 とはいえ、ここでもその概要については説明する。

例えば、次の ER ファイルでは users というテーブルの中に三つのカラムを定義している。 主キーとなる id と、名前と年齢を入れる nameage だ。

$ cat << 'EOF' > example.er 
[users]
*id
name
age
EOF

上記を ER 図にレンダリングしてみよう。 eralchemy-i オプションに上記のファイルを指定したら、出力先を -o で指定する。

$ eralchemy -i example.er -o example.png

するとレンダリングされた画像が次のように生成される。

$ file example.png 
example.png: PNG image data, 89 x 159, 8-bit/color RGBA, non-interlaced

f:id:momijiame:20171230060152p:plain

レンダリング先のフォーマットとしては画像ファイル以外に PDF にも対応している。

$ eralchemy -i example.er -o example.pdf
$ file example.pdf 
example.pdf: PDF document, version 1.3

リレーションを表現する

リレーショナルデータベースの ER 図を描くのだから当然リレーションについても図示できないとまずい。 続いてはリレーションを含む ER 図を描いてみよう。

次の例ではテーブル users とテーブル emails が 1:n 対応しているところを表現している。 テーブルを定義してから、その後ろでそれらの関係性を書いていく感じ。 ちなみに本家の erd では外部キー参照を + で表現するようだけど ERAlchemy ではまだサポートしていないようだ。

$ cat << 'EOF' > example.er 
[users]
*id
name
age

[emails]
*id
address
user_id

users 1--* emails
EOF

上記をレンダリングしてみよう。

$ eralchemy -i example.er -o example.png

すると、次のような ER 図が得られる。

f:id:momijiame:20171230060525p:plain

先の ER ファイルでテーブル間のリレーションを表現するのには -- の前後に対応関係を表す記号を入れていた。 この中で登場するのは 1* だけだったけど、それ以外には ?+ も使うことができる。

意味 記号
0 or 1 ?
exactly 1 1
0 or more *
1 or more +

型情報などのラベルをつける

リレーショナルデータベースの ER 図を描くのであれば、当然それぞれのカラムの型についても情報がほしい。 そういったときは次のように label で情報を付与する。

$ cat << 'EOF' > example.er 
[users]
*id {label: "INTEGER"}
name {label: "TEXT"}
age {label: "INTEGER"}

[emails]
*id {label: "INTEGER"}
address {label: "TEXT"}
user_id {label: "INTEGER"}

users 1--* emails
EOF

同様にレンダリングする。

$ eralchemy -i example.er -o example.png

上記から得られた ER 図は次の通り。

f:id:momijiame:20171230061628p:plain

既存のデータベースから SQLAlchemy 経由で ER 図を描く

ERAlchemy の特徴として、SQLAlchemy 経由で既存のデータベースから ER 図を描く機能が挙げられる。 試しに SQLite3 のデータベースを作って、そこから ER 図を書いてみることにしよう。

まずは、次のように SQLite3 のデータベースを用意する。

$ sqlite3 example.db
SQLite version 3.16.0 2016-11-04 19:09:39
Enter ".help" for usage hints.
sqlite> CREATE TABLE users (
   ...> id INTEGER NOT NULL, 
   ...> name TEXT NOT NULL, 
   ...> PRIMARY KEY (id)
   ...> );
sqlite> CREATE TABLE emails (
   ...> id INTEGER NOT NULL, 
   ...> address TEXT NOT NULL, 
   ...> user_id INTEGER, 
   ...> PRIMARY KEY (id), 
   ...> FOREIGN KEY(user_id) REFERENCES users (id)
   ...> );
sqlite> .exit
$ file example.db 
example.db: SQLite 3.x database, last written using SQLite version 3016000

用意ができたら ERAlchemy を使って ER 図をレンダリングする。 今度は -i オプションに SQLAlchemy でデータベースの接続に使う URI 形式を渡すのがポイントとなる。

$ eralchemy -i sqlite:///example.db -o example.png

レンダリングされた図は以下の通り。 users の方が 0...N になっていて、なんだから emails の方が主体のような図になってしまった。 感覚的には反対になる気がするんだけどなあ。

f:id:momijiame:20171230062450p:plain

まとめ

今回は ERAlchemy を使って ER 図を描いてみた。 既存のデータベースから ER 図を作る機能は、ちょっと「ん?」という結果になってしまった。 とはいえ ER ファイルから図をレンダリングする部分に関してはちゃんと動くみたいなので、上手く活用していきたい。