DRAFT
This documentation is in early draft form!
NAME
DBR - Database Repository ORM (object-relational mapper).
SYNOPSIS
# common packages
use DBR;
use DBR::Util::Logger;
use DBR::Util::Operator;
# typical connection
my $logger = DBR::Util::Logger->new( -logpath => './dbr.log', -logLevel => 'debug2' );
my $dbr = DBR->new( -logger => $logger, -conf => './dbr.conf' );
my $dbh = $dbr->connect( 'car_dealer' ); # instance handle
# metadata access (dbr tools)
my $meta = $dbr->get_instance( 'dbrconf' ); #
VERSION
1.06b
svn trunk is currently 266.
DESCRIPTION
DBR stands for Database Repository, and functions as an ORM (Object Relational Mapper) to your database.
DBR tries to make your use of a Database resource safe, concise, efficient and clear. The objective is to have your code access and use objects, not spend time expressing future needs (SQL, fields to pull, joins, etc) in one place and using them in another.
FEATURES
- concise
-
A one-liner will often suffice to prepare the data you need. After that, you just use the data and the DBR objects will do (or already have done) the right thing. For example:
while ($dbrh->orders->where( 'customer.name' => LIKE '%Jones' )->next) { print "Order ".$_->order_id." shipped ".$_->shipment.method.name."\n"; }
would be the equivalent of writing out some SQL like:
select o.order_id, m.name from orders o, customers c, shipments s, ship_methods m where c.name like '%Jones' and o.customer_id = c.cust_id and o.shipment_id = s.shipment_id and s.method_id = m.method_id;
- smart
-
DBR learns what your code will need, and will pre-fetch the data.
In the example above, DBR learns about your access to the shipping method name the first time the code runs, and will build the equivalent query on subsequent runs.
- efficient
-
Most performance-critical DBR objects are blessed arrayrefs instead of hashrefs.
Access to large quantities of data are automatically chunked behind the scenes.
- convenient
-
Database fields can hold a representation of data that you can access in raw or formatted form via automatic translators that wrap the field.
Currently available for Dollars, Unixtime, Percent and Enumeration.
- no SQL
-
Table joins are replaced with the names of relationships associated with foreign keys. All you end up doing is:
$car->model->make->name
or
where( 'car.model.make.name' => 'Ford' )
- post-fetch organization
-
Create a lookup map (hash):
# what preference did customers have for shipping method by gender last year? $dbh->orders-> where( order.date => BETWEEN( '1/1/2008', '1/1/2009' ) )-> hashmap_multi( 'order.date.month', 'shipment.method.name', 'customer.gender' );
or
# get purchase items grouped by shipment method and order $dbh->items-> where( 'order.customer' => $customer_id )-> hashmap_multi( 'order.shipment.method.name', 'order.order_id' );
CONFIGURATION
Configuration File
Contains the information needed to get to the configuration/metadata database.
This database contains all the information about schemas and instances you will be connecting to.
For a SQLite config database, your config will define:
name=dbrconf
class=master
dbfile=/path/to/database
type=SQLite
dbr_bootstrap=1
really, all you need to usually do is customize the dbfile path.
For a MySQL config database, your config will define:
name=dbrconf
class=master
hostname=db.host.domain.com
database=myapp
user=dbusername
password=dbpassword
type=Mysql
dbr_bootstrap=1
typically customize just hostname, database, user and password.
The class could also be "query", for a read-only replicated copy, for example.
Bootstrap
When you create a new() DBR, you typically point it at the above config file.
From there, all further actions to your application databases are thru the DBR object.
Debug Logging
A common logger instance is required by DBR and shared by all related objects.
METADATA
Schema
Instance
Table
Field
Enumeration
API
Be sure to also check out:
http://code.google.com/p/perl-dbr/wiki/ObjectsAndMethods
DBR
new
get_instance
connect
timezone
remap
unmap
Instance Handle
TABLENAME
begin
commit
rollback
select (v1)
insert (v1)
update (v1)
delete (v1)
Object
where
all
get
insert
enum
parse
Resultset
next
each
hashmap_multi
hashmap_single
count
values
raw_hashrefs
raw_arrayrefs
raw_keycol
Record
FIELDNAME
get
RELATIONNAME
gethash
set
delete
Translator
Dollars
dollars
format
cents
Unixtime
date
time
datetime
fancytime
fancydate
fancydatetime
unixtime
midnight
endofday
Enum
handle
name
in
id
Operators
use DBR::Util::Operator;
GT (greater-than)
where( 'item.price' => GT 3.59 );
LT (less-than)
where( 'item.price' => LT 3.59 );
GE (greater-than-or-equal-to)
where( 'item.price' => GE 3.59 );
LE (less-than-or-equal-to)
where( 'item.price' => LE 3.59 );
NOT
LIKE
where( name => LIKE( '%ing' )
NOTLIKE
where( name => LIKE( 'George%' )
BETWEEN
where( price => BETWEEN( 3.00, 4.50 ) )
NOTBETWEEN
where( price => NOTBETWEEN( 50, 100 ) )
Logger
logErr
logWarn
logInfo
logDebug
verbose
logDebug2
very verbose
logDebug3
really, really verbose
TOOLS
dbr-admin
dbr-load-spec
dbr-dump-spec
dbr-scan-db
TODO
- dbr-admin
-
This tool works, but it has various quirks that make it a bit difficult to use at present.
- fast metadata browser
-
DBR needs a fast and effective browser, especially for looking up the relationship names and enumeration handles. The dbr-admin tool is helpful but clunky, the dbr-spec-dump also can be use for this purpose, but...
- cross-module scoping
-
DBR's current pre-fetch scoping support only works within a file. It needs to be extended. For now, don't pass DBR objects between packages, unless they are in the same file.
- debug support
-
Attempting to Dumper data with DBR objects will explode with metadata you never wanted to see. DBR needs dumper support.
- OR support
-
DBR doesn't want to you to make an OR query. It usually results in an inefficient table scan. In fact, you just can't with DBR! All the constraints in a where() are ANDed together.
Should you be able to OR?
BUGS
MySQL sub-queries
DBR will magically perform a sub-query when you use the reverse direction of a relationship. For example, given an e-commerce scenario with an Order that has Items, the item has a foreign key to its order, so order.items
would be traversing that foreign key in the reverse direction, causing a sub-query of items matching the order's pkey. MySQL handles the sub-query very poorly, and depending on the volume of data, you may need to identify the order pkeys of interest first, and then use where( order_id => $order_ids )
explicitly instead.
perl-dbr project
See http://code.google.com/p/perl-dbr/issues/list.
SEE ALSO
Google Code project: http://code.google.com/p/perl-dbr
API Diagram: http://code.google.com/p/perl-dbr/wiki/ObjectsAndMethods
AUTHOR
Daniel Norman, dnorman@drjays.com
.
COPYRIGHT AND LICENSE
Copyright 2009, Daniel Norman
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.