File Coverage

blib/lib/DBIx/Fast.pm
Criterion Covered Total %
statement 264 292 90.4
branch 77 112 68.7
condition 25 33 75.7
subroutine 34 36 94.4
pod 20 20 100.0
total 420 493 85.1


line stmt bran cond sub pod time code
1             package DBIx::Fast;
2              
3 8     8   902098 use strict;
  8         19  
  8         348  
4 8     8   61 use warnings;
  8         19  
  8         725  
5              
6             our $VERSION = '0.15';
7              
8 8     8   58 use Carp;
  8         16  
  8         693  
9 8     8   5536 use Moo;
  8         77310  
  8         76  
10              
11 8     8   28408 use DBI;
  8         199364  
  8         816  
12 8     8   6901 use DBIx::Connector;
  8         63162  
  8         405  
13 8     8   9292 use SQL::Abstract;
  8         221131  
  8         42538  
14              
15             has args => ( is => 'rwp' );
16             has db => ( is => 'rw' );
17             has dbd => ( is => 'rwp' );
18             has dsn => ( is => 'rwp' ); # DSN String
19             has errors => ( is => 'rwp' ); # Array errors
20             has results => ( is => 'rw' ); # Last return
21             has sql => ( is => 'rw' ); # SQL Actual
22             has p => ( is => 'rw' );
23             has Q => ( is => 'rw' ); # SQL::Abstract
24             has Tables => ( is => 'rwp' );
25              
26             has last_id => ( is => 'rw' );
27             has last_error => ( is => 'rwp' );
28             has last_sql => ( is => 'rw' );
29              
30             sub now {
31 9     9 1 44 my $self = shift;
32 9         277 my ($sec, $min, $hour, $mday, $mon , $year) = localtime;
33              
34             ## MySQL / MariaDB
35 9         160 return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year + 1900, $mon + 1, $mday, $hour, $min, $sec);
36             }
37              
38             sub set_error {
39 2     2 1 5 my $self = shift;
40              
41 2         35 my $error = {
42             id => shift,
43             error => shift,
44             time => time()
45             };
46              
47 2         10 my $Errors = $self->errors;
48 2         5 push @{$Errors} ,$error;
  2         5  
49              
50 2         35 $self->_set_last_error(qq{$error->{time} - [$error->{id}] - $error->{error}});
51 2         11 $self->_set_errors($Errors);
52             }
53              
54             sub BUILD {
55 12     12 1 1810494 my ($self,$args) = @_;
56              
57             # Force all
58 12 100       59 if ( $args->{Error} ) {
59 3         12 $args->{RaiseError} = 1;
60 3         10 $args->{PrintError} = 0;
61             }
62              
63             # SQLite
64 12 100       48 if ( $args->{SQLite} ) {
65 8 50       290 $self->Exception("No DB Found : ".$args->{SQLite}) unless -e $args->{SQLite};
66 8         49 $args->{db} = $args->{SQLite};
67 8         34 $args->{driver} = 'SQLite'
68             }
69              
70             my $DConf = {
71             DBI => {
72             RaiseError => $args->{RaiseError} // 1,
73             PrintError => $args->{PrintError} // 0,
74             AutoCommit => $args->{AutoCommit} // 1
75             },
76             Auth => {
77             user => $args->{user} // '',
78             password => $args->{password} // '',
79             host => $args->{host} // ''
80             },
81             tn => $args->{tn} // 1,
82             db => $args->{db} // '',
83             dsn => $args->{dsn} // '',
84             driver => $args->{driver} // '',
85             quote => $args->{quote} // '',
86             trace => $args->{trace} // '',
87             profile => $args->{profile} // '',
88 12   100     706 abstract => $args->{abstract} // 1
      100        
      50        
      50        
      50        
      50        
      50        
      100        
      50        
      100        
      100        
      100        
      100        
      100        
89             };
90              
91 12 50       93 $DConf->{DBI}->{mysql_enable_utf8} = 1 if $args->{mysql_enable_utf8};
92              
93 12         90 $self->_set_args($DConf);
94              
95 12 100       242 $self->Q( SQL::Abstract->new ) if $self->args->{abstract};
96            
97             # No DSN or Host
98 12 100 66     2739 unless ( $self->args->{dsn} || $self->args->{db} ) {
99 2         10 $self->Exception("Need a DSN or Host");
100             }
101              
102 10 50       116 $self->_set_dsn($self->args->{dsn} ? $self->_check_dsn($self->args->{dsn}) : $self->_make_dsn($self->args));
103              
104             $self->db( DBIx::Connector->new( $self->dsn,
105             $self->args->{Auth}->{user}, $self->args->{Auth}->{password},
106 10         195 $self->args->{DBI} ) );
107              
108 10         274 $self->db->mode('ping');
109              
110 10 100       222 $self->db->dbh->quote($self->args->{quote}) if $self->args->{quote};
111              
112             $self->db->dbh->{HandleError} = sub {
113 2     2   397 $self->set_error($DBI::err,$DBI::errstr);
114 10         6488 };
115              
116 10 100       57182 $self->db->dbh->trace($self->args->{trace},'dbix-fast-trace') if $self->args->{trace};
117              
118 10 100       430 $self->_profile($self->args->{profile}) if $self->args->{profile};
119              
120             ## Set TablesName
121             #$self->_TablesName() if $self->args->{tn};
122             }
123              
124             sub _TablesName {
125 0     0   0 my $self = shift;
126              
127 0         0 return $self->all('tables'); #SHOW TABLES()');
128             }
129              
130             sub _Driver_dbd {
131 35     35   4213 my $self = shift;
132 35         80 my $dbd = shift;
133              
134 35 50       101 $self->Exception("Error DBD Driver") unless $dbd;
135              
136 35 100       82 map { $self->_set_dbd($_) if lc($dbd) eq lc($_) } qw(SQLite Pg MariaDB mysql);
  140         665  
137              
138 35 50       148 $self->Exception("Error DBD Driver : $dbd") unless $self->dbd;
139             }
140              
141             sub _dsn_dbi {
142 6     6   9 my $self = shift;
143 6         15 my $dsn = shift;
144              
145 6         32 my ($dbi,$driver,$db,$host) = split ':', $dsn;
146              
147 6 50       23 $self->Exception("DSN DBI: $dbi") unless $dbi eq 'dbi';
148              
149             # if ( $driver eq 'SQLite' ) {
150             # $db =~ s/^(dbname|database)\=(.*)$/$2/;
151             # } elsif ( $driver eq 'Pg' ) {
152             # } else {
153             # $self->Exception("DSN Host") unless $host;
154             # }
155              
156 6 100       28 $self->Exception("DSN DataBase: $db") unless $db;
157              
158 5         19 $self->_Driver_dbd($driver);
159              
160 5         60 return $dsn;
161             }
162              
163              
164             sub _check_dsn {
165 7     7   4662 my $self = shift;
166 7         19 my $dsn = shift;
167              
168             ## DSN DBI = ^dbi
169 7 100       48 return $self->_dsn_dbi($dsn) if $dsn =~ /^dbi/;
170              
171             ## DSN to DBI
172 1         5 return $self->_dsn_to_dbi($dsn);
173             }
174              
175             sub _make_dsn {
176 14     14   37 my $self = shift;
177 14         54 my $args = shift;
178              
179 14 50       75 $self->Exception("DSN Driver: Not defined") unless $args->{driver};
180              
181 14         109 $self->_Driver_dbd($args->{driver});
182              
183 14 100       98 return 'dbi:SQLite:dbname='.$args->{db} if $args->{driver} eq 'SQLite';
184              
185 3 50       22 $self->Exception("DSN Host: Not defined") unless $args->{host};
186 3 50       10 $self->Exception("DSN DB: Not defined") unless $args->{db};
187              
188 3         24 return 'dbi:'.$self->dbd.':database='.$args->{db}.':'.$args->{host};
189             }
190              
191             sub _dsn_to_dbi {
192 12     12   10947 my $self = shift;
193 12         26 my $dsn = shift;
194 12         23 my $URI;
195              
196             #SQLite
197 12 50       50 if ( $dsn =~ /^sqlite:\/\/\/(.*)$/ ) {
198 0         0 $self->_set_dbd('SQLite');
199 0         0 return 'dbi:SQLite:dbname='.$1; # , schema => 'sqlite' , db => $1 };
200             }
201              
202 12         179 ($URI->{schema},$URI->{UI},$URI->{connect},$URI->{db}) = ( $dsn =~ /^(.*):\/\/(.*)\@(.*)\/(.*)$/g );
203              
204 12 100       47 $self->Exception("_dsn_to_dbi : schema") unless $URI->{schema};
205              
206 11         46 $self->_Driver_dbd($URI->{schema});
207            
208 11 50       35 $self->Exception("_dsn_to_dbi : connect") unless $URI->{connect};
209              
210 11 100       90 $URI->{connect} =~ /:/ ? ($URI->{host},$URI->{port}) = split ':',$URI->{connect} : $URI->{host} = $URI->{connect};
211              
212             # UserInfo
213 11 100       39 if ( $URI->{UI} =~ /:/ ) {
214 8         41 ($URI->{user},$URI->{password}) = split ':',$URI->{UI};
215 8         23 my $SetArgs = $self->args;
216 8         21 $SetArgs->{Auth}->{user} = $URI->{user};
217 8         20 $SetArgs->{Auth}->{password} = $URI->{password};
218 8         28 $self->_set_args($SetArgs);
219             } else {
220             $URI->{user} = $URI->{UI}
221 3         12 }
222              
223 11 50       32 $self->Exception('_dsn_to_dbi : No DB value') unless $URI->{db};
224            
225             ## Loop Attrs + Value
226 11 100       55 if ( $URI->{db} =~ s/^(.*)\?(.*)$/$1/ ) {
227 3         27 ($URI->{attribute},$URI->{value}) = split '=',$2;
228             }
229              
230 11 100       65 if ( $dsn =~ /^(postgres|postgresql):/ ) {
    100          
    100          
231 3         13 $self->_set_dbd('Pg');
232 3         10 $URI->{DSN} = 'dbi:Pg:dbname='.$URI->{db}.';host='.$URI->{host}.';port='.$URI->{port};
233             } elsif ( $dsn =~ /^(mariadb):/ ) {
234 2         8 $self->_set_dbd('MariaDB');
235 2         8 $URI->{DSN} = 'dbi:MariaDB:dbname='.$URI->{db}.';host='.$URI->{host}.';port='.$URI->{port};
236             } elsif ( $dsn =~ /^(mysql|mysqlx):/ ) {
237 2         7 $self->_set_dbd('mysql');
238 2         9 $URI->{DSN} = 'dbi:mysql:dbname='.$URI->{db}.';host='.$URI->{host}.';port='.$URI->{port};
239             } else {
240 4         22 $self->Exception("_dsn_to_dbi : $dsn");
241             }
242              
243 7         54 return $URI->{DSN};
244             }
245              
246             sub _profile {
247 1     1   2 my $self = shift;
248 1         3 my $stat = shift."/DBI::ProfileDumper/";
249              
250 1         6 $stat .= qq{File:dbix-fast-$$.log};
251              
252 1         6 $self->db->dbh->{Profile} = $stat;
253             }
254              
255             sub all {
256 1     1 1 1834 my $self = shift;
257              
258 1         6 $self->q(@_);
259              
260             my $res = $self->db->dbh->selectall_arrayref($self->sql,
261 1         8 { Slice => {} },@{$self->p});
  1         122  
262              
263 1 50       278 $self->Exception("ERROR all()") if $DBI::err;
264              
265 1         6 $self->results($res);
266             }
267              
268             sub flat {
269 2     2 1 3292 my $self = shift;
270              
271 2         11 $self->q(@_);
272              
273 2         11 my $sth = $self->db->dbh->prepare($self->sql);
274              
275 2         360 $sth->execute(@{$self->p});
  2         137  
276              
277 2         6 my @Flat;
278              
279 2         31 while(my $row = $sth->fetchrow_array) {
280 12         65 push @Flat,$row;
281             }
282              
283 2         11 $self->results(\@Flat);
284              
285 2         30 return @Flat;
286             }
287              
288             sub hash {
289 1     1 1 900 my $self = shift;
290              
291 1         6 $self->q(@_);
292              
293 1         8 my $sth = $self->db->dbh->prepare($self->sql);
294              
295 1         197 $sth->execute(@{$self->p});
  1         67  
296              
297 1         53 my $res = $sth->fetchrow_hashref;
298              
299 1 50       10 $self->Exception("hash()") if $DBI::err;
300              
301 1         24 $self->results($res);
302             }
303              
304             sub val {
305 3     3 1 3141 my $self = shift;
306              
307 3         19 $self->q(@_);
308              
309 3         97 my $ret = $self->db->dbh->selectrow_array($self->sql, undef, @{$self->p});
  3         421  
310              
311 3 50       769 $self->Exception("val()") if $DBI::err;
312              
313 3         23 return $ret;
314             }
315              
316             sub array {
317 1     1 1 699 my $self = shift;
318              
319 1         5 $self->q(@_);
320              
321 1         9 my $sth = $self->db->dbh->prepare($self->sql);
322              
323 1         196 $sth->execute(@{$self->p});
  1         79  
324              
325 1 50       9 $self->Exception("array()") if $DBI::err;
326              
327 1         3 my @rows = @{ $self->db->dbh->selectcol_arrayref( $self->sql, undef, @{ $self->p } ) };
  1         6  
  1         91  
328              
329 1         144 $self->results(\@rows);
330             }
331              
332             sub count {
333 2     2 1 1359 my $self = shift;
334 2         10 my $table = $self->TableName(shift);
335 2         5 my $skeel = shift;
336              
337 2         12 $self->sql("SELECT COUNT(*) FROM $table");
338              
339 2 100       12 return $self->db->dbh->selectrow_array($self->sql)
340             unless $skeel;
341              
342 1         6 $self->_make_where($skeel);
343              
344 1         45 return $self->db->dbh->selectrow_array($self->sql, undef, @{$self->p});
  1         122  
345             }
346              
347             sub _make_where {
348 5     5   9 my $self = shift;
349 5         10 my $skeel = shift;
350 5         8 my @p;
351              
352 5         10 my $sql = " WHERE ";
353              
354 5         8 for my $K ( keys %{$skeel} ) {
  5         21  
355 5         28 my $key;
356              
357 5 100       20 if ( ref $skeel->{$K} eq 'HASH' ) {
358 4         8 $key = (keys %{$skeel->{$K}})[0];
  4         13  
359 4         15 push @p,$skeel->{$K}->{$key};
360             } else {
361 1         2 $key = '=';
362 1         2 push @p,$skeel->{$K};
363             }
364              
365 5         17 $sql .= qq{$K $key ? };
366             }
367              
368 5         14 $sql =~ s/,$//;
369              
370 5         30 $self->sql($self->sql.$sql);
371 5         20 $self->p(\@p);
372             }
373              
374             sub execute {
375 2     2 1 1209 my $self = shift;
376 2         6 my $sql = shift;
377 2         4 my $extra = shift;
378 2   50     14 my $type = shift // 'arrayref';
379 2         4 my $res;
380              
381 2         11 $self->sql($sql);
382              
383             ## Extra Arguments
384 2 50       7 $self->make_sen($extra) if $extra;
385              
386 2 50       15 if ( $type eq 'hash' ) {
387 0         0 my $sth = $self->db->dbh->prepare($self->sql);
388 0 0       0 if ( $self->p ) {
389 0         0 $sth->execute(@{$self->p});
  0         0  
390             } else {
391 0         0 $sth->execute;
392             }
393 0         0 $res = $sth->fetchrow_hashref;
394             } else {
395 2 50       40 if ($self->p ) {
396             $res = $self->db->dbh->selectall_arrayref($self->sql,
397 2         45 { Slice => {} },@{$self->p});
  2         268  
398             } else {
399 0         0 $res = $self->db->dbh->selectall_arrayref($self->sql,
400             { Slice => {} } );
401             }
402             }
403              
404 2 50       23 $self->Exception("execute()") if $DBI::err;
405              
406 0         0 $self->results($res);
407             }
408              
409             sub up {
410 1     1 1 1265 my ($self,$table,$data,$where,$time) = @_;
411              
412 1 50       6 if ( $time ) {
413 1         6 $self->update( $self->TableName($table) , { sen => $data , where => $where } , time => $time );
414             } else {
415 0         0 $self->update( $self->TableName($table) , { sen => $data , where => $where } );
416             }
417             }
418              
419             sub update {
420 2     2 1 2359 my $self = shift;
421 2         9 my $table = $self->TableName(shift);
422 2         5 my $skeel = shift;
423              
424 2 50       17 $skeel->{sen} = $self->extra_args($skeel->{sen},@_) if scalar @_ > 0;
425              
426 2         23 my @p;
427 2         7 my $sql = "UPDATE $table SET ";
428              
429 2         4 for ( keys %{$skeel->{sen}} ) {
  2         11  
430 4         11 push @p,$skeel->{sen}->{$_};
431 4         12 $sql .= $_.' = ? ,';
432             }
433              
434 2         17 $sql =~ s/,$//;
435 2         6 $sql .= 'WHERE ';
436              
437 2         3 for my $K ( keys %{$skeel->{where}} ) {
  2         8  
438 2         31 push @p,$skeel->{where}->{$K};
439 2         8 $sql .= $K.' = ? AND ';
440             }
441              
442 2         11 $sql =~ s/AND $//;
443              
444 2         12 $self->sql($sql);
445 2         8 $self->execute_prepare(@p);
446             }
447              
448             sub insert {
449 6     6 1 3114 my $self = shift;
450 6         24 my $table = $self->TableName(shift);
451 6         14 my $skeel = shift;
452              
453 6 50       80 $skeel = $self->extra_args($skeel,@_) if scalar @_ > 0;
454              
455 6         11 my @p;
456 6         14 my $sql= "INSERT INTO $table ( ";
457              
458 6         12 for ( keys %{$skeel} ) {
  6         26  
459 13         33 push @p,$skeel->{$_};
460 13         27 $sql .= $_.',';
461             }
462              
463 6         48 $sql =~ s/,$/ )/;
464 6         25 $sql .= ' VALUES ( '.join(',', ('?') x @p).' )';
465              
466 6         27 $self->sql($sql);
467 6         23 $self->execute_prepare(@p);
468              
469 6 50       67 if ( $self->dbd eq 'MariaDB' ) {
    50          
    50          
    0          
470 0         0 $self->last_id($self->db->dbh->{mariadb_insertid});
471             } elsif ( $self->dbd eq 'mysql' ) {
472 0         0 $self->last_id($self->db->dbh->{mysql_insertid});
473             } elsif ( $self->dbd eq 'SQLite' ) {
474 6         53 $self->last_id($self->db->dbh->sqlite_last_insert_rowid());
475             } elsif ( $self->dbd eq 'Pg' ) {
476 0         0 $self->last_id($self->db->dbh->last_insert_id(undef,undef,$table,undef));
477             }
478             }
479              
480             sub delete {
481 4     4 1 2087 my $self = shift;
482 4         15 my $table = $self->TableName(shift);
483 4         8 my $skeel = shift;
484              
485 4         18 $self->sql("DELETE FROM $table");
486              
487             #unless ( $skeel ) {
488             # return $self->db->dbh->selectrow_array($self->sql);
489             #}
490              
491 4         16 $self->_make_where($skeel);
492              
493 4         21 my $sth = $self->db->dbh->prepare($self->sql);
494              
495 4         1949 $sth->execute(@{$self->p});
  4         25707  
496             }
497              
498             sub extra_args {
499 8     8 1 35 my $self = shift;
500 8         17 my $skeel = shift;
501 8         39 my %args = @_;
502              
503 8 50       52 $skeel->{$args{time}} = $self->now() if $args{time};
504              
505 8         37 return $skeel;
506             }
507              
508             sub make_sen {
509 0     0 1 0 my $self = shift;
510 0         0 my $skeel = shift;
511 0         0 my $sql = $self->sql();
512 0         0 my @p;
513              
514             ## Ha de encontrar resultados por el orden de entrada parsear debidamente
515 0         0 for ( keys %{$skeel} ) {
  0         0  
516 0         0 my $arg = ':'.$_;
517 0         0 push @p,$skeel->{$_};
518 0         0 $sql =~ s/$arg/\?/;
519             }
520              
521 0         0 $sql =~ s/,$//;
522              
523 0         0 $self->sql($sql);
524 0         0 $self->p(\@p);
525             }
526              
527             sub q {
528 8     8 1 18 my $self = shift;
529 8         18 my $sql = shift;
530 8         13 my @p;
531              
532 8         20 map { push @p,$_ } @_;
  2         10  
533              
534 8         33 $self->sql($sql);
535 8         39 $self->p(\@p);
536             }
537              
538             sub execute_prepare {
539 8     8 1 15 my $self = shift;
540 8         22 my @p = @_;
541              
542 8         46 my $sth = $self->db->dbh->prepare($self->sql);
543              
544 8         112768 $sth->execute(@p);
545              
546 8 50       659 $self->Exception("execute_prepare()") if $DBI::err;
547            
548 8         377 $self->last_sql($self->sql);
549             }
550              
551             sub TableName {
552 17     17 1 1745 my $self = shift;
553 17         34 my $table = shift;
554              
555 17 50       65 $self->Exception("TableName not defined") unless $table;
556              
557 17 50       93 if ( $self->args->{TableName} ) {
558              
559             }
560            
561 17 100       115 return $table unless $table =~ /\W/;
562              
563 1         6 $self->Exception("TableName not valid: $table");
564             }
565              
566             sub Exception {
567 12     12 1 1375 my $self = shift;
568 12         29 my $msg = shift;
569              
570 12 100       60 unless ( $self->args->{DBI}->{RaiseError} ) {
571 8 50       28 die unless $self->args->{DBI}->{PrintError};
572             }
573              
574 12         50 my $out = "Exception: $msg";
575              
576 12 100       41 $out .= " - Last error: ".$self->last_error if $self->last_error;
577              
578 12         1147 croak $out;
579             }
580              
581             1;
582              
583             __END__