2008年4月19日土曜日

Filter::SQLが使いやすくてしかたがない

Filter::SQL 作った - id:kazuhookuのメモ置き場にある、Filter::SQLが使いやすくて仕方がないという話。

前にも書いたけれど私はPerlのデータベースプログラミングに苦手意識がある。SQLもPerlも人並みにはできるけれど、その両方がまざったのはどうもだめだ。

だいたい、こちらはSELECTだけをすればいいのに

use 5.010;
use DBI;

my $dbh = DBI->connect("dbi:SQLite:dbname=foo.db");
my $sth = $dbh->prepare("SELECT * FROM table WHERE bar > 1");
$sth->execute;
while ( my $row = $sth->fetch ) {
say join "\t", @$row;
}

のような呪文を書かなくてはならないのは苦痛だ。connectはわかるけれどprepareやexecuteは人間のするべき仕事とは思えない。何よりもSQL文と出力を表示するところが離れているのが嫌だ。

SQLを書かずに全部Perlですませればいいかというと、必ずしもそうでもない。SQLを書かないようにするとSQL::Abstractを使ったりして

my ( $stmt, @bind ) = $sql->select( 'table', '*', { bar => { '>', 1 } } );

となるが、これも私の頭のキャパシティを超える。

PerlはPerl、SQLはSQLがそこそこ分離され「見た目にわかりやすい」ものをずっと探し求めていた。そこにFilter::SQLというモジュールの登場である。先の例はこう書き替えられる。

use 5.010;
use DBI;
use Filter::SQL;

Filter::SQL->dbh(DBI->connect("dbi:SQLite:dbname=foo.db"));
for my $row (SELECT * FROM table WHERE bar > 1;) {
say join "\t", @$row;
}

これです、私の長年求めていたものは。SELECTがそのまま書けて、さらにそのまま配列が返る。書きやすくて仕方がないし読むのもわかりやすい。SELECT文のまわりに引用符がいらないのも良い。SELECTの最後のセミコロンは一つのおまじないだけれど、prepareしてexecuteしてfetchするよりずっといい。DBIx::Simpleよりもさらにシンプルだ。

ソースを見てみるとFilter::Simpleを使った小さいモジュール。明快に書いてあってこんなことなら自分で書けばよかった、と思ったがそれを人はコロンブスの卵と呼ぶ。

追記(4月20日)

はてなブックマークでmiyagawaさんいわく

prepare,execute,fetchを一気にやるなら素のDBIでも selectall_hashref とか

コメントありがとうございます。どっちかというとselectall_araryrefのほうが近くて(Filter::SQLの内部で使われています)、上のスクリプトは

my $dbh = DBI->connect("dbi:SQLite:dbname=foo.db");
for my $row ( @{ $dbh->selectall_arrayref("SELECT * from table WHERE bar > 1") } ) {
say join "\t", @$row;
}

と書きかえられます。

SQL::Filterのほうが明らかにインターフェイスが優れていますが(私の好みの問題でもあります)、企業などでモジュールをインストールできないといった方はDBIそのままでもそれほど悪くない、ということだと思います。

SELECTするためにDBIを素で使うことがほとんどないのでselectall_arrayrefなんて忘れてました……ごめんなさい:)

0 件のコメント:

コメントを投稿