Provided by: libalzabo-perl_0.92-6_all bug

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 successfully
           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>

perl v5.34.0                                       2022-06-14                                Alzabo::Design(3pm)