File Coverage

blib/lib/Pg/SQL/PrettyPrinter/Node/A_Expr.pm
Criterion Covered Total %
statement 146 149 97.9
branch 85 96 88.5
condition 4 12 33.3
subroutine 22 22 100.0
pod 4 4 100.0
total 261 283 92.2


line stmt bran cond sub pod time code
1             package Pg::SQL::PrettyPrinter::Node::A_Expr;
2              
3             # UTF8 boilerplace, per http://stackoverflow.com/questions/6162484/why-does-modern-perl-avoid-utf-8-by-default/
4 6     6   6841 use v5.26;
  6         40  
5 6     6   33 use strict;
  6         11  
  6         173  
6 6     6   25 use warnings;
  6         11  
  6         392  
7 6     6   30 use warnings qw( FATAL utf8 );
  6         9  
  6         299  
8 6     6   30 use utf8;
  6         10  
  6         42  
9 6     6   192 use open qw( :std :utf8 );
  6         9  
  6         42  
10 6     6   979 use Unicode::Normalize qw( NFC );
  6         9  
  6         404  
11 6     6   36 use Unicode::Collate;
  6         18  
  6         212  
12 6     6   34 use Encode qw( decode );
  6         9  
  6         1022  
13              
14             if ( grep /\P{ASCII}/ => @ARGV ) {
15             @ARGV = map { decode( 'UTF-8', $_ ) } @ARGV;
16             }
17              
18             # If there is __DATA__,then uncomment next line:
19             # binmode( DATA, ':encoding(UTF-8)' );
20             # UTF8 boilerplace, per http://stackoverflow.com/questions/6162484/why-does-modern-perl-avoid-utf-8-by-default/
21              
22             # Useful common code
23 6     6   41 use autodie;
  6         14  
  6         45  
24 6     6   31407 use Carp qw( carp croak confess cluck );
  6         14  
  6         608  
25 6     6   41 use English qw( -no_match_vars );
  6         12  
  6         49  
26 6     6   2559 use Data::Dumper qw( Dumper );
  6         18  
  6         1568  
27              
28             # give a full stack dump on any untrapped exceptions
29             local $SIG{ __DIE__ } = sub {
30             confess "Uncaught exception: @_" unless $^S;
31             };
32              
33             # now promote run-time warnings into stackdumped exceptions
34             # *unless* we're in an try block, in which
35             # case just generate a clucking stackdump instead
36             local $SIG{ __WARN__ } = sub {
37             if ( $^S ) { cluck "Trapped warning: @_" }
38             else { confess "Deadly warning: @_" }
39             };
40              
41             # Useful common code
42              
43 6     6   45 use parent qw( Pg::SQL::PrettyPrinter::Node );
  6         11  
  6         51  
44 6     6   528 use List::Util qw( any );
  6         11  
  6         3021  
45              
46             sub new {
47 84     84 1 2814 my $class = shift;
48 84         372 my $self = $class->SUPER::new( @_ );
49 84         167 bless $self, $class;
50              
51 84         228 my @types_ok = map { 'AEXPR_' . $_ } qw( BETWEEN IN OP OP_ALL OP_ANY NOT_BETWEEN BETWEEN_SYM NOT_BETWEEN_SYM DISTINCT NOT_DISTINCT LIKE ILIKE NULLIF SIMILAR );
  1176         2173  
52 84         179 my %type_is_ok = map { $_ => 1 } @types_ok;
  1176         2261  
53 84 50       405 if ( !$type_is_ok{ $self->{ 'kind' } } ) {
54 0         0 croak( "Unsupported A_Expr kind: " . $self->{ 'kind' } );
55             }
56              
57 84         424 $self->objectify( 'name', 'rexpr', 'lexpr' );
58 6     6   39 use Data::Dumper;
  6         10  
  6         12188  
59 84         647 return $self;
60             }
61              
62             sub operator {
63 198     198 1 297 my $self = shift;
64 198 100       294 if ( 1 == scalar @{ $self->{ 'name' } } ) {
  198         493  
65 196         561 return $self->{ 'name' }->[ 0 ]->string;
66             }
67 2         5 my @elements = map { $_->as_ident() } @{ $self->{ 'name' } };
  4         9  
  2         5  
68 2         6 $elements[ -1 ] = $self->{ 'name' }->[ -1 ]->string;
69 2         8 return sprintf( "OPERATOR( %s )", join( '.', @elements ) );
70             }
71              
72             sub as_text {
73 96     96 1 145 my $self = shift;
74              
75 96 100       825 if ( $self->{ 'kind' } eq 'AEXPR_IN' ) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
76 2 50       11 my $op = $self->operator eq '<>' ? 'NOT IN' : 'IN';
77             return sprintf(
78             '%s %s %s',
79             $self->{ 'lexpr' }->as_text,
80             $op,
81 2         12 $self->{ 'rexpr' }->as_text
82             );
83             }
84             elsif ( $self->{ 'kind' } eq 'AEXPR_OP_ANY' ) {
85             return sprintf(
86             '%s %s ANY( %s )',
87             $self->{ 'lexpr' }->as_text,
88             $self->operator,
89 1         6 $self->{ 'rexpr' }->as_text
90             );
91             }
92             elsif ( $self->{ 'kind' } eq 'AEXPR_OP_ALL' ) {
93             return sprintf(
94             '%s %s ALL( %s )',
95             $self->{ 'lexpr' }->as_text,
96             $self->operator,
97 1         7 $self->{ 'rexpr' }->as_text
98             );
99             }
100 359     359   1014 elsif ( any { $_ eq $self->{ 'kind' } } qw( AEXPR_BETWEEN AEXPR_NOT_BETWEEN AEXPR_BETWEEN_SYM AEXPR_NOT_BETWEEN_SYM ) ) {
101             return sprintf(
102             '%s %s %s AND %s',
103             $self->{ 'lexpr' }->as_text,
104             $self->operator,
105             $self->{ 'rexpr' }->{ 'items' }->[ 0 ]->as_text,
106 5         21 $self->{ 'rexpr' }->{ 'items' }->[ 1 ]->as_text,
107             );
108             }
109             elsif ( $self->{ 'kind' } eq 'AEXPR_DISTINCT' ) {
110             return sprintf(
111             '%s IS DISTINCT FROM %s',
112             $self->{ 'lexpr' }->as_text,
113 2         7 $self->{ 'rexpr' }->as_text,
114             );
115             }
116             elsif ( $self->{ 'kind' } eq 'AEXPR_NOT_DISTINCT' ) {
117             return sprintf(
118             '%s IS NOT DISTINCT FROM %s',
119             $self->{ 'lexpr' }->as_text,
120 2         5 $self->{ 'rexpr' }->as_text,
121             );
122             }
123             elsif ( $self->{ 'kind' } eq 'AEXPR_LIKE' ) {
124 1 50       5 my $op = $self->operator eq '!~~' ? 'NOT LIKE' : 'LIKE';
125             return sprintf(
126             '%s %s %s',
127             $self->{ 'lexpr' }->as_text,
128             $op,
129 1         6 $self->{ 'rexpr' }->as_text,
130             );
131             }
132             elsif ( $self->{ 'kind' } eq 'AEXPR_NULLIF' ) {
133             return sprintf(
134             'NULLIF( %s, %s )',
135             $self->{ 'lexpr' }->as_text,
136 1         6 $self->{ 'rexpr' }->as_text,
137             );
138             }
139             elsif ( $self->{ 'kind' } eq 'AEXPR_ILIKE' ) {
140             return sprintf(
141             '%s ILIKE %s',
142             $self->{ 'lexpr' }->as_text,
143 1         7 $self->{ 'rexpr' }->as_text,
144             );
145             }
146             elsif ( $self->{ 'kind' } eq 'AEXPR_SIMILAR' ) {
147 1         4 my $right_side;
148 1 50 33     22 if ( ( $self->{ 'rexpr' }->isa( 'Pg::SQL::PrettyPrinter::Node::FuncCall' ) )
      33        
149             && ( $self->{ 'rexpr' }->func_name eq 'pg_catalog.similar_to_escape' )
150 1         6 && ( 1 == scalar @{ $self->{ 'rexpr' }->{ 'args' } } ) )
151             {
152 1         6 $right_side = $self->{ 'rexpr' }->{ 'args' }->[ 0 ]->as_text;
153             }
154             else {
155 0         0 $right_side = $self->{ 'rexpr' }->as_text;
156             }
157             return sprintf(
158             '%s SIMILAR TO %s',
159 1         8 $self->{ 'lexpr' }->as_text,
160             $right_side,
161             );
162             }
163              
164 79         251 my @parts = ();
165 79 100       189 if ( exists $self->{ 'lexpr' } ) {
166 78         124 my $this_expr = '';
167 78         108 my $add_parens = 0;
168 78 100       475 if ( $self->{ 'lexpr' }->isa( 'Pg::SQL::PrettyPrinter::Node::A_Expr' ) ) {
169 7 100       13 $add_parens = 1 if $self->{ 'lexpr' }->operator ne $self->operator;
170             }
171 78 100       212 $this_expr .= '( ' if $add_parens;
172 78         235 $this_expr .= $self->{ 'lexpr' }->as_text;
173 78 100       190 $this_expr .= ' )' if $add_parens;
174 78         145 push @parts, $this_expr;
175             }
176              
177 79         198 push @parts, $self->operator;
178              
179 79 50       210 if ( exists $self->{ 'rexpr' } ) {
180 79         202 my $this_expr = '';
181 79         119 my $add_parens = 0;
182 79 100       420 if ( $self->{ 'rexpr' }->isa( 'Pg::SQL::PrettyPrinter::Node::A_Expr' ) ) {
183 2 50       7 $add_parens = 1 if $self->{ 'rexpr' }->operator ne $self->operator;
184             }
185 79 100       148 $this_expr .= '( ' if $add_parens;
186 79         218 $this_expr .= $self->{ 'rexpr' }->as_text;
187 79 100       169 $this_expr .= ' )' if $add_parens;
188 79         143 push @parts, $this_expr;
189             }
190              
191 79         267 return join( ' ', @parts );
192             }
193              
194             sub pretty_print {
195 80     80 1 147 my $self = shift;
196 80 100       693 if ( $self->{ 'kind' } eq 'AEXPR_IN' ) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
197 2 50       7 my $op = $self->operator eq '<>' ? 'NOT IN' : 'IN';
198             return sprintf(
199             '%s %s %s',
200             $self->{ 'lexpr' }->pretty_print,
201             $op,
202 2         11 $self->{ 'rexpr' }->pretty_print
203             );
204             }
205             elsif ( $self->{ 'kind' } eq 'AEXPR_OP_ANY' ) {
206             return sprintf(
207             '%s %s ANY( %s )',
208             $self->{ 'lexpr' }->pretty_print,
209             $self->operator,
210 1         7 $self->{ 'rexpr' }->pretty_print
211             );
212             }
213             elsif ( $self->{ 'kind' } eq 'AEXPR_OP_ALL' ) {
214             return sprintf(
215             '%s %s ALL( %s )',
216             $self->{ 'lexpr' }->pretty_print,
217             $self->operator,
218 1         8 $self->{ 'rexpr' }->pretty_print
219             );
220             }
221 295     295   851 elsif ( any { $_ eq $self->{ 'kind' } } qw( AEXPR_BETWEEN AEXPR_NOT_BETWEEN AEXPR_BETWEEN_SYM AEXPR_NOT_BETWEEN_SYM ) ) {
222             return sprintf(
223             '%s %s %s AND %s',
224             $self->{ 'lexpr' }->pretty_print,
225             $self->operator,
226             $self->{ 'rexpr' }->{ 'items' }->[ 0 ]->pretty_print,
227 5         23 $self->{ 'rexpr' }->{ 'items' }->[ 1 ]->pretty_print,
228             );
229             }
230             elsif ( $self->{ 'kind' } eq 'AEXPR_DISTINCT' ) {
231             return sprintf(
232             '%s IS DISTINCT FROM %s',
233             $self->{ 'lexpr' }->pretty_print,
234 2         12 $self->{ 'rexpr' }->pretty_print,
235             );
236             }
237             elsif ( $self->{ 'kind' } eq 'AEXPR_NOT_DISTINCT' ) {
238             return sprintf(
239             '%s IS NOT DISTINCT FROM %s',
240             $self->{ 'lexpr' }->pretty_print,
241 2         10 $self->{ 'rexpr' }->pretty_print,
242             );
243             }
244             elsif ( $self->{ 'kind' } eq 'AEXPR_LIKE' ) {
245 1 50       6 my $op = $self->operator eq '!~~' ? 'NOT LIKE' : 'LIKE';
246             return sprintf(
247             '%s %s %s',
248             $self->{ 'lexpr' }->pretty_print,
249             $op,
250 1         8 $self->{ 'rexpr' }->pretty_print,
251             );
252             }
253             elsif ( $self->{ 'kind' } eq 'AEXPR_NULLIF' ) {
254             return sprintf(
255             'NULLIF( %s, %s )',
256             $self->{ 'lexpr' }->pretty_print,
257 1         6 $self->{ 'rexpr' }->pretty_print,
258             );
259             }
260             elsif ( $self->{ 'kind' } eq 'AEXPR_ILIKE' ) {
261             return sprintf(
262             '%s ILIKE %s',
263             $self->{ 'lexpr' }->pretty_print,
264 1         7 $self->{ 'rexpr' }->pretty_print,
265             );
266             }
267             elsif ( $self->{ 'kind' } eq 'AEXPR_SIMILAR' ) {
268 1         5 my $right_side;
269 1 50 33     15 if ( ( $self->{ 'rexpr' }->isa( 'Pg::SQL::PrettyPrinter::Node::FuncCall' ) )
      33        
270             && ( $self->{ 'rexpr' }->func_name eq 'pg_catalog.similar_to_escape' )
271 1         5 && ( 1 == scalar @{ $self->{ 'rexpr' }->{ 'args' } } ) )
272             {
273 1         5 $right_side = $self->{ 'rexpr' }->{ 'args' }->[ 0 ]->pretty_print;
274             }
275             else {
276 0         0 $right_side = $self->{ 'rexpr' }->pretty_print;
277             }
278             return sprintf(
279             '%s SIMILAR TO %s',
280 1         5 $self->{ 'lexpr' }->pretty_print,
281             $right_side,
282             );
283             }
284              
285 63         202 my @parts = ();
286 63 100       152 if ( exists $self->{ 'lexpr' } ) {
287 62         122 my $this_expr = '';
288 62         87 my $add_parens = 0;
289 62 100       292 if ( $self->{ 'lexpr' }->isa( 'Pg::SQL::PrettyPrinter::Node::A_Expr' ) ) {
290 7 100       22 $add_parens = 1 if $self->{ 'lexpr' }->operator ne $self->operator;
291             }
292 62 100       147 $this_expr .= '( ' if $add_parens;
293 62         202 $this_expr .= $self->{ 'lexpr' }->pretty_print;
294 62 100       149 $this_expr .= ' )' if $add_parens;
295 62         125 push @parts, $this_expr;
296             }
297              
298 63         148 push @parts, $self->operator;
299              
300 63 50       140 if ( exists $self->{ 'rexpr' } ) {
301 63         100 my $this_expr = '';
302 63         95 my $add_parens = 0;
303 63 100       261 if ( $self->{ 'rexpr' }->isa( 'Pg::SQL::PrettyPrinter::Node::A_Expr' ) ) {
304 2 50       7 $add_parens = 1 if $self->{ 'rexpr' }->operator ne $self->operator;
305             }
306 63 100       125 $this_expr .= '( ' if $add_parens;
307 63         188 $this_expr .= $self->{ 'rexpr' }->pretty_print;
308 63 100       159 $this_expr .= ' )' if $add_parens;
309 63         118 push @parts, $this_expr;
310             }
311              
312 63         261 return join( ' ', @parts );
313             }
314              
315             1;