File Coverage

blib/lib/DBIx/AbstractLite.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package DBIx::AbstractLite;
2              
3 1     1   848 use strict;
  1         2  
  1         48  
4              
5             =head1 NAME
6              
7             DBIx::AbstractLite - Lightweight DBI SQL abstraction in a hybrid interface
8              
9             =head1 SYNOPSIS
10              
11             use Project::DB;
12              
13             my $DB = new Project::DB; # connect to DB
14             $DB->setWhere('date >= sysdate-1'); # global condition for all queries to follow
15             my $sth = $DB->select({
16             fields => [ 'user', 'email' ],
17             table => 'users',
18             where => { 'user' => [ 'like', 'me%' ],
19             'length(email)' => [ '>', '20' ],
20             },
21             }) or die $DB->error();
22             print $sth->fetchrow_array();
23              
24             $DB->query('SELECT user, email FROM users WHERE user like ?', 'me%')
25             or die $DB->error();
26             my $userEmail = $DB->fetch_hash();
27             print "someuser's email is: ", $userEmail->{someuser}, "\n";
28              
29             $DB->query('SELECT email FROM users WHERE user = ?', 'me')
30             or die $DB->error();
31             print "my email is ", $DB->fetch_col();
32              
33              
34             package Project::DB;
35              
36             use DBIx::AbstractLite;
37             use vars qw (@ISA);
38             @ISA = qw(DBIx::AbstractLite);
39              
40             sub _initMembers {
41             my ($self) = @_;
42              
43             $self->{DSN} = "dbi:Oracle:$ENV{ORACLE_SID}";
44             $self->{USER} = 'username';
45             $self->{PASS} = 'password';
46             }
47              
48             =head1 DESCRIPTION
49              
50             This module is based on DBIx::Abstract, but is much simpler.
51             It also doesn't deviate from the DBI interface as much as DBIx::Abstract does.
52             The main similarity between DBIx::AbstractLite and DBIx::Abstract
53             is in the select method.
54             Unlike Abstract, AbstractLite is not 100% abstract in that it still allows
55             conventional access to the DBI interface,
56             using plain SQL and the DBI statement handle methods.
57              
58             CGI::LogCarp is used internally to trace the queries sent to DBI.
59             To see the trace statements, add this statement at the beginning of your program:
60             use CGI::LogCarp qw(:STDBUG);
61              
62              
63              
64             MORE DOCUMENTATION TBD...
65              
66             =cut
67              
68 1     1   8754 use DBI;
  1         25337  
  1         108  
69 1     1   800 use Error::Dumb;
  1         263  
  1         28  
70 1     1   1515 use CGI::LogCarp qw(:STDBUG);
  0            
  0            
71              
72             use vars qw($VERSION @ISA);
73              
74             @ISA = qw(Error::Dumb);
75             $VERSION = do { my @r=(q$Revision: 1.5 $=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
76              
77              
78             sub new {
79             my ($class) = @_;
80            
81             my $self= {};
82             $self->{WHERE} = undef; # a list of where conditions
83              
84             bless $self, $class;
85              
86             $self->_initMembers() if $self->can('_initMembers');
87              
88             $self->{DBH} = $self->connect() or die $DBI::errstr;
89             trace "$self->{DSN} successfully connected\n";
90              
91             return $self;
92             }
93              
94             sub DESTROY {
95             my ($self) = @_;
96              
97             $self->{STH}->finish() if $self->{STH};
98              
99             # don't disconnect if running under mod_perl and Apache::DBI
100             return if $ENV{MOD_PERL};
101              
102             $self->disconnect() if $self;
103             }
104              
105             sub connect {
106             my ($self) = @_;
107              
108             return DBI->connect($self->{DSN}, $self->{USER}, $self->{PASS},
109             { ChopBlanks => 1 } );
110             }
111              
112             my %aliases = (
113             group => 'group_by',
114             order => 'order_by',
115             );
116              
117             sub select {
118             my ($self, $args) = @_;
119              
120             my @bind = ();
121             my @where = ();
122              
123             $args->{fields_global} = $self->{FIELDS};
124              
125             # convert aliases
126             while ( my ($alias, $real) = each %aliases ) {
127             if ( defined $args->{$alias} ) {
128             $args->{$real} = $args->{$alias};
129             delete $args->{$alias};
130             }
131             }
132              
133             # "join" arg is a special case. add it to @where list directly,
134             if ( $args->{join} && ref $args->{join} eq 'ARRAY' ) {
135             push @where, @{ $args->{join} };
136             delete $args->{join};
137             }
138              
139             # convert scalar to arrayref,
140             # then convert arrayref to comma-separated string.
141             # this is to accomodate a choice of input: either arrayref or scalar
142             foreach my $key ( keys %$args ) {
143             unless ( ref $args->{$key} ) {
144             $args->{$key} = [ $args->{$key} ];
145             }
146             if ( ref $args->{$key} eq 'ARRAY') {
147             $args->{$key} = join ', ', @{ $args->{$key} };
148             }
149             }
150              
151             $args->{fields} .= ", $args->{fields_global}" if $args->{fields_global};
152             my $query = "SELECT $args->{fields} FROM $args->{table} ";
153             if ( $args->{where} ) {
154             while ( my ($key, $value) = each %{ $args->{where} } ) {
155             my ($operator, $targetValue) = @$value;
156             push @where, "($key $operator ?)";
157             push @bind, $targetValue;
158             }
159             }
160             if ( $args->{where_raw} ) {
161             while ( my ($key, $value) = each %{ $args->{where_raw} } ) {
162             my ($operator, $targetValue) = @$value;
163             push @where, "($key $operator $targetValue)";
164             }
165             }
166             push @where, @{ $self->{WHERE} } if $self->{WHERE};
167             if ( @where ) {
168             $query .= 'WHERE ';
169             $query .= join ' AND ', @where;
170             }
171             if ( $args->{group_by} ) {
172             $query .= " GROUP BY $args->{group_by}";
173             }
174             if ( $args->{order_by} ) {
175             $query .= " ORDER BY $args->{order_by}";
176             }
177             if ( $args->{extra} ) {
178             $query .= " $args->{extra}";
179             }
180             $self->{QUERY} = $query;
181             $self->{BIND} = \@bind;
182             return $self->_query();
183             }
184              
185             sub query {
186             my ($self, $query, @args) = @_;
187              
188             $self->{QUERY} = $query;
189             $self->{BIND} = \@args;
190             return $self->_query();
191             }
192              
193             sub _query {
194             my ($self) = @_;
195              
196             my @args = @{ $self->{BIND} };
197             my $args = join ',', @args;
198             trace "$self->{DSN} query: $self->{QUERY}; args: $args\n";
199             $self->{STH} = $self->{DBH}->prepare($self->{QUERY})
200             or return $self->_setError($self->{DBH}->errstr);
201             $self->{STH}->execute(@args) or return $self->_setError($self->{STH}->errstr);
202            
203             return $self->{STH};
204             }
205              
206             sub disconnect {
207             my ($self) = @_;
208              
209             $self->{DBH}->disconnect() if $self->{DBH};
210             }
211              
212             sub fetch_col {
213             my ($self) = @_;
214              
215             my ($col) = $self->{STH}->fetchrow_array();
216             return $col;
217             }
218              
219             sub fetch_hash {
220             my ($self) = @_;
221              
222             my $hash = {};
223             while ( my ($key, $value) = $self->{STH}->fetchrow_array() ) {
224             $hash->{$key} = $value;
225             }
226              
227             return $hash;
228             }
229              
230             sub setWhere {
231             my ($self, $where) = @_;
232              
233             push @{ $self->{WHERE} }, $where;
234             }
235              
236             sub getWhere {
237             my ($self) = @_;
238              
239             if ( defined $self->{WHERE} ) {
240             return ' WHERE ' . join (' AND ', @{ $self->{WHERE} }) . ' ';
241             }
242             else {
243             return '';
244             }
245             }
246              
247             sub setFields {
248             my ($self, $field) = @_;
249              
250             push @{ $self->{FIELDS} }, $field;
251             }
252              
253             sub getDistinct {
254             my ($self, $colname, $table) = @_;
255              
256             my @cols = ();
257             my $sth = $self->select({
258             fields => "distinct($colname)",
259             table => $table
260             });
261             while ( my ($col) = $sth->fetchrow_array() ) {
262             push @cols, $col;
263             }
264             return \@cols;
265             }
266              
267             1;
268              
269             __END__