天然パーマです。

DBIx::Mint、使ってみる

RowクラスをMooで定義するのが面白くて使ってみた。

こういうテーブルを持つデータベースがあるとする。

CREATE TABLE entry (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT NOT NULL,
    body TEXT NOT NULL
);

CREATE TABLE comment (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    entry_id INTEGER NOT NULL,
    body TEXT NOT NULL,
    FOREIGN KEY (entry_id) REFERENCES entry (id)
);

Blog::Entryという名前でRowクラスを定義する。Mooのクラスなのでhasでカラムに対応したプロパティを記載する。

package Blog::Entry;
use Moo;
use strictures 2;

with 'DBIx::Mint::Table';

has 'id' => (
    is => 'rw',
    required => 1,
);

has 'title' => (
    is => 'rw',
    required => 1,
);

has 'body' => (
    is => 'rw',
    required => 1,
);

1;

Blog::Commentもおんなじように書く。次はBlog::Schemaにテーブルとクラスの対応、リレーションの設定を書く。one_to_manyのとこの記述をすると$entry->get_commentとか$comment->get_entryができるようになる。

package Blog::Schema;
use strictures 2;
use DBIx::Mint;
use Blog::Entry;
use Blog::Comment;

my $schema = DBIx::Mint->instance->schema;
$schema->add_class(
    class => 'Blog::Entry',
    table => 'entry',
    pk => 'id',
    auto_pk => 1,
);

$schema->add_class(
    class => 'Blog::Comment',
    table => 'comment',
    pk => 'id',
    auto_pk => 1,
);

$schema->one_to_many(
    conditions => ['Blog::Entry', { id => 'entry_id' }, 'Blog::Comment'],
    method => 'get_comments',
    inverse_method => 'get_entry',
);

いよいよこれらを使ってみる。

データベースに接続。内部でDBIx::Connectorを使っている。

DBIx::Mint->connect( 'dbi:SQLite:dbname=blog.db', '', '',
                     { AutoCommit => 1, RaiseError => 1 } );

INSERT。返り値はプライマリーキーが返ってくる。

my $id = Blog::Entry->insert( title => 'Hello world', body => 'It is rainy today.' );
my @ids = Blog::Comment->insert(
    {entry_id => $id, body => 'You are crazy.'},
    { entry_id => $id, body => 'You are funny.' },
    { entry_id => $id, body => 'You are weird.' },
);

SELECT。この場合のfindメソッドの返り値はBlog::Entryのインスタンス

my $entry = Blog::Entry->find($id);

say sprintf("entry[%s]: %s", $entry->id, $entry->title);
say sprintf("entry[%s]: %s", $entry->id, $entry->body);

result_setを経由してsearchすることもできる。where句はSQL::Abstractのシンタックスで、limitとかorder_byはSQL::Abstract::Moreのもので指定できる。この場合の返り値はオブジェクトインスタンスじゃなくてハッシュ値になる。ハッシュの方が扱いやすいだろ、っていう観点らしい。

my $latest_entry = Blog::Entry->result_set->search->order_by({ -desc => 'id' })->single;
use Data::Dumper;
print Dumper $latest_entry;
# $VAR1 = {
#           'title' => 'Hello world',
#           'body' => 'It is rainy today.',
#           'id' => 1
#         };

EntryについたCommentを取ってくるところはリレーションのところで指定したget_commentsメソッドが使える。逆にComment側からはget_entryができる。この辺が記述もわかりやすくてよい。

my @comments = $entry->get_comments;
for my $comment (@comments) {
    say sprintf (
        "commnet[%s]: %s for entry[%s]",
        $comment->id,
        $comment->body,
        $comment->get_entry->id
    );
}

DBIx::Mint、いい感じ。