File Coverage

blib/lib/SQL/Abstract/Complete.pm
Criterion Covered Total %
statement 82 89 92.1
branch 58 78 74.3
condition 14 21 66.6
subroutine 9 9 100.0
pod 2 2 100.0
total 165 199 82.9


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