File Coverage

blib/lib/DBIx/Simple/Batch.pm
Criterion Covered Total %
statement 21 330 6.3
branch 0 134 0.0
condition 0 24 0.0
subroutine 7 40 17.5
pod 9 12 75.0
total 37 540 6.8


line stmt bran cond sub pod time code
1             package DBIx::Simple::Batch;
2              
3 1     1   31760 use warnings;
  1         2  
  1         29  
4 1     1   4 use strict;
  1         1  
  1         32  
5 1     1   1023 use DBIx::Simple;
  1         34425  
  1         38  
6 1     1   1525 use SQL::Abstract;
  1         12780  
  1         58  
7 1     1   1267 use SQL::Interp ':all';
  1         18159  
  1         10  
8 1     1   2166 use File::Find::Object;
  1         24645  
  1         2419  
9              
10             =head1 NAME
11              
12             DBIx::Simple::Batch - An Alternative To ORM and SQL Stored Procedures.
13              
14             =head1 VERSION
15              
16             Version 1.69
17              
18             =head1 DOCUMENTATION
19              
20             =over 4
21              
22             =item * L
23              
24             =item * L
25              
26             =back
27              
28             =cut
29              
30             our $VERSION = '1.69';
31             our @properties = caller();
32              
33             =head1 METHODS
34              
35             =head2 new
36              
37             I
38              
39             new B
40              
41             =over 3
42              
43             =item L<$path|/"$path">
44              
45             =item L<@connection_string|/"@connection_string">
46              
47             =back
48              
49             new B
50              
51             $db = DBIx::Simple::Batch->new($path);
52            
53             takes 2 arguments
54             1st argument - required
55             $path - path to folder where sql files are stored
56             2nd argument - required
57             @connection_string - display help for a specific command
58            
59             # Simple Example:
60             my $db = DBIx::Simple::Batch->new($path, @connection_string);
61             $db->call->folder->file(@parameters);
62            
63             ---
64            
65             # Got It? Now lets look at that again in slow-motion
66             my $path = '/var/www/app/queries';
67             my @connection_string = ('dbi:SQLite:/var/www/app/foo.db');
68             my $db = DBIx::Simple::Batch->new($path, @connection_string);
69            
70             # $path can also take a file pattern which turns on object mapping
71             my $path = '/var/www/app/queries/*.sql';
72             my @connection_string = ('dbi:SQLite:/var/www/app/foo.db');
73             my $db = DBIx::Simple::Batch->new($path, @connection_string);
74             $db->call->folder->file(...);
75              
76             =cut
77              
78             sub new {
79 0     0 1   my ($class, $path, @connect_options) = @_;
80            
81 0           my $self = {};
82 0           my $file_pattern = '';
83 0           bless $self, $class;
84            
85 0           $self->{set_names} = {};
86 0           $self->{sets} = [];
87 0           $self->{map_key} .= (@{['A'..'Z',0..9]})[rand(36)]
88 0           for (1..5);
89            
90 0 0         if (@connect_options) {
91 0 0         $self->{dbix} = DBIx::Simple->connect(@connect_options)
92             or die DBIx::Simple->error;
93             }
94            
95 0           ($path, $file_pattern) = $path =~ m/([^\*]+)(\*\.[\w\*]+)?/;
96            
97 0 0 0       unless (-d $path && -r $path) {
98 0           die "The path specified '$path', " .
99             "does not exist and/or is not accessible.";
100             }
101            
102 0 0         $self->{path} = $path =~ m/[\\\/]$/ ? $path : "$path/";
103 0           $self->{file_pattern} = $file_pattern;
104            
105             # turn-on object mapping
106 0 0         if ($self->{file_pattern}) {
107             #no warnings 'redefine';
108             #our @package = ("package DBIx::Simple::Batch::Map::$self->{map_key};\n");
109             #our $package_switch = 0;
110             #our $new_routine = 'sub new {my $class = shift;my $base = shift;my $self = {};$self->{base} = $base;bless $self, $class;return $self;}';
111             #our $has_folder = 0;
112             #find sub {
113             # my $file = $_;
114             # my $file_path = $File::Find::name;
115             # my $directory = $File::Find::dir;
116             # my $namespace = 'DBIx::Simple::Batch::Map::' . $self->{map_key} . '::';
117             #
118             # # specify package
119             # if (-d $file_path) {
120             # my $package_name = $file_path;
121             # my $prune = $path; $prune =~ s/[\\\/]+$//;
122             # $package_name =~ s/^$prune([\\\/])?//;
123             # if ($package_name) {
124             # $package_name =~ s/[\\\/]/::/g;
125             # $package_name =~ s/[^:a-zA-Z0-9]/\_/g;
126             # push @package, "$new_routine\n";
127             # my $fqns = "$namespace$package_name";
128             # my $instantiator = "$fqns"."->new(". 'shift->{base}' .")";
129             # my $sub = $package_name; $sub =~ s/.*::([^:]+)$/$1/;
130             # push @package, "sub $sub { return $instantiator }\n" . "package $fqns;\n";
131             # $package_switch = 1;
132             # $has_folder = 1;
133             # }
134             # }
135             # elsif (-f $file_path) {
136             # my $pat = $self->{file_pattern};
137             # if ($pat) {
138             # $pat =~ s/^\*\.([\*\w]+)/\.\*\.$1/;
139             # }
140             # else {
141             # $pat = '.*';
142             # }
143             # if ($file =~ /$pat/) {
144             # my $name = $file;
145             # $name =~ s/\.\w+$//g;
146             # $name =~ s/\W/\_/g;
147             # push(@package, "$new_routine\n") if $package_switch == 1;
148             # #
149             # $package_switch = 0;
150             # push @package, "sub $name ". '{ my $db = shift->{base}; return $db->queue(\''. $file_path .'\')->process(@_); }' ."\n";
151             # }
152             # }
153             # else {
154             # push @package, "$file -> ???\n";
155             # }
156             #
157             #}, $self->{path};
158             ## ugly no folders hack, this whole instantiation should be rewritten
159             #unless ($has_folder){
160             # my $package_name = shift(@package);
161             # unshift @package, $package_name, $new_routine;
162             #}
163 0           my $package = "DBIx::Simple::Batch::Map::$self->{map_key}";
164 0           my @objects = ();
165 0           my $tree = File::Find::Object->new({}, ($path));
166 0           while (my $o = $tree->next()) {
167 0           push @objects, $o;
168             }
169             # Build folder objects
170 0           foreach my $object (@objects) {
171 0 0 0       if (-d $object && -r $object) {
172 0           my $base_path = $objects[0];
173 0           my $base_path_re = $base_path;
174 0           $base_path_re =~ s/(\W)/\\$1/g;
175 0           my $this_path = $object;
176 0           my $rel_path = $this_path;
177 0           $rel_path =~ s/^$base_path_re//;
178            
179 0 0         if ($rel_path) {
180 0           my $namespace = $rel_path;
181 0           $namespace =~ s/[\\\/]/::/g;
182            
183             # Build packages
184 0 0         eval "package $package$namespace"; die $@ if $@;
  0            
185 0           eval "sub $package$namespace" . '::new {
186             my $class = shift;
187             my $base = shift;
188             my $self = {};
189             $self->{base} = $base;
190             bless $self, $class;
191             return $self;
192 0 0         }'; die $@ if $@;
193            
194             # Build pointers
195 0           eval "sub $package$namespace" . ' {
196             return ' . "$package$namespace" . '->new(shift->{base});
197 0 0         }'; die $@ if $@;
198            
199             }
200             }
201             }
202 0 0         eval "package $package"; die $@ if $@;
  0            
203 0           eval "sub $package" . '::new {
204             my $class = shift;
205             my $base = shift;
206             my $self = {};
207             $self->{base} = $base;
208             bless $self, $class;
209             return $self;
210 0 0         }'; die $@ if $@;
211             # Build file objects
212 0           foreach my $object (@objects) {
213 0 0 0       if (-f $object && -r $object) {
214 0           my $base_path = $objects[0];
215 0           my $base_path_re = $base_path;
216 0           $base_path_re =~ s/(\W)/\\$1/g;
217 0           my $this_path = $object;
218 0           my $rel_path = $this_path;
219 0           $rel_path =~ s/^$base_path_re//;
220            
221 0 0         if ($rel_path) {
222 0           my @structure = split /[\\\/]/, $rel_path;
223 0           my $filename = $structure[$#structure];
224 0           my $namespace = $rel_path;
225 0           $namespace =~ s/[\\\/]/::/g;
226 0           my $pat = $self->{file_pattern};
227 0 0         if ($pat) {
228 0           $pat =~ s/^\*\.([\*\w]+)/\.\*\.$1/;
229             }
230             else {
231 0           $pat = '.*';
232             }
233 0 0         if ($namespace =~ /$pat/) {
234 0           $namespace =~ s/\.\w+$//g;
235 0           $namespace =~ s/[^:a-zA-Z0-9]/\_/g;
236            
237 0           eval "sub $package$namespace" . ' {
238             my $db = shift->{base};
239             return $db->queue(\''. $this_path .'\')->process(@_);
240 0 0         }'; die $@ if $@;
241             }
242             }
243             }
244             }
245             }
246            
247             # load directives
248 0           $self->_load_commands;
249 0           return $self;
250             }
251              
252             =head2 call
253              
254             I
255              
256             call B
257              
258             No arguments.
259              
260             call B
261              
262             $db->call;
263            
264             takes 0 arguments
265            
266             example:
267             $db->call->file(...);
268             $db->call->folder->file;
269             $db->call->folder->folder->file;
270              
271             =cut
272              
273             sub call {
274 0     0 1   my $self = shift;
275 0           return ("DBIx::Simple::Batch::Map::".$self->{map_key})->new($self);
276             }
277              
278             =head2 constants
279              
280             I
281             be including in the execution of all commands.>
282              
283             constants B
284              
285             =over 3
286              
287             =item L<$custom_params|/"\%custom_params">
288              
289             =back
290              
291             constants B
292              
293             $self->constants({ param1 => 1, param2 => 2});
294            
295             takes 1 argument
296             1st argument - required
297             \%hashref - display help for a specific command
298            
299             example:
300             $self->constants({ id => 1 });
301             Now, in every command `$!id` will be replaced with `1` unless a custom
302             param is passed to the process_queue method or call accessors.
303              
304             =cut
305              
306             sub constants {
307 0     0 1   my $self = shift;
308 0           $self->{constants} = shift;
309             }
310              
311             # The _load_commands method is an internal method for building the commands
312             # dispatch table.
313              
314             sub _load_commands {
315 0     0     my $self = shift;
316            
317             # identify commands that can only contain select statements
318 0           $self->{select_required} = ['capture', 'replace', 'declare'];
319            
320             # determine how blank parameters are handled by default
321 0           $self->{settings}->{blank} = '0';
322            
323             #! connect: creates or replaces the database connection
324             $self->{commands}->{connect} = sub {
325 0     0     my ($statement, @parameters) = @_;
326 0           my @connect_options = $statement =~ m/(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)/g;
327 0 0         $connect_options[1] = '' if $connect_options[1] eq '-';
328 0 0         $connect_options[2] = '' if $connect_options[2] eq '-';
329 0 0         if ($connect_options[3]) {
330 0           $connect_options[3] = join ",", splice @connect_options, 3;
331 0           $connect_options[3] = eval "$connect_options[3]";
332 0 0         $self->{dbix} = DBIx::Simple->connect(@connect_options)
333             or die DBIx::Simple->error;
334             }
335             else {
336 0           die $self->_error('Invalid database connection.');
337             }
338 0           };
339            
340             #! capture: stores the resultset for later usage
341             $self->{commands}->{capture} = sub {
342 0     0     my ($statement, @parameters) = @_;
343 0           $self->{processing}->{resultset} = $self->_execute_query($statement, @parameters);
344 0           $self->{sets}->[@{$self->{sets}}] = $self->{processing}->{resultset}->hashes;
  0            
345            
346             # store resultset via name
347 0           $self->{set_names}->{$self->{processing}->{set_name}} =
348 0 0         $self->{sets}->[(@{$self->{sets}})-1]
349             if $self->{processing}->{set_name};
350 0 0         $self->{processing}->{set_name} = ''
351             if $self->{processing}->{set_name};
352 0           };
353            
354             #! execute: execute sql commands only, nothing else, nothing fancy
355             $self->{commands}->{execute} = sub {
356 0     0     my ($statement, @parameters) = @_;
357 0           $self->{processing}->{resultset} = $self->_execute_query($statement, @parameters);
358 0           };
359            
360             #! proceed: evaluates the statement passed (perl code) for truth, if true, it continues if false it
361             # skips to the next proceed command or until the end of the sql file.
362             $self->{commands}->{proceed} = sub {
363 0     0     my ($statement, @parameters) = @_;
364 0 0         if (@parameters) {
365 0           foreach my $parameter (@parameters) {
366 0 0         $parameter = $self->{settings}->{blank} unless defined $parameter;
367 0           $statement =~ s/\?/$parameter/;
368             }
369             }
370 0 0         $self->{processing}->{skip_switch} = eval $statement ? 0 : 1;
371 0           };
372            
373             #! ifvalid: a synonym for proceed
374 0           $self->{commands}->{ifvalid} = $self->{commands}->{proceed};
375 0           $self->{commands}->{validif} = $self->{commands}->{proceed};
376            
377             #! replace: replaces parameters with the data from the last row of the resultset
378             $self->{commands}->{replace} = sub {
379 0     0     my ($statement, @parameters) = @_;
380 0           $self->{processing}->{resultset} = $self->_execute_query($statement, @parameters);
381 0           $self->{processing}->{parameters} = @{$self->{processing}->{resultset}->array};
  0            
382 0           };
383            
384             #! include: processes another (sql) text file
385             $self->{commands}->{include} = sub {
386 0     0     my ($statement, @parameters) = @_;
387 0           my ($sub_sqlfile, $placeholders) = split /\s/, $statement;
388 0 0         @parameters = split /[\,\s]/, $placeholders if $placeholders;
389 0           my $sub = DBIx::Simple::Batch->new($self->{path}, $self->{dbix}->{dbh});
390 0           $sub->queue($self->{path}.$sub_sqlfile)->process_queue(@parameters,
391             $self->{processing}->{custom_parameters});
392             # copying sub resultsets
393 0 0         if (keys %{$sub->{set_names}}) {
  0            
394 0           map {
395 0           $self->{set_names}->{$_} = $sub->{set_names}->{$_}
396 0           } keys %{$sub->{set_names}};
397             }
398 0           };
399            
400             #! storage: stores sql statements for later
401             $self->{commands}->{storage} = sub {
402 0     0     my ($statement, @parameters) = @_;
403 0           };
404            
405             #! declare: uses an sql select statement to add vairables to the scope for processing
406             $self->{commands}->{declare} = sub {
407 0     0     my ($statement, @parameters) = @_;
408 0           $self->{processing}->{resultset} = $self->_execute_query($statement, @parameters);
409 0           my $results = $self->{processing}->{resultset}->hash;
410 0 0         if ($results) {
411 0           my %params = %{$results};
  0            
412 0           while ( my ($key, $val) = each %params ) {
413 0           $self->{processing}->{custom_parameters}->{$key} = $val;
414             }
415             }
416 0           };
417            
418             #! forward: changes the queue position, good for looping
419             $self->{commands}->{forward} = sub {
420 1     1   14 no warnings;
  1         3  
  1         2650  
421 0     0     my ($statement, @parameters) = @_;
422 0           $self->{cursor} = $statement;
423 0           next; # purposefully next out of the loop to avoid incrementation. warning should be turned off.
424 0           };
425            
426             #! process: executes a command in the queue by index number
427             $self->{commands}->{process} = sub {
428 0     0     my ($statement, @parameters) = @_;
429 0           $self->process_command($statement, @parameters);
430 0           };
431            
432             #! examine: dumps the passed sql statement to the screen (should not be left in the sql file)
433             $self->{commands}->{examine} = sub {
434 0     0     my ($statement, @parameters) = @_;
435 0           my $db = $self->{dbix}->{dbh};
436 0           foreach my $parameter (@parameters) {
437 0           my $placeholder = $db->quote($parameter);
438 0           $statement =~ s/\?/$placeholder/;
439             }
440 0           die $self->_error( $statement );
441 0           };
442            
443             #! setting: configures how the module handles blank parameters
444             $self->{commands}->{setting} = sub {
445 0     0     my ($statement, @parameters) = @_;
446 0 0         $self->{settings}->{blank} = '0' if (lc($statement) eq 'blank as zero');
447 0 0         $self->{settings}->{blank} = '' if (lc($statement) eq 'blank as blank');
448 0 0         $self->{settings}->{blank} = 'NULL' if (lc($statement) eq 'blank as null');
449 0           };
450            
451             #! setname: configures how the module handles blank parameters
452             $self->{commands}->{setname} = sub {
453 0     0     my ($statement, @parameters) = @_;
454 0 0         $self->{processing}->{set_name} = $statement if $statement;
455 0           };
456            
457             #! perl -e: provides access to perl's eval function
458             $self->{commands}->{perl} = sub {
459 0     0     my ($statement, @parameters) = @_;
460 0           $statement =~ s/^\-e//;
461 0           eval $statement;
462             }
463 0           }
464              
465             # The _execute_query method is an internal method for executing queries
466             # against the databse in a standardized fashion.
467              
468             sub _execute_query {
469 0     0     my ($self, $statement, @parameters) = @_;
470 0 0         if ($statement =~ /\$\%/) {
471             # find and replace any standard placeholders
472 0           my $dbh = $self->{dbix}->dbh;
473 0 0         if (@parameters) {
474 0           foreach my $param (@parameters) {
475 0           my $p = $dbh->quote($param);
476 0           $statement =~ s/\?/$p/;
477             }
478             }
479            
480             # process sql::interp style queries, *new*, experimental
481 0           my @params = $statement =~ /\$\%([a-z0-9A-Z\_\-]+)/g;
482 0           my @sql = split /\,/, $statement;
483 0           foreach my $term (@sql) { $term =~ s/(^\s+|\s+$)//;
  0            
484 0 0         if ($term =~ /^\$\%([a-z0-9A-Z\_\-]+)$/) {
485 0           my $param = $self->{processing}->{custom_parameters}->{$1};
486 0 0         $term = ref($param) ? $param : \$param;
487             }
488             }
489 0           ($statement, @parameters) = sql_interp(@sql);
490 0 0         my $resultset = $self->{dbix}->query( $statement, @parameters ) or
491             die $self->_error(undef, @parameters);
492 0           return $resultset;
493            
494             }
495             else {
496 0 0         my $resultset = $self->{dbix}->query( $statement, @parameters ) or
497             die $self->_error(undef, @parameters);
498 0           return $resultset;
499             }
500             }
501              
502             # The _error method is an internal method that dies with a standardized
503             # error message.
504              
505             sub _error {
506 0     0     my ( $self, $message, @parameters ) = @_;
507 0   0       my $error_message = ref($self)
508             . " - sql file $self->{file} processing failed or is being examined,\n"
509             . ($message || "database error") . ".";
510 0 0         if (ref($self->{cmds}) eq "ARRAY") {
511 0 0 0       $error_message .= " \nPoint of failure, command number "
    0 0        
    0          
512             . ( $self->{cursor} || '0' ) . " ["
513             . ( $self->{cmds} ? $self->{cmds}->[ $self->{cursor} ]->{command} : '' )
514             . "] "
515             . (
516             $self->{cmds}->[ $self->{cursor} ]->{statement}
517             ? ( "and statement \n("
518             . substr( $self->{cmds}->[ $self->{cursor} ]->{statement}, 0, 20 )
519             . "...) " )
520             : " "
521             )
522             . ( @parameters ? ( "using " . join( ', ', @parameters ) . " " ) : "" )
523             . "at $properties[1]"
524             . " on line $properties[2], "
525             . ( $message || $self->{dbix}->error || "Check the sql file for errors" )
526             . ".";
527             }
528 0           return $error_message;
529             }
530              
531             # The _processor method is an internal methoed that when passed a command
532             # hashref, processes the command.
533              
534             sub _processor {
535 0     0     my ($self, $cmdref) = @_;
536 0           my $command = $cmdref->{command};
537 0           my $statement = $cmdref->{statement};
538            
539             # replace statement placeholders with actual "?" placeholders while building the statement params list
540             # my @statement_parameters = map { $self->{processing}->{parameters}[$_] } $statement =~ m/\$(\d+)/g;
541             # $self->{processing}->{statement_parameters} = \@statement_parameters;
542             # $statement =~ s/\$\d+/\?/g;
543            
544             # reset statement parameters
545 0           $self->{processing}->{statement_parameters} = ();
546            
547             # replace statement placeholders with actual "?" placeholders while building the statement params
548             # list using passed or custom parameters
549 0           while ($statement =~ m/(\$\!([a-z0-9A-Z\_\-]+))|(\$(\d+(?!\w)))/) {
550 0           my $custom = $2;
551 0           my $passed = $4;
552             # if the found param is a custom param
553 0 0         if (defined $custom) {
554 0           push @{$self->{processing}->{statement_parameters}}, $self->{processing}->{custom_parameters}->{$custom};
  0            
555 0           $statement =~ s/\$\!$custom/\?/;
556             }
557             # if the found param is a passed-in param
558 0 0         if (defined $passed) {
559 0           push @{$self->{processing}->{statement_parameters}}, $self->{processing}->{parameters}[$passed];
  0            
560 0           $statement =~ s/\$$passed/\?/;
561             }
562             }
563            
564 0 0 0       if ($self->{processing}->{skip_switch} && ( $command ne "proceed" && $command ne "ifvalid" && $command ne "validif" ) )
      0        
      0        
565             {
566             # skip command while skip_switch is turned on
567 0           return;
568             }
569             else
570             {
571             # execute command
572 0           $self->{commands}->{$command}->($statement, @{$self->{processing}->{statement_parameters}});
  0            
573 0           return $self->{processing}->{resultset};
574             }
575             }
576              
577             # The _parse_parameters method examines each initially passed in parameter
578             # specifically looking for a hashref to add its values to the custom
579             # parameters key.
580              
581             sub _parse_parameters {
582 0     0     my ($self, @parameters) = @_;
583             # process constants
584 0 0         if ($self->{constants}) {
585 0 0         if (ref($self->{constants}) eq "ARRAY") {
586 0           unshift @parameters, @{$self->{constants}};
  0            
587             }
588 0 0         if (ref($self->{constants}) eq "HASH") {
589 0           while (my($key, $val) = each (%{$self->{constants}})) {
  0            
590 0           $self->{processing}->{custom_parameters}->{$key} = $val;
591             }
592             }
593             }
594             # normal operation
595 0           for (my $i=0; $i < @parameters; $i++) {
596 0           my $param = $parameters[$i];
597 0 0         if (ref($param) eq "HASH") {
598 0           while (my($key, $val) = each (%{$param})) {
  0            
599 0           $self->{processing}->{custom_parameters}->{$key} = $val;
600             }
601 0           delete $parameters[$i];
602             }
603             }
604 0           $self->{processing}->{parameters} = \@parameters;
605 0           return $self;
606             }
607              
608             # The _parse_sqlfile method scans the passed (sql) text file and returns
609             # a list of sql statement queue objects.
610              
611             sub _parse_sqlfile {
612 0     0     my ($self, $sqlfile) = @_;
613 0           my (@lines, @statements);
614             # open file and fetch commands
615 0           $self->{file} = $sqlfile;
616 0 0         open (SQL, "$sqlfile") || die $self->_error( "Could'nt open $sqlfile sql file" );
617 0           push @lines, $_ while();
618 0 0         close SQL || die $self->_error( "Could'nt close $sqlfile sql file" );
619             # attempt to parse commands w/multi-line sql support
620 0           my $use_mlsql = 0;
621 0           my $mlcmd = '';
622 0           my $mlsql = '';
623 0           foreach my $command (@lines) {
624 0 0         if ($command =~ /^\!/) {
625 0           my @commands = $command =~ /^\!\s(\w+)\s(.*)/;
626 0 0         if (grep ( $commands[0] eq $_, keys %{$self->{commands}})) {
  0            
627 0 0         if ($commands[1] =~ /^\{/) {
628 0           $use_mlsql = 1;
629 0           $mlcmd = $commands[0];
630 0           next;
631             }
632             else {
633 0           push @statements, { "command" => "$commands[0]", "statement" => "$commands[1]" };
634             }
635             }
636             }
637 0 0         if ( $use_mlsql == 1 ) {
638 0 0         if ( $command !~ /^\}$/ ) {
639 0           $mlsql .= $command;
640 0           next;
641             }
642             else {
643 0           push @statements, { "command" => "$mlcmd", "statement" => "$mlsql" };
644 0           $use_mlsql = 0;
645 0           $mlcmd = '';
646 0           $mlsql = '';
647             }
648             }
649             }
650             # validate statements
651 0           $self->_validate_sqlfile(@statements);
652 0           return @statements;
653             }
654              
655             # The _validate_sqlfile method make sure that the supplied (sql) text
656             # file conforms to its command(s) rules.
657              
658             sub _validate_sqlfile {
659 0     0     my ($self, @statements) = @_;
660             # rule1: replace, and capture can only be used with select statements
661 0           foreach my $statement (@statements) {
662 0 0         if (grep ( $statement->{command} eq $_, @{$self->{select_required}})) {
  0            
663 0 0         if (lc($statement->{statement}) !~ /^(\s+)?select/) {
664 0           die $self->_error( "Validation of the sql file $self->{file} failed. The command ($statement->{command}) can only be used with an SQL (select) statement.", $statement->{statement});
665             }
666             }
667             }
668             }
669              
670             =head2 queue
671              
672             I
673             of sql statements to be executed and how.>
674              
675             queue B
676              
677             =over 3
678              
679             =item L<$sql_file|/"$sql_file">
680              
681             =back
682              
683             queue B
684              
685             $db->queue($sql_file);
686            
687             takes 1 argument
688             1st argument - required
689             $sql_file - path to the sql file to process
690            
691             example:
692             $db->queue($sql_file);
693              
694             =cut
695              
696             sub queue {
697 0     0 1   my ($self, $sqlfile) = @_;
698 0           my (@statements);
699 0           $self->{cmds} = '';
700            
701             # set caller data for error reporting
702 0           @properties = caller();
703 0           @statements = $self->_parse_sqlfile($sqlfile);
704 0           $self->{cmds} = \@statements;
705 0           return $self;
706             }
707              
708             =head2 process_queue
709              
710             I
711             found the (sql) text file.>
712              
713             process_queue B
714              
715             =over 3
716              
717             =item L<@parameters|/"@parameters">
718              
719             =back
720              
721             process_queue B
722              
723             $self->process_queue(@parameters);
724            
725             takes 1 argument
726             1st argument - required
727             @parameters - parameters to be used in parsing the sql file
728            
729             example:
730             $db->process_queue(@parameters);
731             $db->process_queue($hashref, @parameters);
732            
733             process_queue B
734              
735             =over 3
736              
737             =item * process
738              
739             =back
740              
741             =cut
742              
743             sub process_queue {
744 0     0 1   my ($self, @parameters) = @_;
745             # set caller data for error reporting
746 0           @properties = caller();
747 0 0         $self->_parse_parameters(@parameters) if @parameters;
748 0           $self->{processing}->{skip_switch} = 0;
749 0           $self->{cursor} = 0;
750 0 0         if (@{$self->{cmds}}) {
  0            
751             # process sql commands
752 0           for (my $i = 0; $self->{cursor} < @{$self->{cmds}}; $i++) {
  0            
753 0           my $cmd = $self->{cmds}->[$self->{cursor}];
754 0 0         if ( grep($cmd->{command} eq $_, keys %{$self->{commands}}) )
  0            
755             {
756             # process command
757 0           $self->_processor($cmd);
758 0           $self->{cursor}++;
759             }
760             }
761 0           return $self->{processing}->{resultset};
762             }
763             else {
764 0           die $self->_error( "File has no commands to process" );
765             }
766 0           return $self;
767             }
768              
769             # process_queue synonym
770              
771             sub process {
772 0     0 1   shift->process_queue(@_);
773             }
774              
775             # The sets method provides direct access to the resultsets array or
776             # resultsets.
777              
778             sub sets {
779 0     0 0   return shift->{sets};
780             }
781              
782             =head2 cache
783              
784             I
785             using the (sql file) capture command and returns the resultset of the
786             index or name passed to it or returns 0.>
787              
788             cache B
789              
790             =over 3
791              
792             =item L<$index|/"$index">
793              
794             =back
795              
796             cache B
797              
798             my $results = $db->cache($index);
799            
800             takes 1 argument
801             1st argument - required
802             $index - name or array index of the desired resultset
803            
804             example:
805             my $resultset = $db->cache('new_group');
806             my $resultset = $db->cache(2);
807              
808             cache B
809              
810             =over 3
811              
812             =item * rs
813              
814             =back
815              
816             =cut
817              
818             sub cache {
819 0     0 1   my ($self, $index) = @_;
820 0 0         if ($index =~ /^\d+$/) {
821 0 0         if ($self->{sets}->[$index]) {
822 0           return $self->{sets}->[$index];
823             }
824             }
825             else {
826 0 0         if ($self->{set_names}->{$index}) {
827 0           return $self->{set_names}->{$index};
828             }
829             }
830 0           return 0;
831             }
832              
833             # The rs method is a synonym for the cache method
834              
835             sub rs {
836 0     0 1   return shift->cache(@_);
837             }
838              
839             # The command method is used to queue a command to be processed later by the # # # process_queue method. Takes two arguments, "command" and "sql statement",
840             # e.g. command('execute', 'select * from foo').
841              
842             sub command {
843 0     0 0   my ($self, $command, $statement) = @_;
844 0           my @statements = @{$self->{cmds}};
  0            
845 0           push @statements, { "command" => "$command", "statement" => "$statement" };
846 0           $self->{cmds} = \@statements;
847 0           return $self;
848             }
849              
850             # The process_command method allows you to process the indexed sql
851             # satements from your sql file individually. It take two argument, the
852             # index of the command as it is encountered in the sql file and tries
853             # returns a resultset, and any parameters that need to be passed to it.
854              
855             sub process_command {
856 0     0 0   my ($self, $index, @parameters) = @_;
857 0           my $cmd = $self->{cmds}->[$index];
858 0 0         if ( grep($cmd->{command} eq $_, keys %{$self->{commands}}) )
  0            
859             {
860             # process command
861 0 0         $self->_parse_parameters(@parameters) if @parameters;
862 0           return $self->_processor($cmd);
863             }
864             }
865              
866             =head2 clear
867              
868             I
869              
870             clear B
871              
872             No arguments.
873              
874             clear B
875              
876             $db->clear;
877            
878             takes 0 arguments
879            
880             example:
881             $db->clear
882              
883             =cut
884              
885             sub clear {
886 0     0 1   my $self = shift;
887 0           $self->{cmds} = '';
888 0           $self->{set_names} = {};
889 0           $self->{sets} = [];
890 0           $self->{processing}->{resultset} = '';
891 0           $self->{processing}->{skip_switch} = 0;
892 0           $self->{processing}->{parameters} = [];
893 0           $self->{processing}->{custom_parameters} = {};
894 0           $self->{cursor} = 0;
895            
896 0           return $self;
897             }
898              
899             =head1 AUTHOR
900              
901             Al Newkirk, C<< >>
902              
903             =head1 BUGS
904              
905             Please report any bugs or feature requests to C, or through
906             the web interface at L.
907             I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
908              
909             =head1 SUPPORT
910              
911             You can find documentation for this module with the perldoc command.
912              
913             perldoc DBIx::Simple::Batch
914              
915             You can also look for information at:
916              
917             =over 4
918              
919             =item * RT: CPAN's request tracker
920              
921             L
922              
923             =item * AnnoCPAN: Annotated CPAN documentation
924              
925             L
926              
927             =item * CPAN Ratings
928              
929             L
930              
931             =item * Search CPAN
932              
933             L
934              
935             =back
936              
937             =head1 ACKNOWLEDGEMENTS
938              
939             =head1 COPYRIGHT & LICENSE
940              
941             Copyright 2009 Al Newkirk.
942              
943             This program is free software; you can redistribute it and/or modify it
944             under the terms of either: the GNU General Public License as published
945             by the Free Software Foundation; or the Artistic License.
946              
947             See http://dev.perl.org/licenses/ for more information.
948              
949             =cut
950              
951             1; # End of DBIx::Simple::Batch