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