NAME
App::Repository - Logical data access layer for the App::Context Framework, providing a uniform API to access data in databases, file systems, remote web sites, etc.
SYNOPSIS
use App::Repository;
$context = App->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
###################################################################
$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";
# 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";
$table_def = $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";
$column_def = $rep->get_column_def($tablename,$columnname); # print "%$column\n";
#################################################
# RELATIONAL
#################################################
... (see App::Repository::DBI) ...
$relation_names = $rep->get_relation_names($table);
$relation_labels = $rep->get_relation_labels($table);
$relation_def = $rep->get_relation_def($table, $relation_name);
@keys = $rep->get_related_keys($table, $key, $relation_name);
#################################################
# OBJECT-ORIENTED
#################################################
# OBJECT-ORIENTED
$class = $table;
$obj = $rep->object($class, $key);
# OBJECT-ORIENTED (on RepositoryObject)
$relation_names = $obj->get_relation_names();
$relation_labels = $obj->get_relation_labels();
$relation_def = $obj->get_relation_def($relation_name);
@objs = $obj->get_related_objects($relation_name);
#################################################
# TECHNICAL
#################################################
$rep->commit();
$rep->rollback();
$rep->import_rows($table, $columns, $file, $options);
$rep->export_rows($table, $columns, $file, $options);
DESCRIPTION
A Repository is a means by which data may be stored somewhere or retrieved from somewhere without knowing what underlying technology is storing the data.
A Repository is the central persistence concept within the App. 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. RepositoryObjects) 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 RepositoryObjects 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
What follows are some developing thoughts on this API...
* The API should have two levels:
= physical
- no error-checking/defaults/security
- provided by the driver
- based on a physical table segment
- application should never call this (private methods)
= logical
- error-checking
- constraints (foreign key, check constraints)
- column-level and row-level security
- support transactions, caching, volatility
- auditing
* Isolation levels
= do writers block readers, etc.
Class Group: Repository
The following classes might be a part of the Repository Class Group.
Class: App::Repository
Class: App::Repository::DBI
Class: App::Repository::File
Class: App::Repository::BerkeleyDB
Class: App::Repository::LDAP
Class: App::Repository::HTML - for data stored in a web page
Class: App::Repository::SOAP - remote data storage
Class: App::Repository::Cache - use the Cache::Cache module
Class: App::Repository::SPOPS - maybe?
Class: App::Repository::Tangram - maybe?
Class: App::Repository::Alzabo - maybe?
Class: App::Repository::ClassDBI - maybe?
Class: App::Repository
A Repository is a means by which data may be stored somewhere without knowing what underlying technology is storing the data.
* Throws: App::Exception::Repository
* Since: 0.01
Class Design
...
Methods
new()
The constructor is inherited from App::Service
.
_connect()
* Signature: $repository->_connect();
* Param: void
* Return: void
* Throws: App::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: App::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: App::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).
Public Methods
error()
* Signature: $errormsg = $repository->error();
* Param: void
* Return: $errormsg string
* Throws: App::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: App::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).
get()
* Signature: $value = $rep->get ($table, $key, $col, $options); [tbd]
* Signature: $value = $rep->get ($table, $params, $col, $options); [tbd]
* Signature: @row = $rep->get ($table, $key, $cols, $options); [tbd]
* Signature: @row = $rep->get ($table, $params, $cols, $options); [tbd]
* Param: $table string
* Param: $key string
* Param: $params undef,HASH
* Param: $col string
* Param: $cols ARRAY
* Param: $options undef,HASH
* Return: $value any
* Return: @row any
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$value = $rep->get($table, $key, $col, \%options);
$value = $rep->get($table, \%params, $col, \%options);
@row = $rep->get($table, $key, \@cols, \%options);
@row = $rep->get($table, \%params, \@cols, \%options);
tbd.
set()
* Signature: $nrows = $rep->set($table, $key, $col, $value, $options); [tbd]
* Signature: $nrows = $rep->set($table, $params, $col, $value, $options); [tbd]
* Param: $table string
* Param: $key string
* Param: $params undef,HASH
* Param: $col string
* Param: $value any
* Param: $options undef,HASH
* Return: $nrows integer
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$nrows = $rep->set($table, $key, $col, $value, \%options);
$nrows = $rep->set($table, \%params, $col, $value, \%options);
tbd.
get_row()
* Signature: $row = $rep->get_row ($table, $key, $cols, $options);
* Signature: $row = $rep->get_row ($table, $params, $cols, $options);
* Param: $table string
* Param: $key string
* Param: $params undef,HASH
* Param: $cols ARRAY
* Param: $options undef,HASH
* Return: $row ARRAY
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$row = $rep->get_row($table, $key, \@cols, \%options);
$row = $rep->get_row($table, \%params, \@cols, \%options);
tbd.
set_row()
* Signature: $nrows = $rep->set_row($table, $key, $cols, $row, $options);
* Signature: $nrows = $rep->set_row($table, $params, $cols, $row, $options);
* Signature: $nrows = $rep->set_row($table, $params, $cols, $rowhash, $options);
* Signature: $nrows = $rep->set_row($table, $hash, undef, undef,$options);
* Signature: $nrows = $rep->set_row($table, $params, $hash, undef,$options);
* Param: $table string
* Param: $cols ARRAY
* Param: $row ARRAY
* Param: $rowhash HASH
* Param: $key string
* Param: $hash HASH
* Param: $params undef,HASH
* Param: $options undef,HASH
* Return: $nrows integer
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$nrows = $rep->set_row($table, $key, \@cols, $row, \%options);
$nrows = $rep->set_row($table, \%params, \@cols, $row, \%options);
$nrows = $rep->set_row($table, undef, \@cols, $row, \%options);
tbd.
get_column()
* Signature: $colvalues = $rep->get_column ($table, $params, $col, $options);
* Param: $table string
* Param: $params undef,HASH
* Param: $col string
* Param: $options undef,HASH
* Return: $colvalues ARRAY
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$colvalues = $rep->get_column ($table, \%params, $col, \%options);
tbd.
get_rows()
* Signature: $rows = $rep->get_rows($table, $params, $cols, $options);
* Signature: $rows = $rep->get_rows($table, $keys, $cols, $options);
* Param: $table string
* Param: $params undef,HASH
* Param: $keys ARRAY
* Param: $cols ARRAY
* Param: $options undef,HASH
* Return: $rows ARRAY
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$rows = $rep->get_rows ($table, \%params, \@cols, \%options);
$rows = $rep->get_rows ($table, \%params, $col, \%options);
$rows = $rep->get_rows ($table, \@keys, \@cols, \%options);
tbd.
set_rows()
* Signature: $nrows = $rep->set_rows($table, $keys, $cols, $rows, $options);
* Param: $table string
* Param: $keys undef,ARRAY
* Param: $cols ARRAY
* Param: $rows ARRAY
* Param: $options undef,HASH
* Return: $nrows integer
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$nrows = $rep->set_rows($table, \%params, \@cols, $rows, \%options);
$nrows = $rep->set_rows($table, undef, \@cols, $rows, \%options);
$nrows = $rep->set_rows($table, \@keys, \@cols, $rows, \%options);
tbd.
get_hash()
* Signature: $values = $rep->get_hash ($table, $key, $cols, $options);
* Signature: $values = $rep->get_hash ($table, $params, $cols, $options);
* Param: $table string
* Param: $cols ARRAY,undef
* Param: $key string
* Param: $params undef,HASH
* Param: $options undef,HASH
* Return: $values HASH
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$values = $rep->get_hash ($table, $key, \@cols, \%options);
$values = $rep->get_hash ($table, \%params, \@cols, \%options);
$values = $rep->get_hash ($table, $key, undef, \%options);
$values = $rep->get_hash ($table, \%params, undef, \%options);
tbd.
get_hashes()
* Signature: $hashes = $rep->get_hashes ($table, $key, $cols, $options);
* Signature: $hashes = $rep->get_hashes ($table, $params, $cols, $options);
* Param: $table string
* Param: $cols ARRAY,undef
* Param: $key string
* Param: $params undef,HASH
* Param: $options undef,HASH
* Return: $hashes ARRAY
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$hashes = $rep->get_hashes ($table, $key, \@cols, \%options);
$hashes = $rep->get_hashes ($table, \%params, \@cols, \%options);
$hashes = $rep->get_hashes ($table, $key, undef, \%options);
$hashes = $rep->get_hashes ($table, \%params, undef, \%options);
tbd.
get_object()
* Signature: $object = $rep->get_object ($table, $key, $cols, $options);
* Signature: $object = $rep->get_object ($table, $params, $cols, $options);
* Param: $table string
* Param: $cols ARRAY,undef
* Param: $key string
* Param: $params undef,HASH
* Param: $options undef,HASH
* Return: $object App::RepositoryObject
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$object = $rep->get_object ($table, $key, \@cols, \%options);
$object = $rep->get_object ($table, \%params, \@cols, \%options);
$object = $rep->get_object ($table, $key, undef, \%options);
$object = $rep->get_object ($table, \%params, undef, \%options);
tbd.
get_objects()
* Signature: $objects = $rep->get_objects ($table, $key, $cols, $options);
* Signature: $objects = $rep->get_objects ($table, $params, $cols, $options);
* Param: $table string
* Param: $cols ARRAY,undef
* Param: $key string
* Param: $params undef,HASH
* Param: $options undef,HASH
* Return: $objects ARRAY
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$objects = $rep->get_objects ($table, $key, \@cols, \%options);
$objects = $rep->get_objects ($table, \%params, \@cols, \%options);
$objects = $rep->get_objects ($table, $key, undef, \%options);
$objects = $rep->get_objects ($table, \%params, undef, \%options);
tbd.
get_hash_of_values_by_key()
* Signature: $hashes = $rep->get_hash_of_values_by_key ($table, $params, $valuecol, $keycol, $options);
* Param: $table string
* Param: $params undef,HASH
* Param: $valuecol string
* Param: $keycol string
* Param: $options undef,HASH
* Return: $hash HASH
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$hash = $rep->get_hash_of_values_by_key ($table, \%params, $valuecol, $keycol, \%options);
tbd.
get_hash_of_hashes_by_key()
* Signature: $hashes = $rep->get_hash_of_hashes_by_key ($table, $params, $cols, $keycol, $options);
* Param: $table string
* Param: $params undef,HASH
* Param: $cols ARRAY
* Param: $keycol string
* Param: $options undef,HASH
* Return: $hash HASH
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$hash = $rep->get_hash_of_hashes_by_key ($table, \%params, $cols, $keycol, \%options);
tbd.
set_hash()
* Signature: $nrows = $rep->set_hash ($table, $key, $cols, $values, $options);
* Signature: $nrows = $rep->set_hash ($table, $params, $cols, $values, $options);
* Param: $table string
* Param: $key string
* Param: $params undef,HASH
* Param: $cols ARRAY,undef
* Param: $options undef,HASH
* Return: $nrows integer
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$nrows = $rep->set_hash ($table, $key, \@cols, $values, \%options);
$nrows = $rep->set_hash ($table, $key, undef, $values, \%options);
$nrows = $rep->set_hash ($table, undef, \@cols, $values, \%options);
$nrows = $rep->set_hash ($table, undef, undef, $values, \%options);
$nrows = $rep->set_hash ($table, \%params, \@cols, $values, \%options);
$nrows = $rep->set_hash ($table, \%params, undef, $values, \%options);
tbd.
format_repdate()
* Signature: $date = $repository->format_repdate($freeform_date);
* Param: $freeform_date string
* Return: $date string
* Throws: App::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.
get_type_names()
* Signature: $typenames = $repository->get_type_names();
* Param: void
* Return: $typenames []
* Throws: App::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: App::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 => "Text"
* 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: App::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: App::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: App::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: $table_def = $rep->get_table_def($tablename);
* Param: $tablename string
* Return: $table_def {}
* Throws: App::Exception::Repository
* Since: 0.01
Sample Usage:
$table_def = $rep->get_table_def($tablename);
print "$table_def->{name} $table_def->{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: App::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: App::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: $column_def = $rep->get_column_def($tablename,$columnname);
* Param: $tablename string
* Param: $columnname string
* Return: $column_def {}
* Throws: App::Exception::Repository
* Since: 0.01
Sample Usage:
$column_def = $rep->get_column_def($tablename,$columnname);
print "$column_def->{name} $column_def->{label} $column_def->{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.
Methods: Transaction Control
begin_work()
* Signature: $rep->begin_work();
* Param: void
* Return: void
* Throws: App::Exception::Repository
* Since: 0.01
Sample Usage:
$rep->begin_work();
commit()
* Signature: $rep->commit();
* Param: void
* Return: void
* Throws: App::Exception::Repository
* Since: 0.01
Sample Usage:
$rep->commit();
rollback()
* Signature: $rep->rollback();
* Param: void
* Return: void
* Throws: App::Exception::Repository
* Since: 0.01
Sample Usage:
$rep->rollback();
Methods: Import/Export Data From File
import_rows()
* Signature: $rep->import_rows($table, $columns, $file);
* Signature: $rep->import_rows($table, $columns, $file, $options);
* Param: $table string
* Param: $columns ARRAY names of columns of the fields in the file
* Param: $file string
* Param: $options named
* Param: replace boolean rows should replace existing rows based on unique indexes
* Param: field_sep char character which separates the fields in the file (can by "\t")
* Param: field_quote char character which optionally encloses the fields in the file (i.e. '"')
* Param: field_escape char character which escapes the quote chars within quotes (i.e. "\")
* Return: void
* Throws: App::Exception::Repository
* Since: 0.01
Sample Usage:
$rep->import_rows("usr","usr.dat");
# root:x:0:0:root:/root:/bin/bash
$rep->import_rows("usr",
[ "username", "password", "uid", "gid", "comment", "home_directory", "shell" ],
"/etc/passwd" ,
{ field_sep => ":", });
export_rows()
* Signature: $rep->export_rows($table, $columns, $file);
* Signature: $rep->export_rows($table, $columns, $file, $options);
* Param: $table string
* Param: $file string
* Param: $options named
* Param: columns ARRAY names of columns of the fields in the file
* Param: replace boolean rows should replace existing rows based on unique indexes
* Param: field_sep char character which separates the fields in the file (can by "\t")
* Param: field_quote char character which optionally encloses the fields in the file (i.e. '"')
* Param: field_escape char character which escapes the quote chars within quotes (i.e. "\")
* Return: void
* Throws: App::Exception::Repository
* Since: 0.01
Sample Usage:
$rep->export_rows("usr","usr.dat");
# root:x:0:0:root:/root:/bin/bash
$rep->export_rows("usr", "passwd.dat" ,{
field_sep => ":",
columns => [ "username", "password", "uid", "gid", "comment", "home_directory", "shell" ],
});
Methods: Locking (Concurrency Management)
Methods: Miscellaneous
summarize_rows()
* Signature: $summarized_rows = $rep->summarize_rows($table, $rows, $columns, $summary_keys, $options);
* Param: $table string
* Param: $rows [][]
* Param: $columns []
* Param: $summary_keys []
* Param: $formulas {}
* Return: $summarized_rows []
* Throws: App::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" );
@summary_keys = ( "team" );
$summarized_rows = $rep->summarize_rows(\@rows, \@columns, \@summary_keys, \%formulas);
@rows = (
{ id=>5, name=>"Jim", team=>"Green", rating=>13.5, score=>320, },
{ id=>3, name=>"Bob", team=>"Green", rating=> 4.2, score=>230, },
{ id=>9, name=>"Ken", team=>"Green", rating=>27.4, score=>170, },
{ id=>2, name=>"Kim", team=>"Blue", rating=>11.7, score=>440, },
{ id=>7, name=>"Jan", team=>"Blue", rating=>55.1, score=> 90, },
{ id=>1, name=>"Ben", team=>"Blue", rating=>22.6, score=>195, },
);
@columns = ( "rating", "score" ); # summarize a subset of the columns
@summary_keys = ( "team" );
%options = (
ext_summaries => \%summaries, # extended summaries
ext_summary_columns => [ "rating", "score", "team", ], # optional
ext_summary_functions => { # optional
sum => 1,
count => 1,
sum_sq => 1,
distinct => 1,
min => 1,
max => 1,
average => 1, # requires sum, count
median => 1, # requires distinct
mode => 1, # requires min, max
stddev => 1, # requires sum, sum_sq, count
},
);
# returns the "natural" summaries
$summarized_rows = $rep->summarize_rows(\@rows, \@columns, \@summary_keys, \%options);
sort()
* Signature: $sorted_rows = $rep->sort($rows, $sortkeys);
* Signature: $sorted_rows = $rep->sort($rows, $sortkeys, $sorttype);
* Signature: $sorted_rows = $rep->sort($rows, $sortkeys, $sorttype, $sortdir);
* Param: $rows [][]
* Param: $sortkeys []
* Param: $sorttype []
* Param: $sortdir []
* Return: $sorted_rows []
* Throws: App::Exception::Repository
* Since: 0.01
Sample Usage: (to sort arrayrefs)
@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
@sortkeys = ( 2, 4 ); # "team", "score" (descending)
@sorttype = ( "C", "N" ); # Character, Numeric
@sortdir = ( "asc", "desc" ); # Ascending, Descending
$sorted_rows = $rep->sort(\@rows, \@sortkeys, \@sorttype, \@sortdir);
OR (to sort hashrefs)
@rows = (
{ id => 5, name => "Jim", team => "Green", rating => 13.5, score => 320, },
{ id => 3, name => "Bob", team => "Green", rating => 4.2, score => 230, },
{ id => 9, name => "Ken", team => "Green", rating => 27.4, score => 170, },
{ id => 2, name => "Kim", team => "Blue", rating => 11.7, score => 440, },
{ id => 7, name => "Jan", team => "Blue", rating => 55.1, score => 90, },
{ id => 1, name => "Ben", team => "Blue", rating => 22.6, score => 195, },
);
# @columns = ( "id", "name", "team", "rating", "score" ); # not needed
@sortkeys = ( "team", "score" ); # "team", "score" (descending)
@sorttype = ( "C", "N" ); # Character, Numeric
@sortdir = ( "asc", "desc" ); # Ascending, Descending
$sorted_rows = $rep->sort(\@rows, \@sortkeys, \@sorttype, \@sortdir);
evaluate_expressions()
* Signature: $nrows = $rep->evaluate_expressions($table, $params, $cols, $rows, $options);
* Param: $table string
* Param: $params HASH,scalar
* Param: $cols ARRAY
* Param: $rows ARRAY
* Param: $options undef,HASH
* Return: $nrows integer
* Throws: App::Exception::Repository
* Since: 0.50
Sample Usage:
$rep->evaluate_expressions($table, $params, \@cols, $rows, \%options);
tbd.
serial()
* Signature: $serial_num = $repository->serial($category);
* Param: $category string
* Return: $serial_num integer
* Throws: App::Exception::Repository
* Since: 0.01
Sample Usage:
$serial_num = $repository->serial($category);
Methods: Metadata
_load_rep_metadata()
* Signature: $repository->_load_rep_metadata();
* Param: void
* Return: void
* Throws: App::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_from_source() in order for the repository itself to be consulted for its metadata information.
_load_rep_metadata_from_source()
* Signature: $repository->_load_rep_metadata_from_source();
* Param: void
* Return: void
* Throws: App::Exception::Repository
* Since: 0.01
Sample Usage:
$repository->_load_rep_metadata_from_source();
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: App::Exception::Repository
* Since: 0.01
Sample Usage:
$self->_load_table_metadata();
First it calls _load_table_metadata_from_source() 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_from_source()
* Signature: $repository->_load_table_metadata_from_source();
* Param: void
* Return: void
* Throws: App::Exception::Repository
* Since: 0.01
Sample Usage:
$self->_load_table_metadata_from_source();
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).
Methods: Miscellaneous
_init()
* Signature: $repository->_init();
* Param: defer_connection integer
* Return: void
* Throws: App::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();
* Param: defer_connection integer
* Return: void
* Throws: App::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 = App::Repository->service_type();
* Param: void
* Return: $service_type string
* Since: 0.01
$service_type = $widget->service_type();
current_datetime()
Returns 'Repository'.
* Signature: $current_datetime = App::Repository->current_datetime();
* Param: void
* Return: $current_datetime string
* Since: 0.01
$current_datetime = $widget->current_datetime();
rows_by_indexed_values()
* Signature: &App::Repository::rows_by_indexed_values($a,$b);
* Param: $a []
* Param: $b []
* Return: void
* Throws: App::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, ],
);
@App::Repository::sort_keys = ( 1, 3, 2 );
@App::Repository::sort_types = ("C", "N", "C");
@App::Repository::sort_dirs = ("asc", "desc", "desc");
# OR @App::Repository::sort_dirs = ("_asc", "_desc", "_desc");
# OR @App::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.
hashes_by_indexed_values()
* Signature: &App::Repository::hashes_by_indexed_values($a,$b);
* Param: $a []
* Param: $b []
* Return: void
* Throws: App::Exception::Repository
* Since: 0.01
Sample Usage:
@data = (
{ size => 5, name => "Jim", color => "Red", score => 13.5, ],
{ size => 3, name => "Bob", color => "Green", score => 4.2, ],
{ size => 9, name => "Ken", color => "Blue", score => 27.4, ],
{ size => 2, name => "Kim", color => "Yellow", score => 11.7, ],
{ size => 7, name => "Jan", color => "Purple", score => 55.1, ],
);
@App::Repository::sort_keys = ( "size", "color", "name" );
@App::Repository::sort_types = ("C", "N", "C");
@App::Repository::sort_dirs = ("asc", "desc", "desc");
# OR @App::Repository::sort_dirs = ("_asc", "_desc", "_desc");
# OR @App::Repository::sort_dirs = ("UP", "DOWN", "DOWN");
@sorted_data = sort hashes_by_indexed_values @data;
The hashes_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: App::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 <spadkins@gmail.com>
* License: This is free software. It is licensed under the same terms as Perl itself.