Shibuya. pm #12連動企画
本日開催のShibuya Perl Mongersテクニカルトーク#12のテーマは "No Perl, NoSQL, NoKVS" または "Not only Perl, Not only SQL, Not only KVS" ということなので,
オブジェクトをまるごと保存する
牧大輔氏も
オブジェクトをまるごと保存といってもピンとこないかもしれませんので,
テキストを持たせるクラスは簡単です。
package Post;
use Moose;
has 'name' => (is => 'rw', isa => 'Str');
has 'body' => (is => 'rw', isa => 'Str');
has 'author' => (is => 'rw', isa => 'Person', weak_ref => 1);
__PACKAGE__->meta->make_immutable;
写真を持たせるクラスも,
package Photo;
use Moose;
has 'name' => (is => 'rw', isa => 'Str');
has 'image' => (is => 'rw');
has 'author' => (is => 'rw', isa => 'Person', weak_ref => 1);
__PACKAGE__->meta->make_immutable;
両者をとりまとめるPersonはこんな感じです。postsのなかにはテキスト記事も写真記事も入る予定です。単純にArrayRef型にしておいてもよいのですが,
package Person;
use Moose;
use KiokuDB::Util 'set';
has 'name' => (is => 'rw', isa => 'Str');
has 'posts' => (
is => 'rw',
does => 'KiokuDB::Set',
default => sub { set() },
);
__PACKAGE__->meta->make_immutable;
では,
use strict;
use warnings;
use KiokuDB;
use KiokuDB::Util 'set';
use Person;
use Post;
use Photo;
my $db = KiokuDB->connect( 'dbi:SQLite:db', create => 1 );
まずは必要なモジュールを読み込んで,
my $person_id;
{
my $scope = $db->new_scope;
my $person = Person->new(name => 'Foo Bar');
my $post = Post->new(
name => 'my post',
body => 'MyPost',
author => $person,
);
my $photo = Photo->new(
name => 'my photo',
image => 'MyPhoto',
author => $person,
);
$person->posts(set($post, $photo));
$person_id = $db->store($person);
}
保存するオブジェクトをつくって,
$person_id = $db->store(my_id => $person);
ただし,
if ($db->object_to_id($person)) {
$person_id = $db->store($person);
}
else {
$person_id = $db->store(my_id => $person);
}
いまつくった$person以下のオブジェクトはスコープを抜けたところでメモリから消えます。ここではまだnew_
{
my $other_scope = $db->new_scope;
my $person = $db->lookup($person_id);
foreach my $post ($person->posts->members) {
print $post->name, " by ", $post->author->name, "\n";
}
}
別のスコープで,
KiokuDBはアプリケーションの仕様が変わっても柔軟に対応できます。今度はムービー記事も投稿できるようにしたいという要望があがってきました。RDBMSならテーブルの変更やらなにやらが必要になるところですが,
package Movie;
use Moose;
has 'name' => (is => 'rw', isa => 'Str');
has 'movie' => (is => 'rw');
has 'author' => (is => 'rw', isa => 'Person', weak_ref => 1);
__PACKAGE__->meta->make_immutable;
Movieを追加するコードはこうなります。
{
use Movie;
my $yet_another_scope = $db->new_scope;
my $person = $db->lookup($person_id);
my $movie = Movie->new(
name => 'my movie',
movie => 'MyMovie',
author => $person,
);
$person->posts->insert($movie);
$db->store($person);
}
なお,
$db->txn_do(sub { ... });