File Coverage

blib/lib/Anansi/DatabaseComponent.pm
Criterion Covered Total %
statement 6 599 1.0
branch 0 426 0.0
condition n/a
subroutine 2 16 12.5
pod 13 14 92.8
total 21 1055 1.9


line stmt bran cond sub pod time code
1             package Anansi::DatabaseComponent;
2              
3              
4             =head1 NAME
5              
6             Anansi::DatabaseComponent - A manager template for database drivers.
7              
8             =head1 SYNOPSIS
9              
10             package Anansi::Database::Example;
11              
12             use base qw(Anansi::DatabaseComponent);
13              
14             sub connect {
15             my ($self, $channel, %parameters) = @_;
16             return $self->SUPER::connect(
17             undef,
18             INPUT => [
19             'some text',
20             {
21             NAME => 'someParameter',
22             }, {
23             INPUT => [
24             'more text',
25             {
26             NAME => 'anotherParameter',
27             },
28             'yet more text',
29             ]
30             }, {
31             DEFAULT => 'abc',
32             NAME => 'yetAnotherParameter',
33             },
34             ],
35             (%parameters),
36             );
37             }
38              
39             sub validate {
40             my ($self, $channel, %parameters) = @_;
41             $parameters{DRIVER} = 'Example';
42             return Anansi::DatabaseComponent::validate(undef, %parameters);
43             }
44              
45             Anansi::Component::addChannel('Anansi::Database::Example', 'AUTOCOMMIT' => 'Anansi::DatabaseComponent::autocommit');
46             Anansi::Component::addChannel('Anansi::Database::Example', 'COMMIT' => 'Anansi::DatabaseComponent::commit');
47             Anansi::Component::addChannel('Anansi::Database::Example', 'CONNECT' => 'connect');
48             Anansi::Component::addChannel('Anansi::Database::Example', 'DISCONNECT' => 'Anansi::DatabaseComponent::disconnect');
49             Anansi::Component::addChannel('Anansi::Database::Example', 'FINISH' => 'Anansi::DatabaseComponent::finish');
50             Anansi::Component::addChannel('Anansi::Database::Example', 'HANDLE' => 'Anansi::DatabaseComponent::handle');
51             Anansi::Component::addChannel('Anansi::Database::Example', 'PREPARE' => 'Anansi::DatabaseComponent::prepare');
52             Anansi::Component::addChannel('Anansi::Database::Example', 'ROLLBACK' => 'Anansi::DatabaseComponent::rollback');
53             Anansi::Component::addChannel('Anansi::Database::Example', 'STATEMENT' => 'Anansi::DatabaseComponent::statement');
54             Anansi::Component::addChannel('Anansi::Database::Example', 'VALIDATE_AS_APPROPRIATE' => 'validate');
55              
56             1;
57              
58             package main;
59              
60             use Anansi::Database;
61              
62             my $database = Anansi::Database->new();
63             my $component = $database->addComponent(undef,
64             DRIVER => 'Example',
65             );
66             if(defined($component)) {
67             if($database->connect(
68             undef,
69             $component,
70             someParameter => 'some data',
71             anotherParameter => 'more data',
72             yetAnotherParameter => 'further data',
73             )) {
74             my $result = $database->statement(
75             undef,
76             $component,
77             SQL => 'SELECT someThing FROM someTable where modified = ?;',
78             INPUT => [
79             {
80             NAME => 'modified',
81             },
82             ],
83             modified => '2011-02-22 00:21:46',
84             );
85             if(!defined($result)) {
86             } elsif(ref($result) =~ /^ARRAY$/i) {
87             foreach my $record (@{$result}) {
88             next if(ref($record) !~ /^HASH$/i);
89             print 'someThing: "'.${$record}{someThing}.'"'."\n";
90             }
91             }
92             }
93             }
94              
95             1;
96              
97             =head1 DESCRIPTION
98              
99             Manages a database connection providing generic processes to allow it's opening,
100             closing and various SQL interactions. Uses L.
101              
102             =cut
103              
104              
105             our $VERSION = '0.04';
106              
107 1     1   24724 use base qw(Anansi::Component);
  1         2  
  1         968  
108              
109 1     1   35972 use Anansi::Actor;
  1         2  
  1         7  
110              
111              
112             =head1 METHODS
113              
114             =cut
115              
116              
117             =head2 Anansi::Class
118              
119             See L for details. A parent module of L.
120              
121             =cut
122              
123              
124             =head3 DESTROY
125              
126             See L for details.
127              
128             =cut
129              
130              
131             =head3 finalise
132              
133             See L for details. Overridden by L. A virtual method.
134              
135             =cut
136              
137              
138             =head3 implicate
139              
140             See L for details. A virtual method.
141              
142             =cut
143              
144              
145             =head3 import
146              
147             See L for details.
148              
149             =cut
150              
151              
152             =head3 initialise
153              
154             See L for details. A virtual method.
155              
156             =cut
157              
158              
159             =head3 new
160              
161             See L for details.
162              
163             =cut
164              
165              
166             =head3 old
167              
168             See L for details.
169              
170             =cut
171              
172              
173             =head3 used
174              
175             See L for details.
176              
177             =cut
178              
179              
180             =head3 uses
181              
182             See L for details.
183              
184             =cut
185              
186              
187             =head3 using
188              
189             See L for details.
190              
191             =cut
192              
193              
194             =head2 Anansi::Component
195              
196             See L for details. A parent module of L.
197              
198             =cut
199              
200              
201             =head3 Anansi::Class
202              
203             See L for details. A parent module of L.
204              
205             =cut
206              
207              
208             =head3 addChannel
209              
210             See L for details.
211              
212             =cut
213              
214              
215             =head3 channel
216              
217             See L for details.
218              
219             =cut
220              
221              
222             =head3 componentManagers
223              
224             See L for details.
225              
226             =cut
227              
228              
229             =head3 removeChannel
230              
231             See L for details.
232              
233             =cut
234              
235              
236             =head2 autoCommit
237              
238             if(1 == Anansi::DatabaseComponent::autocommit($OBJECT, undef));
239              
240             if(1 == Anansi::DatabaseComponent::channel($OBJECT, 'AUTOCOMMIT'));
241              
242             if(1 == $OBJECT->autocommit(undef));
243              
244             if(1 == $OBJECT->channel('AUTOCOMMIT'));
245              
246             =over 4
247              
248             =item self I<(Blessed Hash, Required)>
249              
250             An object of this namespace.
251              
252             =item channel I<(String, Required)>
253              
254             The abstract identifier of a subroutine.
255              
256             =item parameters I<(Hash, Optional)>
257              
258             Named parameters.
259              
260             =back
261              
262             Attempts to perform a database autocommit. Returns B<1> I<(one)> on success and
263             B<0> I<(zero)> on failure.
264              
265             =cut
266              
267              
268             sub autocommit {
269 0     0 0   my ($self, $channel, %parameters) = @_;
270 0 0         return 0 if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
271 0           my $autocommit;
272             eval {
273 0           $autocommit = $self->{HANDLE}->autocommit();
274 0           1;
275 0 0         } or do {
276 0           return 0;
277             };
278 0 0         return 0 if(!defined($autocommit));
279 0 0         return 0 if(ref($autocommit) !~ /^$/);
280 0 0         return 0 if($autocommit !~ /^[\+\-]?\d+$/);
281 0 0         return 1 if($autocommit);
282 0           return 0;
283             }
284              
285             Anansi::Component::addChannel('Anansi::DatabaseComponent', 'AUTOCOMMIT' => 'autocommit');
286              
287              
288             =head2 bind
289              
290             if(Anansi::DatabaseComponent::bind($OBJECT,
291             HANDLE => $HANDLE,
292             INPUT => [
293             {
294             NAME => 'someParameter'
295             }, {
296             DEFAULT => 123,
297             NAME => 'anotherParameter'
298             }
299             ],
300             VALUE => {
301             someParameter => 'abc'
302             }
303             ));
304              
305             if($OBJECT->bind(
306             HANDLE => $HANDLE,
307             INPUT => [
308             {
309             NAME => 'yetAnotherParameter',
310             TYPE => 'TEXT'
311             }
312             ],
313             VALUE => [
314             yetAnotherParameter => 456
315             ]
316             ));
317              
318             =over 4
319              
320             =item self I<(Blessed Hash B String, Required)>
321              
322             Either an object or a string of this namespace.
323              
324             =item parameters I<(Hash, Optional)>
325              
326             Named parameters.
327              
328             =over 4
329              
330             =item HANDLE I<(DBI::st, Required)>
331              
332             The database statement handle.
333              
334             =item INPUT I<(Array, Required)>
335              
336             An array of hashes. Each element of the array corresponds to an equivalent B
337             I<(Question mark)> within the prepared SQL statement. Each hash contains a
338             I key with a value that represents a possible key within the I
339             parameter. Each hash may also contain a I key which contains the value
340             to use if the equivalent I parameter does not exist and a I key
341             which contains the SQL type to associate with the assigned value. When no
342             corresponding I parameter key exists and no I key has been
343             defined then an empty string is used for the value.
344              
345             =item VALUE I<(Hash, Required)>
346              
347             A hash of values to assign in the order specified by the I parameter.
348              
349             =back
350              
351             =back
352              
353             Attempts to use the supplied parameters to assign values to a SQL statement that
354             has already been prepared to accept them. Returns B<0> I<(zero)> on failure and
355             the database statement handle on success.
356              
357             =cut
358              
359              
360             sub bind {
361 0     0 1   my ($self, %parameters) = @_;
362 0 0         return 0 if(!defined($parameters{HANDLE}));
363 0 0         return 0 if(!defined($parameters{INPUT}));
364 0 0         return 0 if(ref($parameters{INPUT}) !~ /^ARRAY$/i);
365 0 0         return 0 if(!defined($parameters{VALUE}));
366 0 0         return 0 if(ref($parameters{VALUE}) !~ /^HASH$/i);
367 0           my $index = 1;
368 0           foreach my $input (@{$parameters{INPUT}}) {
  0            
369 0 0         if(defined(${$parameters{VALUE}}{${$input}{NAME}})) {
  0 0          
  0 0          
  0            
370 0 0         if(defined(${$input}{TYPE})) {
  0            
371 0           $parameters{HANDLE}->bind_param($index, ${$parameters{VALUE}}{${$input}{NAME}}, ${$input}{TYPE});
  0            
  0            
  0            
372             } else {
373 0           $parameters{HANDLE}->bind_param($index, ${$parameters{VALUE}}{${$input}{NAME}});
  0            
  0            
374             }
375 0           } elsif(defined(${$input}{DEFAULT})) {
376 0 0         if(defined(${$input}{TYPE})) {
  0            
377 0           $parameters{HANDLE}->bind_param($index, ${$input}{DEFAULT}, ${$input}{TYPE});
  0            
  0            
378             } else {
379 0           $parameters{HANDLE}->bind_param($index, ${$input}{DEFAULT});
  0            
380             }
381             } elsif(defined(${$input}{TYPE})) {
382 0           $parameters{HANDLE}->bind_param($index, '', ${$input}{TYPE});
  0            
383             } else {
384 0           $parameters{HANDLE}->bind_param($index, '');
385             }
386 0           $index++;
387             }
388 0           return $parameters{HANDLE};
389             }
390              
391              
392             =head2 binding
393              
394             if(1 == Anansi::DatabaseComponent::binding($OBJECT));
395              
396             if(1 == $OBJECT->binding());
397              
398             =over 4
399              
400             =item self I<(Blessed Hash B String, Required)>
401              
402             Either an object or a string of this namespace.
403              
404             =item parameters I<(Array, Optional)>
405              
406             An array of hashes. Each hash should contain a I key with a string value.
407              
408             =back
409              
410             Verifies that the supplied parameters are all hashes and that they each contain
411             a I key with a string value. Returns B<1> I<(one)> when validity is
412             confirmed and B<0> I<(zero)> when an invalid structure is determined. Used to
413             validate the I parameter of the B method.
414              
415             =cut
416              
417              
418             sub binding {
419 0     0 1   my ($self, @parameters) = @_;
420 0           foreach my $parameter (@parameters) {
421 0 0         return 0 if(ref($parameter) !~ /^HASH$/i);
422 0 0         return 0 if(!defined(${$parameter}{NAME}));
  0            
423 0 0         return 0 if(ref(${$parameter}{NAME}) !~ /^$/);
  0            
424 0 0         return 0 if(${$parameter}{NAME} !~ /^[a-zA-Z_]+(\s*[a-zA-Z0-9_]+)*$/);
  0            
425             }
426 0           return 1;
427             }
428              
429              
430             =head2 commit
431              
432             if(1 == Anansi::DatabaseComponent::commit($OBJECT, undef));
433              
434             if(1 == Anansi::DatabaseComponent::channel($OBJECT, 'COMMIT'));
435              
436             if(1 == $OBJECT->commit(undef));
437              
438             if(1 == $OBJECT->channel('COMMIT'));
439              
440             =over 4
441              
442             =item self I<(Blessed Hash B String, Required)>
443              
444             Either an object or a string of this namespace.
445              
446             =item channel I<(String, Required)>
447              
448             The abstract identifier of a subroutine.
449              
450             =item parameters I<(Hash, Optional)>
451              
452             Named parameters.
453              
454             =back
455              
456             Attempts to perform a database commit. Returns B<1> I<(one)> on success and
457             B<0> I<(zero)> on failure.
458              
459             =cut
460              
461              
462             sub commit {
463 0     0 1   my ($self, $channel, %parameters) = @_;
464 0 0         return 0 if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
465 0 0         return 0 if(!defined($self->{HANDLE}));
466 0 0         return 1 if($self->autocommit());
467 0           my $commit;
468             eval {
469 0           $commit = $self->{HANDLE}->commit();
470 0           1;
471 0 0         } or do {
472 0           $self->rollback();
473 0           return 0;
474             };
475 0 0         return 0 if(!defined($commit));
476 0 0         return 0 if(ref($commit) !~ /^$/);
477 0 0         return 0 if($commit !~ /^[\+\-]?\d+$/);
478 0 0         return 1 if($commit);
479 0           return 0;
480             }
481              
482             Anansi::Component::addChannel('Anansi::DatabaseComponent', 'COMMIT' => 'commit');
483              
484              
485             =head2 connect
486              
487             if(1 == Anansi::DatabaseComponent::connect($OBJECT, undef
488             INPUT => [
489             'some text',
490             {
491             NAME => 'someParameter'
492             }, {
493             INPUT => [
494             'more text',
495             {
496             NAME => 'anotherParameter'
497             },
498             'yet more text'
499             ]
500             }, {
501             DEFAULT => 'abc',
502             NAME => 'yetAnotherParameter'
503             }
504             ],
505             someParameter => 12345,
506             anotherParameter => 'blah blah blah'
507             ));
508              
509             if(1 == Anansi::DatabaseComponent::channel($OBJECT, 'CONNECT',
510             INPUT => [
511             'blah blah blah',
512             {
513             DEFAULT => 123,
514             NAME => 'someParameter',
515             }
516             ],
517             someParameter => 'some text'
518             ));
519              
520             if(1 == $OBJECT->connect(undef,
521             INPUT => [
522             {
523             INPUT => [
524             'some text',
525             {
526             NAME => 'someParameter'
527             },
528             'more text'
529             ]
530             }
531             ],
532             someParameter => 'in between'
533             ));
534              
535             if(1 == $OBJECT->channel('CONNECT',
536             INPUT => [
537             {
538             INPUT => [
539             {
540             NAME => 'abc'
541             }, {
542             NAME => 'def'
543             }
544             },
545             REF => 'HASH'
546             }
547             ]
548             ));
549              
550             =over 4
551              
552             =item self I<(Blessed Hash, Required)>
553              
554             An object of this namespace.
555              
556             =item channel I<(String, Required)>
557              
558             The abstract identifier of a subroutine.
559              
560             =item parameters I<(Hash, Required)>
561              
562             Named parameters.
563              
564             =over 4
565              
566             =item HANDLE I<(DBI::db, Optional)>
567              
568             The database handle of an existing database connection. Used in preference to
569             the I parameter.
570              
571             =item INPUT I<(Array B Scalar, Optional)>
572              
573             An array or single value containing a description of each parameter in the order
574             that it is passed to the database driver's I method. Used when the
575             I parameter does not exist.
576              
577             =over 4
578              
579             =item I<(Non-Hash)>
580              
581             An element that does not contain a hash value will be used as the corresponding
582             I method's parameter value.
583              
584             =item I<(Hash)>
585              
586             An element that contains a hash value is assumed to be a description of how to
587             generate the corresponding I method's parameter value. when a value
588             can not be generated, an B value will be used.
589              
590             =over 4
591              
592             =item DEFAULT I<(Optional)>
593              
594             The value to use if no other value can be determined.
595              
596             =item INPUT I<(Array B Scalar, Optional)>
597              
598             Contains a structure like that given in I above with the exception that
599             any further I keys will be ignored. As this key is only valid when
600             I is undefined and I either specifies a string or a hash, it's value
601             will be either a concatenation of all the calculated strings or a hash
602             containing all of the specified keys and values.
603              
604             =item NAME I<(String, Optional)>
605              
606             The name of the parameter that contains the value to use.
607              
608             =item REF I<(Array B String, Optional)>
609              
610             The data types used to validate the value to use.
611              
612             =back
613              
614             =back
615              
616             =back
617              
618             =back
619              
620             Either uses an existing database connection or attempts to perform a database
621             connection using the supplied parameters. Returns B<1> I<(one)> on success and
622             B<0> I<(zero)> on failure.
623              
624             =cut
625              
626              
627             sub connect {
628 0     0 1   my ($self, $channel, %parameters) = @_;
629 0 0         return 0 if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
630 0           $self->disconnect();
631 0 0         if(defined($parameters{HANDLE})) {
    0          
    0          
632 0 0         return 0 if(ref($parameters{HANDLE}) !~ /^DBI::db$/);
633 0           $self->{HANDLE} = $parameters{HANDLE};
634 0           $self->{MANAGE_HANDLE} = 0;
635             } elsif(!defined($parameters{INPUT})) {
636 0           return 0;
637             } elsif(ref($parameters{INPUT}) !~ /^ARRAY$/i) {
638 0           return 0;
639             } else {
640 0           my @inputs;
641 0           foreach my $input (@{$parameters{INPUT}}) {
  0            
642 0 0         if(ref($input) !~ /^HASH$/i) {
643 0           push(@inputs, $input);
644 0           next;
645             }
646 0           my $value = undef;
647 0 0         $value = ${$input}{DEFAULT} if(defined(${$input}{DEFAULT}));
  0            
  0            
648 0 0         if(!defined(${$input}{NAME})) {
  0 0          
  0 0          
649 0 0         if(!defined(${$input}{INPUT})) {
  0 0          
  0 0          
    0          
    0          
    0          
650 0           } elsif(ref(${$input}{INPUT}) !~ /^ARRAY$/i) {
651 0           } elsif(!defined(${$input}{REF})) {
652 0           } elsif(ref(${$input}{REF}) !~ /^$/i) {
653 0           } elsif('' eq ${$input}{REF}) {
654 0           my @subInputs;
655 0           for(my $index = 0; $index < scalar(@{${$input}{INPUT}}); $index++) {
  0            
  0            
656 0 0         if(ref(${${$input}{INPUT}}[$index]) =~ /^$/i) {
  0 0          
  0            
  0            
657 0           push(@subInputs, ${${$input}{INPUT}}[$index]);
  0            
  0            
658 0           next;
659 0           } elsif(ref(${${$input}{INPUT}}[$index]) !~ /^HASH$/) {
660 0           next;
661             }
662 0           my $subValue = '';
663 0 0         $subValue = ${${${$input}{INPUT}}[$index]}{DEFAULT} if(defined(${${${$input}{INPUT}}[$index]}{DEFAULT}));
  0            
  0            
  0            
  0            
  0            
  0            
664 0 0         if(!defined(${${${$input}{INPUT}}[$index]}{NAME})) {
  0 0          
  0 0          
  0            
  0            
665 0           } elsif(ref(${${${$input}{INPUT}}[$index]}{NAME}) !~ /^$/) {
  0            
  0            
666 0           } elsif(defined($parameters{${${${$input}{INPUT}}[$index]}{NAME}})) {
  0            
667 0 0         if(!defined(${${${$input}{INPUT}}[$index]}{REF})) {
  0 0          
  0 0          
  0 0          
  0            
668 0 0         $subValue = $parameters{${${${$input}{INPUT}}[$index]}{NAME}} if('' eq ref($parameters{${${${$input}{INPUT}}[$index]}{NAME}}));
  0            
  0            
  0            
  0            
  0            
  0            
669 0           } elsif(ref(${${${$input}{INPUT}}[$index]}{REF}) !~ /^$/) {
  0            
  0            
670 0           } elsif('' ne ${${${$input}{INPUT}}[$index]}{REF}) {
  0            
  0            
671 0           } elsif('' ne ref($parameters{${${${$input}{INPUT}}[$index]}{NAME}})) {
  0            
672             } else {
673 0           $subValue = $parameters{${${${$input}{INPUT}}[$index]}{NAME}};
  0            
  0            
  0            
674             }
675             }
676 0           push(@subInputs, $subValue);
677             }
678 0           $value = join('', @subInputs);
679             } elsif(${$input}{REF} =~ /^HASH$/i) {
680 0           my %subInputs;
681 0           foreach my $subInput (@{${$input}{INPUT}}) {
  0            
  0            
682 0 0         next if(ref($subInput) !~ /^HASH$/i);
683 0           my $subValue = undef;
684 0 0         $subValue = ${$subInput}{DEFAULT} if(defined(${$subInput}{DEFAULT}));
  0            
  0            
685 0 0         if(!defined(${$subInput}{NAME})) {
  0 0          
  0 0          
686 0           } elsif(ref(${$subInput}{NAME}) !~ /^$/) {
687             } elsif(defined($parameters{${$subInput}{NAME}})) {
688 0 0         if(!defined(${$subInput}{REF})) {
  0 0          
  0 0          
    0          
689 0           } elsif(ref(${$subInput}{REF}) =~ /^ARRAY$/i) {
690 0           my %refs = map { $_ => 1 } (@{${$subInput}{REF}});
  0            
  0            
  0            
691 0 0         $subValue = $parameters{${$subInput}{NAME}} if(defined($refs{ref($parameters{${$subInput}{NAME}})}));
  0            
  0            
692 0           } elsif(ref(${$subInput}{REF}) !~ /^$/) {
693 0           } elsif(${$subInput}{REF} ne ref($parameters{${$subInput}{NAME}})) {
694             } else {
695 0           $subValue = $parameters{${$subInput}{NAME}};
  0            
696             }
697             }
698 0           $subInputs{${$subInput}{NAME}} = $subValue;
  0            
699             }
700 0           $value = \%subInputs;
701             }
702 0           } elsif(ref(${$input}{NAME}) !~ /^$/) {
703             } elsif(defined($parameters{${$input}{NAME}})) {
704 0 0         if(!defined(${$input}{REF})) {
  0 0          
  0 0          
    0          
    0          
705 0           } elsif(ref(${$input}{REF}) =~ /^ARRAY$/i) {
706 0           my %refs = map { $_ => 1 } (@{${$input}{REF}});
  0            
  0            
  0            
707 0 0         if(!defined($refs{ref($parameters{${$input}{NAME}})})) {
  0 0          
  0            
708             } elsif(ref($parameters{${$input}{NAME}}) !~ /^HASH$/i) {
709 0           $value = $parameters{${$input}{NAME}};
  0            
710             } else {
711 0 0         if(!defined(${$input}{INPUT})) {
  0 0          
  0            
712 0           $value = $parameters{${$input}{NAME}};
  0            
713             } elsif(ref(${$input}{INPUT}) !~ /^HASH$/i) {
714 0           $value = $parameters{${$input}{NAME}};
  0            
715             } else {
716 0           my %subInputs;
717 0           foreach my $subInput (keys(%{${$input}{INPUT}})) {
  0            
  0            
718 0 0         if(ref($subInput) !~ /^HASH$/i) {
719 0           $subInputs{$subInput} = $subInput;
720 0           next;
721             }
722 0           my $subValue = undef;
723 0 0         $value = ${${${$input}{INPUT}}{$subInput}}{DEFAULT} if(defined(${${${$input}{INPUT}}{$subInput}}{DEFAULT}));
  0            
  0            
  0            
  0            
  0            
  0            
724 0 0         if(!defined(${${${$input}{INPUT}}{$subInput}}{NAME})) {
  0 0          
  0 0          
  0            
  0            
725 0           } elsif(ref(${${${$input}{INPUT}}{$subInput}}{NAME}) !~ /^$/) {
  0            
  0            
726 0           } elsif(defined($parameters{${${${$input}{INPUT}}{$subInput}}{NAME}})) {
  0            
727 0 0         if(!defined(${${${$input}{INPUT}}{$subInput}}{REF})) {
  0 0          
  0 0          
  0 0          
  0            
728 0           } elsif(ref(${${${$input}{INPUT}}{$subInput}}{REF}) =~ /^ARRAY$/i) {
  0            
  0            
729 0           my %refs = map { $_ => 1 } (@{${${${$input}{INPUT}}{$subInput}}{REF}});
  0            
  0            
  0            
  0            
  0            
730 0 0         $subValue = $parameters{${${${$input}{INPUT}}{$subInput}}{NAME}} if(defined($refs{ref($parameters{${${${$input}{INPUT}}{$subInput}}{NAME}})}));
  0            
  0            
  0            
  0            
  0            
  0            
731 0           } elsif(ref(${${${$input}{INPUT}}{$subInput}}{REF}) !~ /^$/) {
  0            
  0            
732 0           } elsif(${${${$input}{INPUT}}{$subInput}}{REF} ne ref($parameters{${${${$input}{INPUT}}{$subInput}}{NAME}})) {
  0            
  0            
  0            
  0            
733             } else {
734 0           $subValue = $parameters{${${${$input}{INPUT}}{$subInput}}{NAME}};
  0            
  0            
  0            
735             }
736             }
737 0           $subInputs{$subInput} = $subValue;
738             }
739 0           $value = \%subInputs;
740             }
741             }
742 0           } elsif(ref(${$input}{REF}) !~ /^$/) {
743 0           } elsif(${$input}{REF} ne ref($parameters{${$input}{NAME}})) {
  0            
744             } elsif(ref($parameters{${$input}{NAME}}) !~ /^HASH$/i) {
745 0           $value = $parameters{${$input}{NAME}};
  0            
746             } else {
747 0 0         if(!defined(${$input}{INPUT})) {
  0 0          
  0            
748 0           $value = $parameters{${$input}{NAME}};
  0            
749             } elsif(ref(${$input}{INPUT}) !~ /^HASH$/i) {
750 0           $value = $parameters{${$input}{NAME}};
  0            
751             } else {
752 0           my %subInputs;
753 0           foreach my $key (keys(%{${$input}{INPUT}})) {
  0            
  0            
754 0 0         if(ref($subInput) !~ /^HASH$/i) {
755 0           push(@subInputs, $subInput);
756 0           next;
757             }
758 0           my $subValue = undef;
759 0 0         $value = ${${${$input}{INPUT}}{$subInput}}{DEFAULT} if(defined(${${${$input}{INPUT}}{$subInput}}{DEFAULT}));
  0            
  0            
  0            
  0            
  0            
  0            
760 0 0         if(!defined(${${${$input}{INPUT}}{$subInput}}{NAME})) {
  0 0          
  0 0          
  0            
  0            
761 0           } elsif(ref(${${${$input}{INPUT}}{$subInput}}{NAME}) !~ /^$/) {
  0            
  0            
762 0           } elsif(defined($parameters{${${${$input}{INPUT}}{$subInput}}{NAME}})) {
  0            
763 0 0         if(!defined(${${${$input}{INPUT}}{$subInput}}{REF})) {
  0 0          
  0 0          
  0 0          
  0            
764 0           } elsif(ref(${${${$input}{INPUT}}{$subInput}}{REF}) =~ /^ARRAY$/i) {
  0            
  0            
765 0           my %refs = map { $_ => 1 } (@{${${${$input}{INPUT}}{$subInput}}{REF}});
  0            
  0            
  0            
  0            
  0            
766 0 0         $subValue = $parameters{${${${$input}{INPUT}}{$subInput}}{NAME}} if(defined($refs{ref($parameters{${${${$input}{INPUT}}{$subInput}}{NAME}})}));
  0            
  0            
  0            
  0            
  0            
  0            
767 0           } elsif(ref(${${${$input}{INPUT}}{$subInput}}{REF}) !~ /^$/) {
  0            
  0            
768 0           } elsif(${${${$input}{INPUT}}{$subInput}}{REF} ne ref($parameters{${${${$input}{INPUT}}{$subInput}}{NAME}})) {
  0            
  0            
  0            
  0            
769             } else {
770 0           $subValue = $parameters{${${${$input}{INPUT}}{$subInput}}{NAME}};
  0            
  0            
  0            
771             }
772             }
773 0           $subInputs{$subInput} = $subValue;
774             }
775 0           $value = \%subInputs;
776             }
777             }
778             }
779 0           push(@inputs, $value);
780             }
781 0 0         return 0 if(0 == scalar(@inputs));
782 0           my $handle = DBI->connect(@inputs);
783 0 0         return 0 if(!defined($handle));
784 0           $self->{HANDLE} = $handle;
785 0           $self->{MANAGE_HANDLE} = 1;
786             }
787 0           return 1;
788             }
789              
790             Anansi::Component::addChannel('Anansi::DatabaseComponent', 'CONNECT' => 'connect');
791              
792              
793             =head2 disconnect
794              
795             if(1 == Anansi::DatabaseComponent::disconnect($OBJECT, undef));
796              
797             if(1 == Anansi::DatabaseComponent::channel($OBJECT, 'DISCONNECT'));
798              
799             if(1 == $OBJECT->disconnect(undef));
800              
801             if(1 == $OBJECT->channel('DISCONNECT'));
802              
803             =over 4
804              
805             =item self I<(Blessed Hash B String, Required)>
806              
807             Either an object or a string of this namespace.
808              
809             =item channel I<(String, Required)>
810              
811             The abstract identifier of a subroutine.
812              
813             =item parameters I<(Hash, Optional)>
814              
815             Named parameters.
816              
817             =back
818              
819             Attempts to perform a database disconnection. Returns B<1> I<(one)> on success
820             and B<0> I<(zero)> on failure.
821              
822             =cut
823              
824              
825             sub disconnect {
826 0     0 1   my ($self, $channel, %parameters) = @_;
827 0 0         return 0 if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
828 0 0         return 0 if(!defined($self->{HANDLE}));
829 0 0         if(!defined($self->{MANAGE_HANDLE})) {
    0          
830 0           $self->{MANAGE_HANDLE} = 0;
831             } elsif(1 == $self->{MANAGE_HANDLE}) {
832 0           $self->{HANDLE}->disconnect();
833 0           $self->{MANAGE_HANDLE} = 0;
834 0           delete $self->{HANDLE};
835             } else {
836 0           delete $self->{HANDLE};
837             }
838 0           return 1;
839             }
840              
841             Anansi::Component::addChannel('Anansi::DatabaseComponent', 'DISCONNECT' => 'disconnect');
842              
843              
844             =head2 finalise
845              
846             Overrides L. A virtual method.
847              
848             =cut
849              
850              
851             sub finalise {
852 0     0 1   my ($self, %parameters) = @_;
853 0           $self->finish();
854 0           $self->disconnect();
855             }
856              
857              
858             =head2 finish
859              
860             if(1 == Anansi::DatabaseComponent::finish($OBJECT, undef));
861              
862             if(1 == Anansi::DatabaseComponent::channel($OBJECT, 'FINISH'));
863              
864             if(1 == $OBJECT->finish(undef));
865              
866             if(1 == $OBJECT->channel('FINISH'));
867              
868             =over 4
869              
870             =item self I<(Blessed Hash, Required)>
871              
872             Either an object or a string of this namespace.
873              
874             =item channel I<(String, Required)>
875              
876             The abstract identifier of a subroutine.
877              
878             =item parameters I<(Hash, Optional)>
879              
880             Named parameters.
881              
882             =over 4
883              
884             =item STATEMENT I<(String, Optional)>
885              
886             The name associated with a prepared SQL statement.
887              
888             =back
889              
890             =back
891              
892             Either releases the named SQL statement preparation or all of the SQL statement
893             preparations. Returns B<1> I<(one)> on success and B<0> I<(zero)> on failure.
894              
895             =cut
896              
897              
898             sub finish {
899 0     0 1   my ($self, $channel, %parameters) = @_;
900 0 0         return 0 if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
901 0 0         if(!defined($self->{STATEMENTS})) {
  0 0          
902 0           return 0;
903             } elsif(0 == scalar(keys(%{$self->{STATEMENTS}}))) {
904 0           return 0;
905             }
906 0 0         if(!defined($parameters{STATEMENT})) {
    0          
    0          
    0          
907 0           foreach my $statement (keys(%{$self->{STATEMENTS}})) {
  0            
908 0 0         if(defined(${${$self->{STATEMENTS}}{$statement}}{HANDLE})) {
  0            
  0            
909 0           eval {
910 0           ${${$self->{STATEMENTS}}{$statement}}{HANDLE}->finish();
  0            
  0            
911 0           1;
912             };
913             }
914 0           delete ${$self->{STATEMENTS}}{$statement};
  0            
915             }
916 0           } elsif(ref($parameters{STATEMENT}) !~ /^$/) {
917 0           return 0;
918 0           } elsif(!defined(${$self->{STATEMENTS}}{$parameters{STATEMENT}})) {
919 0           return 0;
920 0           } elsif(!defined(${${$self->{STATEMENTS}}{$parameters{STATEMENT}}}{HANDLE})) {
921 0           return 0;
922             } else {
923 0           eval {
924 0           ${${$self->{STATEMENTS}}{$parameters{STATEMENT}}}{HANDLE}->finish();
  0            
  0            
925 0           1;
926             };
927 0           delete ${$self->{STATEMENTS}}{$parameters{STATEMENT}};
  0            
928             }
929 0 0         delete $self->{STATEMENTS} if(0 == scalar(keys(%{$self->{STATEMENTS}})));
  0            
930 0           return 1;
931             }
932              
933             Anansi::Component::addChannel('Anansi::DatabaseComponent', 'FINISH' => 'finish');
934              
935              
936             =head2 handle
937              
938             my $HANDLE = Anansi::DatabaseComponent::handle($OBJECT, undef);
939              
940             my $HANDLE = Anansi::DatabaseComponent::channel($OBJECT, 'HANDLE');
941              
942             my $HANDLE = $OBJECT->handle(undef);
943              
944             my $dbh = DBI->connect('DBI:mysql:database=someDatabase', 'someUser', 'somePassword');
945             my $HANDLE = $OBJECT->channel('HANDLE', $dbh);
946             if(defined($HANDLE));
947              
948             =over 4
949              
950             =item self I<(Blessed Hash, Required)>
951              
952             An object of this namespace.
953              
954             =item channel I<(String, Required)>
955              
956             The abstract identifier of a subroutine.
957              
958             =item handle I<(DBI::db, Optional)>
959              
960             A replacement database handle.
961              
962             =back
963              
964             Attempts to redefine an existing database handle when a handle is supplied.
965             Either returns the database handle or B on failure.
966              
967             =cut
968              
969              
970             sub handle {
971 0     0 1   my ($self, $channel, $handle) = @_;
972 0 0         return if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
973 0 0         if(defined($handle)) {
974 0 0         if(defined($self->{HANDLE})) {
975 0           $self->finish();
976 0           $self->disconnect();
977             }
978 0 0         return if(ref($handle) !~ /^DBI::db$/);
979 0           $self->{HANDLE} = $handle;
980 0           $self->{MANAGE_HANDLE} = 0;
981             }
982 0 0         return $self->{HANDLE} if(defined($self->{HANDLE}));
983 0           return;
984             }
985              
986             Anansi::Component::addChannel('Anansi::DatabaseComponent', 'HANDLE' => 'handle');
987              
988              
989             =head2 initialise
990              
991             Overrides L. A virtual method.
992              
993             =cut
994              
995              
996             sub initialise {
997 0     0 1   my ($self, %parameters) = @_;
998 0           Anansi::Actor->new(
999             PACKAGE => 'DBI',
1000             );
1001 0           $self->{STATEMENT} = {};
1002             }
1003              
1004              
1005             =head2 prepare
1006              
1007             my $PREPARATION = if(1 == Anansi::DatabaseComponent::prepare($OBJECT, undef,
1008             STATEMENT => 'an associated name'
1009             );
1010             if(defined($PREPARATION));
1011              
1012             if(1 == Anansi::DatabaseComponent::channel($OBJECT, 'PREPARE',
1013             INPUT => [
1014             {
1015             NAME => 'someParameter'
1016             }
1017             ],
1018             SQL => 'SELECT abc, def FROM some_table WHERE ghi = ?',
1019             STATEMENT => 'another associated name'
1020             ));
1021              
1022             if(1 == $OBJECT->prepare(undef,
1023             INPUT => [
1024             {
1025             NAME => 'abc'
1026             }, {
1027             NAME => 'def'
1028             }, {
1029             NAME => 'ghi'
1030             }
1031             ],
1032             SQL => 'INSERT INTO some_table (abc, def, ghi) VALUES (?, ?, ?);',
1033             STATEMENT => 'yet another name'
1034             ));
1035              
1036             if(1 == $OBJECT->channel('PREPARE',
1037             INPUT => [
1038             {
1039             NAME => ''
1040             }
1041             ],
1042             SQL => '',
1043             STATEMENT => 'and another',
1044             ));
1045              
1046             =over 4
1047              
1048             =item self I<(Blessed Hash, Required)>
1049              
1050             Either an object or a string of this namespace.
1051              
1052             =item channel I<(String, Required)>
1053              
1054             The abstract identifier of a subroutine.
1055              
1056             =item parameters I<(Hash, Required)>
1057              
1058             Named parameters.
1059              
1060             =over 4
1061              
1062             =item INPUT I
1063              
1064             An array of hashes. Each hash should contain a I key with a string value
1065             that represents the name of a parameter to associate with the corresponding B
1066             I<(Question mark)>. See the I method for details.
1067              
1068             =item SQL I<(String, Optional)>
1069              
1070             The SQL statement to prepare.
1071              
1072             =item STATEMENT I<(String, Required)>
1073              
1074             The name to associate with the prepared SQL statement.
1075              
1076             =back
1077              
1078             =back
1079              
1080             Attempts to prepare a SQL statement to accept named parameters in place of B
1081             I<(Question mark)>s as required. Either returns all of the preparation data
1082             required to fulfill the SQL statement when called as a namespace method or B<1>
1083             I<(one)> when called through a channel on success and B<0> I<(zero)> on failure.
1084              
1085             =cut
1086              
1087              
1088             sub prepare {
1089 0     0 1   my ($self, $channel, %parameters) = @_;
1090 0 0         return 0 if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
1091 0 0         $self->{STATEMENTS} = {} if(!defined($self->{STATEMENTS}));
1092 0 0         return 0 if(!defined($parameters{STATEMENT}));
1093 0 0         return 0 if(ref($parameters{STATEMENT}) !~ /^$/);
1094 0 0         if(!defined(${$self->{STATEMENTS}}{$parameters{STATEMENT}})) {
  0            
1095 0 0         return 0 if(!defined($parameters{SQL}));
1096 0 0         return 0 if(ref($parameters{SQL}) !~ /^$/);
1097 0           $parameters{SQL} =~ s/^\s*(.*)|(.*)\s*$/$1/g;
1098 0           my $questionMarks = $parameters{SQL};
1099 0           my $questionMarks = $questionMarks =~ s/\?/$1/sg;
1100 0 0         if(0 == $questionMarks) {
    0          
    0          
    0          
1101 0 0         return 0 if(defined($parameters{INPUT}));
1102             } elsif(!defined($parameters{INPUT})) {
1103 0           return 0;
1104 0           } elsif(ref($parameters{INPUT}) !~ /^ARRAY$/i) {
1105 0           return 0;
1106             } elsif(scalar(@{$parameters{INPUT}}) != $questionMarks) {
1107 0           return 0;
1108             } else {
1109 0 0         return 0 if(!$self->binding((@{$parameters{INPUT}})));
  0            
1110             }
1111 0           my $handle;
1112             eval {
1113 0           $handle = $self->{HANDLE}->prepare($parameters{SQL});
1114 0           1;
1115 0 0         } or do {
1116 0           $self->rollback();
1117 0           return 0;
1118             };
1119 0           my %statement = (
1120             HANDLE => $handle,
1121             SQL => $parameters{SQL},
1122             );
1123 0 0         $statement{INPUT} = $parameters{INPUT} if(defined($parameters{INPUT}));
1124 0           ${$self->{STATEMENTS}}{$parameters{STATEMENT}} = \%statement;
  0            
1125             }
1126 0 0         return 1 if(defined($channel));
1127 0           return ${$self->{STATEMENTS}}{$parameters{STATEMENT}};
  0            
1128             }
1129              
1130             Anansi::Component::addChannel('Anansi::DatabaseComponent', 'PREPARE' => 'prepare');
1131              
1132              
1133             =head2 rollback
1134              
1135             if(1 == Anansi::DatabaseComponent::rollback($OBJECT, undef));
1136              
1137             if(1 == Anansi::DatabaseComponent::channel($OBJECT, 'ROLLBACK'));
1138              
1139             if(1 == $OBJECT->rollback(undef));
1140              
1141             if(1 == $OBJECT->channel('ROLLBACK'));
1142              
1143             =over 4
1144              
1145             =item self I<(Blessed Hash, Required)>
1146              
1147             Either an object or a string of this namespace.
1148              
1149             =item channel I<(String, Required)>
1150              
1151             The abstract identifier of a subroutine.
1152              
1153             =item parameters I<(Hash, Optional)>
1154              
1155             Named parameters.
1156              
1157             =back
1158              
1159             Attempts to undo all of the database changes since the last database I.
1160             Returns B<1> I<(one)> on success and B<0> I<(zero)> on failure.
1161              
1162             =cut
1163              
1164              
1165             sub rollback {
1166 0     0 1   my ($self, $channel, %parameters) = @_;
1167 0 0         return 0 if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
1168 0 0         return 0 if($self->autocommit());
1169 0           my $rollback;
1170             eval {
1171 0           $rollback = $self->{HANDLE}->rollback();
1172 0           1;
1173 0 0         } or do {
1174 0           return 0;
1175             };
1176 0 0         return 0 if(!defined($rollback));
1177 0 0         return 0 if(ref($rollback) !~ /^$/);
1178 0 0         return 0 if($rollback !~ /^[\+\-]?\d+$/);
1179 0 0         return 1 if($rollback);
1180 0           return 0;
1181             }
1182              
1183             Anansi::Component::addChannel('Anansi::DatabaseComponent', 'ROLLBACK' => 'rollback');
1184              
1185              
1186             =begin comment
1187              
1188             ################################################################################
1189              
1190             =head2 script
1191              
1192             my $result = $object->script(
1193             undef,
1194             SCRIPT => [
1195             {
1196             COMMAND => 'LOOP',
1197             TEST => '',
1198             }, [
1199             {
1200             },
1201             ],
1202             ],
1203             );
1204              
1205             =over 4
1206              
1207             =item self I<(Blessed Hash, Required)>
1208              
1209             Either an object or a string of this namespace.
1210              
1211             =item channel I<(String, Required)>
1212              
1213             The abstract identifier of a subroutine.
1214              
1215             =item parameters I<(Hash, Required)>
1216              
1217             Named parameters.
1218              
1219             =over 4
1220              
1221             =item SCRIPT I<(Array, Required)>
1222              
1223             The SQL statements, control structures and external process triggers that are
1224             iterated through in sequence.
1225              
1226             =over 4
1227              
1228             =item I<(Array)>
1229              
1230             A sequence of statements like the I