NAME
    DBIx::MoCo - Light & Fast Model Component

SYNOPSIS
      # First, set up your db.
      package Blog::DataBase;
      use base qw(DBIx::MoCo::DataBase);

      __PACKAGE__->dsn('dbi:mysql:dbname=blog');
      __PACKAGE__->username('test');
      __PACKAGE__->password('test');

      1;

      # Second, create a base class for all models.
      package Blog::MoCo;
      use base qw 'DBIx::MoCo'; # Inherit DBIx::MoCo
      use Blog::DataBase;

      __PACKAGE__->db_object('Blog::DataBase');

      1;

      # Third, create your models.
      package Blog::User;
      use base qw 'Blog::MoCo';

      __PACKAGE__->table('user');
      __PACKAGE__->has_many(
          entries => 'Blog::Entry',
          { key => 'user_id' }
      );
      __PACKAGE__->has_many(
          bookmarks => 'Blog::Bookmark',
          { key => 'user_id' }
      );

      1;

      package Blog::Entry;
      use base qw 'Blog::MoCo';

      __PACKAGE__->table('entry');
      __PACKAGE__->has_a(
          user => 'Blog::User',
          { key => 'user_id' }
      );
      __PACKAGE__->has_many(
          bookmarks => 'Blog::Bookmark',
          { key => 'entry_id' }
      );

      1;

      package Blog::Bookmark;
      use base qw 'Blog::MoCo';

      __PACKAGE__->table('bookmark');
      __PACKAGE__->has_a(
          user => 'Blog::User',
          { key => 'user_id' }
      );
      __PACKAGE__->has_a(
          entry => 'Blog::Entry',
          { key => 'entry_id' }
      );

      1;

      # Now, You can use some methods same as in Class::DBI.
      # And, all objects are stored in cache automatically.
      my $user = Blog::User->retrieve(user_id => 123);
      print $user->name;
      $user->name('jkontan'); # update db immediately
      print $user->name; # jkontan

      my $user2 = Blog::User->retrieve(user_id => 123);
      # $user is same as $user2

      # You can easily get has_many objects array.
      my $entries = $user->entries;
      my $entries2 = $user->entries;
      # $entries is same reference as $entries2
      my $entry = $entries->first; # isa Blog::Entry
      print $entry->title; # you can use methods in Entry class.

      Blog::Entry->create(
        user_id => 123,
        title => 'new entry!',
      );
      # $user->entries will be flushed automatically.
      my $entries3 = $user->entries;
      # $entries3 isnt $entries

      print ($entries->last eq $entries2->last); # 1
      print ($entries->last eq $entries3->last); # 1
      # same instance

      # You can delay update/create query to database using session.
      DBIx::MoCo->start_session;
      $user->name('jkondo'); # not saved now. changed in cache.
      print $user->name; # 'jkondo'
      $user->save; # update db
      print Blog::User->retrieve(123)->name; # 'jkondo'

      # Or, update queries will be thrown automatically after ending session.
      $user->name('jkontan');
      DBIx::MoCo->end_session;
      print Blog::User->retrieve(123)->name; # 'jkontan'

DESCRIPTION
    Light & Fast Model Component

CACHE ALGORITHM
    MoCo caches objects effectively. There are 3 functions to control MoCo's
    cache. Their functions are called appropriately when some operations are
    called to a particular object.

    Here are the 3 functions.

    store_self_cache
        Stores self instance for all own possible object ids.

    flush_self_cache
        Flushes all caches for all own possible object ids.

    _flush_belongs_to
        Flushes all caches whose have has_many arrays including the object.

    And, here are the triggers which call their functions.

    _after_create
        Calls "store_self_cache" and "_flush_belongs_to".

    _before_update
        Calls "flush_self_cache".

    _after_update
        Calls "store_self_cache".

    _before_delete
        Calls "flush_self_cache" and "_flush_belongs_to".

CLASS METHODS
    Here are common class methods of DBIx::MoCo.

    has_a
        Defines has_a relationship between 2 models.

    has_many
        Defines has_many relationship between 2 models.

    retrieve_keys
        Defines keys for retrieving by retrieve_all etc. If there aren't any
        unique keys in your table, please specify these keys.

          package Blog::Bookmark;

          __PACKAGE__->retrieve_keys(['user_id', 'entry_id']);
          # When user can add multiple bookmarks onto same entry.

    start_session
    end_session
    is_in_session
    cache_status
        Returns cache status hash reference. cache_status provides
        retrieve_count, retrieve_cache_count, retrieved_oids
        retrieve_all_count, has_many_count, has_many_cache_count,

    cache
        Set or get cache.

    schema
        Returns DBIx::MoCo::Schema object reference related with your model
        class.

    primary_keys
    unique_keys
    columns
    has_column(col_name)
        Returns which the table has the column or not.

    retrieve
    retrieve_or_create
    retrieve_all
    retrieve_all_id_hash
    create
    delete_all
    count
    search
    find
        Similar to search, but returns only the first item as a reference
        (not array).

    retrieve_by_column(_and_column2)
    retrieve_by_column(_and_column2)_or_create
    retrieve_by_column_or_column2
    column_as_something
        Inflate column value by using DBIx::MoCo::Column::* plugins. If you
        set up your plugin like this,

          package DBIx::MoCo::Column::MyColumn;

          sub MyColumn {
            my $self = shift;
            return "My Column $$self";
          }

          1;

        Then, you can use column_as_MyColumn method

          my $o = MyObject->retrieve(..);
          print $o->name; # "jkondo"
          print $o->name_as_MyColumn; # "My Column jkondo";

        You can also inflate your column value with blessing with other
        classes. Method name which will be imported must be same as the
        package name.

    has_a, has_many auto generated methods
        If you define has_a, has_many relationships,

          package Blog::Entry;
          use base qw 'Blog::MoCo';

          __PACKAGE__->table('entry');
          __PACKAGE__->has_a(
              user => 'Blog::User',
              { key => 'user_id' }
          );
          __PACKAGE__->has_many(
              bookmarks => 'Blog::Bookmark',
              { key => 'entry_id' }
          );

        You can use those keys as methods.

          my $e = Blog::Entry->retrieve(..);
          print $e->user; # isa Blog::User
          print $e->bookmarks; # isa ARRAY of Blog::Bookmark

CLASS OR INSTANCE METHODS
    Here are common class or instance methods of DBIx::MoCo.

    object_id
    delete
    quote

INSTANCE METHODS
    Here are common instance methods of DBIx::MoCo.

    flush_self_cache
        Flush caches for self possible object ids.

    store_self_cache
        Store self into cache for possible object ids.

    flush
        Delete attribute from given attr. name.

    param
        Set or get attribute from given attr. name.

    set Set attribute which is not related with DB schema or set temporary.

    has_primary_keys
    save
        Saves changed columns in session.

    object_ids
        Returns all possible object-ids.

FORM VALIDATION
    You can validate user parameters using moco's schema. For example you
    can define your validation profile using param like this,

      package Blog::User;

      __PACKAGE__->schema->param([
        name => ['NOT_BLANK', 'ASCII', ['DBIC_UNIQUE', 'Blog::User', 'name']],
        mail => ['NOT_BLANK', 'EMAIL_LOOSE'],
      ]);

    And then,

      # In your scripts
      sub validate {
        my $self = shift;
        my $q = $self->query;
        my $prof = Blog::User->schema->param('validation');
        my $result = FormValidator::Simple->check($q => $prof);
        # handle errors ...
      }

SEE ALSO
    SQL::Abstract, Class::DBI, Cache,

AUTHOR
    Junya Kondo, <http://use.perl.org/~jkondo/>, Naoya Ito,
    <naoya@hatena.ne.jp>

COPYRIGHT AND LICENSE
    Copyright (C) Hatena Inc. All Rights Reserved.

    This library is free software; you may redistribute it and/or modify it
    under the same terms as Perl itself.