The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
=head1 NAME

Tangram::Type::Extending - teaching Tangram about new types

=head1 DESCRIPTION

Tangram::Type is the root of a hierarchy of classes that are
responsible mapping individual field to SQL entities (columns in the
simplest cases). There is one Type object per persistent field.

Adding support for new types amounts to adding subclasses to
Tangram::Type.

=head1 DISCLAIMERS

THIS IS ADVANCED MATERIAL!!!

THIS MATERIAL IS SUBJECT TO CHANGE!!!

The Type hierarchy has been entirely reworked. Its protected
interfaces are considered in alpha stage, and may change in the
future.

=head1 WRITING NEW TYPES

Tangram is organized in several subsystems, described below.

Schema is the repository for information about all the persistent
aspects of a system: classes, inheritance relationships, fields,
etc. It also contains graph-traversal algorithms, which are not
currently documented.

Storage deals with objects as a whole: insertion, updating, multiple
load detection, cycle handling, transactions, connections. It also
serves as an entry point in the system. Storage does not manipulate
fields directly.

Cursor deals with polymorphic retrieval of objects. It builds SELECT
statements on the basis of the information in the hash. Cursor does
not manipulate fields directly either.

The Type hierarchy deals with individual fields, and not with entire
objects. More about it in a moment.

The Expr hierarchy deals with entities on the remote side; this
includes expressions proper, Filters and Remotes.

Types are responsible for performing the mapping between a field of a
given Perl type and a relational entity. The simplest Types merely
transfer between one Perl field and one column. Sometimes it makes
sense to have several mappings (and hence several Types) for the same
Perl type; for example, Perl arrays can be mapped either using a link
table, or one or several columns that live on the element's table.

Users don't deal with Type objects directly: they indicate that a
series of fields should be mapped in a certain way by putting the
fields under a given 'typetag' in the field hash. The type registers
itself with Tangram by adding a typetag in the %Tangram::Schema::TYPES
hash. The value is the Type object. Up to now all Types have been
singletons, but this is not a rule.

Anybody who's planning to write new Types should examine Scalar.pm
first. It contains very simple mappings between one field and one
column.

A Type must implement the methods described below. Keep the following
facts in mind while reading further:

1. A Type is responsible for transfering all the *direct* fields for a
given *class*. This excludes inherited fields. OTOH, the same Type can
be called more than once for the same object, because the same Type
may be used in several classes that appear in a particular object's
inheritance graph.

=head1 INSTANCE METHODS

=head2 reschema

   reschema($self, $members, $class)

This method is called when the schema hash is being converted into a
Schema object. The Type finds all the fields it is responsible for
mapping in the Perl structure refered by $members. The Type decides
the exact format of this structure.

=head2 get_export_cols

	get_export_cols($self, $context)

Called when building INSERT and UPDATE statements;
the Type returns a list of columns to be inserted in the statement.

=head2 get_exporter

	get_exporter($self, $context)

Called when building a function for reading the state of an object:
the Type may return either a string or a closure.

=head2 get_import_cols

	get_import_cols($self, $context)

Called when building SELECT statements; the Type returns a list of
columns to be inserted in the statement.

=head2 get_importer

	get_importer($self, $context)

Called when building a function for setting the state of an object:
the Type may return either a string or a closure.

=head2 remote_expr

	remote_expr($self, $obj, $tid, $storage)

Called when building a Remote. The Type returns an Expr object.

=head1 HANDLING ASSOCIATIONS

Ref and Collections have in common that they don't load their
controlled fields upfront. Their importer method ties the controlled
fields to a package that will demand-load the final value of the field
- if it's ever needed. The exact procedure for achieving this is not
imposed by Tangram itself, in fact, a Type has the liberty of doing
just anything it sees fit, if it can manage it with the arguments that
it gets passed by the higher layer. Ref ties a field to the
RefOnDemand package, and Collections tie to CollOnDemand. These two
packages will probably merge at someday.

Ref and those collections that contain references to other objects
must deal cycles. This can be done quite easily but I don't have to go
into those details right now.

Collections (of references of or values (the so-called 'flat'
collections)) typically save their state when the demand-load is
triggered. Later, when the collection is saved, the Collection compares
the current field state (iow collection content) with the state at
load time, and updates the database accordingly.

Types that need to remember field state at load time should store it
under $storage->{scratch}{TYPE_CLASS}, and typically under
$storage->{scratch}{TYPE_CLASS}{OBJECT_ID}{FIELD}. Coll defines two
utility functions to help manage load-time state:

* set_load_state($self, $storage, $obj, $field, $state)

Remember $state of the $field of $obj, retrieved from $storage.

* get_load_state($self, $storage, $obj, $member)

Retrieve that state.