Mixin 機能その1B!

はじめに

さて、昨日はレコード総数をとるための COUNT クエリを投げるのがめんどくさいというところで終わりました。

Data::Model にはスキーマクラスに任意のメソッドを生やす為の Mixin という仕組みがあります。

今日はその Mixin 機能を使って COUNT クエリを楽に発行できるようにしましょう。

Mixin を作る

mixin を作るためには以下のようなクラスを作ります。

package MyBookmark::Mixin::Count;
use strict;
use warnings;

sub register_method {
    +{
        count => \&count;,
    };
}

sub count {
    my($self, $model) = @_;

    my $dbh = $self->get_driver($model)->r_handle;
    my $sth = $dbh->prepare_cached(
       'SELECT COUNT(*) AS count FROM ' . $model
    );
    $sth->execute;
    my $count;
    $sth->bind_columns(undef, \$count);
    $count = 0 unless $sth->fetch;
    $sth->finish;
    return $count;
}

1;

昨日の COUNT クエリのためのコードにいくつかコードをくるんだ感じになりました。

Data::Model の Mixin として機能するためには register_method が定義されているだけで良いのです。

register_method は HASH リファレンスを返して、 key が生やしたいメソッド名を入れて value は、そのメソッドのコードリファレンスを渡します。

mixin で追加したメソッドの第一引数にはスキーマクラスのオブジェクト( MyBookmark->new した時のオブジェクト)が渡され、第二引数以降はユーザによって渡された引数がそのまま入ります。

Mixin をスキーマに割り当てる

mixin を作ったらスキーマクラスで使えるようにする必要があります。

例えば MyBookmark クラスに以下の一行を追加すればokです

use Data::Model::Mixin modules => ['+MyBookmark::Mixin::Count'];

ここで MyBookmark.pm の先頭は以下のようになってます。

package MyBookmark;
use strict;
use warnings;
use base 'Data::Model';
use Data::Model::Schema;
use Data::Model::Mixin modules => ['+MyBookmark::Mixin::Count'];

これだけです。

mixin のメソッドを使う

一度割り当てたら set/get/lookup メソッド等と同じように使えます。

my $count = $bookmark->count('user');

とするだけで、特定のテーブルの COUNT を行うことができます。

適当にレコードを作って COUNT するサンプルは下記の通り。

use strict;
use warnings;
use MyBookmark;

my $bookmark = MyBookmark->new;
$bookmark->set(
    user => 1 => { nickname => 'Yappo' }
);
$bookmark->set(
    user => 11 => { nickname => 'nekokak' }
);
$bookmark->set(
    user => 101 => { nickname => 'kan' }
);

print "COUNT: " . $bookmark->count('user') . "\n";

実行結果

COUNT: 3

となれば成功です。

まとめ

今日はスキーマクラスにメソッドを生やす為の Mixin の作り方を紹介しました。

ただ、今回作った count は InnoDB だと悲惨なことになるので、特定のインデクスの結果を COUNT に取るようにしたい所ですが、それはまた今度。