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

NAME

StoredHash - Minimalistic, yet fairly complete DBI Persister with a definite NoSQL feel to it

SYNOPSIS

   use StoredHash;
   use DBI;
   use Data::Dumper;
   
   my $dbh = DBI->connect("dbi:SQLite:dbname=/tmp/zoo.db");
   # Lightweight demonstration of StoredHash in action (with SQLite)
   $dbh->do("CREATE TABLE animals (speciesid INTEGER NOT NULL PRIMARY KEY, name CHAR(16), limbcnt INTEGER, family CHAR(16))");
   my $shp = StoredHash->new('table' => 'animals', 'pkey' => ['speciesid'],
      'autoid' => 1, 'dbh' => $dbh, 'debug' => 0);
   # Hash object to be stored
   my $monkey = {'name' => 'Common Monkey', 'limbcnt' => 5, 'family' => 'mammal',};
   
   # Happens to return numeric id (because of auto-increment pkey / autoid)
   my $spid = $shp->insert($monkey);
   print("Created by: id=$spid\n");
   # Load entry
   my $ent = $shp->load([$spid]);
   print("Fetched (by $spid): ".Dumper($ent)."\n");
   # Get: {'name' => 'Common Monkey', 'speciesid' => 469, 'limbcnt' => 5,'family' => 'mammal',}
   # Fix error in entry (don't count tail to be limb)
   $ent->{'limbcnt'} = 4;
   # Update (with some redundant attributes that do not change)
   print("Update $ent->{'speciesid'}\n");
   $shp->update($ent, [$ent->{'speciesid'}]);
   # Could reduce / optimize change to bare minimum:
   my %change = ('limbcnt' => 4);
   print("Reduce property value on $spid\n");
   $shp->update(\%change, [$spid]);
   # Later ... (species dies extinct ?)
   #$shp->delete([$spid]);
   
   # Test if we need to insert / update (based on presence in DB)
   my $id = 5987;
   my $invals = {'name' => 'Crow', 'limbcnt' => 4, 'family' => 'birds'};
   print("Test Presence of Animal '$id'\n");
   if ($shp->exists([$id])) {$shp->update($invals, [$id]);}
   else {$shp->insert($invals);}
   
   ##### Easy loading of sets / collections
   # Load all the animals
   my $animarr = $shp->loadset();
   print("All Animals: ".Dumper($animarr)."\n");
   # Load only mammals (by filter)
   my $mammarr = $shp->loadset({'family' => 'mammal'});
   print("Mammals: ".Dumper($mammarr)."\n");

DESCRIPTION

Allow DB Persistence operations (insert(), load(), update(), delete(), exists()) on a plain old hash (unblessed or blessed) without writing classes, persistence code or SQL.

Optionally StoredHash allows your classes to inherit peristence capability from StoredHash allowing your objects to call StoredHash persistence methoda via object directly.

GENERAL INFO ON StoredHash PERSISTENCE

  • Connection is stored in persister. Thus there is no need to pass it as parameter to persister methods.

  • Composite keys are supported by StoredHash. Because of this id values are passed in array. Id values must be ordered the same as their attribute names suring construction (as passed in 'pkey' construction parameter).

  • Some persistence methods support 'attrs' parameter. This means "partial attributes" or "only these attributes" whatever the direction is persistence operation is. Examples: load(): load only these attributes, update(): update only these attributes, etc.

  • StoredHash is not validating the hash keys / attribute (or 'attrs' parameter above) against these attributes actually existing in DB schema. Caller of persistence methods is responsible validating the "fit" of hash to a schema.

Above principles are consistent across persistence methods. These details will be not repeated in method documentation.

METHODS

$shp = StoredHash->new(%opts);

Create new instance of StoredHash Persister.

Keyword parameters in %opts:

  • 'pkey' - array (ref) to reflect the identifying attrtibute(s) of entry (e.g. single attr for numeric sequential ids, multiple for composite key)

  • 'dbh' - DBI connection to database (optional). Not passing 'dbh' makes methods insert/update/load/delete return the SQL query only (as a string)

$shp->errstr($v)

Access error string that method may leave to object. Notice that many methods throw exception (by die()) with error message rather than leave it within object.

$shp->insert($e)

Store entry %$e (hash) inserting it as a new entry to a database.

Returns an array of ID values for the entry that got stored (array of one element for numeric primary key, multiple for composite key).

$shp->update($e, $ids, %opts);

Update an existing entry by ID(s) ($ids) in the database with values in hash %$e.

Return true for success, false for failure (direct $ok values from underlying $sth->execute() for 'autoid' => 1 ),

$shp->delete($ids) OR $shp->delete($filter)

Delete an entry from database by passing one of the following:

  • $ids - array with ID(s) for entry to be deleted (the usual use-case)

  • $filter - a hash with a where filter condition to delete by.

Note that passing $filter haphazardly can cause massive destruction. Try to stick with passing $ids.

$shp->exists($ids)

Test if an entry exists in the DB table with ID values passed in @$ids (array). Returns 1 (entry exists) or 0 (does not exist) under normal conditions.

$shp->load($ids)

Load entry from DB table by its IDs passed in @$ids (array, single id typical sequece autoid pkey, multiple for composite primary key).

Entry will be loaded from single table passed at construction (never as result of join from multiple tables). Return entry as a hash (ref).

$shp->loadset($filter, $sort, %opts);

Load a set of Entries from persistent storage. Optionally provide simple "where filter hash" ($filter), whose key-value criteria is ANDed together to form the filter. Allow attibutes (in $sort, arrayref) to define sorting for entry set. Allow %opts to contain 'attrs' (arrayref) to explicitly to define ettributes to load for each entry. Return set / collection of entries as array of hashes (AoH).

$shp->cols(%opts)

Sample Column names from (current) DB table. Return (ref to) array with field names in it.

%opts may contain KW parameter 'full' to get full DBI column_info() structure (See DBI for details).

$shp->count($filter)

Get Count of all or a filtered set of entries (by optional $filter) in table. Return (scalar) count of entries.

INTERNAL METHODS

These methods you should not need working on the high level. However for the curious they are outlined here.

@pkv = $shp->pkeyvals($e)

Return Primary key values (as "real" array, not ref to one) from hash %$e. undef values are produced for non-existing keys. Mostly used for internal operations (and possibly debugging).

$shp->whereid($pkvals);

Generate SQL WHERE Clause for update() (or delete() or load() or exists()) based on primary keys of current (table) type. Return WHERE clause with id-attribute(s) and placeholder(s) (idkey = ?, ...), without the WHERE keyword. Mostly called for internal operations. You should not need this.