Author: Nathan Goodman

# NAME

Class::AutoDB::Serialize - Serialization engine for Class::AutoDB -- MySQL only for now

# SYNOPSIS

This is a mixin class that enables objects to be serialized and stored in a database as independent entities, and later fetched one-by-one or in groups. Whether fetched individually or in groups, the original shared object structure is preserved. It's not necessary for the object to also from Class::AutoClass, although the examples here all do.

## Define class that inherits from Class::AutoDB::Serialize

Person class with attributes 'name', 'sex', 'hobbies', and 'friends', where 'friends' is a list of Persons.

    package Person;
    use Class::AutoClass;
    use Class::AutoDB::Serialize;
    @ISA=qw(Class::AutoClass Class::AutoDB::Serialize);

    @AUTO_ATTRIBUTES=qw(name sex hobbies friends);
    @OTHER_ATTRIBUTES=qw();
    %SYNONYMS=();
    Class::AutoClass::declare(__PACKAGE__);
    1;

## Create and store some objects

    use DBI;
    use Class::AutoDB::Serialize;
    use Person;
    my $dbh=DBI->connect('dbi:mysql:database=ngoodman;host=localhost');
    Class::AutoDB::Serialize->dbh($dbh);

    my $joe=new Person(-name=>'Joe',-sex=>'male',
                       -hobbies=>['mountain climbing', 'sailing']);
    my $mary=new Person(-name=>'Mary',-sex=>'female',
                        -hobbies=>['hang gliding']);
    my $bill=new Person(-name=>'Bill',-sex=>'male',
                        -hobbies=>['cooking', 'eating', 'sleeping']);
    # Set up friends lists
    $joe->friends([$mary,$bill]);
    $mary->friends([$joe,$bill]);
    $bill->friends([$joe,$mary]);

    # Store the objects
    $joe->store;
    $mary->store;
    $bill->store;

    # Print their object id's so you can fetch them later
    for my $obj ($joe, $mary, $bill) {
      print 'name=', $obj->name, ' oid=', $obj->oid, "\n";
    }

## Fetch the objects

Assume that the oid's are passed as command line arguments

    my @oids=@ARGV;
    my $joe=Class::AutoDB::Serialize::fetch($ARGV[0]);
    my $mary=Class::AutoDB::Serialize::fetch($ARGV[1]);
    my $bill=Class::AutoDB::Serialize::fetch($ARGV[2]);
    # Print the objects' attributes
    for my $obj ($joe, $mary, $bill) {
      print 'oid=', $obj->oid, "\n";
      print 'name=', $obj->name, "\n";
      print 'sex=', $obj->sex, "\n";
      print 'hobbies=', join(', ',@{$obj->hobbies}), "\n";
      print 'friends=',"\n";
    for my $friend (@{$obj->friends}) {
      print ' oid=', $friend->oid, ', ';
      print 'name=', $friend->name, "\n";
    }
    print "----------\n";
    }
    # Change an attribute in each object to demonstrate
    # that shared structure is preserved
    for my $obj ($joe, $mary, $bill) {
      $obj->name($obj->name.' Changed');
    }
    for my $obj ($joe, $mary, $bill) {
      print 'oid=', $obj->oid, "\n";
      print 'changed name=', $obj->name, "\n";
      print 'friends=',"\n";
      for my $friend (@{$obj->friends}) {
        print ' oid=', $friend->oid, ', ';
        print 'changed name=', $friend->name, "\n";
      }
      print "----------\n";
    }

# DESCRIPTION

This is a mixin class that implements the serialization and data storage engine for Class::AutoDB. Objects that inherit from this class can be serialized and stored in a database as independent entities. This only works for objects implemented as HASHes in the usual Perl way.

What distinguishes Class::AutoDB::Serialize from the many other excellent Perl serialization packages (eg, Data::Dumper, Storable, YAML) is that we serialize objects as independent entities existing within a large network, rather than serializing entire networks as a whole. When an object is being serialized, other “auto-serializable” objects that are encountered are not serialized then and there; instead a placeholder object called an Oid (short for object identifier) is emitted into the serialization stream. When the object is later fetched, the placeholders are not immediately fetched; instead each placeholder is fetched transparently when the program invokes a method on it (this is accomplished via an AUTOLOAD mechanism).

The purpose of all this is to make it easy for Perl programs to operate on large databases of objects. Objects can be created, stored, and later fetched. If the object points to other objects, they will be fetched when needed. New objects can be created, connected to the network of existing objects, and stored.

# BUGS and WISH-LIST

Name | Description | Priority/When
--- | --- | ---
Auto-store | Automatically store objects when they go out of scope | Essential. This release
Selectable persistence | Make it possible to speciify on a per object basis whether the object should be persistent. This would simplify the Registry code, for example, by allowing separate persistent vs. transient registries | This release or next
transients | Allow specification of attributes that are not stored, and obviously don't store them | Important. This release.
auto-gets | Allow specification of attributes that are automatically fetched when this object is fetched, and obviously get them | (Probably part of AutoDB, not this class). Wish-list
Database object | Provide usual database object. | Important. This release. (May be part of AutoDB, not this class)
Supported DBMSs | Only MySQL now. | Postgres desirable. This release or next. Other DBMSs. Someone else's job!
Fetch Oid | Allow Oid object as arg to Serialize::fetch | Wish-list
Re-fetch | Allow program to re-fetch (refresh might be a better word) object from database | Dunno...

# METHODS and FUNCTIONS - Initialization

Title | dbh
Usage | my $dbh=DBI->connect(...); Class::AutoDB::Serialize->dbh($dbh);
Function | Set database handle for all database operations. With no argument, returns current database handle (mostly for internal use)
Args | $dbh | Database handle from DBI::connect
Returns | Current database handle

# METHODS and FUNCTIONS – store and fetch

Title |
    store
Usage |
    my $joe=new Person(-name=>'Joe',...);
    $joe->store;
Function | Serialize and store object in database.
Args |
    none
Returns | Object

Title |
    fetch
Usage |
    my $oid=...; # get oid somehow
    my $joe=Class::AutoDB::Serialize->fetch($oid);
Function | Fetch object from database.
Args |
    $oid
| Numeric object identifier. Not Oid object
Returns | Object or undef if object not found
Notes | Can be called as function,Class::AutoDB::Serialize::fetch($oid), or object method, $joe->fetch($oid), also.

# METHODS and FUNCTIONS – manage object identifiers (mostly internal use)

Title |
    oid2obj
Usage |
    my $obj=Class::AutoDB::Serialize->oid2obj($oid);
    Class::AutoDB::Serialize->oid2obj($oid,$obj);
Function | Get or set actual object associated with numeric object identifier
Args |
    $oid
| Numeric object identifier. Not Oid object
    $obj
| Object. Should inherit from Class::AutoDB::Serialize
Returns | Object or undef if no object with given oid exists in memory. The object may be a real object or a placeholder (Class::AutoDB::Oid).
Notes | Can be called as function or object method also.

Title |
    obj2oid,oid
Usage |
    my $oid=Class::AutoDB::Serialize->obj2oid($obj);
    Class::AutoDB::Serialize->obj2oid($obj,$oid);

    my $oid=$obj->oid;
    $obj->oid($obj)
Function | Get or set numeric object identifier for object.
Args |
    $obj
| Any object. Should inherit from Class::AutoDB::Serialize for this to be very useful.
$oid | Numeric object identifier. Not Oid object
Returns | Numeric object identifier (not Oid object) or undef if object has no oid.
Notes | obj2oid and oid are exact synonyms. The former is more natural when called as a class method; the latter as an object method. Each can be called as an object method, class method, or function.