File Coverage

blib/lib/DBIx/Romani/Query/SQL/Generate.pm
Criterion Covered Total %
statement 9 164 5.4
branch 0 48 0.0
condition 0 8 0.0
subroutine 3 22 13.6
pod 0 19 0.0
total 12 261 4.6


line stmt bran cond sub pod time code
1              
2             package DBIx::Romani::Query::SQL::Generate;
3              
4 1     1   4 use DBIx::Romani::Query::Comparison;
  1         1  
  1         20  
5 1     1   4 use strict;
  1         2  
  1         22  
6              
7 1     1   1123 use Data::Dumper;
  1         12132  
  1         2103  
8              
9             sub new
10             {
11 0     0 0   my $class = shift;
12 0           my $args = shift;
13              
14 0           my $driver;
15             my $values;
16              
17 0 0         if ( ref($args) eq 'HASH' )
18             {
19 0           $driver = $args->{driver};
20 0           $values = $args->{values};
21             }
22             else
23             {
24 0           $driver = $args;
25             }
26              
27 0 0         if ( not defined $driver )
28             {
29 0           die "no driver.";
30             }
31              
32 0   0       my $self = {
33             driver => $driver,
34             values => $values || { },
35             };
36              
37 0           bless $self, $class;
38 0           return $self;
39             }
40              
41 0     0 0   sub get_driver { return shift->{driver}; }
42              
43             sub visit_select
44             {
45 0     0 0   my ($self, $select) = @_;
46              
47             # check to see that we have a valid select query
48 0 0         if ( scalar @{$select->get_from()} == 0 )
  0            
49             {
50 0           die "Select query must one or more tables";
51             }
52 0 0         if ( scalar @{$select->get_result()} == 0 )
  0            
53             {
54 0           die "Select query must have a result";
55             }
56            
57 0           my $SQL = "SELECT ";
58            
59             # add distinct if necessary
60 0 0         if ( $select->get_distinct() )
61             {
62 0           $SQL .= "DISTINCT ";
63             }
64              
65             # add the result list
66 0           my @results;
67 0           foreach my $result ( @{$select->get_result()} )
  0            
68             {
69 0           my $s = $result->get_value()->visit( $self );
70 0 0         if ( $result->get_name() )
71             {
72 0           $s .= " AS " . $result->get_name();
73             }
74 0           push @results, $s;
75             }
76 0           $SQL .= join ', ', @results;
77              
78             # add the tables
79 0           $SQL .= ' FROM ' . join( ', ', @{$select->get_from()} );
  0            
80              
81             # add the join section
82 0           my $join = $select->get_join();
83 0 0         if ( $join )
84             {
85 0           $SQL .= " " . sprintf "%s JOIN %s ON %s",
86             uc($join->get_type()), $join->get_table(), $join->get_on()->visit($self);
87             }
88              
89             # add the where statement
90 0 0         if ( $select->get_where() )
91             {
92 0           my $where = $select->get_where()->visit($self);
93 0 0         if ( $where )
94             {
95 0           $SQL .= " WHERE " . $select->get_where()->visit($self);
96             }
97             }
98              
99             # add the group by
100 0 0         if ( scalar @{$select->get_group_by()} > 0 )
  0            
101             {
102 0           $SQL .= " GROUP BY " . join( ', ', map { $_->visit($self) } @{$select->get_group_by()} );
  0            
  0            
103             }
104              
105             # add the order by
106 0 0         if ( scalar @{$select->get_order_by()} > 0 )
  0            
107             {
108              
109 0           my @temp;
110 0           foreach my $order_by ( @{$select->get_order_by()} )
  0            
111             {
112 0           push @temp, sprintf( "%s %s", $order_by->get_value()->visit($self), uc($order_by->get_dir()) );
113             }
114              
115 0           $SQL .= " ORDER BY " . join( ', ', @temp );
116             }
117              
118             # limit
119 0           $SQL = $self->get_driver()->apply_limit( $SQL, $select->get_offset(), $select->get_limit() );
120              
121 0           return $SQL;
122             }
123              
124             sub visit_insert
125             {
126 0     0 0   my ($self, $insert) = @_;
127              
128 0           return sprintf "INSERT INTO %s (%s) VALUES (%s)",
129             $insert->get_into(),
130 0           join( ', ', map { $_->{column} } @{$insert->get_values()} ),
  0            
131 0           join( ', ', map { $_->{value}->visit($self) } @{$insert->get_values()} );
  0            
132             }
133              
134             sub visit_update
135             {
136 0     0 0   my ($self, $update) = @_;
137              
138 0           my $SQL = sprintf "UPDATE %s SET ", $update->get_table();
139              
140 0           $SQL .= join ", ", map { sprintf("%s = %s", $_->{column}, $_->{value}->visit($self)) } @{$update->get_values()};
  0            
  0            
141              
142 0 0         if ( $update->get_where() )
143             {
144 0           my $where = $update->get_where()->visit($self);
145 0 0         if ( $where )
146             {
147 0           $SQL .= " WHERE $where";
148             }
149             }
150              
151 0           return $SQL;
152             }
153              
154             sub visit_delete
155             {
156 0     0 0   my ($self, $delete) = @_;
157              
158 0           my $SQL = sprintf "DELETE FROM %s", $delete->get_from();
159            
160 0 0         if ( $delete->get_where() )
161             {
162 0           my $where = $delete->get_where()->visit($self);
163 0 0         if ( $where )
164             {
165 0           $SQL .= " WHERE $where";
166             }
167             }
168              
169 0           return $SQL;
170             }
171              
172             sub visit_sql_column
173             {
174 0     0 0   my ($self, $column) = @_;
175              
176 0           my $name = "";
177 0 0         if ( $column->get_table() )
178             {
179 0           $name .= $column->get_table() . '.';
180             }
181 0           $name .= $column->get_name();
182              
183             # TODO: Column should be escaped, if necessary or possible!
184              
185 0           return $name;
186             }
187              
188             sub visit_sql_literal
189             {
190 0     0 0   my ($self, $literal) = @_;
191             # TODO: we don't always have to escape this! Gahwah!
192 0           return sprintf "'%s'", $self->{driver}->escape_string( $literal->get_value() );
193             }
194              
195             sub visit_variable
196             {
197 0     0 0   my ($self, $variable) = @_;
198              
199 0           my $name = $variable->get_name();
200 0           my $value = $self->{values}->{$name};
201              
202 0 0         if ( not defined $value )
203             {
204 0           die "No value for variable named \"$name\"";
205             }
206              
207 0           return $value->visit($self);
208             }
209              
210             sub visit_null
211             {
212 0     0 0   my ($self, $null) = @_;
213 0           return 'NULL';
214             }
215              
216             sub visit_comparison
217             {
218 0     0 0   my ($self, $comp) = @_;
219              
220 0           my $lstr = $comp->get_lvalue()->visit( $self );
221 0           my $type = $comp->get_type();
222 0           my $rstr;
223              
224 0 0 0       if ( $type eq $DBIx::Romani::Query::Comparison::IS_NULL or
    0 0        
    0          
225             $type eq $DBIx::Romani::Query::Comparison::IS_NOT_NULL )
226             {
227             # there is not nothing
228             }
229             elsif ( $type eq $DBIx::Romani::Query::Comparison::BETWEEN )
230             {
231 0           my $rval = $comp->get_rvalue();
232 0           my $val1 = $rval->[0]->visit( $self );
233 0           my $val2 = $rval->[1]->visit( $self );
234              
235 0           $rstr = "$val1 AND $val2";
236             }
237             elsif ( $type eq $DBIx::Romani::Query::Comparison::IN or
238             $type eq $DBIx::Romani::Query::Comparison::NOT_IN )
239             {
240 0           $rstr = sprintf( "(%s)", join( ',', map { $_->visit($self) } @{$comp->get_rvalue()} ) );
  0            
  0            
241             }
242             else
243             {
244 0           $rstr = $comp->get_rvalue()->visit( $self );
245             }
246              
247             # build the return string
248 0           my $ret = "$lstr $type";
249 0 0         if ( $rstr )
250             {
251 0           $ret .= " " . $rstr;
252             }
253              
254 0           return $ret;
255             }
256              
257             sub visit_operator
258             {
259 0     0 0   my ($self, $operator) = @_;
260              
261 0           my $op_str = $operator->get_type();
262 0           my $s = join( " $op_str ", map { $_->visit($self) } @{$operator->get_values()} );
  0            
  0            
263              
264 0           return "($s)";
265             }
266              
267             sub visit_where
268             {
269 0     0 0   my ($self, $where) = @_;
270              
271 0           my $op = $where->get_type();
272              
273 0           my @result;
274 0           foreach my $value ( @{$where->get_values()} )
  0            
275             {
276 0           my $str = $value->visit( $self );
277              
278 0 0         if ( $value->isa( 'DBIx::Romani::Query::Where' ) )
279             {
280 0           $str = "($str)";
281             }
282              
283 0           push @result, $str;
284             }
285              
286 0           return join " $op ", @result;
287             }
288              
289             sub visit_ttt_function
290             {
291 0     0 0   my ($self, $ttt) = @_;
292              
293 0           my $s = sprintf "%s(", $ttt->get_name();
294 0           $s .= join ", ", map { $_->visit($self) } @{$ttt->get_arguments()};
  0            
  0            
295 0           $s .= ")";
296              
297 0           return $s;
298             }
299              
300             sub visit_ttt_operator
301             {
302 0     0 0   my ($self, $ttt) = @_;
303              
304 0           my $op = $ttt->get_operator();
305 0           my $s = join( " $op ", map { $_->visit($self) } @{$ttt->get_values()} );
  0            
  0            
306              
307 0           return "($s)";
308             }
309              
310             sub visit_ttt_keyword
311             {
312 0     0 0   my ($self, $ttt) = @_;
313              
314             # the bare keyword
315 0           return $ttt->get_keyword();
316             }
317              
318             sub visit_ttt_join
319             {
320 0     0 0   my ($self, $ttt) = @_;
321              
322             # join values by a whitespace
323 0           return join( " ", map { $_->visit($self) } @{$ttt->get_values()} );
  0            
  0            
324             }
325              
326             sub visit_function_count
327             {
328 0     0 0   my ($self, $func) = @_;
329              
330 0 0         if ( scalar @{$func->get_arguments()} == 0 )
  0            
331             {
332 0           die "Count function must have one value";
333             }
334              
335 0           my $s = $func->get_arguments()->[0]->visit( $self );
336 0 0         if ( $func->get_distinct() )
337             {
338 0           $s = "DISTINCT $s";
339             }
340 0           return "COUNT($s)";
341             }
342              
343             sub visit_function_now
344             {
345 0     0 0   my ($self, $func) = @_;
346              
347 0           return "NOW()";
348             }
349              
350             1;
351