DBDesigner 4 の sqlt パーサを書いてみる(挫折編)
Rails だと DBDesigner 4 の吐く XML ファイルから model 等を生成するプロジェクトがあったりします*1が,Perl(Catalyst 等)にはありません。キー,クヤシイ!
くやしがっていても仕方ないのでどう実現するか考えましょう。Perl だと様々なスキーマソースを相互変換する SQL-Translator プロジェクトがあるので,それ用のパーサ/プロデューサを書くと DBIC 等に持って行けるような気がします*2。
パーサを書く方向性として
くらいしか思いつきませんが,XSLT についてはよくわからないし手間数が増えるのでパス。じゃあ自力かぁ…と思っていろいろ探していたら,FabForce::DBDesginer4 というモジュールを cpan で発見しました。おお,とりあえずこれを使って ...::Parser::XML::SQLFairy を真似っこしながら書けばいいんじゃね?
てことでいじってみましたが,だめだこの FabForce::DBDesigner4。
- ファイルからしか読み込めない
- データタイプが固定されたものと仮定して書いてある(<DATATYPE> タグを読んでない)からデータタイプを編集/新設してるとアウト
- フィールド長を取得できない(致命的;DBIC にもってくだけなら充分かも)
- インデックス定義,ビュー等を取得できない(致命的)
まぁ Wishlist として sqlt をサポートしたいという RT があがってるんで(作者本人ぽい),こちら方面はのんびり待ちますか。あーあ XML のパーサの勉強するかなぁ…
一応末尾にモジュールのせておきます。なんせファイルからしか読み込めないので,
$ffdd->parsefile(xml => $translator->filename);
とか格好悪いことになってます。それゆえ標準入力等からは読めないであろう罠。
使い方は
sqlt -f FFDD4 -t YAML schema.xml
とするとスキーマを YAML で吐きますし,YAML の部分を MySQL にすると MySQL 用の SQL 文,PostgreSQL にすると PostgreSQL用の SQL 文になります。ってフィールド長がとれてないので意味がないのでした。
package SQL::Translator::Parser::FFDD4; use strict; use Exporter; use base qw(Exporter); our @EXPORT_OK = qw(parse); use base qw(SQL::Translator::Parser); use SQL::Translator::Utils qw(debug); use FabForce::DBDesigner4; our $DEBUG = 0; sub parse { my ($translator, $data) = @_; my $schema = $translator->schema; local $DEBUG = $translator->debug; my $ffdd = FabForce::DBDesigner4->new(); #$ffdd->parsefile(xml => $data); $ffdd->parsefile(xml => $translator->filename); foreach my $src_table ($ffdd->getTables()) { debug "Adding table:" . $src_table->name(); my $table = $schema->add_table(name => $src_table->name()) or die $schema->error; $table->primary_key($src_table->key()); my %pkeys = map { $_ => 1 } $src_table->key(); my @column_data = $src_table->stringsToTableCols($src_table->columns()); foreach my $column_infos (@column_data) { while (my ($field, $ref_infos) = each %$column_infos) { my ($data_type, $attrs) = @$ref_infos; my %fdata; $fdata{'name'} = $field; $fdata{'data_type'} = $data_type; #$fdata{'size'} IS MISSING! $fdata{'is_primary_key'} = $pkeys{$field} && 1; $fdata{'is_nullable'} = ($attrs !~ m' NOT \s+ NULL 'ixmso); $fdata{'is_auto_increment'} = ($attrs =~ m' AUTOINCREMENT 'ixmso); my $field = $table->add_field(%fdata) or die $table->error; } } } return 1; } 1;