DBIx::Skinny::Pager
DBIx::Skinnyで簡単に使えるpagerが実装されていない主な理由は、
http://perl-users.jp/articles/advent-calendar/2009/dbix-skinny/19.html
とかに書いているんですが、
管理画面にありがちな データを様々な条件で検索するページみたいなのを書くときにはSQLを直書きするのはつらくて、DBICみたいにresultsetを条件によってwhere節を追加するのが楽なこともあります。そういうページに限ってpagingの処理は必要になるけど、ひとつひとつSQLを直接書いてPagerを生成するとかなってくるとなかなかめんどくさいです。
http://d.hatena.ne.jp/nekokak/20090924/1253761408
とかいうのをselectするたびに書いてると、ちょっとごちゃごちゃして見にくいし、結構長くてSQL_CALC_FOUND_ROWSとか書くのがしんどいということで、search_by_sqlを直で使わないケースであれば実装できるかなということで作ってみました。
http://github.com/walf443/p5-dbix-skinny-pager
こんな感じで使います。
package Proj::DB; use DBIx::Skinny; use DBIx::Skinny::Mixin modules => ['Pager']; package main; use Proj::DB; my $rs = Proj::DB->resultset_with_pager('Count'); # $rs can handle like DBIx::Skinny::SQL. $rs->from(['some_table']); $rs->add_where('foo' => 'bar'); $rs->limit(10); $rs->offset(20); $rs->select([qw(foo bar baz)]); my ($iter, $pager) = $rs->retrieve; # $iter is a DBIx::Skinny::Iterator # $pager is a Data::Page # or you can set page my $rs2 = Proj::DB->resultset_with_page('PlusOne'); $rs2->from(['some_table']); $rs2->add_where('foo' => 'bar'); $rs2->limit(10); $rs2->page(2); # offset is 10 * ( 2 - 1) = 10. $rs2->select([qw(foo bar baz)]); my ($iter, $pager) = $rs2->retrieve;
ポイントはresultsetのかわりにresultset_with_pagerを呼ぶことと、retrieveしたときにiteratorを返すだけでなく、pagerを返してくれることです。
resultset_with_pagerの第1引数はロジックのクラス名で、DBIx::Skinny::Pager::Logic::xxxxが呼びだされます。現在は、Count(limit offsetを外してcountを取得)、MySQLFoundRows(mysqlのSQL_CALC_FOUND_ROWSを使う方法)、PlusOne(1レコード多めのSQLを発行してpagerをつくり結果から1つ減らす)が実装されています。
limit, offsetを指定するかわりに、limitとpageをsetするのでもいけます。offsetの計算とかいかにもバグいれちゃいそうですしね。
resultsetを直接処理するのはやや使いづらいので、本当はDBIx::Skinnyのsearchも同様の拡張をほどこしたいんですが、ちょっと色々コードがあるので似たようなコードをコピペで作るのは避けたいなぁということと、Mixinするメソッドが複数あるとこれはほしいけど、これはいらないと思う人も出てきそうだなぁということで実装してません。
また、OracleはDBIx::Skiny::SQL::Oracleという独自のものを使っていて、PagerがDBIx::Skinny::SQLを継承している関係で今のところうまく動きません。
ご意見募集中です。