« きよへろさんのPerlコードをリファクタリングしてみる | メイン | Time::Pieceの罠 »

Class::DBIとTime::Piece

MT::Neko::kak 500 Internal Server ErrorのnekokakさんがClass::DBI::Plugin::TimePieceという記事をアップされてます。

Class::DBIとTime::Pieceの連携(infalte/defalte)はClass::DBI::mysqlの実装がいい感じです。
autoinflateで一発。

__PACKAGE__->autoinflate(column_type => 'Inflation::Class');
#カラム型=>クラス
__PACKAGE__->autoinflate(timestamp => 'Time::Piece');
__PACKAGE__->autoinflate(datetime => 'Time::Piece');
__PACKAGE__->autoinflate(date => 'Time::Piece');
__PACKAGE__->autoinflate(dates => 'Time::Piece');#上の3行を1つでまかなう

inflateクラスにTime::Pieceを指定した場合、内部的にTime::Piece::MySQLを呼び出してフォーマット変換を自動的にやってくれるのもいい具合です。

MySQL限定と思えば、Class::DBI::mysqlを参考にしつつ

package Class::DBI::Plugin::TimePiece::MySQL
use Time::Piece::MySQL;
sub import {
    my $class = shift;
    my $pkg   = caller(0);
    unless($pkg->isa('Class::DBI')){
        croak(__PACKAGE__." is for Class::DBI application.");
    }
    no strict 'refs';
    *{"$pkg\::has_a_timepiece"} = sub {
        my $self  = shift;
        my $colum = shift;
        my $type   = shift;
        $self->has_a(
            $colum  => 'Time::Piece',
            inflate => "from_mysql_$type",
            deflate => "mysql_$type",
       )
    };
}
1;

これで良いと思う。

使い方はTokulogさんのDateTimeを使う方法と同じ。

__PACKAGE__->has_a_timepiece(last_modified=>'datetime');

でどうでしょう。

個人的には、pieceの綴りにいつも自信がないので、has_a_tpとかいうショートカットが欲しいところです。あと、MySQL以外、例えばPostgreSQLなどへ対応をしようと思うと、Time::Piece::Pgがないし、かなり大変かと思う。


あ、そもそもMySQLならClass::DBI::mysqlを使うか。

トラックバック

この一覧は、次のエントリーを参照しています: Class::DBIとTime::Piece:

» Time::Piece::Oracle from MT::Neko::kak 500 Internal Server Error
かぜぶろさんに フォーマット自動判断とかいれないとあまり楽にはならないっすね。も... [詳しくはこちら]

» Class::DBI::Plugin::TimePiece::MySQL from ysk-style memo
[http://tokuhirom.dnsalias.org/~tokuhirom/tokulog/2150.html:title=TokuLogさん]と... [詳しくはこちら]

コメント

はじめまして。nekokakです。
トラバありがとうございます。
Time::Piece::MySQL初めて知りました。
確かにMySQLの場合、かぜぶろさんのがスマートかつ美しいですね。
Class::DBI::Plugin::TimePiece::MySQLって名前ですから、
MySQL限定でもOKなんじゃないですか?
アップ希望w
自分が今やってるシステムの場合、Oracleなんで使えないのですが。。。
自分のはどうもダサイです^^;
Oracleの場合とMySQLの場合でDate型の取得時のデフォルトフォーマットが
ちがうから至れり尽くせりで作るとなるとやっかいっぽいんですよね。
だからせめてTime::Pieceに渡すフォーマットだけでも
パラメータ化できればとも思ってます。
pieceの綴りですが、自分もよく間違えます。
has_a_timepieceのエイリアスってのもありですね。
Class::DBI::Sweetでもpageメソッドのエイリアスとしてpagerを定義してます。
しかしClass::DBI、奥が深いっす。
でわ。

フォーマットを渡すとなると、__PACKAGE__->has_a_timepiece(
last_modified,
deflate_format=>"%Y/%m/%d %T",
inflate_format=>"%Y/%m/%d %T"
);
こういう感じかな。
*{"$pkg\::has_a_timepiece"} = sub {
my $self = shift;
my $colum = shift;
my %args = @_;
$self->has_a(
$colum => 'Time::Piece',
inflate => sub{Time::Piece->strptime(shift,$args{infalte_format})},
deflate=> sub{shift->strptime($args{deflate_format})}
);
}

フォーマット自動判断とかいれないとあまり楽にはならないっすね。もしくはTime::Piece::MySQLを参考に必要なだけのメソッドを追加したTime::Piece::Oracleのようなものを作ってしまうというのはいかがでしょうか?

入れ違いでhttp://www.border.jp/nekokak/blog/archives/2005/11/classdbiplugint_1.htmlを
書いてしまいました。
かぜぶろさんのやりかたでもさっきまで試行錯誤してたのですが、
どうも、updateの際、deflateが呼ばれる前に、inflateが呼ばれるんですよね。
で、deflateとinflateのフォーマットが異なると、与える値によってはエラーになってしまうんです。
なので、deflateとinflateのフォーマットはあわせるしかないかなぁと思ってます。
フォーマット自動判別はあれば便利でしょうね。
Class::DBI::Plugin::TimePieceを親のクラスにして、
Class::DBI::Plugin::TimePiece::Oracle
Class::DBI::Plugin::TimePiece::MySQL
みたいに拡張できればいい感じかもしれないですね。
Time::Pieceに慣れてないので結構くたびれました。

コメントを投稿