File Coverage

lib/SQL/QueryBuilder/Flex.pm
Criterion Covered Total %
statement 194 312 62.1
branch 50 88 56.8
condition 13 26 50.0
subroutine 38 57 66.6
pod 1 34 2.9
total 296 517 57.2


line stmt bran cond sub pod time code
1             package SQL::QueryBuilder::Flex;
2              
3 24     24   648963 use strict;
  24         56  
  24         1099  
4 24     24   125 use warnings;
  24         43  
  24         792  
5 24     24   136 use List::Util qw(first);
  24         43  
  24         3345  
6 24     24   10216 use SQL::QueryBuilder::Flex::Join;
  24         60  
  24         625  
7 24     24   144 use SQL::QueryBuilder::Flex::Exp;
  24         44  
  24         1635  
8 24     24   207 use SQL::QueryBuilder::Flex::Writer;
  24         38  
  24         469  
9 24     24   121 use base 'SQL::QueryBuilder::Flex::Statement';
  24         36  
  24         3616  
10              
11             our $VERSION = '0.01';
12              
13 10     10 0 45 sub get_query { $_[0] };
14              
15             sub import {
16 24     24   283 my ($class, $alias) = @_;
17              
18 24 100       136 if ($alias) {
19 24     24   137 no strict 'refs';
  24         43  
  24         96360  
20 23 50       79 *{ $alias =~ /::/ ? $alias : caller(0).'::'.$alias } = sub () { __PACKAGE__ };
  23         52918  
21             }
22             }
23              
24             sub new {
25 27     27 1 62 my ($class, @options) = @_;
26 27         430 my $self = $class->SUPER::new(
27             columns => [],
28             from => [],
29             update => [],
30             insert => [],
31             join => [],
32             where => undef,
33             group_by => [],
34             having => undef,
35             order_by => [],
36             offset => undef,
37             limit => undef,
38             options => {},
39             union => [],
40             @options,
41             );
42 27         78 return $self;
43             }
44              
45             sub options {
46 1     1 0 2 my ($self, @options) = @_;
47 1         5 $self->{options}{$_} = 1 for @options;
48 1         3 return $self;
49             }
50              
51             sub select {
52 27     27 0 3189 my ($self, @columns) = @_;
53              
54             # Create instance if this method has been called directly
55 27 50       106 if (!ref $self) {
56 27         132 $self = __PACKAGE__->new;
57             }
58              
59             # Unpack hash refs to "$key AS $value" lines
60 54         137 @columns = grep { $_ } map {
61 27 50       74 if (ref $_ eq 'HASH') {
  54         152  
62 0         0 my $hash = $_;
63 0         0 map { "$_ AS $hash->{$_}" } keys %{$hash};
  0         0  
  0         0  
64             } else {
65 54         121 $_;
66             }
67             } @columns;
68              
69 27         49 push @{ $self->{columns} }, @columns;
  27         84  
70 27         132 return $self;
71             }
72              
73             sub from {
74 31     31 0 81 my ($self, $table, $alias) = @_;
75 31         47 push @{ $self->{from} }, [ $table => $alias ];
  31         100  
76 31         135 return $self;
77             }
78              
79             sub update {
80 0     0 0 0 my ($self, $table, $alias) = @_;
81              
82             # Create instance if this method has been called directly
83 0 0       0 if (!ref $self) {
84 0         0 $self = __PACKAGE__->new;
85             }
86              
87 0         0 push @{ $self->{update} }, [ $table => $alias ];
  0         0  
88              
89 0         0 return $self;
90             }
91              
92             sub insert {
93 0     0 0 0 my ($self, $table, @columns) = @_;
94              
95             # Create instance if this method has been called directly
96 0 0       0 if (!ref $self) {
97 0         0 $self = __PACKAGE__->new;
98             }
99              
100 0         0 push @{ $self->{insert} }, [ $table => undef ];
  0         0  
101              
102 0         0 $self->set(@columns);
103              
104 0         0 return $self;
105             }
106              
107             sub set {
108 0     0 0 0 my ($self, @columns) = @_;
109              
110 0         0 while (my $column = shift @columns) {
111 0 0       0 if (ref $column) {
112 0         0 push @{ $self->{columns} }, $column;
  0         0  
113             }
114             else {
115 0         0 my $value = shift @columns;
116 0         0 push @{ $self->{columns} }, [$column, $value];
  0         0  
117             }
118             }
119              
120 0         0 return $self;
121             }
122              
123             sub where {
124 4     4 0 11 my ($self, $cond, @values) = @_;
125 4   66     51 my $exp = $self->{where} ||= SQL::QueryBuilder::Flex::Exp->new(
126             parent => $self,
127             );
128 4 100       30 return $cond
129             ? $exp->and($cond, @values)->parent()
130             : $exp
131             ;
132             }
133              
134             sub having {
135 1     1 0 2 my ($self, $cond, @values) = @_;
136 1   33     7 my $exp = $self->{having} ||= SQL::QueryBuilder::Flex::Exp->new(
137             parent => $self,
138             );
139 1 50       6 return $cond
140             ? $exp->and($cond, @values)->parent()
141             : $exp
142             ;
143             }
144              
145             sub group_by {
146 4     4 0 13 my ($self, $column, $order, @params) = @_;
147 4         5 push @{ $self->{group_by} }, [ $column => $order, @params ];
  4         13  
148 4         10 return $self;
149             }
150              
151             sub order_by {
152 4     4 0 11 my ($self, $column, $order, @params) = @_;
153 4         6 push @{ $self->{order_by} }, [ $column => $order, @params ];
  4         14  
154 4         18 return $self;
155             }
156              
157             sub order_by_asc {
158 1     1 0 4 my ($self, $column, @params) = @_;
159 1         5 return $self->order_by($column, 'ASC', @params);
160             }
161              
162             sub order_by_desc {
163 1     1 0 3 my ($self, $column, @params) = @_;
164 1         4 return $self->order_by($column, 'DESC', @params);
165             }
166              
167             sub limit {
168 4     4 0 7 my ($self, $offset, $limit) = @_;
169 4 100       18 @$self{qw/offset limit/} = (scalar(@_) == 2)
170             ? (undef, $offset)
171             : ($offset, $limit)
172             ;
173 4         12 return $self;
174             }
175              
176             sub offset {
177 2     2 0 2 my ($self, $offset) = @_;
178 2         3 $self->{offset} = $offset;
179 2         5 return $self;
180             }
181              
182             sub union {
183 0     0 0 0 my ($self, $query) = @_;
184 0         0 push @{ $self->{union} }, $query;
  0         0  
185 0         0 return $self;
186             }
187              
188             sub _join {
189 9     9   32 my ($self, @options) = @_;
190 9         74 my $join = SQL::QueryBuilder::Flex::Join->new(
191             parent => $self,
192             @options,
193             );
194 9         17 push @{ $self->{join} }, $join;
  9         23  
195 9         52 return $join;
196             }
197              
198             sub inner_join {
199 2     2 0 3 my ($self, $table, $alias) = @_;
200 2         9 return $self->_join(
201             type => 'INNER',
202             table => $table,
203             alias => $alias,
204             );
205             }
206              
207             sub left_join {
208 5     5 0 7 my ($self, $table, $alias) = @_;
209 5         21 return $self->_join(
210             type => 'LEFT',
211             table => $table,
212             alias => $alias,
213             );
214             }
215              
216             sub right_join {
217 2     2 0 5 my ($self, $table, $alias) = @_;
218 2         8 return $self->_join(
219             type => 'RIGHT',
220             table => $table,
221             alias => $alias,
222             );
223             }
224              
225             sub _build_select {
226 27     27   57 my ($self, $writer, $indent) = @_;
227              
228 27         234 $writer->write(
229 27         54 join(' ', 'SELECT', sort keys %{ $self->{options} })
230             , $indent
231             );
232              
233 27         54 my $columns = $self->{columns};
234 27         56 my $last = scalar(@$columns) - 1;
235 27         49 my ($column, $alias, @params);
236 27         126 for(my $i = 0; $i <= $last; $i++) {
237 52         105 $column = $columns->[$i];
238 52 100       145 if (ref $column) {
239 1         4 ($column, $alias, @params) = @$column;
240 1 50       7 $writer->add_params(@params) if scalar @params;
241 1 50       5 $column = join(' AS ', $column, $alias) if $alias;
242             }
243 52 100       272 $writer->write($column . ($i == $last ? '' : ',') , $indent + 1);
244             }
245              
246 27         65 return;
247             }
248              
249             sub _build_from {
250 27     27   66 my ($self, $writer, $indent) = @_;
251              
252 27         123 $writer->write('FROM', $indent);
253              
254 27         53 my $from_list = $self->{from};
255 27         73 my $last = scalar(@$from_list) - 1;
256 27         50 my ($table, $alias);
257 27         133 for(my $i = 0; $i <= $last; $i++) {
258 29         57 ($table, $alias) = @{ $from_list->[$i] };
  29         80  
259 29 100       121 my $term = $i == $last ? '' : ',';
260 29 100       115 if (ref $table) {
261 1         3 $writer->write('(', $indent);
262 1         5 $table->build($writer, $indent + 1);
263 1         4 $writer->write(') AS ' . $alias . $term, $indent + 1);
264             }
265             else {
266 28 100       205 $writer->write( ($alias ? join(' ', $table, $alias) : $table) . $term, $indent + 1 );
267             }
268             }
269              
270 27         68 return;
271             }
272              
273             sub _build_update {
274 0     0   0 my ($self, $writer, $indent) = @_;
275              
276 0         0 $writer->write(
277 0         0 join(' ', 'UPDATE', keys %{ $self->{options} })
278             , $indent
279             );
280              
281 0         0 my $update_list = $self->{update};
282 0         0 my $last = scalar(@$update_list) - 1;
283 0         0 my ($table, $alias);
284 0         0 for(my $i = 0; $i <= $last; $i++) {
285 0         0 ($table, $alias) = @{ $update_list->[$i] };
  0         0  
286 0 0       0 my $term = $i == $last ? '' : ',';
287 0 0       0 if (ref $table) {
288 0         0 $writer->write('(', $indent);
289 0         0 $table->build($writer, $indent + 1);
290 0         0 $writer->write(') AS ' . $alias . $term, $indent + 1);
291             }
292             else {
293 0 0       0 $writer->write( ($alias ? join(' ', $table, $alias) : $table) . $term, $indent + 1 );
294             }
295             }
296              
297 0         0 return;
298             }
299              
300             sub _build_insert {
301 0     0   0 my ($self, $writer, $indent) = @_;
302              
303 0         0 $writer->write(
304 0         0 join(' ', 'INSERT', keys %{ $self->{options} })
305             , $indent
306             );
307              
308 0         0 my $insert_list = $self->{insert};
309 0         0 my $last = scalar(@$insert_list) - 1;
310 0         0 my ($table, $alias);
311 0         0 for(my $i = 0; $i <= $last; $i++) {
312 0         0 ($table, $alias) = @{ $insert_list->[$i] };
  0         0  
313 0 0       0 my $term = $i == $last ? '' : ',';
314 0 0       0 $writer->write( ($alias ? join(' ', $table, $alias) : $table) . $term, $indent + 1 );
315             }
316              
317 0         0 return;
318             }
319              
320             sub _build_set {
321 0     0   0 my ($self, $writer, $indent) = @_;
322              
323 0         0 $writer->write('SET', $indent);
324              
325 0         0 my $columns = $self->{columns};
326 0         0 my $last = scalar(@$columns) - 1;
327 0         0 for (my $i = 0; $i <= $last; $i++) {
328 0         0 my ($column, @params) = @{ $columns->[$i] };
  0         0  
329 0 0       0 if (scalar @params) {
330 0         0 my $firstValue = shift @params;
331 0 0       0 if (ref $firstValue) {
332 0 0       0 $writer->add_params(@params) if scalar @params;
333 0         0 $column .= "=$$firstValue";
334             }
335             else {
336 0         0 $writer->add_params($firstValue, @params);
337 0         0 $column .= '=?';
338             }
339             }
340 0 0       0 $writer->write($column . ($i == $last ? '' : ',') , $indent + 1);
341             }
342              
343 0         0 return;
344             }
345              
346             sub _build_join {
347 27     27   64 my ($self, $writer, $indent) = @_;
348 27         49 foreach my $join (@{ $self->{join} }) {
  27         82  
349 7         67 $join->build($writer, $indent + 1);
350             }
351 27         95 return;
352             }
353              
354             sub _build_where {
355 27     27   67 my ($self, $writer, $indent) = @_;
356 27 100 66     160 if ( $self->{where} && !$self->{where}->is_empty() ) {
357 3         20 $writer->write('WHERE', $indent);
358 3         33 $self->{where}->build($writer, $indent + 1);
359             }
360 27         102 return;
361             }
362              
363             sub _build_having {
364 27     27   63 my ($self, $writer, $indent) = @_;
365 27 100 66     181 if ( $self->{having} && !$self->{having}->is_empty() ) {
366 1         4 $writer->write('HAVING', $indent);
367 1         4 $self->{having}->build($writer, $indent + 1);
368             }
369 27         69 return;
370             }
371              
372             sub _build_group_by {
373 27     27   50 my ($self, $writer, $indent) = @_;
374 27 100       56 return unless scalar(@{ $self->{group_by} });
  27         124  
375 4         11 $writer->write(
376             join(' ', 'GROUP BY',
377             join(', ', map {
378 2         4 my ($column, $order, @params) = @$_;
379 4         20 $writer->add_params(@params);
380 4 100       22 $order ? join(' ', $column, $order) : $column;
381 2         4 } @{ $self->{group_by} })
382             ),
383             $indent
384             );
385 2         3 return;
386             }
387              
388             sub _build_order_by {
389 27     27   50 my ($self, $writer, $indent) = @_;
390 27 100       48 return unless scalar(@{ $self->{order_by} });
  27         118  
391 4         9 $writer->write(
392             join(' ', 'ORDER BY',
393             join(', ', map {
394 2         6 my ($column, $order, @params) = @$_;
395 4         15 $writer->add_params(@params);
396 4 100       23 $order ? join(' ', $column, $order) : $column;
397 2         5 } @{ $self->{order_by} })
398             ),
399             $indent
400             );
401 2         5 return;
402             }
403              
404             sub _build_limit {
405 27     27   56 my ($self, $writer, $indent) = @_;
406 27 100       108 return unless defined $self->{limit};
407 4 100       11 if ( defined $self->{offset} ) {
408 3         11 $writer->write('LIMIT ?, ?', $indent, @$self{qw/offset limit/});
409 3         13 $writer->add_params( @$self{qw/offset limit/} );
410             }
411             else {
412 1         8 $writer->write('LIMIT ?', $indent);
413 1         4 $writer->add_params( $self->{limit} );
414             }
415 4         5 return;
416             }
417              
418             sub do_build {
419 27     27 0 81 my ($self, $writer, $indent) = @_;
420              
421 27   100     183 $indent ||= 0;
422              
423 27 50       47 if (scalar @{ $self->{from} }) {
  27 0       113  
  0         0  
424 27         150 $self->_build_select ($writer, $indent);
425 27         122 $self->_build_from ($writer, $indent);
426 27         131 $self->_build_join ($writer, $indent);
427             }
428             elsif (scalar @{ $self->{update} }) {
429 0         0 $self->_build_update ($writer, $indent);
430 0         0 $self->_build_join ($writer, $indent);
431 0         0 $self->_build_set ($writer, $indent);
432             }
433             else {
434 0         0 $self->_build_insert ($writer, $indent);
435 0         0 $self->_build_set ($writer, $indent);
436             }
437 27         131 $self->_build_where ($writer, $indent);
438 27         97 $self->_build_group_by($writer, $indent);
439 27         106 $self->_build_having ($writer, $indent);
440 27         107 $self->_build_order_by($writer, $indent);
441 27         100 $self->_build_limit ($writer, $indent);
442              
443 27         40 foreach my $query ( @{ $self->{union} } ) {
  27         125  
444 0         0 $writer->write('UNION', $indent);
445 0         0 $query->do_build($writer, $indent);
446             }
447              
448 27         85 return;
449             }
450              
451             sub clear_options {
452 0     0 0 0 my ($self) = @_;
453 0         0 $self->{options} = {};
454 0         0 return $self;
455             }
456              
457             sub clear_select {
458 0     0 0 0 my ($self) = @_;
459 0         0 $self->{columns} = [];
460 0         0 return $self;
461             }
462              
463             sub clear_from {
464 0     0 0 0 my ($self) = @_;
465 0         0 $self->{from} = [];
466 0         0 return $self;
467             }
468              
469             sub clear_join {
470 0     0 0 0 my ($self) = @_;
471 0         0 $self->{join} = [];
472 0         0 return $self;
473             }
474              
475             sub clear_where {
476 0     0 0 0 my ($self) = @_;
477 0         0 $self->{where} = undef;
478 0         0 return $self;
479             }
480              
481             sub clear_having {
482 0     0 0 0 my ($self) = @_;
483 0         0 $self->{having} = undef;
484 0         0 return $self;
485             }
486              
487             sub clear_order_by {
488 0     0 0 0 my ($self) = @_;
489 0         0 $self->{order_by} = [];
490 0         0 return $self;
491             }
492              
493             sub clear_group_by {
494 0     0 0 0 my ($self) = @_;
495 0         0 $self->{group_by} = [];
496 0         0 return $self;
497             }
498              
499             sub delete_column {
500 2     2 0 7 my ($self, $name) = @_;
501             my @columns = grep {
502 5 100       10 if (ref $_) {
  2         5  
503 2         4 my ($column, $alias) = @$_;
504 2 50       7 if (defined $alias) {
505 2         3 $column = $alias;
506             }
507 2 100       11 ref $name ? $column !~ $name : $column ne $name
508             }
509             else {
510 3 100       10 ref $name ? $_ !~ $name : $_ ne $name
511             }
512 2         3 } @{ $self->{columns} };
513 2         3 $self->{columns} = \@columns;
514 2         12 return $self;
515             }
516              
517             sub delete_from {
518 2     2 0 7 my ($self, $name) = @_;
519 5   66     21 my @from = grep {
520 2         4 my $alias = $_->[1] || $_->[0];
521 5 100       22 ref $name ? $alias !~ $name : $alias ne $name
522 2         3 } @{ $self->{from} };
523 2         4 $self->{from} = \@from;
524 2         9 return $self;
525             }
526              
527             sub delete_join {
528 2     2 0 9 my ($self, $name) = @_;
529 3   66     12 my @join = grep {
530 2         6 my $alias = $_->alias() || $_->table();
531 3 100       20 ref $name ? $alias !~ $name : $alias ne $name
532 2         3 } @{ $self->{join} };
533 2         5 $self->{join} = \@join;
534 2         23 return $self;
535             }
536              
537             sub find_from {
538 0     0 0   my ($self, $name) = @_;
539             my $from = first {
540 0   0 0     my $alias = $_->[1] || $_->[0];
541 0 0         ref $name ? $alias =~ $name : $alias eq $name
542 0           } @{ $self->{from} };
  0            
543 0           return $from;
544             }
545              
546             sub find_join {
547 0     0 0   my ($self, $name) = @_;
548             my $join = first {
549 0   0 0     my $alias = $_->alias() || $_->table();
550 0 0         ref $name ? $alias =~ $name : $alias eq $name
551 0           } @{ $self->{join} };
  0            
552 0           return $join;
553             }
554              
555             1;
556             __END__