File Coverage

blib/lib/Nile/DBI.pm
Criterion Covered Total %
statement 15 111 13.5
branch 0 48 0.0
condition 0 36 0.0
subroutine 5 26 19.2
pod 0 21 0.0
total 20 242 8.2


line stmt bran cond sub pod time code
1             # Copyright Infomation
2             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3             # Author : Dr. Ahmed Amin Elsheshtawy, Ph.D.
4             # Website: https://github.com/mewsoft/Nile, http://www.mewsoft.com
5             # Email : mewsoft@cpan.org, support@mewsoft.com
6             # Copyrights (c) 2014-2015 Mewsoft Corp. All rights reserved.
7             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8             package Nile::DBI;
9              
10             our $VERSION = '0.55';
11             our $AUTHORITY = 'cpan:MEWSOFT';
12              
13             =pod
14              
15             =encoding utf8
16              
17             =head1 NAME
18              
19             Nile::DBI - SQL database manager.
20              
21             =head1 SYNOPSIS
22            
23             # set database connection params to connect
24             # $arg{driver}, $arg{host}, $arg{dsn}, $arg{port}, $arg{attr}
25             # $arg{name}, $arg{user}, $arg{pass}
26             # if called without params, it will try to load from the default config vars.
27              
28             # get app context
29             $app = $self->app;
30              
31             $dbh = $app->db->connect(%arg);
32            
33             =head1 DESCRIPTION
34              
35             Nile::DBI - SQL database manager.
36              
37             =cut
38              
39 1     1   5 use Nile::Base;
  1         1  
  1         8  
40 1     1   7107 use DBI;
  1         13641  
  1         65  
41 1     1   744 use DBI::Profile;
  1         2557  
  1         58  
42 1     1   404 use DBI::ProfileDumper;
  1         1178  
  1         37  
43 1     1   516 use Hash::AsObject;
  1         578  
  1         5  
44             #my $hash = Hash::AsObject->new(\%hash); $hash->foo(27); print $hash->foo; print $hash->baz->quux;
45              
46             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47             =head2 dbh()
48            
49             $app->db->dbh;
50              
51             Get or set the current database connection handle.
52              
53             =cut
54              
55             has 'dbh' => (
56             is => 'rw',
57             );
58             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
59             =head2 connect()
60            
61             $dbh = $app->db->connect(%arg);
62              
63             Connect to the database. If %arg empty, it will try to get arg from the config object.
64             Returns the database connection handle is success.
65              
66             =cut
67              
68             sub connect {
69              
70 0     0 0   my ($self, %arg) = @_;
71 0           my ($dbh, $dsn, $app);
72            
73 0           $app = $self->app;
74            
75 0           my $default = $app->config->get("dbi");
76 0   0       $default ||= +{};
77              
78 0           %arg = (%{$default}, %arg);
  0            
79            
80 0   0       $arg{driver} ||= "mysql";
81 0   0       $arg{dsn} ||= "";
82 0   0       $arg{host} ||= "localhost";
83 0   0       $arg{port} ||= 3306;
84 0   0       $arg{attr} ||= +{};
85             #$arg{attr} = {RaiseError => 0, PrintError => 0, mysql_enable_utf8 => 1}
86              
87 0 0         if (!$arg{name}) {
88 0           $app->abort("Database error: Empty database name.");
89             }
90              
91             #$self->dbh->disconnect if ($self->dbh);
92              
93 0 0         if ($arg{driver} =~ m/ODBC/i) {
94 0 0         $dbh = DBI->connect("DBI:ODBC:$arg{dsn}", $arg{user}, $arg{pass}, $arg{attr})
95             or $self->db_error("$DBI::errstr, DSN: $arg{dsn}");
96             }
97             else {
98 0   0       $arg{dsn} ||= "DBI:$arg{driver}:database=$arg{name};host=$arg{host};port=$arg{port}";
99 0 0         $dbh = DBI->connect($arg{dsn}, $arg{user}, $arg{pass}, $arg{attr})
100             or $self->db_error("$DBI::errstr, DSN: $arg{dsn}");
101             }
102              
103 0           $self->dbh($dbh);
104 0           return $dbh;
105              
106             #$dbh->{'mysql_enable_utf8'} = 1;
107             #$dbh->do('SET NAMES utf8');
108             }
109             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
110             =head2 disconnect()
111            
112             $app->db->disconnect;
113              
114             Disconnect from this connection handle.
115              
116             =cut
117              
118             sub disconnect {
119 0     0 0   my ($self) = @_;
120 0 0         $self->dbh->disconnect if ($self->dbh);
121             }
122             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
123             sub table {
124 0     0 0   my ($self, $name) = @_;
125 0           $self->app->load_once("Nile::DBI::Table");
126 0           $self->app->object("Nile::DBI::Table", (name => $name));
127             }
128             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
129             =head2 run()
130            
131             $app->db->run($qry);
132              
133             Run query using the DBI do command or abort if error.
134              
135             =cut
136              
137             sub run {
138 0     0 0   my ($self, $qry) = @_;
139 0 0         $self->dbh->do($qry) or $self->db_error($qry);
140             }
141             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
142             =head2 do()
143            
144             $app->db->do($qry);
145              
146             Run query using the DBI do command and ignore errors.
147              
148             =cut
149              
150             sub do {
151 0     0 0   my ($self, $qry) = @_;
152 0           $self->dbh->do($qry);
153             }
154             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
155             =head2 exec()
156            
157             $sth = $app->db->exec($qry);
158              
159             Prepare and execute the query and return the statment handle.
160              
161             =cut
162              
163             sub exec {
164 0     0 0   my ($self, $qry) = @_;
165 0 0         my $sth = $self->dbh->prepare($qry) or $self->db_error($qry);
166 0 0         $sth->execute() or $self->db_error($qry);
167 0           return $sth;
168             }
169             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
170             =head2 begin()
171            
172             $app->db->begin;
173              
174             Enable transactions (by turning AutoCommit off) until the next call to commit or rollback. After the next commit or rollback, AutoCommit will automatically be turned on again.
175              
176             =cut
177              
178             sub begin {
179 0     0 0   my ($self) = @_;
180 0 0         return $self->dbh->begin_work or $self->db_error();
181             }
182             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
183             =head2 commit()
184            
185             $app->db->commit;
186              
187             Commit (make permanent) the most recent series of database changes if the database supports transactions and AutoCommit is off.
188              
189             =cut
190              
191             sub commit {
192 0     0 0   my ($self) = @_;
193 0 0         $self->dbh->commit or $self->db_error();
194             }
195             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
196             =head2 rollback()
197            
198             $app->db->rollback;
199              
200             Rollback (undo) the most recent series of uncommitted database changes if the database supports transactions and AutoCommit is off.
201              
202             =cut
203              
204             sub rollback {
205 0     0 0   my ($self) = @_;
206 0 0         $self->dbh->rollback or $self->db_error();
207             }
208             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
209             =head2 quote()
210            
211             $app->db->quote($value);
212             $app->db->quote($value, $data_type);
213              
214             Quote a string literal for use as a literal value in an SQL statement, by escaping any special characters (such as quotation marks)
215             contained within the string and adding the required type of outer quotation marks.
216             =cut
217              
218             sub quote {
219 0     0 0   my ($self, @arg) = @_;
220 0           return $self->dbh->quote(@arg);
221             }
222             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
223             =head2 col()
224            
225             # select id from users. return one column array from all rows
226             @cols = $app->db->col($qry);
227             $cols_ref = $app->db->col($qry);
228              
229             Return one column array from all rows
230              
231             =cut
232              
233             sub col {
234 0     0 0   my ($self, $qry) = @_;
235             # select id from users. return one column array from all rows
236 0           my $ret = $self->dbh->selectcol_arrayref($qry);
237 0 0 0       if (!defined($ret) && $self->dbh->err()) {$self->db_error($qry);}
  0            
238 0 0         return wantarray? @{$ret} : $ret;
  0            
239             }
240             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
241             =head2 row()
242            
243             # select id, email, fname, lname from users
244             @row = $app->db->row($qry);
245              
246             Returns one row as array.
247              
248             =cut
249              
250             sub row {
251 0     0 0   my ($self, $qry) = @_;
252             # select id, email, fname, lname from users
253 0           my @ret = $self->dbh->selectrow_array($qry);
254 0 0 0       if (!@ret && $self->dbh->err()) {$self->db_error($qry);}
  0            
255 0           return @ret;
256             }
257             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
258             =head2 rows()
259            
260             # select id, fname, lname, email from users
261             @rows = $app->db->rows($qry);
262             $rows_ref = $app->db->rows($qry);
263              
264             Returns all matched rows as array or array ref.
265              
266             =cut
267              
268             sub rows {
269 0     0 0   my ($self, $qry) = @_;
270             # select id, fname, lname, email from users
271 0           my $ret = $self->dbh->selectall_arrayref($qry);
272 0 0 0       if (!defined($ret) && $self->dbh->err()) {$self->db_error($qry);}
  0            
273 0 0         return wantarray? @$ret : $ret;
274             }
275             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
276             =head2 hash()
277            
278             # select * from users where id=$id limit 1
279             %user = $app->db->hash($qry);
280             $user_ref = $app->db->hash($qry);
281              
282             Returns one row as a hash or hash ref
283              
284             =cut
285              
286             sub hash {
287 0     0 0   my ($self, $qry) = @_;
288             # select * from users where id=$id limit 1
289 0           my $ret = $self->dbh->selectrow_hashref($qry);
290 0 0 0       if (!defined($ret) && $self->dbh->err()) {$self->db_error($qry);}
  0            
291 0 0         return wantarray? %{$ret} : $ret;
  0            
292             }
293             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
294             =head2 row_object()
295            
296             # select * from users where id=$id limit 1
297             $row_obj = $app->db->row_object($qry);
298             print $row_obj->email;
299             print $row_obj->fname;
300             print $row_obj->lname;
301              
302             Returns one row as object with columns names as object properties.
303              
304             =cut
305              
306             sub row_object {
307 0     0 0   my ($self, $qry) = @_;
308             # select * from users where id=$id limit 1
309 0           my $ret = $self->dbh->selectrow_hashref($qry);
310 0 0 0       if (!defined($ret) && $self->dbh->err()) {$self->db_error($qry);}
  0            
311 0           return Hash::AsObject->new($ret);
312             }
313             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
314             =head2 hashes()
315            
316             %hashes = $app->db->hashes($qry, $col);
317             $hashes_ref = $app->db->hashes($qry, $col);
318              
319             Returns list or hashes of all rows. Each hash element is a hash of one row
320             =cut
321              
322             sub hashes {
323 0     0 0   my ($self, $qry, $col) = @_;
324 0           my $ret = $self->dbh->selectall_hashref($qry, $col);
325 0 0 0       if (!defined($ret) && $self->dbh->err()) {$self->db_error($qry);}
  0            
326 0 0         return wantarray? %{$ret} : $ret;
  0            
327             }
328             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
329             =head2 colhash()
330            
331             # select id, user from users
332             %hash = $app->db->colhash($qry);
333              
334             Returns all rows as a hash of the first column as the keys and the second column as the values.
335              
336             =cut
337              
338             sub colhash {
339 0     0 0   my ($self, $qry) = @_;
340             # select id, user from users
341 0           my %list = map {$_->[0], $_->[1]} @{$self->dbh->selectall_arrayref($qry)};
  0            
  0            
342 0 0         return wantarray? %list : \%list;
343             }
344             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
345             =head2 value()
346            
347             # select email from users where id=123. return one column value
348             $value = $app->db->value($qry);
349              
350             Returns one column value from one row.
351              
352             =cut
353              
354             sub value {
355 0     0 0   my ($self, $qry) = @_;
356             # select email from users where id=123. return one column value
357 0           my $ret = $self->dbh->selectcol_arrayref($qry);
358 0 0 0       if (!defined($ret) && $self->dbh->err()) {$self->db_error($qry);}
  0            
359 0           ($ret) = @{$ret};
  0            
360 0           return $ret;
361             }
362             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
363             =head2 insertid()
364            
365             $id = $app->db->insertid;
366              
367             Returns the last insert id from auto increment.
368              
369             =cut
370              
371             sub insertid {
372 0     0 0   my ($self) = @_;
373 0           return $self->dbh->{mysql_insertid};
374             }
375             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
376             =head2 profile()
377            
378             # level:
379             # 0x01=DBI, 0x02=!Statement ,0x04=!MethodName, 0x06=!Statement:!Method,
380             # 0x08=!MethodClass, 0x10=!Caller2, 0=disable
381              
382             $app->db->profile($level);
383              
384             # this will generate the reports file app/log/dbi.prof
385             # then run the command dbiprof to view it:
386             # dbiprof --number 15 --sort count
387              
388              
389             Enable DBI profiling. See L<DBI::Profile> and L<DBI::ProfileDumper>.
390              
391             =cut
392              
393             sub profile {
394            
395 0     0 0   my ($self, $level) = @_;
396              
397 0 0         if (!$level) {
398 0           $self->dbh->{Profile} = 0;
399 0           return;
400             }
401             # level: ,0x01=DBI, 0x02=!Statement ,0x04=!MethodName, 0x06=!Statement:!Method,
402             # 0x08=!MethodClass, 0x10=!Caller2, 0=disable
403              
404 0           my $file = $self->app->file->catfile($self->app->var->get("log_dir"), "dbi.prof");
405              
406 0           $self->dbh->{Profile} = "$level/DBI::ProfileDumper/File:$file";
407             #then run % dbiprof --number 15 --sort count
408              
409             #shell: >set DBI_PROFILE=2/DBI::ProfileDumper then %perl program.pl
410              
411             #$sth->{Profile} = 4;
412             #$sth->execute; while (@array = $sth->fetchrow_array()) {};
413             #print $sth->{Profile}->format;
414             #finally, disable the profile status, so it does nothing at DESTROY time
415             #$sth->{Profile} = 0;
416             #mysql: mysql>SET profiling=1;mysql>show profiles;mysql>show profile for query 1;
417             }
418             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
419             =head2 db_error()
420            
421             $app->db->db_error;
422              
423             Aborts the application and display the last database error message.
424              
425             =cut
426              
427             sub db_error {
428 0     0 0   my $self = shift;
429 0           $self->app->abort("Database Error: $DBI::errstr<br>@_");
430             }
431             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
432              
433             =pod
434              
435             =head1 Bugs
436              
437             This project is available on github at L<https://github.com/mewsoft/Nile>.
438              
439             =head1 HOMEPAGE
440              
441             Please visit the project's homepage at L<https://metacpan.org/release/Nile>.
442              
443             =head1 SOURCE
444              
445             Source repository is at L<https://github.com/mewsoft/Nile>.
446              
447             =head1 SEE ALSO
448              
449             See L<Nile> for details about the complete framework.
450              
451             =head1 AUTHOR
452              
453             Ahmed Amin Elsheshtawy, احمد امين الششتاوى <mewsoft@cpan.org>
454             Website: http://www.mewsoft.com
455              
456             =head1 COPYRIGHT AND LICENSE
457              
458             Copyright (C) 2014-2015 by Dr. Ahmed Amin Elsheshtawy احمد امين الششتاوى mewsoft@cpan.org, support@mewsoft.com,
459             L<https://github.com/mewsoft/Nile>, L<http://www.mewsoft.com>
460              
461             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
462              
463             =cut
464              
465             1;