NAME
Tangram::Schema
SYNOPSIS
use Tangram;
$schema = Tangram::Schema->new( %hash );
use Tangram::Deploy;
$schema->deploy( \*FILE );
DESCRIPTION
A Schema defines a mapping between a system of classes and a relational database.
CLASS METHODS
new( %h )
Returns a new Schema object. %h contains a description of the system of classes to map.
The Schema object becomes the owner of the hash, which can no longer be modified nor reused by client code.
INSTANCE METHODS
deploy( FILEHANDLE )
Writes SQL statements to FILEHANDLE. The resulting SQL code prepares an empty database for use with this Schema.
If FILEHANDLE is omitted, deploy() writes to STDOUT.
Note that method deploy() must be explicitly loaded via a use Tangram::Deploy
directive.
SCHEMA HASH
Currently the Schema hash has only one documented entry:
classes => "class dictionary"
Class dictionary
The class dictionary is a hash that associates class names to "class description"s. It contains one entry per persistent class in a database.
Example:
$schema = Tangram::Schema->new(
classes =>
{
Person =>
{
# class description
},
NaturalPerson =>
{
# class description
},
LegalPerson =>
{
# class description
},
# etc etc etc
} );
Class description
A class description is a hash that contains all the information necessary for mapping the objects of a given class. It has the following entries:
table => "table name"
abstract => "abstract specifier"
bases => "base array"
members => "member dictionary"
All fields are optional.
Currently Tangram uses one table per class. The table does not contain the attributes inherited from base classes. Consequently an object usually spans several tables. A future release will provide more flexibility in the mapping.
table name
The table
field in the class hash contains the name of the table that correspond to the class. In the absence of this field, the table has the same name as the class. If the class name is a SQL reserved word, the table
field can be used to specify a different name.
Example:
$schema = Tangram::Schema->new(
classes =>
{
Person =>
{
# no 'table' field - table will be named 'Person'
},
Identity =>
{
table => 'IdentityInfo', # Identity is not a valid table name
...
},
} );
abstract specifier
The abstract
field in the "class description" hash should be set to true
is the class is abstract. Tangram will not waste time attempting to retrieve objects of this exact type since none exists - in theory.
Example:
$schema = Tangram::Schema->new(
classes =>
{
Shape =>
{
abstract => 1,
...
},
} );
base array
The bases
field in the "class description" contains a reference to an array of base class names. When an object of this type (or of a derived type) will be loaded, the state pertaining to its base classes will be loaded as well.
Tangram also uses this field to compute the derivation tree of each class and implement polymorphism.
member dictionary
The member hash contains one (optional) entry per possible member type. The value associated to each entry describes all the members of that type. Its exact format depends on the type.
Currently the possible entries are:
string => "scalar members"
int => "scalar members"
real => "scalar members"
ref => "scalar members"
array => "array members"
iarray => "iarray members"
set => "set members"
iset => "iset members"
scalar members
Strings. integers, reals and references are collectively called 'scalar members'. Attributes of scalar types occupy a single column on the class' corresponding table. They can be specified either as an array of member names or as a hash. If the array form is used, the name of the column is the name of the member. The hash form associates member names to column names.
Example:
$schema = Tangram::Schema->new(
classes =>
{
Person =>
{
int => [ qw( age ) ],
strings => { name => 'name', where => 'where_col' },
},
} );
Note that we must use the hash form because 'where' is not a valid column name.
Collections
Array or set?
Currently Tangram supports two collection types: plain Perl arrays and Set::Object. More collections will be added in the future.
Extrusive or intrusive?
Tangram supports offers two options for mapping the standard collections: 'extrusive' and 'intrusive'.
The extrusive mapping uses an intermediate table (often called a 'link' table) to store the state of the collection. Each row in that table contains two foreign keys: one pointing to the containing object, and one pointing to the element. Extra columns contain collection-specific data, like the position of the element in the case of a Perl array. This mapping is ideal for representing many-to-many relationships.
The intrusive mapping stores the collection data in the element's table. It adds at least one column, which contains a foreign key that points to the containing object. Again, extra columns may be needed to host additional information if the collection requires it. This mapping is typically used to map one-to-many relationships.
Note that the intrusive mapping does not allow the same object to be contained in the same collection in two different objects. Consider the following code:
$homer->{children} = [ $bart ];
$marge->{children} = [ $bart ];
$storage->insert( $homer, $marge );
This is okay if children
uses the extrusive mapping. Otherwise, Tangram will silently make Marge the sole parent of Bart.
Also note that the intrusive mapping is not always the best way to map a one-to-many relationship. It consumes at least one column per collection, even for objects that are not part of any collection.
array members
Maps Perl arrays of objects in a non-intrusive fashion.
The array hash contains one entry per persistent member of array type. The associated value can be either the class of the elements, or a hash containing the following entries:
class => the class of the elements
table => the name of the intermediate table
If the short form is used, Tangram computes a default table name.
Example:
$schema = Tangram::Schema->new(
classes =>
{
NaturalPerson =>
{
members =>
{
array =>
{
children => 'NaturalPerson',
colleagues =>
{
class => 'NaturalPerson',
table => 'NCC1701'
}
},
},
} );
iarray members
Maps Perl arrays of objects in an intrusive fashion.
The iarray hash contains one entry per persistent member of array type. The associated value can be either the class of the elements, or a hash containing the following entries:
class => the class of the elements
coll => the name of the column on the element's table containing the foreign key to the containing object
slot => the name of the column on the element's table containing the position of the element in the collection
Example:
$schema = Tangram::Schema->new(
classes =>
{
NaturalPerson =>
{
members =>
{
iarray =>
{
hobbies => 'Hobby',
opinions =>
{
class => 'Opinion',
coll => 'beholder',
slot => 'opinion_ix'
}
},
},
} );
set members
Maps Set::Object in a non-intrusive fashion.
The set hash contains one entry per persistent member of Set::Object. The associated value can be either the class of the elements, or a hash containing the following entries:
class => the class of the elements
table => the name of the intermediate table
If the short form is used, Tangram computes a default table name.
Example:
$schema = Tangram::Schema->new(
classes =>
{
NaturalPerson =>
{
members =>
{
set =>
{
children => 'NaturalPerson',
colleagues =>
{
class => 'NaturalPerson',
table => 'NCC1701'
}
},
},
} );
iset members
Maps Set::Object in an intrusive fashion.
The iset hash contains one entry per persistent member of array type. The associated value can be either the class of the elements, or a hash containing the following entries:
class => the class of the elements
coll => the name of the column on the element's table containing the foreign key to the containing object
Example:
$schema = Tangram::Schema->new(
classes =>
{
NaturalPerson =>
{
members =>
{
iset =>
{
hobbies => 'Hobby',
opinions =>
{
class => 'Opinion',
coll => 'beholder',
}
},
},
} );