NAME¶
Alzabo::Design - Documentation on Alzabo's design
DESCRIPTION¶
This document describes some of the Alzabo's design.
ARCHITECTURE¶
There are objects representing the schema, which contains table objects. Table
  objects contain column, foreign key, and index objects. Column objects contain
  column definition objects. A single column definition may be shared by
  multiple columns, but has only one owner.
This is a diagram of these inheritance relationships:
  Alzabo::* (::Schema, ::Table, ::Column, ::ColumnDefinition, ::ForeignKey, ::Index)
                   /   \
                is parent to
                 /       \
 Alzabo::Create::*   Alzabo::Runtime::*
This a diagram of how objects contain other objects:
                      Schema - makes--Alzabo::SQLMaker subclass object (many)
                     /      \
              contains       contains--Alzabo::Driver subclass object (1)
                  |                 \
               Table (0 or more)     Alzabo::RDBMSRules subclass object (1)
                /  \                  (* Alzabo::Create::Schema only)
               /    \
              contains--------------------
             /        \                   \
            /          \                   \
     ForeignKey      Column (0 or more)    Index (0 or more)
     (0 or more)       |
                    contains
                       |
                  ColumnDefinition (1)
Note that more than one column 
may share a single definition object (this
  is explained in the "Alzabo::Create::ColumnDefinition"
  documentation). This is only relevant if you are writing a schema creation
  interface.
Other classes¶
  - •
 
  - "Alzabo::Driver"
    
    These objects handle all the actual communication with the database, using a
      thin wrapper over DBI. The subclasses are used to implement functionality
      that must be handled uniquely for a given RDBMS, such as creating new
      values for sequenced columns.
 
  - •
 
  - "Alzabo::SQLMaker"
    
    These objects handle the generation of all SQL for runtime operations. The
      subclasses are used to implement functionality that varies between
      RDBMS's, such as outer joins.
 
  - •
 
  - "Alzabo::RDBMSRules"
    
    These objects perform several funtions. First, they validate things such as
      schema or table names, column type and length, etc.
    
    Second they are used to generate SQL for creating and updating the database
      and its tables.
    
    And finally, they also handle the reverse engineering of an existing
      database.
 
  - •
 
  - "Alzabo::Runtime::Row" and
      "Alzabo::Runtime::RowState::*"
    
    The "Alzabo::Runtime::Row" class represents a single row. These
      objects are created by "Alzabo::Runtime::Table",
      "Alzabo::Runtime::RowCursor", and
      "Alzabo::Runtime::JoinCursor" objects. It is the sole interface
      by which actual data is retrieved, updated, or deleted in a table.
    
    The various "RowState" classes are used in order to change a row's
      behavior depending on whether it is live, live and cached, potential, or
      deleted.
 
  - •
 
  - "Alzabo::Runtime::JoinCursor" and
      "Alzabo::Runtime::RowCursor"
    
    These objects are cursor that returns row objects. Using a cursor saves a
      lot of memory for big selects.
 
  - •
 
  - "Alzabo::Runtime::UniqueRowCache"
    
    Loading this class turns on Alzabo's simple row caching mechanism.
 
  - •
 
  - "Alzabo::Config"
    
    This class is generated by Makefile.PL during installation and contains
      information such as what directory contains saved schemas and other
      configuration information.
 
  - •
 
  - "Alzabo::ChangeTracker"
    
    This object provides a method for an object to register a series to backout
      from multiple changes. This is done by providing the ChangeTracker object
      with a callback after a change is succesfully made to an object or
      objects. If a future change in a set of operations fail, the tracker can
      be told to back the changes out. This is used primarily in
      "Alzabo::Create::Schema".
 
  - •
 
  - "Alzabo::MethodMaker"
    
    This module can auto-generate useful methods for you schema, table, and row
      objects based on the structure of your schema.
 
  - •
 
  - "Alzabo::Exceptions"
    
    This object creates the exception subclasses used by Alzabo.
 
WHY THE SUBDIVISION BETWEEN Alzabo::*, Alzabo::Create::*, and Alzabo::Runtime::*?¶
There are several reasons for doing this:
  - •
 
  - In some environments (mod_perl) we would like to optimize for memory. For
      an application that uses an existing schema, all we need is to be able
      read object information, rather than needing to change the schema's
      definition. This means there is no reason to have the overhead of
      compiling all the methods used when creating and modifying objects.
 
  - •
 
  - In other environments (for example, when running as a separately spawned
      CGI process) compile time is important.
 
  - •
 
  - Many people using Alzabo will use the schema creation GUI and then write
      an application using that schema. At the simplest level, they would only
      need to learn how to instantiate "Alzabo::Runtime::Row" objects
      and how that class's methods work. For more sophisticated users, they can
      still avoid having to ever look at documentation on methods that alter the
      schema and its contained objects.
 
RATIONALE FOR CURSORS¶
Using cursors is definitely more complicated. However, there are two excellent
  reasons for using them: speed and memory savings. As an example, I did a test
  with the old code (which returned all its objects at once) against a table
  with about 8,000 rows using the
  "Alzabo::Runtime::Table->all_rows" method. Under the old
  implementation, it took significantly longer to return the first row. Even
  more importantly than that, the old implementation used up about 10MB of
  memory versus about 4MB! Now imagine that with a 1,000,000 row table.
Thus Alzabo uses cursors so it can scale better. This is a particularly big win
  in the case where you are working through a long list of rows and may stop
  before the end is reached. With cursors, Alzabo creates only as many rows as
  you need. Plus the start up time on your loop is much, much quicker. In the
  end, your program is quicker and less of a memory hog. This is good.
AUTHOR¶
Dave Rolsky, <autarch@urth.org>