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:

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:

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:

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 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 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',
               }
            },
      },
   } );