$shibayu36->blog;

株式会社はてなでエンジニアをしています。プログラミングや読書のことなどについて書いています。

Teng::Schema::DeclareにPlugin機構があったらいいのにって妄想してた

 id:nekokakさんのTengの中のTeng::Schema::Declareを使ってて、あーこんな感じなのがあったらいいのになーって妄想してたのでメモしておきます。正直、必要なのかはわかりません。。。

やりたい事

 例えば、現在のTeng::Schema::Declareを使って、DateTimeのinflateをやろうとすると、こんな感じになります。

package My::Schema;
use strict;
use warnings;

use Teng::Schema::Declare;
Teng::Schema::Declare->load_plugin('Column::DateTime');

table {
    name "example";
    pk "id";
    columns qw( name created_at updated_at );
    inflate qr{^(?:created_at|updated_at)$} => \&inflate_datetime;
    deflate qr{^(?:created_at|updated_at)$} => \&deflate_datetime;
};

sub inflate_datetime {
    my ($col_value) = @_;
    return DateTime::Format::MySQL->parse_datetime($col_value);
}

sub deflate_datetime {
    my ($col_value) = @_;
    return DateTime::Format::MySQL->format_datetime($col_value);
}

1;

 でもこれだといちいちinflate_datetimeとか書くの面倒です。また、もう少し定義が複雑になってきたときに、使いまわしたいなとも思いました。

Plugin機構?

 例えば以下のようなPlugin機構があったらやりたいと思ったことが出来て、便利なのかなと思いました。Plugin側とSchema側で分けています。

Plugin側

Plugin側はload_pluginされたときに呼び出すregisterメソッドを定義して、その中でcolumn定義メソッドを登録する感じ?

package Teng::Schema::Declare::Plugin::Column::DateTime;
use strict;
use warnings;

use base qw(Teng::Schema::Declare::Plugin);

sub register {
    my ($self, $option) = @_;

    $self->register_declare_method(datetime_columns => sub {
        my (@columns) = @_;
        my $columns_regexp = join('|', @columns);
        my $regexp = qr{^(?:$columns_regexp)$};

        inflate $regexp => \&inflate_datetime;
        deflate $regexp => \&deflate_datetime;
    });
}

sub inflate_datetime {
    my ($col_value) = @_;
    return DateTime::Format::MySQL->parse_datetime($col_value);
}

sub deflate_datetime {
    my ($col_value) = @_;
    return DateTime::Format::MySQL->format_datetime($col_value);
}

1;
Schema側

Schema側はこんな感じ。

package My::Schema;
use strict;
use warnings;

use Teng::Schema::Declare;
Teng::Schema::Declare->load_plugin('Column::DateTime');
# load_pluginしたときにregisterが呼ばれる感じ
# Teng::Schema::Declare->load_plugin('Column::DateTime', {...});とか

table {
    name "sample";
    pk "id";
    columns qw( name created_at updated_at );
    datetime_columns qw(created_at updated_at);
    # 下と同様の効果があったらいいな
    # inflate qr{^(?:created_at|updated_at)$} => \&inflate_datetime;
    # deflate qr{^(?:created_at|updated_at)$} => \&deflate_datetime;
};

# sub inflate_datetime {
#     my ($col_value) = @_;
#     return DateTime::Format::MySQL->parse_datetime($col_value);
# }

# sub deflate_datetime {
#     my ($col_value) = @_;
#     return DateTime::Format::MySQL->format_datetime($col_value);
# }

1;

最後に

 というわけで今回はちょっと思いついたことをメモしてみました。正直なところ、パッと思いついただけだったので、そもそもこれが使いやすいかどうかも疑問です。もっと簡単に同じようなことができるよってことがあれば教えてください。。。