File Coverage

blib/lib/MarpaX/Languages/PowerBuilder/SRQ.pm
Criterion Covered Total %
statement 6 143 4.2
branch 0 42 0.0
condition 0 19 0.0
subroutine 2 41 4.8
pod 0 32 0.0
total 8 277 2.8


line stmt bran cond sub pod time code
1             package MarpaX::Languages::PowerBuilder::SRQ;
2 1     1   1183 no if $] >= 5.018, warnings => "experimental::smartmatch";
  1         11  
  1         4  
3 1     1   53 use base qw(MarpaX::Languages::PowerBuilder::base);
  1         2  
  1         1581  
4              
5             #a SRQ parser and compiler to SQL by Nicolas Georges
6              
7             sub unref{
8 0 0   0 0   return unless defined wantarray;
9 0           my $val = shift;
10 0           my $ref = ref $val;
11 0 0         return unless $ref;
12             my $unref={
13 0     0     ARRAY => sub{ @$val },
14 0     0     HASH => sub{ %$val },
15 0     0     SCALAR => sub{ $$val },
16 0     0     GLOB => sub{ $$val },
17 0     0     REF => sub{ $$val },
18 0     0     Regexp => sub{ $val }, #don't unref a regexp.
19 0           };
20 0 0         return $unref->{$ref}() if exists $unref->{$ref};
21 0           for(keys %$unref){
22 0 0         return $unref->{$_}()
23             if $val->isa($_);
24             }
25 0           return;
26             }
27              
28             sub value{
29 0     0 0   my $self =shift;
30             #lazzy retrieve of value
31 0 0         $self->{value} = $self->{recce}->value unless exists $self->{value};
32 0           $self->{value};
33             }
34              
35             sub sql{
36 0     0 0   my $self = shift;
37 0           my $val = $self->value();
38 0           return _compile( $$val );
39             }
40              
41             sub _compile{
42 0     0     my $ast = shift;
43 0   0       my $level = shift // 1;
44 0           my $tabs = "\t" x $level;
45 0 0         my $select = exists $ast->{select} ? $ast->{select} : $ast;
46 0           my $sql;
47             #arguments
48 0           foreach my $arg(unref $ast->{arguments}){
49 0           $sql .= "// argument $arg->{name} ($arg->{type})\n";
50             }
51 0           $sql .= "SELECT";
52 0 0         $sql .= ' DISTINCT ' if exists $select->{distinct};
53 0           $sql .= "\n\t";
54 0   0       $sql .= join ",\n\t", map{ $$_ } unref $select->{selection}//[];
  0            
55 0           $sql .= "\n\tFROM ";
56 0   0       $sql .= join ",\n\t", unref $select->{tables}//[];
57             #joins are threated like where clause
58 0 0 0       if(unref $select->{wheres}//[] + unref $select->{joins}//[]){
      0        
59 0           $sql .= "\n\tWHERE ";
60 0           my $where = "(";
61 0           foreach( unref $select->{wheres} ){
62 0           $where .= "\t";
63 0           $where .= "($_->{exp1} " . uc($_->{op})." ";
64 0 0         if(ref $_->{exp2}){
65 0           $where .= "(" . _compile($_->{exp2}, $level+1) . ")";
66             }
67             else{
68 0           $where .= "$_->{exp2}";
69             }
70 0           $where .= ")";
71 0 0         $where .= uc " $_->{logic}\n" if exists $_->{logic};
72             }
73 0           $where .=")\n";
74            
75 0           my @joins = map{ "\t(" . join(" ", $_->{left}, uc($_->{op}), $_->{right}).")" } unref $select->{joins};
  0            
76 0           $sql .= join " AND\n", @joins, $where;
77             }
78             #groups
79 0 0 0       if(unref $select->{groups}//[]){
80 0           $sql .= "\tGROUP BY ";
81 0           $sql .= join ",\n\t", unref $select->{groups};
82             }
83             #havings
84 0 0 0       if(unref $select->{havings}//[]){
85 0           $sql .= "\n\tHAVING ";
86 0           foreach( unref $select->{havings} ){
87 0           $sql .= "\t";
88 0           $sql .= "($_->{exp1} " . uc($_->{op})." ";
89 0           $sql .= "$_->{exp2})";
90 0 0         $sql .= uc " $_->{logic}\n" if exists $_->{logic};
91             }
92             }
93             #unions
94 0 0         $sql .= "\n" if exists $select->{unions};
95 0   0       foreach my $union ( unref $select->{unions}//[] ){
96 0           $sql .= "UNION(\n";
97 0           $sql .= _compile( $union, $level+1 );
98 0           $sql .= ")\n";
99             }
100             #orders
101 0 0         if(exists $ast->{orders}){
102 0           $sql .= "\tORDER BY ";
103 0           $sql .= join ",\n\t" , map { $_->{name} . " " . uc $_->{dir} } unref $ast->{orders};
  0            
104             }
105            
106 0 0         if($level > 1){
107 0           $sql =~ s/^/$tabs/gm;
108             }
109 0           return $sql;
110             }
111              
112             sub version{
113 0     0 0   my (undef, $name, @children) = @_;
114 0           return { lc $name => $children[1] };
115             }
116              
117             sub table{
118 0     0 0   my (undef, $name, @children) = @_;
119 0           return $children[3];
120             }
121              
122             sub tables{
123 0     0 0   my (undef, @children) = @_;
124 0           return { 'tables' => \@children };
125             }
126              
127 0 0   0 0   sub distinct{ { 'distinct' => @_>1?1:0 } }
128              
129             sub column{
130 0     0 0   my (undef, $name, @children) = @_;
131 0           return bless \$children[3], 'column';
132             }
133              
134             sub selection{
135 0     0 0   my (undef, @children) = @_;
136 0           return { 'selection' => \@children };
137             }
138              
139             sub compute{
140 0     0 0   my (undef, $name, @children) = @_;
141 0           return bless \$children[3], 'compute';
142             }
143              
144             sub join{
145 0     0 0   my (undef, $name, @children) = @_;
146 0           return { left => $children[3], op => $children[6], right => $children[9] };
147             }
148              
149             sub joins{
150 0     0 0   my (undef, @children) = @_;
151 0           return { 'joins' => \@children };
152             }
153              
154             sub argument{
155 0     0 0   my (undef, $name, @children) = @_;
156 0           return { name => $children[3], type => $children[6] };
157             }
158              
159             sub arguments{
160 0     0 0   my (undef, @children) = @_;
161 0           return { 'arguments' => \@children };
162             }
163              
164             sub where_logic{
165 0     0 0   my (undef, $name, @children) = @_;
166 0           return { exp1 => $children[3], op => $children[6], exp2 => $children[7], logic => $children[10] };
167             }
168              
169             sub where{
170 0     0 0   my (undef, $name, @children) = @_;
171 0           return { exp1 => $children[3], op => $children[6], exp2 => $children[7] };
172             }
173              
174             sub where_exp2{
175 0     0 0   my (undef, $name, @children) = @_;
176 0           return $children[1];
177             }
178              
179             sub where_nest{
180 0     0 0   my (undef, $name, @children) = @_;
181 0           return $children[1];
182             }
183              
184             sub wheres{
185 0     0 0   my (undef, @children) = @_;
186 0           return { 'wheres' => \@children };
187             }
188              
189             sub group{
190 0     0 0   my (undef, $name, @children) = @_;
191 0           return $children[3];
192             }
193              
194             sub groups{
195 0     0 0   my (undef, @children) = @_;
196 0           return { 'groups' => \@children };
197             }
198              
199             sub having_logic{
200 0     0 0   my (undef, $name, @children) = @_;
201 0           return { exp1 => $children[3], op => $children[6], exp2 => $children[7], logic => $children[10] };
202             }
203              
204             sub havings{
205 0     0 0   my (undef, @children) = @_;
206 0           return { 'havings' => \@children };
207             }
208              
209             sub order{
210 0     0 0   my (undef, $name, @children) = @_;
211 0 0 0       return { name => $children[3], dir => (lc($children[6]//'no') eq 'yes')?'asc':'desc' };
212             }
213              
214             sub orders{
215 0     0 0   my (undef, @children) = @_;
216 0           return \@children;
217             }
218              
219             sub pbselect{
220 0     0 0   my (undef, @children) = @_;
221 0           my %mixed;
222 0 0         %mixed = (%mixed, %$_) for grep{ exists $_->{unions} ? not $_->{unions} ~~ [] : 1 } grep { ref eq 'HASH' } @children;
  0            
  0            
223 0           return \%mixed;
224             }
225              
226 0     0 0   sub unions{ shift; { unions => [ @_ ] } }
  0            
227 0     0 0   sub union { $_[3] }
228              
229             sub query{
230 0     0 0   my (undef, @children) = @_;
231 0           my $h = { select => $children[0] };
232 0 0         $h->{orders} = $children[1] unless $children[1] ~~ [];
233 0 0         $h->{arguments} = $children[2]->{arguments} unless $children[2]->{arguments} ~~ [];
234 0           return $h;
235             }
236              
237             sub selection_item{
238 0     0 0   my (undef, $item) = @_;
239 0           return $item;
240             }
241              
242             sub string{
243 0     0 0   my (undef, $string) = @_;
244             #remove bounding quotes and escape chars.
245 0           $string =~ s/^"|"$//g;
246 0           $string =~ s/~(.)/$1/g;
247 0           return $string;
248             }
249              
250             sub quoted_db_identifier{
251 0     0 0   my (undef, $dbidentifier) = @_;
252 0           return $dbidentifier;
253             }
254              
255             1;