先日状態遷移図を自動生成するPyagramというコマンドラインツールを作ったのですが、それの追加機能としてCREATE TABLE文からテーブル間の関連のみがわかるシンプルなER図を自動生成する機能を実装しました。
個人的には外部キーは一切使わない派なので、MySQLWorkbanchを使った場合にテーブル間のリレーションが張られた状態のER図が生成できない問題がありました。そのため外部キーがなくてもカラム名から親子を推測して関連づけてくれるようなツールを作ることにしました。
利用にあたりいくつか制約がありますので、以下をご理解いただいた上でご使用ください。
- MySQLのみ対応
- 主キー名は常にid
- テーブル名は基本的に複数形(中間テーブルを除く)
- いくつかのデータ型には未対応(ENUMなど)
また検証がまだ不十分かもしれませんので、もしかしたらうまく動かないことがあるかもしれません。コメント欄かGithubのIssueにご報告いただけますと幸いです。
以下が生成された図になります。
入力ファイルとして以下のようなCREATE TABLE文が定義されてるファイルを用意します。
CREATE TABLE employees (
id INT(11) NOT NULL AUTO_INCREMENT,
birth_date DATE NOT NULL,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
gender INT(11) NOT NULL,
hire_date DATE NOT NULL,
department_id int(11),
PRIMARY KEY('id')
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
CREATE TABLE departments (
id INT(11) NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
PRIMARY KEY('id')
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
CREATE TABLE titles (
id INT(11) NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
PRIMARY KEY('id')
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
CREATE TABLE employee_title (
employee_id INT(11) NOT NULL,
title_id INT(11) NOT NULL,
from_date DATE NOT NULL,
to_date DATE NOT NULL,
PRIMARY KEY('employee_id', 'title_id')
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
CREATE TABLE salaries (
id INT(11) NOT NULL AUTO_INCREMENT,
employee_id INT(11) NOT NULL,
salary INT(11) NOT NULL,
from_date DATE NOT NULL,
to_date DATE NOT NULL,
PRIMARY KEY('id'),
KEY('employee_id')
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
以下のコマンドを実行すると、図が生成されます。
pyagram -t {画像タイプ} -o {出力パス} -i {入力ファイル} -f {フォント名} -d erd
また以下のコマンドでインストールできます。
pip3 install pyagram
今回の修正のために作りを大きく変え、プラガブルな実装にしました。Diagramというクラスを継承することで、いくつでも図の生成クラスを作れるようになっています。
Diagramクラスには
- lexical_analysis(字句解析)
- syntactic_analysis(構文解析)
- generate_dot(ドットファイル用のデータ生成)
- generate_image(画像ファイル生成)
の大きく分けて4つの処理があるのですが、Diagramを継承したクラスでは1から3までを実装すればいいような作りになっています。
今後については、もう少し出力される項目を増やしたり、対応するRDBMSの種類を増やしたりしたいのですが、ちょっと骨が折れるので時間をかけて進めていきたいと思います。