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