File Coverage

blib/lib/SQL/Composer/Expression.pm
Criterion Covered Total %
statement 80 82 97.5
branch 27 30 90.0
condition 9 11 81.8
subroutine 10 10 100.0
pod 0 3 0.0
total 126 136 92.6


line stmt bran cond sub pod time code
1             package SQL::Composer::Expression;
2              
3 7     7   14337 use strict;
  7         14  
  7         165  
4 7     7   31 use warnings;
  7         13  
  7         183  
5              
6             require Carp;
7 7     7   3863 use Storable ();
  7         17140  
  7         173  
8 7     7   509 use SQL::Composer::Quoter;
  7         46  
  7         4382  
9              
10             sub new {
11 37     37 0 39061 my $class = shift;
12 37         123 my (%params) = @_;
13              
14 37   50     137 my $expr = $params{expr} || [];
15 37 100       120 $expr = [$expr] unless ref $expr eq 'ARRAY';
16              
17 37         76 my $self = {};
18 37         69 bless $self, $class;
19              
20 37         103 $self->{default_prefix} = $params{default_prefix};
21              
22             $self->{quoter} =
23 37   66     173 $params{quoter} || SQL::Composer::Quoter->new(driver => $params{driver});
24              
25 37         116 my ($sql, $bind) = $self->_build_subexpr('-and', $expr);
26              
27 37         93 $self->{sql} = $sql;
28 37         78 $self->{bind} = $bind;
29              
30 37         116 return $self;
31             }
32              
33             sub _build_subexpr {
34 40     40   71 my $self = shift;
35 40         91 my ($op, $params) = @_;
36              
37 40         1080 $params = Storable::dclone($params);
38              
39 40         120 $op = uc $op;
40 40         149 $op =~ s{-}{};
41              
42 40         90 my @parts;
43             my @bind;
44 40         175 while (my ($key, $value) = splice(@$params, 0, 2)) {
45 44         80 my $quote = 1;
46 44 100       118 if (ref $key) {
47 5         15 $quote = 0;
48              
49 5         19 my ($_key, $_bind) = $self->_build_value($key);
50              
51 5         13 $key = $_key;
52 5         14 push @bind, @$_bind;
53             }
54              
55 44 100 100     281 if ($key eq '-or' || $key eq '-and') {
    100          
    100          
56 3         16 my ($sql, $bind) = $self->_build_subexpr($key, $value);
57 3         9 push @parts, '(' . $sql . ')';
58 3         14 push @bind, @$bind;
59             }
60             elsif (ref $value eq 'HASH') {
61 7         29 my ($op) = keys %$value;
62 7         24 my ($subvalue) = values %$value;
63              
64 7 100       25 if ($op eq '-col') {
65 2         9 push @parts,
66             $self->_quote($quote, $key) . ' = ' . $self->_quote(1, $subvalue);
67             }
68             else {
69 5         22 my ($_value, $_bind) = $self->_build_value($subvalue);
70              
71 5         19 push @parts, $self->_quote($quote, $key) . " $op $_value";
72 5         34 push @bind, @$_bind;
73             }
74             }
75             elsif (defined $value) {
76 31         83 my ($_value, $_bind) = $self->_build_value($value);
77              
78 31 100 100     115 my $op = ref($value) && ref($value) eq 'ARRAY' ? '' : '= ';
79 31         79 push @parts, $self->_quote($quote, $key) . " $op$_value";
80 31         142 push @bind, @$_bind;
81             }
82             else {
83 3         13 push @parts, $key;
84             }
85             }
86              
87 40         141 my $sql = join " $op ", @parts;
88              
89 40         119 return ($sql, \@bind);
90             }
91              
92             sub _build_value {
93 41     41   94 my $self = shift;
94 41         79 my ($value) = @_;
95              
96 41         76 my $sql;
97             my @bind;
98 41 100       168 if (ref $value eq 'SCALAR') {
    100          
    100          
    100          
99 5         13 $sql = $$value;
100             }
101             elsif (ref $value eq 'ARRAY') {
102 2         13 $sql = 'IN (' . (join ',', split('', '?' x @$value)) . ')';
103 2         7 push @bind, @$value;
104             }
105             elsif (ref $value eq 'REF') {
106 3 50       18 if (ref $$value eq 'ARRAY') {
107 3         8 $sql = $$value->[0];
108 3         9 push @bind, @$$value[1 .. $#{$$value}];
  3         11  
109             }
110             else {
111 0         0 Carp::croak('unexpected reference');
112             }
113             }
114             elsif (ref($value) eq 'HASH') {
115 1         6 my ($key) = keys %$value;
116 1         5 my ($subvalue) = values %$value;
117              
118 1 50       6 if ($key eq '-col') {
119 1         5 $sql = $self->_quote(1, $subvalue);
120             }
121             else {
122 0         0 Carp::croak('unexpected reference');
123             }
124             }
125             else {
126 30         49 $sql = '?';
127 30         86 @bind = ($value);
128             }
129              
130 41         141 ($sql, \@bind);
131             }
132              
133 37     37 0 167 sub to_sql { shift->{sql} }
134 36 50   36 0 9649 sub to_bind { @{shift->{bind} || []} }
  36         230  
135              
136             sub _quote {
137 41     41   69 my $self = shift;
138 41         81 my ($yes, $column) = @_;
139              
140 41 100       126 return $column unless $yes;
141              
142 38         126 return $self->{quoter}->quote($column, $self->{default_prefix});
143             }
144              
145             1;
146             __END__