File Coverage

blib/lib/Deeme/Backend/DBI.pm
Criterion Covered Total %
statement 145 158 91.7
branch 21 40 52.5
condition 4 6 66.6
subroutine 19 19 100.0
pod 1 8 12.5
total 190 231 82.2


line stmt bran cond sub pod time code
1             package Deeme::Backend::DBI;
2              
3             our $VERSION = '0.04';
4 2     2   31910 use Deeme::Obj 'Deeme::Backend';
  2         6  
  2         16  
5 2     2   5728 use DBI;
  2         30951  
  2         108  
6 2     2   1699 use Deeme::Utils qw(_serialize _deserialize);
  2         3679  
  2         131  
7 2     2   13 use Carp 'croak';
  2         6  
  2         99  
8 2     2   12 use constant EVENT_TABLE => "deeme_events";
  2         4  
  2         228  
9 2     2   12 use constant FUNCTIONS_TABLE => "deeme_functions";
  2         7  
  2         10496  
10             has [qw(database _connection)];
11              
12             sub new {
13 1     1 1 421 my $self = shift;
14 1         14 $self = $self->SUPER::new(@_);
15 1 50       53 croak "No database string defined, database option missing"
16             if ( !$self->database );
17 1         21 $self->_setup;
18 1         135 return $self;
19             }
20              
21             sub _connect {
22 0         0 return $_[0]->_connection(
23             DBI->connect(
24             ref $_[0]->database eq 'ARRAY'
25 68 50   68   2850 ? @{ $_[0]->database }
26             : $_[0]->database
27             )
28             );
29             }
30              
31             sub _disconnect {
32 68 50   68   3707 eval { $_[0]->_connection->commit() }
  0         0  
33             if ( $_[0]->_connection->{AutoCommit} == 0 );
34 68         5000 $_[0]->_connection->disconnect;
35             }
36              
37             sub _table_exists {
38 2     2   5 my $self = shift;
39 2         62 my $db = $self->_connection;
40 2         14 my $table = shift;
41 2         20 my @tables = $db->tables( '', '', '', 'TABLE' );
42 2 50       1470 if (@tables) {
43 0         0 for (@tables) {
44 0 0       0 next unless $_;
45 0 0       0 return 1 if $_ eq $table;
46             }
47             }
48             else {
49 2         6 eval {
50 2         54 local $db->{PrintError} = 0;
51 2         20 local $db->{RaiseError} = 1;
52 2         16 $db->do(qq{SELECT * FROM $table WHERE 1 = 0 });
53             };
54 2 50       393 return 1 unless $@;
55             }
56 0         0 return 0;
57             }
58              
59             sub _setup {
60 1     1   3 my $self = shift;
61 1         5 $self->_connect;
62             #### Check event table, creating if not exists
63 1 50       675 $self->_connection->do( "
64             CREATE TABLE " . EVENT_TABLE . " (
65             id INTEGER PRIMARY KEY ,
66             name VARCHAR(100)
67             )" ) if ( !$self->_table_exists(EVENT_TABLE) );
68             #### Check functions table, creating if not exists
69              
70 1 50       4 $self->_connection->do( "
71             CREATE TABLE " . FUNCTIONS_TABLE . " (
72             id INTEGER PRIMARY KEY,
73             function TEXT,
74             events_id INT(10) NOT NULL,
75             once INT(1) NOT NULL,
76             foreign key (events_id) references " . EVENT_TABLE . " (id)
77             )" ) if ( !$self->_table_exists(FUNCTIONS_TABLE) );
78 1         7 $self->_disconnect;
79             }
80              
81             sub events_get {
82 26     26 0 10865 my $self = shift;
83 26         66 my $name = shift;
84 26   100     174 my $deserialize = shift // 1;
85 26         119 $self->_connect;
86 26         18492 my $sth = $self->_connection->prepare( "
87             SELECT
88             f.function
89             FROM
90             " . FUNCTIONS_TABLE . " f
91             INNER JOIN " . EVENT_TABLE . " e ON (f.events_id=e.id)
92             WHERE e.name = ?
93             " );
94 26         17285 $sth->execute($name);
95 26         89 my $functions = [];
96 26         438 while ( my $aref = $sth->fetchrow_arrayref ) {
97 31         47 push( @{$functions}, @$aref );
  31         340  
98             }
99 26         170 $self->_disconnect;
100             #deserializing subs and returning a reference
101 26 100       1987 return undef if ( @{$functions} == 0 );
  26         130  
102 24 100       77 return [ map { _deserialize($_) } @{$functions} ]
  14         308  
  13         41  
103             if ( $deserialize == 1 );
104              
105 11         176 return $functions;
106             } #get events
107              
108             sub events_reset {
109 3     3 0 17754 $_[0]->_connect;
110 3         1755 $_[0]->_connection->do( "DELETE FROM '" . EVENT_TABLE . "'" );
111 3         84040 $_[0]->_connection->do( "DELETE FROM '" . FUNCTIONS_TABLE . "'" );
112 3         53270 $_[0]->_disconnect;
113             }
114              
115             sub events_onces {
116 20     20 0 7089 my $self = shift;
117 20         48 my $name = shift;
118 20         60 $self->_connect;
119 20         13944 my $sth = $self->_connection->prepare( "
120             SELECT
121             f.once
122             FROM
123             " . FUNCTIONS_TABLE . " f
124             INNER JOIN " . EVENT_TABLE . " e ON (f.events_id=e.id)
125             WHERE e.name = '" . $name . "'
126             " );
127 20         10947 $sth->execute;
128 20         69 my @onces = ();
129 20         309 while ( my $aref = $sth->fetchrow_arrayref ) {
130 24         240 push( @onces, @$aref );
131             }
132 20         57 $self->_disconnect;
133             #deserializing subs and returning a reference
134 20         1593 return @onces;
135             } #get events
136              
137             sub _event_name_to_id {
138             return shift->_connection->selectrow_array(
139 18     18   764 'SELECT id FROM ' . EVENT_TABLE . ' WHERE name = ? LIMIT 1',
140             undef, shift );
141             }
142              
143             sub once_update {
144 2     2 0 291 my $self = shift;
145 2         8 my $name = shift;
146 2         3 my $onces = shift;
147 2         13 $self->_connect;
148 2         1357 my $event_id = $self->_event_name_to_id($name);
149 2         1127 my $sth = $self->_connection->prepare( "
150             SELECT
151             id
152             FROM
153             " . FUNCTIONS_TABLE . "
154             WHERE events_id = ?
155             " );
156 2         329 $sth->execute($event_id);
157 2         7 my @functions_id = ();
158 2         28 while ( my $aref = $sth->fetchrow_arrayref ) {
159 3         30 push( @functions_id, @$aref );
160             }
161 2         68 $self->_connection->{AutoCommit} = 0; # enable transactions, if possible
162 2         81 $self->_connection->{RaiseError} = 1;
163 2         25 my $sql = "UPDATE " . FUNCTIONS_TABLE . "
164             SET once=? WHERE id=? ";
165 2         11 warn "-- Something unpredictable happened, please contact the mantainer"
166 2 50       6 if ( scalar @{$onces} != scalar(@functions_id) );
167 2         5 eval {
168 2         1045 $self->_connection->prepare($sql)
169 2 50       59 ->execute( shift @{$onces}, shift @functions_id )
170             unless ( @functions_id == 0 );
171 2         100 $self->_connection->commit();
172             };
173 2 50       35967 if ($@) {
174 0         0 warn "-- Error inserting the functions in Deeme: $@\n";
175 0         0 $self->_connection->rollback();
176             }
177 2         151 $self->_connection->{AutoCommit} = 1; # disable transactions
178 2         110 $self->_connection->{RaiseError} = 0;
179 2         38 $self->_disconnect;
180             }
181              
182             sub event_add {
183 10     10 0 11569 my $self = shift;
184 10         34 my $name = shift;
185 10         23 my $cb = shift;
186 10   50     42 my $once = shift // 0;
187 10         62 $cb = _serialize($cb);
188 10         27614 $self->_connect;
189              
190 10 100       7029 if ( my $e_id = $self->_event_name_to_id($name) ) {
191 2 50       1309 return $cb
192             if $self->_connection->selectrow_array(
193             'SELECT id FROM '
194             . FUNCTIONS_TABLE
195             . ' WHERE events_id = ? AND function=? LIMIT 1',
196             undef, $e_id, $cb
197             );
198 2         628 $self->_connection->prepare(
199             "INSERT INTO "
200             . FUNCTIONS_TABLE
201             . " (events_id,function,once)
202             VALUES(?,?,?)"
203             )->execute( $e_id, $cb, $once );
204             }
205             else {
206 8         4112 $self->_connection->prepare(
207             "INSERT INTO "
208             . EVENT_TABLE
209             . " (name)
210             VALUES(?)"
211             )->execute($name);
212 8         1052451 $self->_connection->prepare(
213             "INSERT INTO "
214             . FUNCTIONS_TABLE
215             . " (events_id,function,once)
216             VALUES(?,?,?)"
217             )->execute(
218             $self->_connection->last_insert_id(
219             undef, undef, FUNCTIONS_TABLE, undef
220             ),
221             $cb, $once
222             );
223             }
224 10         250574 $self->_disconnect;
225              
226 10         1043 return $cb;
227             }
228              
229             sub event_delete {
230 4     4 0 153 my $self = shift;
231 4         9 my $name = shift;
232 4         79 $self->_connect;
233              
234 4         1440 my $event_id = $self->_event_name_to_id($name);
235 4         3635 $self->_connection->{AutoCommit} = 0; # enable transactions, if possible
236 4         161 $self->_connection->{RaiseError} = 1;
237 4         43 eval {
238 4         86 $self->_connection->prepare(
239             "DELETE
240             FROM " . FUNCTIONS_TABLE . " WHERE events_id=?"
241             )->execute($event_id);
242 4         1713 $self->_connection->prepare(
243             "DELETE
244             FROM " . EVENT_TABLE . " WHERE id=?"
245             )->execute($event_id);
246 4         557 $self->_connection->commit();
247             };
248              
249 4 50       106452 if ($@) {
250 0         0 warn "-- Error inserting the functions in Deeme: $@\n";
251 0         0 $self->_connection->rollback();
252             }
253              
254 4         704 $self->_connection->{AutoCommit} = 1; # enable transactions, if possible
255 4         425 $self->_connection->{RaiseError} = 0;
256 4         69 $self->_disconnect;
257              
258             } #delete event
259              
260             sub event_update {
261 2     2 0 116 my $self = shift;
262 2         6 my $name = shift;
263 2         5 my $functions = shift;
264 2   50     9 my $serialize = shift // 1;
265 2 50       5 return $self->event_delete($name) if ( scalar( @{$functions} ) == 0 );
  2         9  
266 2         7 $self->_connect;
267              
268 2         1465 my $event_id = $self->_event_name_to_id($name);
269              
270 2         748 $self->_connection->{AutoCommit} = 0; # enable transactions, if possible
271 2         68 $self->_connection->{RaiseError} = 1;
272 2         22 eval {
273 2         48 $self->_connection->prepare(
274             "DELETE
275             FROM " . FUNCTIONS_TABLE . " WHERE events_id=?"
276             )->execute($event_id);
277 2         1044 my $sql
278             = "INSERT INTO "
279             . FUNCTIONS_TABLE
280             . " (events_id,function,once)
281             VALUES(?,?,?)";
282              
283 2         5 foreach my $f ( @{$functions} ) {
  2         7  
284 3 50       117 if ( $serialize == 1 ) {
285 0         0 $self->_connection->prepare($sql)
286             ->execute( $event_id, _serialize($f), 0 );
287             }
288             else {
289 3         95 $self->_connection->prepare($sql)
290             ->execute( $event_id, $f, 0 );
291             }
292              
293             }
294 2         367 $self->_connection->commit();
295             };
296              
297 2 50       40884 if ($@) {
298 0         0 warn "-- Error inserting the functions in Deeme: $@\n";
299 0         0 $self->_connection->rollback();
300             }
301              
302 2         145 $self->_connection->{AutoCommit} = 1; # enable transactions, if possible
303 2         105 $self->_connection->{RaiseError} = 0;
304 2         34 $self->_disconnect;
305              
306             } #update event
307              
308             1;
309             __END__