File Coverage

blib/lib/SQL/Abstract/Complete.pm
Criterion Covered Total %
statement 84 91 92.3
branch 58 78 74.3
condition 14 21 66.6
subroutine 10 10 100.0
pod 2 2 100.0
total 168 202 83.1


line stmt bran cond sub pod time code
1             package SQL::Abstract::Complete;
2             # ABSTRACT: Generate complete SQL from Perl data structures
3              
4 1     1   202442 use 5.008;
  1         6  
5 1     1   4 use strict;
  1         1  
  1         16  
6 1     1   3 use warnings;
  1         2  
  1         22  
7              
8 1     1   575 use SQL::Abstract 1.5;
  1         14954  
  1         49  
9 1     1   546 use Storable 'dclone';
  1         2433  
  1         62  
10              
11 1     1   9 use vars '@ISA';
  1         2  
  1         988  
12             @ISA = 'SQL::Abstract';
13              
14             our $VERSION = '1.08'; # VERSION
15              
16             sub new {
17 2     2 1 77 my $self = shift;
18 2         16 $self = $self->SUPER::new(@_);
19 2   100     403 $self->{'part_join'} ||= ' ';
20 2         13 return $self;
21             }
22              
23             sub _wipe_space {
24             return join( '', map {
25 58     58   323 s/\s{2,}/ /g;
  58         114  
26 58         146 s/^\s+|\s+$//g;
27 58         80 s/\s+,/,/g;
28 58         177 $_;
29             } @_ );
30             }
31              
32             sub _sqlcase {
33 67 100   67   2685 return ( $_[0]->{'case'} ) ? $_[1] : uc( ( defined( $_[1] ) ) ? $_[1] : '' );
    50          
34             }
35              
36             sub select {
37 15     15 1 1966 my ( $self, $tables, $columns, $where, $meta ) = @_;
38 15 100 66     39 $columns = ['*'] unless ( $columns and @{$columns} > 0 );
  6         15  
39 15 100       195 $tables = dclone($tables) if ( ref $tables );
40              
41             my $columns_sql = $self->_sqlcase('select') . ' ' . _wipe_space(
42 0         0 ( ref($columns) eq 'SCALAR' ) ? ${$columns} :
43             ( not ref($columns) ) ? $self->_quote($columns) :
44             join( ', ', map {
45 1         2 ( ref($_) eq 'SCALAR' ) ? ${$_} :
46             ( not ref($_) ) ? $self->_quote($_) :
47 23 50       150 join( ' AS ', map { $self->_quote($_) } ( ref($_) eq 'HASH' ) ? %{$_} : @{$_} );
  2 100       13  
  1 100       3  
  0         0  
48 15 50       31 } @{$columns} )
  15 50       320  
49             );
50              
51 15         22 my $core_table;
52             my $tables_sql = join(
53             $self->{'part_join'},
54             map { _wipe_space( join( ' ',
55 22         39 $self->_sqlcase( shift( @{$_} ) ),
56 22         126 grep { defined } @{$_} )
  31         65  
  22         33  
57             ) } (
58 1         2 ( ref($tables) eq 'SCALAR' ) ? [ undef, ${$tables} ] :
59             ( not ref($tables) ) ? [ 'from', $self->_quote($tables) ] :
60             map {
61 2         6 ( ref($_) eq 'SCALAR' ) ? [ undef, ${$_} ] :
62             ( not ref($_) ) ? [ 'from', $self->_quote($_) ] :
63 12 100       23 do {
    100          
64 9 50       14 my @parts = ( ref($_) eq 'HASH' ) ? %{$_} : @{$_};
  0         0  
  9         16  
65 9 100       15 my $join_type = ( ref( $parts[0] ) eq 'SCALAR' ) ? ${ shift(@parts) } : 'join';
  2         3  
66              
67             my $join_on =
68 1         1 ( ref( $parts[-1] ) eq 'SCALAR' ) ? ${ pop(@parts) } :
69 9 100 66     34 ( ref( $parts[-1] ) eq 'HASH' and @parts > 1 ) ? do {
    100 66        
    100          
70 1         2 my $join_def = pop(@parts);
71 1 50       5 $join_type = $join_def->{'join'} . ' join' if ( $join_def->{'join'} );
72              
73             ( ref( $join_def->{'using'} || $join_def->{'on'} ) eq 'SCALAR' )
74 0 0       0 ? ${ $join_def->{'using'} || $join_def->{'on'} } :
75             ( $join_def->{'using'} )
76             ? $self->_sqlcase('using') . '(' . $join_def->{'using'} . ')' :
77             ( $join_def->{'on'} )
78 1 0 33     5 ? $self->_sqlcase('on') . ' ' . $join_def->{'on'} : '';
    50          
    50          
79             } :
80             ( not ref( $parts[-1] ) and @parts > 1 )
81             ? $self->_sqlcase('using') . '(' . $self->_quote( pop(@parts) ) . ')'
82             : '';
83              
84 9         54 my $table_def = shift(@parts);
85             $table_def =
86             ( not ref($table_def) ) ? $table_def :
87 0         0 ( ref($table_def) eq 'SCALAR' ) ? ${$table_def} :
88 9 50       15 do {
    50          
89 9 100       17 $table_def = [ %{$table_def} ] if ( ref($table_def) eq 'HASH' );
  4         10  
90 9         7 my $table_name = shift( @{$table_def} );
  9         12  
91              
92 9 100       15 unless ($core_table) {
93 3         3 $core_table = $table_name;
94 3         4 $join_type = 'from';
95             }
96              
97 9         101 $self->_quote($table_name) . ( ( @{$table_def} ) ? ' ' . join(
98             ' ',
99             $self->_sqlcase('as'),
100 9 50       14 map { $self->_quote($_) } @{$table_def},
  9         14  
  9         12  
101             ) : '' );
102             };
103              
104 9         109 [ $join_type, $table_def, $join_on ];
105             };
106 15 50       46 } ( ( ref($tables) ) ? @{$tables} : $tables )
  5 100       9  
    100          
107             )
108             );
109              
110 15         40 my ( $where_sql, @bind ) = $self->where($where);
111              
112 15   50     199 my ( $offset, $rows ) = ( $meta->{'offset'} || 0, $meta->{'rows'} || 0 );
      100        
113 15 50       27 if ( $meta->{'limit'} ) {
114             ( $offset, $rows ) = ( ref( $meta->{'limit'} ) eq 'ARRAY' )
115 0         0 ? @{ $meta->{'limit'} }
116 0 0       0 : ( 0, $meta->{'limit'} );
117             }
118 15 100       27 $offset = ( $meta->{'page'} - 1 ) * $rows if ( $meta->{'page'} );
119              
120             my $sql = join(
121             $self->{'part_join'},
122 105 100       197 grep { defined and $_ } (
123             $columns_sql,
124             $tables_sql,
125             _wipe_space($where_sql),
126             ( ( $meta->{'group_by'} ) ? do {
127             (
128 2         8 my $group_by = scalar( $self->_order_by( $meta->{'group_by'} ) )
129             ) =~ s/\s*ORDER BY/GROUP BY/;
130 2         18 _wipe_space($group_by);
131             } : undef ),
132             ( ( $meta->{'having'} ) ? do {
133 2         5 my ( $having, @having_bind ) = $self->where( $meta->{'having'} );
134 2         17 $having =~ s/\s*WHERE/HAVING/;
135 2 50       7 push( @bind, @having_bind ) if ( scalar(@having_bind) );
136 2         3 _wipe_space($having);
137             } : undef ),
138 15 100 66     27 ( ( $meta->{'order_by'} ) ? _wipe_space( $self->_order_by( $meta->{'order_by'} ) ) : undef ),
    100          
    100          
    100          
139             ( $offset or $rows )
140             ? $self->_sqlcase('limit') . " $rows " . $self->_sqlcase('offset') . " $offset"
141             : undef,
142             ),
143             );
144              
145 15         97 $sql =~ s/^\s+|\s+$//g;
146 15 100       187 return ( wantarray() ) ? ( $sql, @bind ) : $sql;
147             }
148              
149             1;
150              
151             __END__