Data::Model::SQL を使ってオブジェクト定義から SQL を作る
はじめに
5日目に Mixin 機能の紹介として SELECT COUNT(*) FROM foo を行う MyBookmark::Mixin::Count を作りました。
ここで問題なのは、テーブルの全件カウントしか取れない中途半端さで使いにくい点です。
今日は特定の絞り込み条件を MyBookmark::Mixin::Count に実装するための前提知識としてオブジェクトから SQL を組み立てる方法を解説します。
導入
Data::Model には SQL::Abstract 的な事が出来る Data::Model::SQL という物が付属しています。
実際 get/update/delete メソッドの条件式を SQL に変換する部分で使われています。
Data::Model::SQL に対してのパラメータは、4日目にとりああげた様々な方法での検索の仕方も殆ど同じようにかけます。
my $sql = Data::Model::SQL->new( select => [qw/ id nickname /], # 取り出すカラム from => 'user', # テーブル名 where => [ # 検索条件 id => { '<=' => 100 }, nickname => 'Yappo' ], limit => 10, );
get メソッド等と違うところは、 SELECT で取ってくるカラム名一覧とテーブル名を明示的に指定することです。
組み立てたオブジェクトを SQL にするには as_sql メソッドが使えます。
# 組み立てた SQL を出力 # SELECT id, nickname FROM user WHERE (id <= ?) AND (nickname = ?) LIMIT 10 print $sql->as_sql . "\n";
そして、重要なのは WHERE 句の中で使われている bind された値を取り出すことです。
それには bind メソッドを使います。
# bind されたカラム名 を取り出す # id, nickname print join(", ", @{ $sql->bind_column }) . "\n";
bind メソッドの値に対応するカラム名も必要になる時もあるので bind_column メソッドで取り出すことが出来ます。
# bind されたカラム名 を取り出す # id, nickname print join(", ", @{ $sql->bind_column }) . "\n";
index 定義から検索
ちなみに index 定義を使って絞り込むとかはよくあるパターンなのですが、それを実現するには Data::Model::Driver::DBI の中にある add_index_to_where メソッドを使うと簡単に実現出来ます。
しかし add_index_to_where の引数には、スキーマ定義オブジェクトが必要になるのですが、これはスキーマオブジェクトから簡単に取得することが出来ます。
先程の where 条件式で nickname を絞り込んでいたものを、 nickname index 定義を使って絞り込む物に変えた場合は以下のようになります。
my $sql = Data::Model::SQL->new( select => [qw/ id nickname /], # 取り出すカラム from => 'user', # テーブル名 where => [ # 検索条件 id => { '<=' => 100 }, ], limit => 10, ); # user テーブルのスキーマ定義を取り出して index カラムの設定をする my $schema = $bookmark->get_schema('user'); # nickname index を Yappo で絞り込み Data::Model::Driver::DBI->add_index_to_where($schema, $sql, { nickname => 'Yappo' }); # 組み立てた SQL を出力 # SELECT id, nickname FROM user WHERE (id <= ?) AND (nickname = ?) LIMIT 10 print $sql->as_sql . "\n"; # bind されたカラム名 を取り出す # id, nickname print join(", ", @{ $sql->bind_column }) . "\n"; # bind された値を取り出す # 100, Yappo print join(", ", @{ $sql->bind }) . "\n";
primary key で検索
primary key で絞り込む場合ですが、これも Data::Model::Driver::DBI の中にある add_key_to_where を使います。
add_index_to_where とはやや統一感のない引数になってますが以下のように使えます。
my $sql = Data::Model::SQL->new( select => [qw/ url_id user_id /], # 取り出すカラム from => 'bookmark', # テーブル名 ); # bookmark テーブルのスキーマ定義を取り出して primary key 検索の設定をする my $schema = $bookmark->get_schema('bookmark'); # url_id = 1 AND user_id = 2 で絞り込み Data::Model::Driver::DBI->add_key_to_where($sql, $schema->key, [ 1, 2 ]); # 組み立てた SQL を出力 # SELECT url_id, user_id FROM bookmark WHERE (url_id = ?) AND (user_id = ?) print $sql->as_sql . "\n"; # bind されたカラム名 を取り出す # url_id, user_id print join(", ", @{ $sql->bind_column }) . "\n"; # bind された値を取り出す # 1, 2 print join(", ", @{ $sql->bind }) . "\n";
まとめ
今日は Count Mixin の機能強化の為に必要なオブジェクトから SQL を作る方法を紹介しました。
もちろん Mixin でなくとも Row クラスにメソッドを生やす add_method 等でも使うことは出来ます。
明日はいよいよ Count Mixin に条件指定機能を組み込みましょう。今日の内容を踏まえればあっという間のはず。