File Coverage

blib/lib/Cosmic/DB.pm
Criterion Covered Total %
statement 28 160 17.5
branch 3 94 3.1
condition 1 52 1.9
subroutine 8 13 61.5
pod 6 6 100.0
total 46 325 14.1


line stmt bran cond sub pod time code
1             package Cosmic::DB;
2 2     2   41389 use strict;
  2         4  
  2         81  
3 2     2   10 use warnings;
  2         4  
  2         53  
4 2     2   11 use Carp;
  2         8  
  2         533  
5 2     2   5951 use DBI;
  2         33155  
  2         116  
6            
7 2     2   1393 use Cosmic::DB::SQL;
  2         97  
  2         75  
8            
9             BEGIN {
10 2     2   10 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  2         2  
  2         176  
11 2     2   5328 $VERSION = '0.01_05';
12             }#BEGIN
13            
14             my %params_default = (
15             prefix => '',
16             suffix => '',
17             debug => 0,
18             debug_newline => "\n",
19             );
20            
21            
22             =head1 NAME
23            
24             Cosmic::DB - Lightweight SQL generation, portable across Oracle, MySQL, Postgres
25             & SQL Server
26            
27             =head1 SYNOPSIS
28            
29             use Cosmic::DB;
30            
31            
32             =head1 DESCRIPTION
33            
34             DEVELOPMENT RELEASE - Don't use this, like Magnum it's nowhere near ready.
35            
36             (Yes that was a Zoolander reference)
37            
38             This module acts as a gateway to L and L,
39             providing some additional convenient functionality.
40            
41             You may well wish to use your current DBI wrapper, such as L
42             and instantiate L and L directly.
43            
44             =head1 USAGE
45            
46            
47             =head1 METHODS
48            
49             =head2 new
50            
51             Usage
52            
53             my $db = new Cosmic::DB( dsn => $DSN, user => $user, pass => $pass, attrs => \%attrs);
54             my $dbclone = $db->new();
55             my $dbcopy = $db->new( param => value, attrs => \%attrs);
56            
57             Purpose : Creates new Cosmic::DB instance, clones an existing instance
58             Parameters:
59            
60             =over
61            
62             attrs => %attrs - passed to DBI connect, see L for details
63             debug = 0|1 - turn on debugging warnings
64             debug_newline = "\n
" - for debugging newline characters
65             prefix = STRING - used to prefix table names
66             prefix = STRING - used to suffix table names
67            
68             =back
69            
70             An instance can be cloned by calling new against it. You can optionally pass new
71             params and attributes that will overwrite any existing ones for the clone. The
72             clone will still need to L
73            
74             See Also : L
75            
76             =cut
77            
78             sub new {
79 1     1 1 13 my $class = shift;
80 1         13 my %params = (
81             %params_default,
82             @_
83             );
84 1 50       8 my %attrs = $params{attrs} ? %{ $params{attrs} } : ( AutoCommit => 1 );
  0         0  
85 1         3 delete $params{attrs};
86 1 50       5 if ( ref ($class) ) {
87 0         0 %params = (
88 0         0 %{ $class->{param} },
89             %params,
90             );
91 0         0 %attrs = {
92 0         0 %{ $class->{attrs} },
93             %attrs,
94             };
95             }#if
96 1         7 my $self = {
97             connected => 0,
98             param => \%params,
99             attrs => \%attrs,
100             };
101 1   33     10 bless ($self, ref ($class) || $class);
102             # Connect if we are passed DBH
103 1 50       4 $self->connect( $params{dbh} ) if $params{dbh};
104 1         4 return $self;
105             }#new
106            
107            
108             =head2 connect
109            
110             Usage
111            
112             $db->connect;
113             $db->connect( $dbh );
114            
115             Connects with details sent to new, or can optionally be given a DBH which it's
116             use instead. Returns true upon connection or croaks.
117            
118             =cut
119            
120             sub connect {
121 0     0 1   my $self = shift;
122 0           my $dbh = shift;
123             # Connect to DB if we aren't already connected
124 0 0         unless ($self->{connected}) {
125 0 0         if ( $dbh ) {
126 0           $self->{dbh} = $dbh;
127             }#if
128             else {
129 0 0         carp "Connecting to DB with $self->{param}->{dsn}, $self->{param}->{user}, $self->{param}->{pass}$self->{param}->{debug_newline}" if $self->{param}->{debug};
130 0   0       $self->{dbh} = DBI->connect( $self->{param}->{dsn}, $self->{param}->{user}, $self->{param}->{pass}, { %{ $self->{attrs} } } )
131             || croak("Cannot connect to database: $DBI::errstr\n");
132 0           $self->{connected} = 1;
133             }#else
134             # Create SQL generation object
135 0           $self->{sql} = new Cosmic::DB::SQL($self->{dbh});
136             }#unless
137 0           return $self->{connected};
138             }#sub
139            
140            
141             =head2 disconnect
142            
143             Usage
144             $db->disconnect;
145            
146             Disconnects the database connection.
147            
148             =cut
149            
150             sub disconnect {
151 0     0 1   my $self = shift;
152 0           $self->{dbh}->disconnect;
153 0           $self->{connected} = 0;
154             }#sub
155            
156             =head2 insert
157            
158             Usage
159            
160             $db->insert( $table, \@columns, \@values );
161             $db->insert( $table, \@columns, \%values );
162             $db->insert( $table, \%values );
163             $db->insert( $table, \@columns, [ \@values, \@values, ... ] );
164             $db->insert( $table, \@columns, [ \%values, \%values, ... ] );
165             $db->insert( $table, [ \%values, \%values, ... ] );
166            
167             Purpose : Inserts \@values into the \@columns of $table
168             Parameters:
169            
170             =over
171            
172             $table = STRING - name of the table
173             \@columns = LIST - array reference to column names
174             \@values = LIST - array reference to values
175             \%values = HASH - hash reference to values keyed by column names
176            
177             =back
178            
179             Uses do for single inserts, or prepare and a loop for multiple. If columns is
180             ommitted and %values is a hash (or arrary ref of hashes) then the hash keys are
181             used as the columns. If %values is a hash and columns is passed, then other hash
182             keys are ignored.
183            
184             =cut
185            
186             sub insert {
187 0     0 1   my $self = shift;
188 0           my ( $table, $columns, $values ) = @_;
189 0           $self->{success} = 0;
190            
191 0           my $insert_method = 'insert';
192             # Is table actually config?
193 0           my $config;
194 0 0         if ( ref $table ) {
195 0           $config = $table;
196 0           $table = $config->{table};
197 0 0         $insert_method = 'merge_replace' if $config->{replace};
198             }
199 0           $table = "$self->{param}->{prefix}$table$self->{param}->{suffix}";
200            
201 0           my $sql_values = '?';
202 0           my $columns_values;
203            
204             # See if columns is actually values and columns need to be generated
205 0 0 0       if ( ref( $columns ) eq 'HASH' ) {
    0 0        
206 0           $values = $columns;
207 0           $columns = [ keys %$values ];
208             }#if
209             elsif ( ref( $columns ) eq 'ARRAY' && !defined $values && ref( $columns->[0] ) eq 'HASH' ) {
210 0           $values = $columns;
211 0           $columns = [ keys %{ $values->[0] } ];
  0            
212             }#elsif
213             else {
214             # Is this a relationship table insert with 1 fixed ID?
215 0 0 0       if ( ref $values eq 'ARRAY' && ! ref $values->[0] && ref $values->[1] eq 'ARRAY' ) {
      0        
216             # Make 1st column fixed, take off value
217 0           $columns->[0] = {
218             name => $columns->[0],
219             value => shift( @$values ),
220             };
221             }#elsif
222             # We have columns, look for fixed values
223 0           for( my $i = 0; $i <= $#$columns; $i++ ) {
224 0 0         if ( ref $columns->[$i] ) {
    0          
225 0 0         unless ( ref $sql_values ) {
226 0           $sql_values = [];
227 0           push( @$sql_values, \'?' ) for 0..$i-1;
228             }
229 0           push( @$sql_values, $columns->[$i]->{value} );
230 0           $columns->[$i] = $columns->[$i]->{name};
231             }
232             elsif ( ref $sql_values ) {
233 0           push( @$sql_values, \'?' );
234             }
235             }#for
236 0 0         $columns_values = grep { ! ref $_ } @$sql_values if ref $sql_values;
  0            
237             }#else
238 0   0       $columns_values ||= @$columns; # Columns with values
239            
240             # Generate values if needed
241 0 0         if ( ref( $values ) eq 'HASH' ) {
242 0           my @vals;
243 0           foreach my $column (@$columns) {
244 0           push( @vals, $values->{$column} );
245             }#foreach
246 0           $values = \@vals;
247             }#else
248            
249             # Check for multiple insert
250 0 0 0       if ( ref $values && ref( $values->[0] ) ) {
251 0           my $sql = $self->{sql}->sql->$insert_method( $table, $columns, $sql_values )->sql;
252 0           my $sth = $self->{dbh}->prepare($sql);
253 0 0         if ( ref( $values->[0] ) eq 'ARRAY' ) {
    0          
254             # Is this a relationship table insert with 1 fixed ID?
255 0 0 0       if ( @$values == 1 && @{ $values->[0] } > $columns_values ) {
  0            
256 0           foreach my $value ( @{ $values->[0] } ) {
  0            
257 0 0 0       $sth->execute($value) && do {$self->{success} = 1} || croak("Cannot insert to $table: SQL = $sql VALUES = $value\n $DBI::errstr\n");
  0            
258 0 0         carp "SQL $sql VALUES $value$self->{param}->{debug_newline}" if $self->{param}->{debug};
259             }#foreach
260             }#if
261             else {
262 0           foreach my $values ( @$values ) {
263 0 0 0       $sth->execute(@$values) && do {$self->{success} = 1} || croak("Cannot insert to $table: SQL = $sql VALUES = @$values\n $DBI::errstr\n");
  0            
264 0 0         carp "SQL $sql VALUES @$values$self->{param}->{debug_newline}" if $self->{param}->{debug};
265             }#foreach
266             }#else
267             }#if
268             elsif ( ref( $values->[0] ) eq 'HASH' ) {
269 0           foreach my $valuehash ( @$values ) {
270 0           my @values;
271 0           foreach my $column (@$columns) {
272 0           push( @values, $valuehash->{$column} );
273             }#foreach
274 0 0 0       $sth->execute(@values) && do {$self->{success} = 1} || croak("Cannot insert to $table: SQL = $sql VALUES = @values\n $DBI::errstr\n");
  0            
275 0 0         carp "SQL $sql VALUES @$values$self->{param}->{debug_newline}" if $self->{param}->{debug};
276             }#foreach
277             }#else
278 0           $sth->finish();
279             }#if
280             else {
281 0           my $sql = $self->{sql}->sql->$insert_method($table, $columns, $values)->sql;
282 0 0 0       $self->{dbh}->do($sql) && do {$self->{success} = 1} || croak("Cannot insert to $table: SQL = $sql\n $DBI::errstr\n");
  0            
283 0 0         carp "SQL $sql $self->{param}->{debug_newline}" if $self->{param}->{debug};
284             }#else
285 0           return $self->{success};
286             }#sub
287            
288            
289             =head2 delete
290            
291             Usage
292            
293             $db->delete( $table, \%where );
294             $db->delete( $table, \%where, \@values );
295            
296             Purpose : Deletes rows from $table where %where is true for @values
297             Parameters:
298            
299             =over
300            
301             $table = STRING - name of the table
302             \%where = HASH - a L where hash
303             \@values = LIST - list of values to replace placeholders
304            
305             =back
306            
307             Uses do for single deletes, or prepare and a loop for multiple. Values must
308             contain arrayref of arrayrefs if used.
309            
310             =cut
311            
312             sub delete {
313 0     0 1   my ( $self, $table, $where, $values ) = @_;
314 0           $self->{success} = 0;
315 0           $table = "$self->{param}->{prefix}$table$self->{param}->{suffix}";
316 0           my $sql = $self->{sql}->sql->delete->from($table)->where( $where )->sql; #$where->{left},$where->{comp},$where->{right} )->sql;
317 0 0         if ($values) {
318 0           my $sth = $self->{dbh}->prepare($sql);
319 0 0         if ( ref( $values->[0] ) eq 'ARRAY' ) {
320 0           foreach my $value ( @$values ) {
321 0 0 0       $sth->execute(@$value) && {$self->{success} = 1} || croak("Cannot insert to $table: SQL = $sql VALUES = @$value\n $DBI::errstr\n");
322 0 0         carp "SQL $sql VALUES @$value$self->{param}->{debug_newline}" if $self->{param}->{debug};
323             }#foreach
324             }#if
325             }#if
326             else {
327 0 0 0       $self->{dbh}->do($sql) && {$self->{success} = 1} || croak("Cannot delete from $table: SQL = $sql\n $DBI::errstr\n");
328 0 0         carp "SQL $sql$self->{param}->{debug_newline}" if $self->{param}->{debug};
329             }#if
330 0           return $self->{success};
331             }#sub
332            
333            
334             =head2 update
335            
336             Usage
337            
338             $db->update( $table, \@columns, \@data, \%where );
339             $db->update( $table, \@columns, \%data, \%where );
340             $db->update( $table, \%data, \%where );
341             $db->update( $table, \@columns, [ \@data, \@data, ... ], \%where );
342             $db->update( $table, \@columns, [ \%data, \%data, ... ], \%where );
343             $db->update( $table, [ \%data, \%data, ... ], \%where );
344            
345             Purpose : Updates \@data into the \@columns of $table where %where is true
346             Parameters:
347            
348             =over
349            
350             $table = STRING - name of the table
351             \@columns = LIST - array reference to column names
352             \@data = LIST - array reference to values
353             \%data = HASH - hash reference to values keyed by column names
354             \%where = HASH - a L where hash
355            
356             =back
357            
358             Uses do for single upates, or prepare and a loop for multiple. If columns is
359             ommitted and %data is a hash (or arrary ref of hashes) then the hash keys are
360             used as the columns. If %data is a hash and columns is passed, then other hash
361             keys are ignored.
362            
363             =cut
364            
365             sub update {
366 0     0 1   my ( $self, $table, $columns, $data, $where ) = @_;
367 0           $self->{success} = 0;
368 0           $table = "$self->{param}->{prefix}$table$self->{param}->{suffix}";
369 0           my $sql = $self->{sql}->sql->update($table);
370            
371             # See if columns is actually data and columns need to be generated
372 0 0         if ( ref( $columns ) eq 'HASH' ) {
373 0           $data = $columns;
374 0           $columns = [ keys %$data ];
375             }#if
376 0 0 0       if ( ref( $columns ) eq 'ARRAY' && ref( $columns->[0] ) eq 'HASH' ) {
377 0           $data = $columns;
378 0           $columns = [ keys %{ $data->[0] } ];
  0            
379             }#if
380            
381             # Create values for update
382 0           my $values = [];
383 0 0         if ( ref( $data ) eq 'ARRAY' ) {
    0          
384 0           $values = $data;
385             }#if
386             elsif ( ref( $data ) eq 'HASH' ) {
387 0           foreach my $column (@$columns) {
388 0           push( @$values, $data->{$column} );
389             }#foreach
390             }#else
391            
392             # Check for multiple update
393 0 0         if ( ref( $values->[0] ) ) {
394 0           $sql = $sql->set( map { $_ => '?' } @$columns )->where( $where )->sql;
  0            
395 0           my $sth = $self->{dbh}->prepare($sql);
396 0 0         if ( ref( $values->[0] ) eq 'ARRAY' ) {
    0          
397 0           foreach my $values ( @$data ) {
398 0 0 0       $sth->execute(@$values) && {$self->{success} = 1} || croak("Cannot update $table: SQL = $sql VALUES = @$values\n $DBI::errstr\n");
399 0 0         carp "SQL $sql VALUES @$values$self->{param}->{debug_newline}" if $self->{param}->{debug};
400             }#foreach
401             }#if
402             elsif ( ref( $data->[0] ) eq 'HASH' ) {
403 0           foreach my $valuehash ( @$data ) {
404 0           my @values;
405 0           foreach my $column (@$columns) {
406 0           push( @values, $valuehash->{$column} );
407             }#foreach
408 0 0 0       $sth->execute(@values) && {$self->{success} = 1} || croak("Cannot update $table: SQL = $sql VALUES = @values\n $DBI::errstr\n");
409 0 0         carp "SQL $sql VALUES @$values$self->{param}->{debug_newline}" if $self->{param}->{debug};
410             }#foreach
411             }#else
412 0           $sth->finish();
413             }#if
414             else {
415 0           $sql = $sql->set( map { $columns->[$_] => $values->[$_] } 0..$#{$columns} )->where( $where )->sql;
  0            
  0            
416 0 0 0       $self->{dbh}->do($sql) && {$self->{success} = 1} || croak("Cannot update $table: SQL = $sql\n $DBI::errstr\n");
417 0 0         carp "SQL $sql $self->{param}->{debug_newline}" if $self->{param}->{debug};
418             }#else
419 0           return $self->{success};
420             }#sub
421            
422            
423             =head1 INTERNAL FUNCTIONS
424            
425            
426             =head1 BUGS
427            
428             Use RT, or you'll probably get a better responce on the mailing list.
429            
430             =head1 SUPPORT
431            
432             Mailing list coming soon
433            
434             =head1 AUTHOR
435            
436             Lyle Hopkins
437             CPAN ID: cosmicnet
438             Bristol & Bath Perl Moungers
439             cosmicnet@cpan.org
440             http://perl.bristolbath.org
441            
442             =head1 COPYRIGHT
443            
444             This program is free software; you can redistribute
445             it and/or modify it under the same terms as Perl itself.
446            
447             The full text of the license can be found in the
448             LICENSE file included with this module.
449            
450            
451             =head1 SEE ALSO
452            
453             perl(1).
454            
455             =cut
456            
457            
458             1;