introduction to dbix::moco
DESCRIPTION
Introduction to DBIx::MoCo. Naoya Ito http://www.hatena.ne.jp/. What is DBIx::MoCo?. “ Light and Fast Model Component” O/R Mapper for MySQL and SQLite. Features. Easy SQL operations like CDBI / ActiveRecord (Rails) Ruby-like list operations - PowerPoint PPT PresentationTRANSCRIPT
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Introduction to DBIx::MoCo
Naoya Itohttp://www.hatena.ne.jp/
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
What is DBIx::MoCo?
“Light and Fast Model Component”
O/R Mapper for MySQL and SQLite
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Features
Easy SQL operations like CDBI / ActiveRecord (Rails)
Ruby-like list operations Transparent caching with
Cache::* (usually with Cache::Memcached)
Test fixture
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Quick start
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Install
"cpan DBIx::MoCo" You may need force install as of
now.
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
setup your own classes
DBIx::MoCoDBIx::MoCo::
DataBase
Bookmark::MoCo
Bookmark::DataBase
Bookmark::User
Bookmark::Entry
uses
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
setup: 1. create DataBase classpackage Bookmark::DataBase;use base qw/DBIx::MoCo::DataBase/;
__PACKAGE__->dsn('dbi:mysql:dbname=bookmark');__PACKAGE__->username(‘foo');__PACKAGE__->password(‘bar');
1;
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
setup: 1. create DataBase class
DBIx::MoCoDBIx::MoCo::
DataBase
Bookmark::DataBase
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
setup: 2. create base class of your models
package Bookmark::MoCo;use base qw/DBIx::MoCo/;use UNIVERSAL::require;use Expoter::Lite;
our @EXPORT = qw/moco/;
__PACKAGE__->db_object('Bookmark::DataBase');
## moco('User') returns "Bookmark::MoCo::User"sub moco (@) { my $model = shift; return __PACKAGE__ unless $model; $model = join '::', 'Bookmark::MoCo', $model; $model->require or die $@; $model;}
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
setup: 2. create base class of your models
DBIx::MoCoDBIx::MoCo::
DataBase
Bookmark::MoCo
Bookmark::DataBase
uses
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
setup: 3. create model classespackage Bookmark::MoCo::Entry;use base qw/Bookmark::MoCo/;
__PACKAGE__->table('entry');__PACKAGE__->primary_keys(qw/entry_id/);__PACKAGE__->unique_keys(qw/url/);__PACKAGE__->utf8_columns(qw/title/);
1;
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
setup: 3. create model classes
DBIx::MoCoDBIx::MoCo::
DataBase
Bookmark::MoCo
Bookmark::DataBase
Bookmark::User
Bookmark::Entry
uses
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
retrieve()
my $entry = moco('Entry')>retrieve(url => $url);say $entry->entry_id;say $entry->title;say $entry->url;
## retrieve_by_foo(...) equals retrieve(foo => ...)$entry = moco('Entry')->retrieve_by_url($url);$entry = moco('Entry')->retrieve_by_entry_id($id);
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
SQL operations
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
search()
my @entries = moco('Entry')->search( where => "url like 'http://d.hatena.ne.jp/%'", order => 'entry_id desc', limit => 10,);
say $_->title for @entries;
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
search() : placeholders
my @entries = moco('Entry')->search( where => [ "url like ?", 'http://d.hatena.ne.jp/%' ], order => 'entry_id desc', limit => 10,);
say $_->title for @entries;
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
search() : named placeholdersmy @entries = moco('Entry')->search( where => [ "url like :url and is_public = :is_public", url => 'http://d.hatena.ne.jp/%', is_public => 1 ], order => 'entry_id desc', limit => 10,);
say $_->title for @entries;
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
search() : where ... in (...)
## SELECT * from entry where entry_id in (1, 2, 5, 6, 10)my @entries = moco('Entry')->search( where => [ "entry_id in (:entry_id)", entry_id => [1, 2, 5, 6, 10], ], order => 'entry_id desc',);
say $_->title for @entries;
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Create, Update, Delete
## create new recordmy $entry = moco('Entry')->create( url => 'http://www.yahoo.co.jp/', title => 'Yahoo!';);
## update a column$entry->title('Yahoo! Japan');
## save (in session)## If it is not in session, updates are automatically saved.$entry->save;
## delete the record$entry->delete;
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
List operations
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Ruby-like list operations
## Scalar contextmy $entries = moco('Entry')->search(...);
say $entries->size;
say $entries ->collect(sub { $_->title }) ->join("\n");
say $entries ->grep(sub { $_->is_public }) ->collect(sub { $_->num_of_bookmarks }} ->sum;
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Ruby-like methods
push, pop, shift, unshift, add, append, prepend size first, last slice, zip map, collect, each grep compact flatten delete, delete_if, delete_at inject find join reduce sum uniq dup dump
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
List::RubyLike
google:github list-rubylike
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Using your own list class
## create your own list class of Blog::Entrypackage Blog::Entry::List;use base qw/DBIx::MoCo::List/;
sub to_json { ...}
## setup list_class()package Blog::Entry;...__PACKAGE__->list_class('Blog::Entry::List');
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Using your own list class
## $entries is a Blog::Entry::Listmy $entries = moco('Entry')->search(...);
say $entries->to_json;
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Relationships
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
An entry has many bookmarkspackage Bookmark::MoCo::Entry;use Bookmark::MoCo;use base qw/Bookmark::MoCo/;
__PACKAGE__->table('entry');...
__PACKAGE__->has_many( bookmarks => moco('Bookmark'), { key => 'entry_id', order => 'timestamp desc', },);
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
$entry->bookmarks
my $entry = moco('Entry')->retrieve_by_url(...);
## bookmarks() returns bookmarks of the entrymy @bookmarks = $entry->bookmarks;
## offset and limit (offset 10, limit 50)@bookmarks = $entry->bookmarks(10, 50);
## Ruby-like list operations in scalar contextprint $entry->bookmarks(10, 50)->grep(...)->size;
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
bookmarks has an entry and an owner
package Bookmark::MoCo::Bookmark;use Bookmark::MoCo;use base qw/Bookmark::MoCo/;
__PACKAGE__->table('bookmark');...
__PACKAGE__->has_a( entry => moco('Entry'), { key => 'entry_id' });
__PACKAGE__->has_a( owner => moco('User'), { key => 'user_id' });
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
$bookmark->entry
my $bookmark = moco('Bookmark')->retrieve;
say $bookmark->entry->title;say $bookmark->owner->name
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
BTW: SQL is executed too many times ...
my $entry = moco('Entry')->retrieve(...);say $entry->bookmarks->size; ## 1,000
## oops, SQL is executed in 1,000 times.for ($entry->bookmarks) { say $_->owner->name;}
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
A entry has many bookmarks with owner (prefetching)
my $entry = moco('Entry')->retrieve(...);say $entry->bookmarks->size; ## 1,000
## bookmarks and owners will be retrieved at the same time.## (SQL stetements are executed only 2 times.)for ($entry->bookmarks(0, 0, {with => [qw/owner/]})) { say $_->owner->name;}
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Implicit prefetching
package Bookmark::MoCo::Entry;use Bookmark::MoCo;use base qw/Bookmark::MoCo/;...
__PACKAGE__->has_many( bookmarks => moco('Bookmark'), { key => 'entry_id', order => 'timestamp desc', with => [qw/owner/] },);
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
inflate / deflate
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
inflate / deflate (explicitly)
my $entry = moco('Entry')->retrieve(1);
## plain stringsay $entry->timestamp;
## timestamp column as DateTime objectsay $entry->timestamp_as_DateTime->hms;
## url column as URI objectsay $entry->url_as_URI->host;
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
inflate / deflate (implicitly)
package Bookmark::MoCo::Entry;...
## plain string__PACKAGE__->inflate_column( url => 'URI', timestamp => 'DateTime,);
package main;
say moco('Entry')->retrieve(1)->url->host;
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
inflate_column() without builtin classes
package Bookmark::MoCo::Entry;...
## plain string__PACKAGE__->inflate_column( title => { inflate => sub { My::String->new(shift) } deflate => sub { shift->as_string } });
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Transparent caching
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Transparent caching
## Just do itmy $cache = Cache::Memcached->new({...});Bookmark::MoCo->cache_object( $cache );
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Transparent caching
## The entry object will be cachedmy $entry = moco('Entry')->retrieve(1);
## Cached object will be retrieved from memcached$entry = moco('Entry')->retrieve(1);
## both cache and database record will be updated$entry->title('foobar');$entry->save;
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
NOTE: "session" is needed when you use caching feature or prefetching.
Blog::MoCo->start_session;
my $entry = moco('Entry')->retrieve(...);
Blog::MoCo->end_session;
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Testing
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Fixtures: building records for testing from YAML
## fixtures/entries.ymlmodel: Bookmark::Entryrecords: first: id: 1 title: Hatena Bookmark url: http://b.hatena.ne.jp/
second: id: 2 title: Yahoo! Japan url: http://www.yahoo.co.jp/
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Writing tests with fixtures
## t/entry.tuse DBIx::MoCo::Fixture;use Bookmark::Entry;
use Test::More tests => 2;
## loading records from entries.yml,## then returns them as objects.my $f = fixtures(qw/entries/);my $entry = $f->{entry}->{first};
is $entry->title, "...";is $entry->url, "...";
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Pros and Cons
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Pros
Simple and easy List operations are very sexy. Transparent caching is "DB に優し
い " Test fixture
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Cons
less document some difficulties (especially in
session and cache) low test coverage some bugs
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
patches are welcome.
jkondo at hatena ne jp (primary author)
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
We're hiring!
google: はてな 求人
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
nice office.
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
nice development environment.
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
ところで ... (By the way)
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
勤務地は京都です (Our HQ is located at Kyoto.)
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Thank you!
©2008 株式会社はてな 本資料の一部または全部の無断複製・転載を禁じます
Any Questions?