NAME
   ORM::Tutorial - Guided tour to ORM module.

SYNOPSIS
   Purpose of this document is to brief introduce usage of PerlORM library
   on simple example. Example is 'Tasks Planner' (or 'Todo List')
   application.

OBJECT MODEL
   Let's start with simple object model, which will be improved and
   modified as needed later. Object classes of our example application are:

   1. Task
       Properties:

       * Title (title)
       * Detailed description (desc)
       * Creation time (created)
       * Start time (start_date), can be undef
       * End time (end_date), can be undef
       * Deadline (deadline), can be undef
       * Responsible worker (worker)

   2. Worker
       Properties:

       * Worker name (name)

   First step in creation of object model is to create so called initial
   class. Initial class is base class for all classes of our object model.

   File Todo/ORM.pm

     package Todo::ORM;

     use ORM::Db::DBI::MySQL;
     use base 'ORM';

     Todo::ORM->_init
     (
         prefer_lazy_load     => 0,
         emulate_foreign_keys => 1,
         default_cache_size   => 200,

         db => ORM::Db::DBI::MySQL->new
         (
             host        => 'localhost',
             database    => 'todo_list',
             user        => 'root',
             password    => '',
         ),
     );

     1;

   Now let's declare classes of our model.

   PerlORM was developed with usage simplicity in mind therefore it does
   not require you to declare class properties and relations in both class
   declaration and database. Creation of database table for storing objects
   of the class is quite enough. Fields in this table are correspond to
   object properties.

   Also there is tool-script in development that allows to screate database
   tables and templates of Perl-modules from UML schemes, but if you
   doesn't want to spend time to build additional class or database schemes
   you are always able to use short way.

   One or more database tables are assigned to each class (more than one
   table is used in case of inheritance). Each object of the class is
   represented by single row in table or inner join of rows in case of
   inheritance.

   Initial declaration of classes looks very simple:

   File Todo/Task.pm

     package Todo::Task;

     $VERSION=0.1;

     use ORM::Base 'Todo::ORM';

   File Todo/Worker.pm

     package Todo::Worker;

     $VERSION=0.1;

     use ORM::Base 'Todo::ORM';

   There is one question: how PerlORM detects what table to use for certain
   class? If table name is not specified obviously then ORM class calls
   method "_guess_table_name" which is by default uses regexp "$class =~
   s/::/_/g;" to detect table name from class name. You can change this
   behaviour by overriding "_guess_table_name" method in your initial
   class. For example:

     sub _guess_table_name
     {
         my $my_class = shift;
         my $class = shift;
         my $table;

         $table = substr( $class, index( $class, '::' )+2 );
         $table =~ s/::/_/g;

         return $table;
     }

   Now table for class "Todo::Task" should be named "Task" and not
   "Todo_Task".

   It's time to create database tables. (Name of database being used is
   specified in storage driver constructor.)

     CREATE DATABASE todo_list;

     DROP TABLE IF EXISTS `todo_list`.`_ORM_refs`;
     CREATE TABLE `_ORM_refs` (
         `class` varchar(45) NOT NULL default '',
         `prop`  varchar(45) NOT NULL default '',
         `ref_class` varchar(45) NOT NULL default '',
         PRIMARY KEY  (`class`,`prop`)
     ) ENGINE=InnoDB;

     INSERT INTO `_ORM_refs` VALUES ( 'Todo::Task', 'worker', 'Todo::Worker' );

     DROP TABLE IF EXISTS `todo_list`.`Task`;
     CREATE TABLE `task` (
         `id` bigint(20) unsigned NOT NULL auto_increment,
         `title` varchar(255) NOT NULL default '',
         `desc` text NOT NULL,
         `created` date default NULL,
         `start_date` date default NULL,
         `deadline` date default NULL,
         `worker` bigint(20) unsigned default NULL,
         PRIMARY KEY  (`id`)
     ) ENGINE=InnoDB;

     DROP TABLE IF EXISTS `todo_list`.`Worker`;
     CREATE TABLE `worker` (
         `id` bigint(20) unsigned NOT NULL auto_increment,
         `name` varchar(100) NOT NULL default '',
         PRIMARY KEY  (`id`)
     ) ENGINE=InnoDB;

   We just created 3 tables, first of them "_ORM_refs" is special table.
   ORM uses it to detect relations between classes in our model and usage
   of third party classes. In our model "worker" property of class
   "Todo::Task" should be reference to an object of class "Todo::Worker".
   To tell it to ORM we should insert following row in "_ORM_refs":

     class       | prop      | ref_class
     ------------------------------------
     Todo::Task  | worker    | Todo::Worker

   This is the usual way the relations between classes are defined. Note
   that when you define reference property in "Todo::Task" class to
   "Todo::Worker", the second one automatically gets so called reversive
   property or collection property that contains all tasks assigned to
   particular worker object. In RDBMS terms such kind of relation is called
   one-to-many.

   For frequently used classes there is another way to define relations
   between objects, this way is to override "ORM::_db_type_to_class" method
   in our initial class. "_db_type_to_class" method accepts table field
   name and type as its arguments and returns class that should be assigned
   to property.

   The default behavior of "_db_type_to_class" method defined in ORM class
   is to assign classes ORM::Date and ORM::Datetime to properties described
   by fields of type "DATE" and "DATETIME" respectively. This behaviour is
   also can be changed to use another classes to represend dates and times,
   the chapter "THIRD PARTY CLASSES" tells how to do it.

   Every table that is used with ORM should have autoincremented field "id"
   which stored ID of objects of corresponding class. (Functionality that
   allows to use arbitrary column or multiple columns to represent object
   ID is subject to furthrer development.)

CREATING OBJECTS
   Creation of objects in ORM is performed by calling 'new' method. For
   example let's create 'Worker' object:

     use Todo::Worker;

     $error  = ORM::Error->new;
     $worker = Todo::Worker->new
     (
         prop  => { name => 'E. Cartman' },
         error => $error,
     );

     print $error->text;

   If 'new' operation fails then $error object contains information about
   occured errors. Use of $error object is not necessary but strongly
   recomended.

   Now to more easily manage objects of our model we will create perl
   script for object creation "new.pl"

   File new.pl

     #!/usr/bin/perl
     #
     # Use: perl new.pl <Class> <Prop1Name> <Prop1Value> <Prop2Name> <Prop2Value>...
     #
     # Class - Name of the class without 'Todo::' prefix.
     #

     use lib "lib";
     use lib "../ORM/lib";

     $nick  = shift;
     $class = "Todo::$nick";

     eval "require $class" or die $@;

     $error = ORM::Error->new;
     %prop  = @ARGV;
     $obj   = $class->new( prop=>\%prop, error=>$error );

     if( $obj )
     {
         print "New $nick was created with id:".$obj->id."\n" if( $obj );
         $obj->print;
     }

     print $error->text;

   Above script uses "print" method we doesn't declare yet. This method is
   aimed to print plain text information about specified object. This
   method should be defined in initial class so every object of our model
   can acces it.

     sub print
     {
         my $self  = shift;
         my $ident = shift||0;
         my @ref;

         # Do not dive deeper that third level of recursion
         # when printing information about related objects.

         return if( $ident > 3 );

         # Print information about specified object

         print ' 'x($ident*2),('-'x20),"\n";
         for my $prop ( (ref $self)->_all_props )
         {
             printf "%".(20+$ident*2)."s %s\n", "$prop:",
                 (defined $self->_property_id($prop) ? $self->_property_id($prop) : '*UNDEF*');

             if( (ref $self)->_prop_is_ref( $prop ) && $self->_property( $prop ) )
             {
                 push @ref, $prop;
             }
         }
         print ' 'x($ident*2),('-'x20),"\n\n";

         # Print information about related objects

         for my $prop ( @ref )
         {
             print ' 'x(($ident+1)*2),"Related object '$prop':\n";
             $self->_property( $prop )->print( $ident+1 );
         }
     }

   Note the way properties were accessed. For this purpose
   "$obj->_property( $property_name )" were used in above code. To access
   object properties with more grace there is AUTOLOAD method. So you can
   simply call "$obj->$property_name()" (or just "$obj->deadline" for
   example). The "ORM::_property" method is for cases when $property_name
   method should be redefined in child class for some reason.

   Also you can use "$obj->_property_id( $property_name )" to get raw
   database value of the property. Its result is:

   * the same as of "ORM::_property" for plain (non-object) properties
   * database property value for non-ORM third party classes
   * object's ID for ORM classes

   Now we can fill our model with some more objects.

     # perl new.pl Worker name "Kenny McCormic"
     New Worker was created with id:2
     --------------------
                      id: 2
                   class: Todo::Worker
                    name: Kenny McCormic
     --------------------

     # perl new.pl Task \
           title "Kill Kenny" \
           desc "Just kill Kenny!" \
           worker 1 \
           created "2005-12-18" \
           start_date "2006-01-01" \
           deadline "2006-01-02"

     New Task was created with id:1
     --------------------
                      id: 1
                   class: Todo::Task
                 created: 2005-12-18
                    desc: Just kill Kenny!
                  worker: 1
                deadline: 2006-01-02
                   title: Kill Kenny
              start_date: 2006-01-01
     --------------------

       Related object 'worker':
       --------------------
                        id: 1
                     class: Todo::Worker
                      name: Eric Cartman
       --------------------

     # perl new.pl Task \
           title "Eat Chocolate pie" \
           desc "Ask your mummy." \
           worker 1 \
           created "2005-12-18" \
           start_date "2006-01-01" \
           deadline "2006-01-02"

     New Task was created with id:2
     --------------------
                      id: 2
                   class: Todo::Task
                 created: 2005-12-18
                    desc: Ask your mummy.
                  worker: 1
                deadline: 2006-01-02
                   title: Eat Chocolate pie
              start_date: 2006-01-01
     --------------------

       Related object 'worker':
       --------------------
                        id: 1
                     class: Todo::Worker
                      name: Eric Cartman
       --------------------

   For more comfort let's modify "Todo::Task" class so it can automatically
   assign current time to "created" property when explicit value is not
   specified:

     sub _validate_prop
     {
         my $self = shift;
         my %arg  = @_;

         if( $arg{method} eq 'new' && ! $self->created )
         {
             $self->_fix_prop
             (
                 prop  => { created=>ORM::Date->current },
                 error => $arg{error},
             );
         }

         $self->SUPER::_validate_prop( %arg );
     }

   * Method "_validate_prop" is implicitly called when new object is being
   created ("new" method) and when object is being updated ("update"
   method).
   * Condition "( $arg{method} eq 'new' )" is true only when called from
   within "new" method. In another words this means that object is not yet
   stored in database table.
   * Method "ORM::_fix_prop" is intended to use only within
   "_validate_prop".
   * Do not forget to call "SUPER::_validate_prop".

   Let's add one more task:

     # perl new.pl Task \
           title "Keep alive" \
           desc "Just keep alive!" \
           worker 2 \
           start_date "2005-12-31" \
           deadline "2006-01-02"

     New Task was created with id:3
     --------------------
                      id: 3
                   class: Todo::Task
                 created: 2005-12-18
                    desc: Just keep alive!
                  worker: 2
                deadline: 2006-01-02
                   title: Keep alive
              start_date: 2005-12-31
     --------------------

       Related object 'worker':
       --------------------
                        id: 2
                     class: Todo::Worker
                      name: Kenny McCormic
       --------------------

   As you can see "created" property is implicitly initialized with default
   value of current time. (It seems like Kenny will die anyway after
   deadline.)

UPDATING OBJECTS
   Update of object is performed with the same simplicitly:

     use Todo::Worker;

     $error  = ORM::Error->new;
     $worker = Todo::Worker->find_id( id=>1, error=>$error );
     $worker && $worker->update( prop=>{ name=> 'Eric Cartman' }, error=>$error );

     print $error->text;

   To easily update objects from command line there will be another script
   that is very similar to "new.pl".

   File update.pl

     #!/usr/bin/perl
     #
     # Use: perl update.pl <Class> <ObjectID> <Prop1Name> <Prop1Value> <Prop2Name> <Prop2Value>...
     #
     # Class - Name of the class without 'Todo::' prefix.
     #

     use lib "lib";
     use lib "../ORM/lib";

     $nick  = shift;
     $class = "Todo::$nick";

     eval "require $class" or die $@;

     $id    = shift;
     $error = ORM::Error->new;
     %prop  = @ARGV;
     $obj   = $class->find_id( id=>$id, error=>$error );

     if( $obj )
     {
         $obj->update( prop=>\%prop, error=>$error ) unless( $error->fatal );
         print "Updated $nick with id:".$obj->id."\n";
         $obj->print;
     }
     else
     {
         print STDERR "Object #$id of $class not found!\n";
     }

     print $error->text;

SELECTING AND FILTERING
   Now when we have some tasks planned for workers it's time to make some
   reports about tasks state. Interesting reports are:

   * Tasks planned to be done by specific worker
   * Tasks that should be done due specified date

   Tasks for first report can be selected as follows:

     ORM::DbLog->write_to_stderr( 1 );
     @tasks = Todo::Task->find
     (
         filter => ( Todo::Task->M->worker == $worker ),
         error  => $error,
     );

   "Todo::Task->M->worker" - is so named Meta-property, Meta-property is
   object of class "ORM::Metaprop" or its descendants. In resulting
   SQL-query Meta-properties are replaced with names of corresponding table
   fields. Special meta-property "Todo::Task->M" means object of class
   "Todo::Task" itself. Below you will see that meta-properties is very
   powerful facility and is also easy to use.

   Variable $worker should contain "Todo::Worker" object or just its
   integer ID.

   Variable $error of type "ORM::Error" contains description of error if
   any occured during query. "error" parameter is not required, if it is
   omitted then error is silently ignored. In future version this behavious
   can be changed.

   Call "ORM::DbLog->write_to_stderr( 1 )" enables trace of so called
   SQL-log to STDERR this is useful tool for debugging you code. In
   described case (assuming $worker=1) SQL-log trace looks as follows:

     --------------------------
     [Mon Dec 26 00:14:27 2005]: ORM::find: Success
     SELECT
       DISTINCT `Task`.*
     FROM
       `Task`
     WHERE
       (`worker` = '1')

   If we need to select tasks by worker name, then call looks like this:

     @tasks = Todo::Task->find
     (
         filter => ( Todo::Task->M->worker->name eq $worker_name ),
         order  => ORM::Order->new( [ Todo::Task->M->created, 'DESC' ] ),
         error  => $error,
     );

   Draw attention on using of operators "==" and "eq". Databases usually
   have no sence to this operator because in most cases they are translated
   to SQL "=" operator which is used for both string and numeric
   comparisons. Nevertheless for best readability it is reasonable to use
   this operators as in native Perl.

   Parameter 'order' specifies that found tasks should be sorted by
   "created" time in descendant order.

   Let's try little more complicated query when we need to find tasks
   assigned to workers containing some string in their names:

     @tasks = Todo::Task->find
     (
         filter => ( Todo::Task->M->worker->name->_like( '%Cartman%' ) ),
         order  => ORM::Order->new( [ Todo::Task->M->created, 'DESC' ] ),
         error  => $error,
     );

   Resulting SQL-query for the call:

     SELECT
       DISTINCT `_T1_Task`.*
     FROM
       `Task` AS `_T1_Task`
         LEFT JOIN `Worker` AS `_T2_Worker` ON( `_T1_Task`.`worker`=`_T2_Worker`.`id` )
     WHERE
       (`_T2_Worker`.`name` LIKE '%Cartman%')
     ORDER BY `_T1_Task`.`created` DESC

   Call for second report looks much similar:

     $M     = Todo::Task->M;
     @tasks = Todo::Task->find( filter => ( $M->deadline < '2006-01-30' ) );

   Variable $M is for brevity, such trick is useful when constructing
   complex meta-expressions.

   Filters can be logically grouped with arbitrary complexity using
   "ORM::Expr->_and" and "ORM::Expr->_or" methods. In simplest case you can
   use overloaded '&' and '|' operators:

     $M     = Todo::Task->M;
     @tasks = Todo::Task->find
     (
         filter =>
           ( $M->deadline < '2006-01-30' )
           & Todo::Task->M->worker->name->_like( '%Cartman%' )
     );

   Be careful with operator priorities while constructing expressions with
   these operators.

   There is another interesting report about number of tasks assigned to
   each worker, for this report we will use "stat" method, This method is
   useful when you need info about related objects:

     $M   = Todo::Worker->M;
     $res = Todo::Worker->stat
     (
         data =>
         {
             worker => $M,
             tasks  => $M->_rev( 'Todo::Task' => 'worker' )->_count,
         },
         group_by => [ $M ],
         preload  => { worker=>1 },
     );

   Opposite to "find" method which returns array of objects, "stat" method
   returns array of hashes with requested data.

   Parameter "data" is hash reference that defines what kind of data should
   be retrieved from database. Resulting hash contains records with exactly
   the same keys as in "data" parameter and with values retrieved from
   database as specified by values of "data".

   In our case $res contains hashes with two keys "worker" - "Todo::Worker"
   object and "tasks" - number of assigned tasks.

   Parameter "group_by" similar to SQL "GROUP BY" statement. In resulting
   SQL-query "group_by" is replaced with "GROUP BY". It is used to define
   how to apply grouping method "_count".

   Parameter "preload" defines objects that should be loaded by resulting
   query and not later by separate query.

   Meta-property "$M->_rev( 'Todo::Task' => 'worker' )" so called reversive
   meta-property. It is used to access objects that refer by one of their
   property to objects being selected. In our case objects of class
   "Todo::Task" referring to objects of class "Todo::Worker" by property
   "worker", therefore we can reversively access tasks assigned to a
   worker.

   SQL-query for the call:

     --------------------------
     [Mon Dec 26 00:49:34 2005]: ORM::stat: Success
     SELECT
       'Todo::Worker' AS `_worker class`,
       COUNT( `_T2_Task`.`id` ) AS `tasks`,
       `_T1_Worker`.`id` AS `worker`,
       `_T1_Worker`.`name` AS `_worker name`
     FROM
       `Worker` AS `_T1_Worker`
         LEFT JOIN `Task` AS `_T2_Task` ON( `_T1_Worker`.`id`=`_T2_Task`.`worker` )
     GROUP BY `_T1_Worker`.`id`

DELETING OBJECTS
   Method 'delete' is used for deletion of objects from database.

     $worker->delete( error=>$error );

   If 'emulate_foreign_keys' option to "ORM::_init" method is set to true
   then before deletion ORM checks if there are another objects that refer
   to object being deleted. If so $error object contains corresponding
   error message and object is not deleted.

   After object $worker has been deleted from database it is reblessed to
   be object of class "ORM::Broken". Call to any method of this object will
   croak with error message. This is to be sure that object is not being
   used after it has been deleted.

ERROR HANDLING
   Error handling is done by passing 'error' argument to almost every ORM
   method. 'error' argument should contain object of class "ORM::Error".
   Consider the following code:

     use Todo::Task;

     $task  = Todo::Task->find; # first found task
     $error = ORM::Error->new;
     $task->update
     (
         prop  => { worker=>-1 },
         error => $error,
     );
     print STDERR "Failed to update\n" if( $error->fatal );
     print STDERR $error->text;

   Output for this code:

     Failed to update
     fatal: ORM->_normalize_prop_to_db_value(): Property 'worker' of type 'Todo::Worker' with id='-1' was not found

   Classes of our object model also can produce their own errors and send
   them to the caller.

   For example we should not permit to set "Todo::Task->deadline" property
   to be less than current date. To implement this functionality we will
   modify "Todo::Task" class by adding new condition to "_validate_prop"
   method:

     if( $self->deadline && $self->deadline < ORM::Datetime->current )
     {
         $arg{error}->add_fatal( "Deadline is in past!" );
     }

   As far as "_validate_prop" method is called only implicitly from 'new'
   and 'delete' methods, you can be sure that $arg{error} contains correct
   "ORM::Error" object. That's why there is no reason to test it before
   use.

   In cases when you not sure that user has passed $error object to your
   method you can use following scheme:

     sub my_metod
     {
         my $self  = shift;
         my %arg   = @_;
         my $error = ORM::Error->new;

         $error->add_fatal( "test 1" );
         $error->add_warn( "test 2" );

         $error->upto( $arg{error} );
         return undef;
     }

   Call to 'upto' method sends error back to user if $arg{error} contains
   valid error-object. It is equivalent to "$arg{error} &&
   $arg{error}->add( $error )".

   In current ORM version all errors are ignored if 'error' argument is not
   passed to a method. But it seems like a good practice to throw
   exceptions in such cases. This functionality is to be implemented in
   future releases without affecting object interface.

META-CLASSES
   Why do you need meta-classes? Meta-classes give you the way to make
   meta-objects (or meta-properties) behave almost the same as objects
   itself. So you can construct meta-expressions the way similar to those
   for usual Perl-expressions.

   (To be documented)

THIRD PARTY CLASSES (To be documented)
OBJECT CHANGES HISTORY
   To enable built-in feature to trace object changes simply use
   "history_class" argument to "ORM::_init" method as shown below:

     Todo::ORM->_init
     (
         history_class => 'Todo::History',
         %another_args,
     );

   Next step is to declare "Todo::History" class. This class behaves as any
   other regular ORM-class of our model. This means that any change of any
   object is introduced by one or more 'Todo::History' object. History
   class declaration is quite simple:

   File Todo/History.pm

     package Todo::History;

     $VERSION=0.1;

     use ORM::Base 'Todo::ORM', i_am_history=>1;

     1;

   As we have redefined "ORM::_guess_table_name" method, the table for
   "Todo::History" class has assumed name 'History'. Structure of the table
   should be as follows:

     DROP TABLE IF EXISTS `todo_list`.`History`;
     CREATE TABLE `History` (

         `id`        bigint(20)   NOT NULL auto_increment,

         `obj_class` varchar(100) NOT NULL default '',
         `obj_id`    int(11)      NOT NULL default '0',

         `prop_name` varchar(100) NOT NULL default '',
         `old_value` varchar(255)          default '',
         `new_value` varchar(255)          default '',

         `date`      datetime     NOT NULL,
         `editor`    varchar(255) NOT NULL default '',
         `slaved_by` bigint(20) unsigned   default NULL,

         PRIMARY KEY  (`id`)

     ) TYPE=InnoDB;

   From this moment every 'new' (SQL INSERT), 'update' (SQL UPDATE) and
   'delete' (SQL DELETE) actions will be logged in 'History' table.

   Each action is stored in at least one history object. 'new' action
   creates exactly one "Todo::History" object. 'update' and 'delete'
   actions create more than one "Todo::History" objects. 'update' action
   creates number of additional history objects equal to number of
   properties affected by operation. 'delete' action creates number of
   additional history objects equal to number of properties of deleted
   object.

   All history objects created for 'delete' or 'update' actions execpt
   first object has property 'slaved_by' set to id of first history object,
   this object is called 'master'.

   Main use of History class is to store all changes made to objects of our
   model. But there is one more interesting feature. You can undo changes
   with 'Todo::History::rollback' method. For example you can restore
   deleted object by its ID like this:

     $hist = Todo::History->find
     (
         filter => ORM::Expr->_and
         (
             # rollback operation should be called on master history object
             Todo::History->M->master,
             Todo::History->M->obj_class eq 'Todo::Worker',
             Todo::History->M->obj_id == 1,
         ),
     );
     $hist && $hist->rollback;

   This code does the following:

   1. Find 'slaved' history objects
   2. Create 'Todo::Worker' object with properties from 'slaved' history
   objects
   3. Delete 'slaved' and 'master' history objects

   Also it is possible to restore object not by ID but by arbitrary
   property like this:

     $hist = Todo::History->find
     (
         filter => ORM::Expr->_and
         (
             Todo::History->M->obj_class eq 'Todo::Worker',
             Todo::History->M->prop_name == 'name',
             Todo::History->M->old_value->_like( '%Cartman%' ),
             Todo::History->M->delete_slave,
         ),
     );
     $hist && $hist->slaved_by->rollback;

   It is possible to rollback 'new' and 'update' actions by similar
   fashion. You can find more detailed description of this feature in
   ORM::History.

CACHING
 ORM-object caching
   Object's in-memory cache implemented on per-primary-class basis. Primary
   class - is class that is a direct descendant of initial class.

   The idea of such cache strategy is to have several caches, by one for
   every primary class. Objects of non-primary class use cache of its
   primary class. With that in mind its time to say that
   "default_cache_size" argument to "ORM::_init" specifies cache size for
   one primary class and not total cache size.

   In our object model this means that there is maximum of 200 cached
   objects for "Todo::Worker" class and 200 cached objects for "Todo::Task"
   class.

   You can change cache size of individual primary class this way:

     package Todo::Task;

     $VERSION=0.1;

     use ORM::Base 'Todo::ORM', cache_size=>1000;

   You can get current efficiency of in-memory cache by calling
   "ORM::Cache->total_efficiency" and reset the cache counters by calling
   "ORM::Cache->clear_stat"

   When "default_cache_size" is set to zero, it is still possible that
   object will be loaded from cache. This is because of instance caching
   (see below).

   Cache is organized in the fashion when you do not need to purge it
   manually.

 Perl-object caching
   This mechanism is mostly common for ORMs and persistence tools in Perl.
   This means that after

     $task1 = Todo::Task->find_id( id=>1 );
     $task2 = Todo::Task->find_id( id=>1 );

   $task1 and $task2 contain the same blessed reference. And even in the
   following case:

     $task1 = Todo::Task->find_id( id=>1 );
     $task2 = Todo::Task->find( order=>[ Todo::Task->M->id ] );
     $task3 = Todo::Task->find( filter=>( Todo::Task->M->desc->_like( %kill Kenny% ) ) );

   All three variables contain the same object.

   Perl-object caching works even when cache size is set to 0.

   Note: Perl-object caching is performed by means of "weaken" (see
   Scalar::Util). Perl-object caching is significantly restricted for the
   versions of Perl that doesn't support "weaken" feature. The restrictions
   are: with cache size set to 0 Perl-object caching doesn't work at all;
   with cache size set to non-zero value this kind of caching works only
   for objects those are still in cache's pool queue. Once object is
   deleted from cache queue, the consequent requests to load the object
   from the cache will result in 'not cached' responce, even if there are
   instances of the same object still present in the memory.

 Properties caching
   When you first access some object-property of ORM-object, then ORM tries
   to create expected object for you (using find_id for ORM-object
   properties and __ORM_new_db_value for non-ORM-properties) and then store
   it in internal object's hash.

   When you access the same object-property later it is not created again
   but fetched from hash.

   When you need to refresh object's contents simply call
   "$object->refresh".

TRANSACTIONS
   The usual way transactions should be used is to set up a correspondence
   between single method and single transaction. If it is not the case then
   there is probably some conceptual error take place.

     package Todo::Worker;

     # Delegate all worker's tasks to new worker
     sub delegate_tasks
     {
         my $self  = shift;
         my %arg   = @_;
         my $error = ORM::Error->new;
         my $ta    = Todo::ORM->new_transaction( error=>$error );

         for my $task ( $self->_rev_prop( 'Todo::Task'=>'worker', error=>$error ) )
         {
             $task->worker( new_value=>$arg{worker}, error=>$error );
         }

         $error->upto( $arg{error} );
     }

   As you can see the way transactions is used in ORM is different than
   commonly used in other packages. In ORM you do not need to 'finish'
   transaction explicitly. This helps you to avoid situations when you
   forget to call method to finish transaction. $ta contains the object
   assigned to a newly started transactions. Transaction is finished when
   $ta object is destroyed. In our case this happens when method is
   finished.

   If $error contain one or more fatal errors when $ta is being destroyed,
   then transaction is rolled back. Also rollback is performed for active
   transaction when die function called or runtime error occured.

   Note use of '_rev_prop' method in foreach loop:

     $self->_rev_prop( 'Todo::Task'=>'worker', error=>$error );

   That is the way reversive properties (see "CREATING OBJECT MODEL") are
   accessed. If certain reversive property is frequently used then you can
   define shortcut method for it:

     sub tasks { shift->_rev_prop( 'Todo::Task'=>'worker', @_ ); }

   And access it like this:

     @tasks = $self->tasks( error=>$error );
     @tasks = $self->tasks( error=>$error, page=>2, pagesize=>10 );
     $iterator = $self->tasks( error=>$error, return_res=>1 );

   In fact the call to "_rev_prop" first appeared in this chapter is
   similar to:

     Todo::Task->find( filter=>( Todo::Task->M->worker==$self ), error=>$error );

   Transactions in ORM can be nested:

     package Todo::Worker;

     # Delegate all old worker's tasks to new worker
     # and delete old worker
     sub discharge
     {
         my $self  = shift;
         my %arg   = @_;
         my $error = ORM::Error->new;
         my $ta    = Todo::ORM->new_transaction( error=>$error );

         $self->delegate_tasks( worker=>$arg{worker}, error=>$error );
         $self->delete( error=>$error );

         $error->upto( $arg{error} );
     }

   As you can see transactional method 'delegate_tasks' is called from
   another transactional method 'discharge'. Nested transactional object
   simply not issues transaction related statements to SQL-server. In case
   when nested transaction is failed then outer transaction is failed too
   and therefore is rolled back.

   It's planned to support transactions emulation for non-transactional
   databases in cases when it's possible. It's up to ORM users to decide
   how soon this feature will be implemented.

INHERITANCE
   Suppose there are tasks that have to be done by group of workers. For
   that reason "Todo::Worker::Group" class could be useful that is
   derivative of "Todo::Worker" and have additional properties:

   1. Team leader
   2. Team members

   To implement inheritance ORM uses so called vertical mapping. This means
   that for every child class there is one table must be created which
   contains only child's direct properties and not contain inheritted
   properties of base classes. When you do fetch objects of child class
   it's direct table is joined with tables of all base classes.

   This approach is most useful, its only disadvantage compared to another
   inheritance implementations is that it makes additional overheat to
   RDBMS to do table joins. But for large heavy-loaded sites this drawback
   is exhausted by using various types of RDBMS clustering and replication
   technologies.

   To implement "Todo::Worker::Group" we need following steps:

   1. Create class's module
   2. Add 'class' property to base class
   3. Create DB table for child class

   File Todo/Worker/Group.pm

     package Todo::Worker::Group;

     $VERSION=0.1;

     use ORM::Base 'Todo::Worker';

   Note that argument to "use ORM::Base" is 'Todo::Worker' not 'ORM'.

   Now we have to made changes to database:

     CREATE TABLE  `Worker_Group` (
       `id` bigint(20) unsigned NOT NULL auto_increment,
       `leader` bigint(20) unsigned NOT NULL default '0',
       PRIMARY KEY  (`id`)
     ) ENGINE=InnoDB;

     INSERT INTO '_ORM_refs' VALUES ( 'Todo::Worker::Group', 'leader', 'Todo::Worker' );
     ALTER TABLE `Worker` ADD COLUMN `class` VARCHAR(45) NOT NULL AFTER `id`;
     UPDATE `Worker` SET class='Todo::Worker';

   Now call to "Todo::Worker->find" returns objects of "Todo::Worker" and
   "Todo::Worker::Group". To get only "Todo::Worker" object you should
   filter the result set like this:

     @workers = Todo::Worker->find( filter=>( Todo::Worker->M->class eq 'Todo::Worker' ) );

   The best way to get only "Todo::Worker::Group" objects:

     @workers = Todo::Worker::Group->find;

   Next chapter describes how to implement property of
   "Todo::Worker::Group" containing list of group members.

MANY TO MANY RELATIONS
   In previous chapters one-to-many relation type was shortly described. In
   this chapter you will get to know how to implement many-to-many
   relations using ORM.

   ORM does not share the way other persistence tools and mappers implement
   this kind of relations. In fact ORM does nothing to implement it :)
   Probably because of lazy-loaded author (see below).

   The trick here is easy enought. Let's take a look at the nature of
   many-to-many relations.

   To define members of the workers group we should establish relation
   between "Todo::Worker::Group" and "Todo::Worker". To describe the
   relation in RDBMS terms we need separate linking table called e.g.
   'worker_to_group' or in worst case 'workers_to_groups' (avoid to use
   plural form in class names). Roughly the same we need when using ORM but
   the table is assigned to linking class, let's call it
   "Todo::Worker::GroupMember". (I usually use pair of colons to separate
   child classes so "Todo::Worker::Group::Member" is not so good, but this
   is just my subjective rule).

   "Todo::Worker::GroupMember" class is nothing else but plain ORM-class:

     package Todo::Worker::GroupMember;

     $VERSION=0.1;

     use ORM::Base 'Todo::ORM';

   We should execute some SQL queries:

     CREATE TABLE `Worker_GroupMember` (
       `id` bigint(20) unsigned NOT NULL auto_increment,
       `group` bigint(20) unsigned NOT NULL default '0',
       `worker` bigint(20) unsigned NOT NULL default '0',
       PRIMARY KEY  (`id`),
       UNIQUE KEY `group_worker` (`group`,`worker`)
     ) TYPE=InnoDB;

     INSERT INTO '_ORM_refs' VALUES ( 'Todo::Worker::GroupMember', 'group', 'Todo::Worker::Group' );
     INSERT INTO '_ORM_refs' VALUES ( 'Todo::Worker::GroupMember', 'worker', 'Todo::Worker' );

   After this we can access collecions on both sides.

   To get members of the $group:

     @workers = Todo::Worker->find
     (
         filter=>
         (
             Todo::Worker->M->_rev( 'Todo::Worker::GroupMember'=>'worker' )->group == $group
         )
     );

   or

     @workers = Todo::Worker::GroupMember->stat
     (
         data    => { worker => Todo::Worker::GroupMember->M->worker },
         preload => { worker => 1 },
         filter  => ( Todo::Worker::GroupMember->M->group == $group ),
     );

   To get groups the $worker belongs to:

     @groups = Todo::Worker::Group->find
     (
         filter=>
         (
             Todo::Worker::Group->M->_rev( 'Todo::Worker::GroupMember'=>'group' )->worker == $worker
         )
     );

   or

     @groups = Todo::Worker::GroupMember->stat
     (
         data    => { group => Todo::Worker::GroupMember->M->group },
         preload => { group => 1 },
         filter  => ( Todo::Worker::GroupMember->M->worker == $worker ),
     );

   The advantage of this approach is that you easily can add property to
   "Todo::Worker::GroupMember" that for example describes member's position
   in each group, that is impossible with commonly used 'object collection'
   properties.

   The only drawback of this approach is that linking table should contain
   'ID' field. This is to be fixed in the future by allowing object IDs to
   be multi-field primary keys.

   That's it!

LAZY LOAD
   Lazy loading is a technique in ORMs that attempts to delay fetching of
   data from database to your program object space until the data is known
   to be needed.

   The implementation of ORM supports per-field lazy load. But interface
   currently allows only per-table lazy load. Per-field lazy loading is
   currently used only in cases of updates with server-side expressions
   (see below).

   There are three methods that supports 'lazy_load' option:

   First of them is "find". Suppose we need to get full list of workers. It
   can be done with or without lazy load.

     @workers      = Todo::Worker->find;
     @lazy_workers = Todo::Worker->find( lazy_load=>1 );

   In first case ORM load all data from "Worker" table, if there are
   "Todo::Worker::Group" objects exist then data from "Worker_Group" table
   is loaded and joined.

   In second case only "Worker" table is read and objects are being put in
   lazy loaded state.

   Second method that supports lazy load is "find_id".

     $worker = Todo::Worker->find_id( id=>1, lazy_load=>1 );

   This means not to load any data from database at all. When you try to
   access some $worker property ORM attempts to load object from storage,
   if loading is failed then $worker is reblessed to "ORM::Broken".

   Also note that while $worker is in lazy loaded state it is assumed to be
   object of "Todo::Worker" class even if in fact it is object of
   "Todo::Worker::Group".

   To force load of lazy loaded object you can use "finish_loading" or
   "refresh" methods.

   Finally "stat" method accepts 'lazy_load' option that is forwarded to
   "find_id" when "stat" makes decision to load requested objects.

     $result = Todo::Task->stat
     (
         data      => { task=>Todo::Task->M, worker=>Todo::Task->M->worker },
         lazy_load => $lazy_load,
     );

   This means to load set of tasks and their related workers. If $lazy_load
   is "true" then ORM do not execute separate queries to load complete
   objects, it just calls to "find_id" with "lazy_load" option set to
   "true".

   Note that with using "stat" you can load all objects in one query:

     $result = Todo::Task->stat
     (
         data    => { task=>Todo::Task->M, worker=>Todo::Task->M->worker },
         preload => { task=>1, worker=>1 },
     );

   Also note that Objects of "Todo::Worker::Group" are still not completely
   loaded (only "Worker" table is read).

   There is corresponding query you can see with
   "ORM::DbLog->write_to_stderr(1)".

     --------------------------
     [Sat Jan 21 13:40:57 2006]: ORM::stat: Success
     SELECT
       `_T1_Task`.`worker` AS `_task worker`,
       `_T1_Task`.`title` AS `_task title`,
       `_T1_Task`.`deadline` AS `_task deadline`,
       `_T1_Task`.`id` AS `task`,
       `_T1_Task`.`desc` AS `_task desc`,
       'Todo::Worker' AS `_worker class`,
       `_T1_Task`.`created` AS `_task created`,
       `_T1_Task`.`start_date` AS `_task start_date`,
       `_T2_Worker`.`id` AS `worker`,
       `_T2_Worker`.`name` AS `_worker name`,
       'Todo::Task' AS `_task class`
     FROM
       `Task` AS `_T1_Task`
         LEFT JOIN `Worker` AS `_T2_Worker` ON( `_T1_Task`.`worker`=`_T2_Worker`.`id` )

SERVER-SIDE UPDATES
   There is useful feature in ORM to do updates using server-side
   expressions (or meta expressions):

     $cartman->update
     (
         prop=>{ name=>Todo::Worker->M->name->_append( ' (fatboy)' ) }
     );

   Meta-expressions are constructed in the same fashion as for "find".

   After execution of above code $cartman will fall in lazy loaded state.
   More specifically it will have no idea about new value of "name"
   property (Note also that if history is enabled for method or for entire
   class then the object is being brought to fully loaded state to consider
   history changes).

   This feature is useful to do non-transactional updates in situations
   when you are not sure about freshness of the object being updated.
   Without using server-side update you will get error message if your
   object's data is not up to date.

   There is one unsolved issue about server-side updates. For sake of data
   integrity execution of server-side updates should be permitted only to
   class itself and to defined class friends. The idea how to make it is
   still high in the air. This issue is definetely should be solved earlier
   than version 1.0 of ORM is to be released.

SOME REFACTORING
 Move property to base class (To be documented)
 Move property to child class (To be documented)
 Delete property (To be documented)
ORM + APACHE (To be documented)
SEE ALSO
   http://perlorm.sourceforge.net/

   ORM

   TODO.txt

AUTHOR
   Alexey V. Akimov

COPYRIGHT AND LICENSE
   Copyright (C) 2005-2006 Alexey V. Akimov

   This library is free software; you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 2.1 of the License, or (at
   your option) any later version.

   This library is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
   General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this library; if not, write to the Free Software Foundation,
   Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA