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;