Introduction To Moco

  • 3,777 views
Uploaded on

 

More in: Business , Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
3,777
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
12
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Introduction to DBIx::MoCo Naoya Ito http://www.hatena.ne.jp/
  • 2. What is DBIx::MoCo?
    • “ Light and Fast Model Component”
      • O/R Mapper for MySQL and SQLite
  • 3. Features
    • Easy SQL operations like CDBI / ActiveRecord (Rails)‏
    • Ruby-like list operations
    • Transparent caching with Cache::* (usually with Cache::Memcached)‏
    • Test fixture
  • 4. Quick start
  • 5. Install
    • "cpan DBIx::MoCo"
      • You may need force install as of now.
  • 6. setup your own classes DBIx::MoCo DBIx::MoCo:: DataBase Bookmark:: MoCo Bookmark:: DataBase Bookmark:: User Bookmark:: Entry uses
  • 7. setup: 1. create DataBase class package Bookmark::DataBase; use base qw/DBIx::MoCo::DataBase/; __PACKAGE__->dsn('dbi:mysql:dbname=bookmark'); __PACKAGE__->username(‘foo'); __PACKAGE__->password(‘bar'); 1;
  • 8. setup: 1. create DataBase class DBIx::MoCo DBIx::MoCo:: DataBase Bookmark:: DataBase
  • 9. 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; }
  • 10. setup: 2. create base class of your models DBIx::MoCo DBIx::MoCo:: DataBase Bookmark:: MoCo Bookmark:: DataBase uses
  • 11. setup: 3. create model classes package 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;
  • 12. setup: 3. create model classes DBIx::MoCo DBIx::MoCo:: DataBase Bookmark:: MoCo Bookmark:: DataBase Bookmark:: User Bookmark:: Entry uses
  • 13. 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);
  • 14. SQL operations
  • 15. search()‏ my @entries = moco('Entry') ->search( where => "url like 'http://d.hatena.ne.jp/%'", order => 'entry_id desc', limit => 10, ); say $_->title for @entries;
  • 16. 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;
  • 17. search() : named placeholders my @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;
  • 18. 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;
  • 19. Create, Update, Delete ## create new record my $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;
  • 20. List operations
  • 21. Ruby-like list operations ## Scalar context my $entries = moco('Entry')->search(...); say $entries ->size; say $entries ->collect(sub { $_->title })‏ ->join(" "); say $entries ->grep(sub { $_->is_public })‏ ->collect(sub { $_->num_of_bookmarks }} ->sum;
  • 22. 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
  • 23. List::RubyLike
    • google:github list-rubylike
  • 24. Using your own list class ## create your own list class of Blog::Entry package Blog::Entry::List; use base qw/DBIx::MoCo::List/; sub to_json { ... } ## setup list_class()‏ package Blog::Entry; ... __PACKAGE__->list_class('Blog::Entry::List');
  • 25. Using your own list class ## $entries is a Blog::Entry::List my $entries = moco('Entry')->search(...); say $entries ->to_json ;
  • 26. Relationships
  • 27. An entry has many bookmarks package 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', }, );
  • 28. $entry->bookmarks my $entry = moco('Entry')->retrieve_by_url(...); ## bookmarks() returns bookmarks of the entry my @bookmarks = $entry ->bookmarks; ## offset and limit (offset 10, limit 50)‏ @bookmarks = $entry->bookmarks (10, 50) ; ## Ruby-like list operations in scalar context print $entry->bookmarks(10, 50) ->grep(...)->size;
  • 29. 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' } );
  • 30. $bookmark->entry my $bookmark = moco('Bookmark')->retrieve; say $bookmark ->entry->title; say $bookmark ->owner->name
  • 31. 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 ; }
  • 32. 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 ; }
  • 33. 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/] }, );
  • 34. inflate / deflate
  • 35. inflate / deflate (explicitly) my $entry = moco('Entry')->retrieve(1); ## plain string say $entry->timestamp; ## timestamp column as DateTime object say $entry-> timestamp_as_DateTime ->hms; ## url column as URI object say $entry-> url_as_URI ->host;
  • 36. 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;
  • 37. 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 } } );
  • 38. Transparent caching
  • 39. Transparent caching ## Just do it my $cache = Cache::Memcached->new({...}); Bookmark::MoCo->cache_object( $cache );
  • 40. Transparent caching ## The entry object will be cached my $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;
  • 41. NOTE: "session" is needed when you use caching feature or prefetching. Blog::MoCo->start_session; my $entry = moco('Entry')->retrieve(...); Blog::MoCo->end_session;
  • 42. Testing
  • 43. Fixtures: building records for testing from YAML ## fixtures/entries.yml model: Bookmark::Entry records: first: id: 1 title: Hatena Bookmark url: http://b.hatena.ne.jp/ second: id: 2 title: Yahoo! Japan url: http://www.yahoo.co.jp/
  • 44. Writing tests with fixtures ## t/entry.t use 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, "...";
  • 45. Pros and Cons
  • 46. Pros
    • Simple and easy
    • List operations are very sexy.
    • Transparent caching is "DB に優しい "
    • Test fixture
  • 47. Cons
    • less document
    • some difficulties (especially in session and cache)‏
    • low test coverage
    • some bugs
  • 48. patches are welcome. jkondo at hatena ne jp (primary author)‏
  • 49. We're hiring! google: はてな 求人
  • 50. nice office.
  • 51. nice development environment.
  • 52. ところで ... (By the way)
  • 53. 勤務地は京都です (Our HQ is located at Kyoto.)
  • 54. Thank you!
  • 55. Any Questions?