File Coverage

blib/lib/Pinwheel/Database/Base.pm
Criterion Covered Total %
statement 112 116 96.5
branch 32 32 100.0
condition 20 23 86.9
subroutine 16 18 88.8
pod 0 13 0.0
total 180 202 89.1


line stmt bran cond sub pod time code
1             package Pinwheel::Database::Base;
2              
3 2     2   10 use strict;
  2         4  
  2         70  
4 2     2   10 use warnings;
  2         3  
  2         47  
5              
6 2     2   30228 use DBI;
  2         146227  
  2         7536  
7              
8             sub new
9             {
10 2     2 0 5 my $class = shift;
11 2         20 my $self = {
12             dbh => undef,
13             dbconfig => \@_,
14             connect_time => 0,
15             dbh_checked => 0,
16             dbhostname => undef,
17             prepared => {},
18             orphans => [],
19             };
20 2         11 return bless($self, $class);
21             }
22              
23              
24             sub connect
25             {
26 14     14 0 21 my ($dbh_age, $reconnect);
27 14         23 my $self = shift;
28              
29 14   100     77 $dbh_age = time() - ($self->{connect_time} || 0);
30 14 100 100     116 if (!$self->{dbh} || !$self->{dbh}->ping) {
    100          
31 8         22 $reconnect = 1;
32             } elsif ($dbh_age >= 300) {
33 1         147 finish_all();
34 1         49 $self->{dbh}->disconnect;
35 1         4 $self->{dbhostname} = undef;
36 1         2 $reconnect = 1;
37             } else {
38 5         274 $reconnect = 0;
39             }
40              
41 14 100       38 if ($reconnect) {
42 9         25 $self->{prepared} = {};
43 9         465 $self->{orphans} = [];
44 9         17 $self->{dbh} = DBI->connect(@{$self->{dbconfig}});
  9         67  
45 9         108284 $self->{dbh}->{unicode} = 1;
46 9         35 $self->{connect_time} = time();
47 9         27 $self->{ping_time} = time();
48             }
49            
50             # We have now checked that we are connected
51 14         50 $self->{dbh_checked} = 1;
52             }
53              
54             sub disconnect
55             {
56 3     3 0 7 my $self = shift;
57 3 100       13 if ($self->{dbh}) {
58 2         7 $self->finish_all();
59 2         119 $self->{dbh}->disconnect;
60 2         6 $self->{dbh} = undef;
61 2         3 $self->{dbh_checked} = 0;
62 2         7 $self->{dbhostname} = undef;
63             }
64             }
65              
66             sub do
67             {
68 29     29 0 82 my $self = shift;
69 29 100 66     270 $self->connect() if (!$self->{dbh} || !$self->{dbh_checked});
70 29         691 return $self->{dbh}->do(@_);
71             }
72              
73             sub describe
74             {
75 0     0 0 0 warn "Database specific sub-classes should redefine this method";
76 0         0 return undef;
77             }
78              
79             sub tables
80             {
81 0     0 0 0 warn "Database specific sub-classes should redefine this method";
82 0         0 return undef;
83             }
84              
85             sub without_foreign_keys
86             {
87             ## Database specific sub-classes should redefine this method if required
88 11     11 0 30 my ($self, $block) = @_;
89 11         246 &$block();
90             }
91              
92             sub dbhostname
93             {
94 2     2 0 14 return $_[0]->{dbhostname};
95             }
96              
97             sub prepare
98             {
99 196     196 0 479 my ($self, $query, $transient) = @_;
100 196         423 my $sth;
101              
102 196 100 66     4010 $self->connect() if (!$self->{dbh} || !$self->{dbh_checked});
103              
104 196         2249 $sth = $self->{prepared}->{$query};
105 196 100       733 if ($sth) {
106 146 100       3425 return $sth unless $sth->{Active};
107 3         9 push(@{$self->{orphans}}, $sth);
  3         11  
108             }
109              
110 53         796 $sth = $self->{dbh}->prepare($query);
111 53 100       12512 $self->{prepared}->{$query} = $sth unless $transient;
112 53         352 return $sth;
113             }
114              
115             sub selectcol_array
116             {
117 7     7 0 21 my ($self, $statement) = @_;
118 7         29 my $sth = $self->prepare($statement);
119 7         2076 $sth->execute();
120 7         22 my @result = ();
121 7         96 while (my ($col) = $sth->fetchrow_array()) {
122 28         248 push(@result, $col);
123             }
124 7         49 return @result;
125             }
126              
127             sub finish_all
128             {
129 6     6 0 13 my $self = shift;
130 6         9 foreach my $sth (values(%{$self->{prepared}})) {
  6         25  
131 2 100       30 $sth->finish() if ($sth->{Active});
132             }
133 6         13 foreach my $sth (@{$self->{orphans}}) {
  6         17  
134 3 100       39 $sth->finish() if ($sth->{Active});
135             }
136 6         15 $self->{orphans} = [];
137 6         126 $self->{dbh_checked} = 0; # The database connection needs re-checking
138             }
139              
140             sub fetchone_tables
141             {
142 5     5 0 12 my ($self, $sth, $tables) = @_;
143 5         10 my ($slices, $row);
144              
145 5 100 100     43 if (!$tables || scalar(@$tables) == 0) {
146 2         54 $row = $sth->fetchrow_hashref();
147 2 100       13 return undef unless $row;
148 1         7 return { '' => $row };
149             }
150              
151 3         11 $slices = _get_column_slices($sth);
152 3         25 $row = $sth->fetchrow_arrayref();
153 3 100       22 return undef unless $row;
154 2         9 return _extract_table_data($slices, $tables, $row);
155             }
156              
157             sub fetchall_tables
158             {
159 4     4 0 10 my ($self, $sth, $tables) = @_;
160              
161 4 100 100     69 if (!$tables || scalar(@$tables) == 0) {
162 2         4 my @result = map { { '' => $_ } } @{$sth->fetchall_arrayref({})};
  3         198  
  2         30  
163 2         74 return \@result;
164             }
165              
166 2         4 my (@result, $slices, $row);
167 2         7 $slices = _get_column_slices($sth);
168 2         40 while ($row = $sth->fetchrow_arrayref()) {
169 5         14 push @result, _extract_table_data($slices, $tables, $row);
170             }
171 2         13 return \@result;
172             }
173              
174             sub _get_column_slices
175             {
176 5     5   9 my $sth = shift;
177 5         8 my ($columns, @slices, $i, $j);
178              
179 5         87 $columns = $sth->{NAME_lc};
180 5         28 for ($i = 0, $j = 0; $j <= @$columns; $j++) {
181 29 100 100     171 if ($j == @$columns || ($j > 0 && $columns->[$j] eq 'id')) {
      66        
182 9         32 my @slice = ($i .. $j - 1);
183 9         42 push @slices, [[@$columns[@slice]], \@slice];
184 9         29 $i = $j;
185             }
186             }
187              
188 5         14 return \@slices;
189             }
190              
191             sub _extract_table_data
192             {
193 7     7   14 my ($slices, $tables, $row) = @_;
194 7         8 my (%result, $i, $name, $keys, $slice);
195              
196 7         8 $i = 0;
197 7         13 $name = '';
198 7         9 do {
199 14         14 my %data;
200 14         16 ($keys, $slice) = @{$slices->[$i]};
  14         29  
201 14         70 @data{@$keys} = @$row[@$slice];
202 14         66 $result{$name} = \%data;
203             } while ($name = $tables->[$i++]);
204              
205 7         88 return \%result;
206             }
207              
208             1;
209              
210             __DATA__