P5EEx-Blue-0.01

P5EEx::Blue::Repository


NAME

P5EEx::Blue::Repository - Interface for data persistence


SYNOPSIS

    use P5EEx::Blue::Repository;
    $context = P5EEx::Blue::P5EE->context();
    $repository = $context->service("Repository");  # or ...
    $repository = $context->repository();
    $rep = Repository::Base->new();        # looks for %ENV, then config file
    $rep = Repository::Base->new("sysdb"); # looks for %ENV, then config file using "sysdb"
    $rep2 = $rep->new();                              # copies attributes of existing $rep
    $rep = Repository::Base->new(@positional_args);   # undefined for Repository::Base
    $config = {
      'repository' => {
        'db' => {
          'arg1' => 'value1',
          'arg2' => 'value2',
        },
        'rep2' => {
          'arg1' => 'value1',
          'arg2' => 'value2',
        },
      },
    };
    $rep = Repository::Base->new($config);
    $rep = Repository::Base->new("rep2",$config);
    ###################################################################
    # The following methods are needed for SQL support
    ###################################################################
    $ok = $rep->connect();         # initialize repository (will happen automatically in constructor)
    $ok = $rep->disconnect();      # cleanup repository (will happen automatically in destructor)
    $rep->is_connected();          # returns 1 if connected (ready for use), 0 if not
    $errmsg = $rep->error();       # returns the error string for prev op ("" if no error)
    $numrows = $rep->numrows();    # returns the number of rows affected by prev op
    print $rep->error(), "\n" if (!$rep->connect());
    print $rep->error(), "\n" if ($rep->connect() != $rep->OK);
    # DATA TYPE HELPER METHODS
    $repdate = $rep->format_repdate($date_string);   # free-form date string as entered by a person

    # META-DATA: (about the tables)
    $rep->load_rep_metadata();
    $rep->load_table_metadata($tablename);
    $typenames    = $rep->get_type_names();                        # print "@$typenames\n";
    $typelabels   = $rep->get_type_labels();                       # print "%$typelabels\n";
    $typedef      = $rep->get_type_def($typename);                 # print "%$type\n";
    $tablenames   = $rep->get_table_names();                       # print "@$tablenames\n";
    $tablelabels  = $rep->get_table_labels();                      # print "%$tablelabels\n";
    $tabledef     = $rep->get_table_def($tablename);               # print "%$table\n";
    $columnnames  = $rep->get_column_names($tablename);            # print "@$columnnames\n";
    $columnlabels = $rep->get_column_labels($tablename);           # print "%$columnlabels\n";
    $columndef    = $rep->get_column_def($tablename,$columnname);  # print "%$column\n";
    # MEDIUM-LEVEL
    $row       = $rep->select_row ($table, \@cols,         \@params, \%paramvalues);
    $rows      = $rep->select_rows($table, \@cols,         \@params, \%paramvalues, \@ordercols, $startrow, $endrow);
    $ok        = $rep->insert_row ($table, \@cols, \@row);
    $ok        = $rep->insert_rows($table, \@cols, \@rows);
    $ok        = $rep->update_row ($table, \@cols, \@row,  \@keycolidx);
    $ok        = $rep->update_rows($table, \@cols, \@row,  \@params, \%paramvalues);
    $ok        = $rep->store_row  ($table, \@cols, \@row,  \@keycolidx, $update_first);
    $ok        = $rep->store_rows ($table, \@cols, \@rows, \@keycolidx, $update_first);
    $ok        = $rep->delete_row ($table, \@cols, \@row,  \@keycolidx);
    $ok        = $rep->delete_rows($table,                 \@params, \%paramvalues);
    # HIGH-LEVEL (CACHED)
    $key    = $rep->get_key ($table, \@cols, \@values);
    $key    = $rep->get_key ($table, \@cols, \@values, \@keycolidx);
    @keys   = $rep->get_keys($table, \%paramvalues);
    @keys   = $rep->get_related_keys($table, $key, $related_table, $relation);

    @values = $rep->get_values($table, $key, \@cols);
    $value  = $rep->get_value ($table, $key, "first_name");

    $rep->set_values($table, $key, \@cols, \@values);
    $rep->set_value ($table, $key, $column, $value);
    $rep->set_rows  ($table, \@cols, \@rows);

    $rows = $rep->get_rows($table, undef, \%paramvalues);
    $rows = $rep->get_rows($table, \@cols, \%paramvalues);
    $rows = $rep->get_rows($table, \@cols, \%paramvalues, \@keys);
    $row  = $rep->get_row ($table, $key);
    @idx  = $rep->get_column_idx($table, \@cols);
    ($key, $first_name, $last_name) = @{$row}[@idx];

    $rep->add_columns_fetched   ($table, \@cols);
    $rep->add_columns_fetched   ($table, \@cols, \@colidx);
    $rep->set_row_hint      ($table, \%paramvalues);
    $rep->clear_columns_fetched ($table);
    $rep->clear_row_hint    ($table);
    @columns = $rep->get_required_columns($table);
    $rep->load_cache();
    $rep->clear_cache();
    $rep->commit();
    $rep->rollback();


DESCRIPTION

A Repository is a means by which data may be stored somewhere without knowing what underlying technology is storing the data.

A Repository is the central persistence concept within the P5EE. A Repository does not present a uniquely object-oriented view of its data. Rather it presents a ``logical relational'' data model. It does not return objects, but rows of data.

The ``logical data model'' means that a developer can program to the data model which usually comes out of system requirements analysis, closely modelling the business. All of the changes to this logical data model that are incorporated during physical database design are abstracted away, such as:

  * physical table naming,
  * physical column naming,
  * normalization of data into parent tables, and
  * splitting of tables based on various physical constraints.

This could be called object-to-relational mapping, but it is more accurately called logical-to-physical-relational mapping.

Despite the fact that the Repository is a relational data storage abstraction, persistent objects (i.e. Entity Widgets) can be built to save and restore their state from a Repository. Furthermore, the built-in support for non-scalar fields (references to arbitrarily complex perl data structures) and the ability for Entity Widgets to encapsulate more than one row of data, makes the technology quite fit for object-oriented development.

The design of the Repository is based around three important uses of data.

  * Transaction Processing
  * Batch Processing
  * Report Generation

(more about this later)

The Repository abstraction seeks to solve the following problems.

  * objects may have attributes that come from multiple sources
  * caching
  * isolated from physical database changes
  * transactions
  * data source independence
  * no save/restore
  * devel/test/prod environments


Class Group: Repository

The following classes might be a part of the Repository Class Group.


Class: P5EEx::Blue::Repository

A Repository is a means by which data may be stored somewhere without knowing what underlying technology is storing the data.

 * Throws: P5EEx::Blue::Exception::Repository
 * Since:  0.01

Class Design

...


Constructor Methods:

new()

The constructor is inherited from P5EEx::Blue::Service.


Public Methods: Connection/Status

connect()

    * Signature: $repository->connect();
    * Param:     void
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $repository->connect();

Connects to the repository. Most repositories have some connection initialization that takes time and therefore should be done once. Then many operations may be executed against the repository. Finally the connection to the repository is closed (disconnect()).

The default implementation of connect() does nothing. It is intended to be overridden in the subclass (if necessary).

disconnect()

    * Signature: $repository->disconnect();
    * Param:     void
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $repository->disconnect();

Disconnects from the repository.

The default implementation of disconnect() does nothing. It is intended to be overridden in the subclass (if necessary).

All implementations of disconnect() by a subclass must be sensitive to whether the object is actually currently connected to the repository. Thus, disconnect() should be callable without negative consequences even when the repository is already disconnected.

is_connected()

    * Signature: $connected = $repository->is_connected();
    * Param:     void
    * Return:    $connected         integer
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    if ($repository->is_connected()) {
        ...
    }

Reports whether a connection currently exists to the repository.

The default implementation of is_connected() returns true (1) always. It is intended to be overridden in the subclass (if necessary).

error()

    * Signature: $errormsg = $repository->error();
    * Param:     void
    * Return:    $errormsg          string
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    print $repository->error(), "\n";

Returns the error string associated with the last operation (or ``'' if there was no error).

The default implementation of error() simply returns the attribute {error} which must be cleared at the beginning of every operation and set when appropriate.

It is intended to be overridden in the subclass (if necessary).

numrows()

    * Signature: $nrows = $repository->numrows();
    * Param:     void
    * Return:    $numrows           integer
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $nrows = $repository->numrows();

Returns the number of rows affected by the last operation.

The default implementation of numrows() simply returns the attribute {numrows} which must be set to 0 at the beginning of every operation and set to a higher number when appropriate.

It is intended to be overridden in the subclass (if necessary).

format_repdate()

    * Signature: $date = $repository->format_repdate($freeform_date);
    * Param:     $freeform_date     string
    * Return:    $date              string
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    foreach $freeform_date ("1/2/01", "1-Jan-2003", "january 13, 2000",
            "2000/1/5", "15 jan 99") {
        print "$freeform_date: ", $rep->format_repdate($freeform_date), "\n";
    }

The format_repdate() method takes a free-form date string (such as a human might type into a form field) using many varieties of upper and lower case, punctuation, and ordering, and turns it into a date in canonical YYYY-MM-DD form for storage in the repository.


Public Methods: Metadata

get_type_names()

    * Signature: $typenames = $repository->get_type_names();
    * Param:     void
    * Return:    $typenames         []
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $typenames = $rep->get_type_names();
    print join(",", @$typenames), "\n";

Returns the standard set of type names for columns in a repository. These are perl-friendly type names which are useful to do data validation.

    * string
    * text
    * integer
    * float
    * date
    * time
    * datetime
    * binary

get_type_labels()

    * Signature: $typelabels = $repository->get_type_labels();
    * Param:     void
    * Return:    $typelabels        {}
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $typelabels = $rep->get_type_labels();
    foreach (sort keys %$typelabels) {
        print "$_ => $typelabels->{$_}\n";
    }

Returns a hash of all of the repository types and the labels which should be used when displaying them to the user through the user interface.

    * string   => "Characters"
    * text     => "Paragraph"
    * integer  => "Integer"
    * float    => "Number"
    * date     => "Date"
    * time     => "Time"
    * datetime => "Date and Time"
    * binary   => "Binary Data"

get_type_def()

    * Signature: $typedef = $rep->get_type_def($typename);
    * Param:     $typename          string
    * Return:    $typedef           {}
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $typedef = $rep->get_type_def("string");
    print "$typedef->{name} $typedef->{label}\n";

Gets a reference to a ``type definition'', which allows you to access all of the attributes of the requested type (currently only ``name'' and ``label'').

get_table_names()

    * Signature: $tablenames = $rep->get_table_names();
    * Param:     void
    * Return:    $tablenames        []
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $tablenames = $rep->get_table_names();
    print join(",", @$tablenames), "\n";

Returns the set of table names in the repository.

get_table_labels()

    * Signature: $tablelabels = $rep->get_table_labels();
    * Param:     void
    * Return:    $tablelabels       {}
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $tablelabels = $rep->get_table_labels();
    foreach (sort keys %$tablelabels) {
        print "$_ => $tablelabels->{$_}\n";
    }

Returns a hash of all of the tables and the labels which should be used when displaying them to the user through the user interface.

get_table_def()

    * Signature: $tabledef = $rep->get_table_def($tablename);
    * Param:     $tablename         string
    * Return:    $tabledef          {}
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $tabledef = $rep->get_table_def($tablename);
    print "$tabledef->{name} $tabledef->{label}\n";

Gets a reference to a ``table definition'', which allows you to access all of the attributes of the requested table. By default, this is only ``name'' and ``label''. However, for various types of repositories, there may be additional attributes for a table.

get_column_names()

    * Signature: $columnnames = $rep->get_column_names($tablename);
    * Param:     $tablename         string
    * Return:    $columnnames       []
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $columnnames = $rep->get_column_names($tablename);
    print join(",", @$columnnames), "\n";

Returns the set of column names for the requested table in a repository.

get_column_labels()

    * Signature: $columnlabels = $rep->get_column_labels($tablename);
    * Param:     $tablename         string
    * Return:    $columnlabels      {}
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $columnlabels = $rep->get_column_labels($tablename);
    foreach (sort keys %$columnlabels) {
        print "$_ => $columnlabels->{$_}\n";
    }

Returns a hash of all of the column names and the labels which should be used when displaying them to the user through the user interface.

get_column_def()

    * Signature: $columndef = $rep->get_column_def($tablename,$columnname);
    * Param:     $tablename         string
    * Param:     $columnname        string
    * Return:    $columndef         {}
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $columndef = $rep->get_column_def($tablename,$columnname);
    print "$columndef->{name} $columndef->{label} $columndef->{type}\n";

Gets a reference to a ``column definition'', which allows you to access all of the attributes of the requested column.

By default, this is only ``name'', ``label'', and ``type''. However, for various types of repositories, there may be additional attributes for a column.


Public Methods: Non-Cached Data Access

The methods which implement the non-cached data access methods below make up the body of functionality supplied by the Repository::* subclasses.

In general, they do exactly what they are asked to do and no more.

(A repository also supplies an even higher-level, cached interface to the data. This is mostly implemented in this base class rather than the subclass, but it is built upon the non-cached data access methods supplied by the subclass. This is explained more later.)

select_row()

    * Signature: $row = $rep->select_row ($table, $cols);
    * Signature: $row = $rep->select_row ($table, $cols, undef, $paramvalues);
    * Signature: $row = $rep->select_row ($table, $cols, $params, $paramvalues);
    * Param:     $table             string
    * Param:     $cols              []
    * Param:     $params            []
    * Param:     $paramvalues       {}
    * Return:    $row               []
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $row = $rep->select_row (
        "customer",
        [ "id", "first_name", "last_name"],
        undef,
        { "last_name.contains" => "Smith" }
    );
    print join(",", @$row), "\n";

select_row() retrieves a single row of data from a table in the repository, with the specified columns of data, and restricted by the parameter values specified. If more than one row in the table satisfy the criteria specified by the parameter values, the first row is returned.

The default implementation here does nothing but return ``undef''. It must be overridden in the subclass.

select_rows()

    * Signature: $rows = $rep->select_rows($table, $cols);
    * Signature: $rows = $rep->select_rows($table, $cols, $params, $paramvalues);
    * Signature: $rows = $rep->select_rows($table, $cols, undef,   $paramvalues);
    * Signature: $rows = $rep->select_rows($table, $cols, $params, $paramvalues, $ordercols);
    * Signature: $rows = $rep->select_rows($table, $cols, $params, $paramvalues, $ordercols, $startrow);
    * Signature: $rows = $rep->select_rows($table, $cols, $params, $paramvalues, $ordercols, $startrow, $endrow);
    * Param:     $table             string
    * Param:     $cols              []
    * Param:     $params            []
    * Param:     $paramvalues       {}
    * Param:     $ordercols         []
    * Param:     $startrow          integer
    * Param:     $endrow            integer
    * Return:    $rows              [][]
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rows = $rep->select_rows (
        "customer",
        [ "id", "first_name", "last_name"],
        undef,
        { "last_name.contains" => "Smith" },
        [ "last_name", "first_name", ],
        1,
        20,
    );
    foreach $row (@$rows) {
        print join(",", @$row), "\n";
    }

select_rows() retrieves all rows of data from a table in the repository that satisfy the criteria embodied by the parameter values. Each row contains the specified columns of data.

The default implementation here does nothing but return ``undef''. It must be overridden in the subclass.

insert_row()

    * Signature: $nrows = $rep->insert_row ($table, $cols, $row);
    * Param:     $table             string
    * Param:     $cols              []
    * Param:     $row               []
    * Return:    $nrows             integer
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rep->insert_row (
        "customer",
        [ "first_name", "last_name", "gender", "home_phone" ],
        [ "Stephen", "Adkins", "M", "404-999-7777" ]
    );

Insert a single row of data into the table.

The default implementation here does nothing. It must be overridden in the subclass.

insert_rows()

    * Signature: $nrows = $rep->insert_rows ($table, $cols, $rows);
    * Param:     $table             string
    * Param:     $cols              []
    * Param:     $rows              [][]
    * Return:    $nrows             integer
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $nrows = $rep->insert_rows (
        "customer",
        [ "first_name", "last_name", "gender", "home_phone" ],
        [
          [ "Stephen", "Adkins", "M", "404-999-7777" ],
          [ "Keith", "Adams", "M", "404-999-8888" ],
          [ "Tim", "Alderman", "M", "404-999-9999" ],
        ]
    );

Insert many rows of data into the table.

The default implementation here does nothing. It must be overridden in the subclass.

update_row()

    * Signature: $nrows = $rep->update_row ($table, $cols, $row, $keycolidx);
    * Param:     $table             string
    * Param:     $cols              []
    * Param:     $row               []
    * Param:     $keycolidx         []
    * Return:    $nrows             integer
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rep->update_row ($table, \@cols, \@row, \@keycolidx);
    $rep->update_row (
        "customer",
        [ "first_name", "last_name", "gender", "home_phone" ],
        [ "Stephen", "Adkins", "M", "404-999-7778" ],
        [ 0, 1 ],
    );

Update a single row of data in the table by using the specified columns as keys.

The default implementation here does nothing but return ``undef''. It must be overridden in the subclass.

update_rows()

    * Signature: $nrows = $rep->update_rows($table, $cols, $row, $params, $paramvalues);
    * Param:     $table             string
    * Param:     $cols              []
    * Param:     $row               []
    * Param:     $params            []
    * Param:     $paramvalues       {}
    * Return:    $nrows             integer
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rep->update_rows($table, \@cols, \@row, \@params, \%paramvalues);
    $rep->update_rows (
        "customer",
        [ "address", "city", "state", "home_phone" ],
        [ "7734 Yellowtail Rd.", "Atlanta", "GA", "404-999-7778" ],
        [ "last_name" ],
        { "last_name" => "Adkins" },
    );

Update (potentially) many rows of data in the table based on the values supplied to parameters.

The default implementation here does nothing. It must be overridden in the subclass.

delete_row()

    * Signature: $nrows = $rep->delete_row ($table, $cols, $row, $keycolidx);
    * Param:     $table             string
    * Param:     $cols              []
    * Param:     $row               []
    * Param:     $keycolidx         []
    * Return:    $nrows             integer
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $nrows = $rep->delete_row ($table, \@cols, \@row, \@keycolidx);

Delete a single row of data in the table by using the specified columns as keys.

The default implementation here does nothing. It must be overridden in the subclass.

delete_rows()

    * Signature: $nrows = $rep->delete_rows($table, undef, $paramvalues);
    * Signature: $nrows = $rep->delete_rows($table, $params, $paramvalues);
    * Param:     $table             string
    * Param:     $params            []
    * Param:     $paramvalues       {}
    * Return:    $nrows             integer
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $nrows = $rep->delete_rows($table, \@params, \%paramvalues);

Delete (potentially) many rows of data in the table based on the values supplied to parameters.

The default implementation here does nothing. It must be overridden in the subclass.

store_row()

    * Signature: $nrows = $rep->store_row ($table, $cols, $row, $keycolidx, $update_first);
    * Param:     $table             string
    * Param:     $cols              []
    * Param:     $row               []
    * Param:     $keycolidx         []
    * Param:     $update_first      boolean
    * Return:    $nrows             integer
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rep->store_row ($table, \@cols, \@row, \@keycolidx, $update_first);

The store_row() method ensures that the data is stored by trying both an insert, then an update (or vice-versa, depending on the $update_first flag).

The default implementation here is built on using the insert_row() and update_row() methods. It is fully functional, but it may be overridden in the subclass if there is a more efficient way to do it.

store_rows()

    * Signature: $nrows = $rep->store_rows ($table, $cols, $rows, $keycolidx, $update_first);
    * Param:     $table             string
    * Param:     $cols              []
    * Param:     $rows              [][]
    * Param:     $keycolidx         []
    * Param:     $update_first      boolean
    * Return:    $nrows             integer
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rep->store_rows ($table, \@cols, \@rows, \@keycolidx, $update_first);

The store_rows() method ensures that all rows of data are stored by trying both an insert, then an update (or vice-versa, depending on the $update_first flag).

If any row fails to be stored, the method will exit immediately, returning the number of rows that were successfully stored.

The default implementation here is built on using the store_row() method. It is fully functional, but it may be overridden in the subclass if there is a more efficient way to do it.


Public Methods: Cached Row Operations

get_row()

    * Signature: $row = $rep->get_row ($table, $key);
    * Param:     $table             string
    * Param:     $key               string
    * Return:    $row               []
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $row = $rep->get_row ($table, $key);

This row returns a row from the cache based on the table and key. Because the row is from the cache, you will need to consult the list of columns in the cache to find the column that you are looking for.

If the row doesn't exist in the cache, it will be read in from the data store. If it does not exist in the data store, a row will be created.

get_rows()

    * Signature: $rows = $rep->get_rows($table, undef, $paramvalues);
    * Signature: $rows = $rep->get_rows($table, $cols, $paramvalues);
    * Signature: $rows = $rep->get_rows($table, undef, $paramvalues, $keys);
    * Signature: $rows = $rep->get_rows($table, $cols, $paramvalues, $keys);
    * Param:     $table             string
    * Param:     $cols              []
    * Param:     $paramvalues       {}
    * Param:     $keys              []
    * Return:    $rows              [][]
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rows = $rep->get_rows($table, undef, \%paramvalues);
    $rows = $rep->get_rows($table, \@cols, \%paramvalues);
    $rows = $rep->get_rows($table, \@cols, \%paramvalues, \@keys);

The get_rows() method gets back a list of cached rows (similar to get_row()) based on the parameter values supplied. These rows are guaranteed to include the specified columns, but they may contain many other columns as well. Optionally, an array of keys may be populated to allow the program to reference the rows individually.

set_rows()

    * Signature: $tbd_return = $repository->set_rows($tbd_param);
    * Param:     $tbd_param         integer
    * Return:    $tbd_return        integer
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $tbd_return = $repository->set_rows($tbd_param);

get_column_idx()

    * Signature: $tbd_return = $repository->get_column_idx($tbd_param);
    * Param:     $tbd_param         integer
    * Return:    $tbd_return        integer
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $tbd_return = $repository->get_column_idx($tbd_param);


Public Methods: Cached Value Operations

These are the highest-level data access operations. They allow the developer to access data and modify it without having to consider when or how it is actually read from or written to any persistent medium.

get_value()

    * Signature: $value = $rep->get_value ($table, $key, $col);
    * Param:     $table             string
    * Param:     $key               string
    * Param:     $col               string
    * Return:    $value             string
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $value = $rep->get_value ($table, $key, $col);

This method is the highest level, most abstract way to get data from a repository. It knows nothing about when or from where the data is loaded. The data may be in cache or it may be loaded on demand and saved in the cache for subsequent calls to get_value().

The format of the $key may be known to the developer or it may have been returned from a previous call. In general, a key is a comma-separated list of column values that make up the primary key (or an alternate key) to the table.

get_values()

    * Signature: @values = $rep->get_values($table, $key, $cols);
    * Param:     $table             string
    * Param:     $key               string
    * Param:     $cols              []
    * Return:    @values            @
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    @values = $rep->get_values($table, $key, \@cols);

This method does the same thing as get_value(), but it gets several columns of data at a single time.

set_value()

    * Signature: $key = $rep->set_value ($table, $key, $col, $value);
    * Signature: $key = $rep->set_value ($table, undef, $col, $value);
    * Param:     $table             string
    * Param:     $key               string
    * Param:     $col               string
    * Param:     $value             SCALAR
    * Return:    $key               string
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $key = $rep->set_value ($table, $key, "first_name", $value);

This method is the highest level, most abstract way to set data in a repository. It knows nothing about when or from where the data is loaded. The data may be in cache, in which case it is set. Or a row may be loaded on demand and the value saved in the row in the cache. In any case, the value is not written back to the repository until a commit() or a clear_cache() call is made (which performs an implied commit()).

The format of the $key may be known to the developer or it may have been returned from a previous call. In general, a key is a comma-separated list of column values that make up the primary key (or an alternate key) to the table.

If a $key is supplied, it will be returned. If no $key is supplied (the parameter is ``undef''), a new row will be created and its $key will be returned.

set_values()

    * Signature: $key = $rep->set_values($table, $key, $cols, $values);
    * Signature: $key = $rep->set_values($table, undef, $cols, $values);
    * Param:     $table             string
    * Param:     $key               string
    * Param:     $cols              []
    * Param:     $values            []
    * Return:    $key               string
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $key = $rep->set_values($table, $key, \@cols, \@values);

This method does the same thing as set_value(), but it sets several columns of data at a single time.


Public Methods: Cache key operations

get_key()

    * Signature: $key = $rep->get_key ($table, $cols, $values);
    * Signature: $key = $rep->get_key ($table, $cols, $values, $keycolidx);
    * Param:     $table             string
    * Param:     $cols              []
    * Param:     $values            []
    * Param:     $keycolidx         []
    * Return:    $key               string
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $key = $rep->get_key ($table, \@cols, \@values);
    $key = $rep->get_key ($table, \@cols, \@values, \@keycolidx);

get_keys()

    * Signature: @keys = $rep->get_keys($table, $paramvalues);
    * Param:     $table             string
    * Param:     $paramvalues       {}
    * Return:    @keys              @
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    @keys = $rep->get_keys($table, \%paramvalues);

get_related_keys()

    * Signature: @keys = $rep->get_related_keys($table, $key, $related_table);
    * Signature: @keys = $rep->get_related_keys($table, $key, $related_table, $relation);
    * Param:     $table             string
    * Param:     $key               string
    * Param:     $related_table     string
    * Param:     $relation          string
    * Return:    @keys              @
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    @keys = $rep->get_related_keys($table, $key, $related_table, $relation);


Public Methods: Cache control

load_cache()

    * Signature: $rep->load_cache();
    * Param:     void
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rep->load_cache();

clear_cache()

    * Signature: $rep->clear_cache();
    * Signature: $rep->clear_cache($table);
    * Param:     $table    string
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rep->clear_cache();

add_columns_fetched()

    * Signature: $rep->add_columns_fetched ($table, $cols);
    * Signature: $rep->add_columns_fetched ($table, $cols, $colidx);
    * Param:     $table             string
    * Param:     $cols              []
    * Param:     $colidx            []
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rep->add_columns_fetched ($table, \@cols);
    $rep->add_columns_fetched ($table, \@cols, \@colidx);

Tables may have a huge number of valid columns. It may be prohibitively expensive to request all columns of a table whenever the contents of a single column are required.

The add_columns_fetched() method is the way that the Repository can be alerted that the specified columns will be required.

All of the cached row operations operate with a set of columns which is the union of all of the columns submitted at various times via the add_columns_fetched() method.

The add_columns_fetched() method is used to ensure that the required columns will be in the cache. As a result, the indexes of those columns may be returned in the (optional) reference to an array ($colidx).

set_required_columns_fetched()

    * Signature: $rep->set_required_columns_fetched($table);
    * Param:     $table             string
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rep->set_required_columns_fetched($table);

clear_columns_fetched()

    * Signature: $rep->clear_columns_fetched ($table);
    * Param:     $table             string
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rep->clear_columns_fetched ($table);

set_row_hint()

    * Signature: $rep->set_row_hint ($table, $paramvalues);
    * Param:     $table             string
    * Param:     $paramvalues       {}
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rep->set_row_hint ($table, \%paramvalues);

clear_row_hint()

    * Signature: $rep->clear_row_hint ($table);
    * Param:     $table             string
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rep->clear_row_hint ($table);

get_required_columns()

    * Signature: @columns = $rep->get_required_columns($table);
    * Param:     $table             string
    * Return:    @columns           @
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    @columns = $rep->get_required_columns($table);


Public Methods: Transaction Control

commit()

    * Signature: $rep->commit();
    * Param:     void
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rep->commit();

rollback()

    * Signature: $rep->rollback();
    * Param:     void
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $rep->rollback();


Public Methods: Miscellaneous

summarize()

    * Signature: $summarized_rows = $rep->summarize($rows, $columns, $summcolidx, $formulas);
    * Param:     $rows             [][]
    * Param:     $columns          []
    * Param:     $summcolidx        []
    * Param:     $formulas         {}
    * Return:    $summarized_rows  []
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    @rows = (
        [ 5, "Jim", "Green", 13.5, 320, ],
        [ 3, "Bob", "Green",  4.2, 230, ],
        [ 9, "Ken", "Green", 27.4, 170, ],
        [ 2, "Kim", "Blue",  11.7, 440, ],
        [ 7, "Jan", "Blue",  55.1,  90, ],
        [ 1, "Ben", "Blue",  22.6, 195, ],
    );
    @columns = ( "id", "name", "team", "rating", "score" );
    @summcolidx = ( 2 );  # "team"
    %formulas = (
        rating => "{sum(rating)}/{count(rating)}",
    );
    $summarized_rows = $rep->summarize(\@rows, \@columns, \@summcolidx, \%formulas);

sort()

    * Signature: $sorted_rows = $rep->sort($rows, $sortcolidx);
    * Signature: $sorted_rows = $rep->sort($rows, $sortcolidx, $sorttype);
    * Signature: $sorted_rows = $rep->sort($rows, $sortcolidx, $sorttype, $sortdir);
    * Param:     $rows             [][]
    * Param:     $sortcolidx       []
    * Param:     $sorttype         []
    * Param:     $sortdir          []
    * Return:    $sorted_rows      []
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    @rows = (
        [ 5, "Jim", "Green", 13.5, 320, ],
        [ 3, "Bob", "Green",  4.2, 230, ],
        [ 9, "Ken", "Green", 27.4, 170, ],
        [ 2, "Kim", "Blue",  11.7, 440, ],
        [ 7, "Jan", "Blue",  55.1,  90, ],
        [ 1, "Ben", "Blue",  22.6, 195, ],
    );
    # @columns = ( "id", "name", "team", "rating", "score" ); # not needed
    @sortcolidx = ( 2, 4 );      # "team", "score" (descending)
    @sorttype = ( "C", "N" );    # Character, Numeric
    @sortdir = ( "UP", "DOWN" );
    $sorted_rows = $rep->sort(\@rows, \@sortcolidx, \@sorttype, \@sortdir);

serial()

    * Signature: $serial_num = $repository->serial($category);
    * Param:     $category          string
    * Return:    $serial_num        integer
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $serial_num = $repository->serial($category);


Protected Methods: Metadata

load_rep_metadata()

    * Signature: $repository->load_rep_metadata();
    * Param:     void
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $self->load_rep_metadata();

Initializes the repository metadata information from the config.

    * List of tables (+ displayable labels)
    * List of column types (+ displayable labels)

Then it calls load_rep_metadata_auto() in order for the repository itself to be consulted for its metadata information.

load_rep_metadata_auto()

    * Signature: $repository->load_rep_metadata_auto();
    * Param:     void
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $repository->load_rep_metadata_auto();

Loads repository metadata from the repository itself (to complement metadata in the configuration and perhaps override it).

The default implementation does nothing. It is intended to be overridden in the subclass (if the repository has any sort of metadata).

load_table_metadata()

    * Signature: $self->load_table_metadata();
    * Param:     void
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $self->load_table_metadata();

First it calls load_table_metadata_auto() in order for the repository itself to be consulted for any metadata information for the about the table.

Then it initializes the repository metadata information for that table from the config information.

    * List of columns (+ displayable labels, types)
    * List of column types (+ displayable labels)

Then it determines the set of required columns whenever selecting data from the table and clears the cache of selected rows for the table.

load_table_metadata_auto()

    * Signature: $repository->load_table_metadata_auto();
    * Param:     void
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $self->load_table_metadata_auto();

Loads metadata for an individual table from the repository itself (to complement metadata in the configuration and perhaps override it).

The default implementation does nothing. It is intended to be overridden in the subclass (if the repository has any sort of metadata).


Protected Methods: Miscellaneous

init()

    * Signature: $repository->init();
    * Signature: $repository->init($named);
    * Param:     deferConnection     integer
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $self->init();

Every Service constructor (Repository is derived from Service) will invoke the init() method near the end of object construction.

The standard behavior for repositories (implemented here) in init() is to initialize the ``numrows'' and ``error'' attributes, call init2(), connect to the repository, and load the repository metadata.

init2()

    * Signature: $repository->init2();
    * Signature: $repository->init2($named);
    * Param:     deferConnection    integer
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $self->init2();

The default behavior of init2() does nothing and is intended to be overridden (if necessary) in the subclass which implements the details of access to the physical data store.

service_type()

Returns 'Repository'.

    * Signature: $service_type = P5EEx::Blue::Repository->service_type();
    * Param:     void
    * Return:    $service_type  string
    * Since:     0.01
    $service_type = $widget->service_type();

rows_by_indexed_values()

    * Signature: &P5EEx::Blue::Repository::rows_by_indexed_values($a,$b);
    * Param:     $a            []
    * Param:     $b            []
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    @data = (
        [ 5, "Jim", "Red",    13.5, ],
        [ 3, "Bob", "Green",   4.2, ],
        [ 9, "Ken", "Blue",   27.4, ],
        [ 2, "Kim", "Yellow", 11.7, ],
        [ 7, "Jan", "Purple", 55.1, ],
    );
    @P5EEx::Blue::Repository::sort_keys = ( 1, 3, 2 );
    @P5EEx::Blue::Repository::sort_types = ("C", "N", "C");
    @P5EEx::Blue::Repository::sort_dirs = ("UP", "DOWN", "DOWN");
    @sorted_data = sort rows_by_indexed_values @data;

The rows_by_indexed_values() function is used to sort rows of data based on indexes, data types, and directions.

DESTROY()

    * Signature: $self->DESTROY();
    * Param:     void
    * Return:    void
    * Throws:    P5EEx::Blue::Exception::Repository
    * Since:     0.01
    Sample Usage:
    $self->DESTROY();   # never called explicitly. called by Perl itself.

The DESTROY() method is called when the repository object is release from memory. This happen when the calling program lets the variable holding the object reference go out of scope, sets the variable to something else, or exits the program without otherwise releasing the object.

The DESTROY() method simply calls disconnect() to make sure that all connection-related resources are freed. This is safe, assuming (correctly) that the disconnect() method may be called without negative consequences even when already disconnected from the repository.


ACKNOWLEDGEMENTS

 * Author:  Stephen Adkins <stephen.adkins@officevision.com>
 * License: This is free software. It is licensed under the same terms as Perl itself.


SEE ALSO

P5EEx::Blue::Context, P5EEx::Blue::Service