2006-03-27
Class::DBI::Sweet::Pie
気が向いたので集約関数を追加するClass::DBI::Sweet用のプラグインを作ってみました。
Class::DBI::Plugin::AggregateFunctionとか作ってもいいのかもしれません。
package MyData::CD; use base qw/Class::DBI::Sweet/; use Class::DBI::Sweet::Pie; __PACKAGE__->mk_aggregate_function('sum'); __PACKAGE__->mk_aggregate_function( max => 'maximum'); package main; # SELECT MAX(price) FROM __TABLE__ my $max = MyData::CD->maximum( 'price' ); # SELECT SUM(price) FROM __TABLE__ WHERE artist = 'foo' my $sum = MyData::CD->sum( 'price', artist => 'foo' );
ソースコード
package Class::DBI::Sweet::Pie; use strict; use vars qw/$VERSION @EXPORT @EXPORT_OK/; $VERSION = '0.01'; use Exporter::Lite; @EXPORT = qw/mk_aggregate_function/; sub mk_aggregate_function { my $class = shift; my ($aggregate_func, $alias) = @_; $alias ||= $aggregate_func; $class->set_sql( "Join_Retrieve_$aggregate_func" => <<__SQL__ ); SELECT $aggregate_func( %s ) FROM %s WHERE %s __SQL__ no strict 'refs'; *{"$class\::$alias"} = sub { my $proto = shift; my $class = ref($proto) || $proto; my $aggregate_column = shift; my ($criteria, $attributes) = $class->_search_args(@_); # make sure we take copy of $attribues since it can be reused my $sum_attr = { %{$attributes} }; # no need for LIMIT/OFFSET and ORDER BY in AGGREGATE_FUNC() delete @{$sum_attr}{qw( rows offset order_by )}; my ($sql_parts, $classes, $columns, $values) = $proto->_search( $criteria, $sum_attr ); my $sql_method = 'sql_' . ($attributes->{sql_method} || 'Join_Retrieve') . "_$aggregate_func"; my $sth = $class->$sql_method( "me.$aggregate_column", @{%$sql_parts}{qw/ from where /} ); $class->_bind_param( $sth, $columns ); return $sth->select_val(@$values); } } 1; __END__ =head1 NAME Class::DBI::Sweet::Pie =head1 SYNOPSYS package MyData::CD; use base qw/Class::DBI::Sweet/; use Class::DBI::Sweet::Pie; __PACKAGE__->mk_aggregate_function('sum'); __PACKAGE__->mk_aggregate_function( max => 'maximum'); package main; my $sum = MyData::CD->sum( 'price' ); # SELECT SUM(price) my $max = MyData::CD->maximum( 'price' ); # SELECT MAX(price) =cut
Class::DBI::Plugin::AggregateFunction
というわけでClass::DBI::Plugin::AggregateFunctionも作りました。
SQL::Abstractを利用していて、Class::DBI::AbstractSearch風になってます。
ベースクラスを識別してClass::DBI::Sweetの時は上のを使うようにしたほうがいいのかな、と思いつつ。似てるけど別物だしなぁ……。
ソースコード
package Class::DBI::Plugin::AggregateFunction; use strict; use vars qw/$VERSION @EXPORT @EXPORT_OK/; $VERSION = '0.01'; use Exporter::Lite; @EXPORT = qw/mk_aggregate_function/; sub mk_aggregate_function { my $class = shift; my ($aggregate_func, $alias) = @_; $alias ||= $aggregate_func; $class->set_sql( "Retrieve_$aggregate_func" => <<__SQL__ ); SELECT $aggregate_func( %s ) FROM __TABLE__ WHERE %s __SQL__ no strict 'refs'; *{"$class\::$alias"} = sub { my $proto = shift; my $class = ref($proto) || $proto; my $aggregate_column = shift; my $where = (ref $_[0]) ? $_[0] : { @_ }; my $attr = (ref $_[0]) ? $_[1] : undef; my $sql = SQL::Abstract->new(%$attr); my($phrase, @bind) = $sql->where($where); $phrase =~ s/^\s*WHERE\s*//i; my $sql_method = "sql_Retrieve_$aggregate_func"; my $sth = $class->$sql_method( $aggregate_column, $phrase ); return $sth->select_val( @bind ); } } 1; __END__ =head1 NAME Class::DBI::Plugin::AggregateFunction =head1 SYNOPSYS package MyData::CD; use base qw/Class::DBI/; use Class::DBI::Plugin::AggregateFunction; __PACKAGE__->mk_aggregate_function('sum'); __PACKAGE__->mk_aggregate_function( max => 'maximum'); package main; # SELECT MAX(price) FROM __TABLE__ my $max = MyData::CD->maximum( 'price' ); # SELECT SUM(price) FROM __TABLE__ WHERE artist = 'foo' my $sum = MyData::CD->sum( 'price', artist => 'foo' ); =head1 DESCRIPTION Class::DBIを使ったテーブルで簡単に集約関数が使えるようになります。 =cut