Data::Model::SQL を使ってオブジェクト定義から SQL を作るB!

はじめに

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 に条件指定機能を組み込みましょう。今日の内容を踏まえればあっという間のはず。