File Coverage

blib/lib/OPTIMADE/Filter/Comparison.pm
Criterion Covered Total %
statement 92 95 96.8
branch 29 40 72.5
condition 5 6 83.3
subroutine 14 14 100.0
pod 0 10 0.0
total 140 165 84.8


line stmt bran cond sub pod time code
1             package OPTIMADE::Filter::Comparison;
2              
3 6     6   54672 use strict;
  6         17  
  6         2502  
4 6     6   52 use warnings;
  6         11  
  6         217  
5              
6 6     6   527 use parent 'OPTIMADE::Filter::Modifiable';
  6         340  
  6         30  
7 6     6   372 use Scalar::Util qw(blessed);
  6         11  
  6         7076  
8              
9             our $VERSION = '0.10.2'; # VERSION
10              
11             sub new {
12 173     173 0 496 my( $class, $operator ) = @_;
13 173         629 return bless { operands => [], operator => $operator }, $class;
14             }
15              
16             sub push_operand
17             {
18 175     175 0 333 my( $self, $operand ) = @_;
19 175 50       228 die 'attempt to insert more than two operands' if @{$self->{operands}} >= 2;
  175         462  
20 175         251 push @{$self->{operands}}, $operand;
  175         455  
21             }
22              
23             sub unshift_operand
24             {
25 169     169 0 345 my( $self, $operand ) = @_;
26 169 50       250 die 'attempt to insert more than two operands' if @{$self->{operands}} >= 2;
  169         372  
27 169         290 unshift @{$self->{operands}}, $operand;
  169         441  
28             }
29              
30             sub operator
31             {
32 247     247 0 419 my( $self, $operator ) = @_;
33 247         402 my $previous_operator = $self->{operator};
34 247 50       453 $self->{operator} = $operator if defined $operator;
35 247         630 return $previous_operator;
36             }
37              
38             sub left
39             {
40 1     1 0 3 my( $self, $operand ) = @_;
41 1         7 my $previous_operand = $self->{operands}[0];
42 1 50       5 $self->{operands}[0] = $operand if defined $operand;
43 1         2 return $previous_operand;
44             }
45              
46             sub right
47             {
48 5     5 0 126 my( $self, $operand ) = @_;
49 5         10 my $previous_operand = $self->{operands}[1];
50 5 100       13 $self->{operands}[1] = $operand if defined $operand;
51 5         20 return $previous_operand;
52             }
53              
54             sub to_filter
55             {
56 164     164 0 11452 my( $self ) = @_;
57 164         415 $self->validate;
58              
59 164         319 my $operator = $self->{operator};
60 164         233 my @operands;
61 164         216 for my $i (0..$#{$self->{operands}}) {
  164         369  
62 328         571 my $arg = $self->{operands}[$i];
63 328 100 66     1320 if( blessed $arg && $arg->can( 'to_filter' ) ) {
64 176         412 $arg = $arg->to_filter;
65             } else {
66 152         304 $arg =~ s/\\/\\\\/g;
67 152         234 $arg =~ s/"/\\"/g;
68 152         272 $arg = "\"$arg\"";
69             }
70 328         753 push @operands, $arg;
71             }
72              
73 164         600 return "($operands[0] $operator $operands[1])";
74             }
75              
76             sub to_SQL
77             {
78 83     83 0 300 my( $self, $options ) = @_;
79 83         207 $self->validate;
80              
81 83 50       184 $options = {} unless $options;
82             my( $delim, $placeholder ) = (
83             $options->{delim},
84             $options->{placeholder},
85 83         162 );
86 83 50       236 $delim = "'" unless $delim;
87              
88 83         138 my $operator = $self->{operator};
89 83         116 my @operands = @{$self->{operands}};
  83         197  
90              
91             # Handle STARTS/ENDS WITH
92 83 100       289 if( $operator eq 'CONTAINS' ) {
    100          
    100          
93 3         7 $operator = 'LIKE';
94 3 50       19 $operands[1] = '%' . $operands[1] . '%' if !blessed $operands[1];
95             } elsif( $operator =~ /^STARTS( WITH)?$/ ) {
96 4         7 $operator = 'LIKE';
97 4 100       21 $operands[1] = $operands[1] . '%' if !blessed $operands[1];
98             } elsif( $operator =~ /^ENDS( WITH)?$/ ) {
99 1         2 $operator = 'LIKE';
100 1 50       8 $operands[1] = '%' . $operands[1] if !blessed $operands[1];
101             }
102              
103 83         138 my @values;
104             my @operands_now;
105 83         140 for my $arg (@operands) {
106 166         258 my $sql = $arg;
107 166 100 100     695 if( blessed $arg && $arg->can( 'to_SQL' ) ) {
108 89         222 ( $sql, my $values ) = $arg->to_SQL( $options );
109 89 50       389 if( $arg->isa( OPTIMADE::Filter::Comparison:: ) ) {
110 0         0 $sql = "($sql)";
111             }
112 89         176 push @values, @$values;
113             } else {
114 77         139 push @values, $arg;
115 77 100       153 if( $placeholder ) {
116 16         25 $sql = $placeholder;
117             } else {
118 61         127 $sql =~ s/"/""/g;
119 61         113 $sql = "\"$sql\"";
120             }
121             }
122 166         347 push @operands_now, $sql;
123             }
124 83         198 @operands = @operands_now;
125              
126 83 100       154 if( wantarray ) {
127 69         317 return ( "$operands[0] $operator $operands[1]", \@values );
128             } else {
129 14         76 return "$operands[0] $operator $operands[1]";
130             }
131             }
132              
133             sub modify
134             {
135 5     5 0 2235 my $self = shift;
136 5         10 my $code = shift;
137              
138 10         74 $self->{operands} = [ map { OPTIMADE::Filter::Modifiable::modify( $_, $code, @_ ) }
139 5         8 @{$self->{operands}} ];
  5         13  
140 5         64 return $code->( $self, @_ );
141             }
142              
143             sub validate
144             {
145 247     247 0 362 my $self = shift;
146              
147 247 50       357 if( @{$self->{operands}} != 2 ) {
  247         645  
148             die 'number of operands for OPTIMADE::Filter::Comparison must be 2, ' .
149 0         0 'got ' . @{$self->{operands}};
  0         0  
150             }
151 247 50       485 die 'operator undefined for OPTIMADE::Filter::Comparison'
152             if !$self->operator;
153             }
154              
155             1;