File Coverage

blib/lib/SQL/Statement/TermFactory.pm
Criterion Covered Total %
statement 76 79 96.2
branch 38 42 90.4
condition 2 3 66.6
subroutine 13 13 100.0
pod 1 2 50.0
total 130 139 93.5


line stmt bran cond sub pod time code
1             package SQL::Statement::TermFactory;
2              
3             ######################################################################
4             #
5             # This module is copyright (c), 2009-2017 by Jens Rehsack.
6             # All rights reserved.
7             #
8             # It may be freely distributed under the same terms as Perl itself.
9             # See below for help and copyright information (search for SYNOPSIS).
10             #
11             ######################################################################
12              
13 16     16   56 use strict;
  16         16  
  16         421  
14 16     16   50 use warnings FATAL => "all";
  16         19  
  16         410  
15              
16 16     16   6006 use SQL::Statement::Term ();
  16         27  
  16         261  
17 16     16   6765 use SQL::Statement::Operation ();
  16         28  
  16         283  
18 16     16   6229 use SQL::Statement::Placeholder ();
  16         26  
  16         244  
19 16     16   6209 use SQL::Statement::Function ();
  16         46  
  16         355  
20              
21 16     16   6902 use Data::Dumper;
  16         58357  
  16         973  
22 16     16   86 use Params::Util qw(_HASH _ARRAY0 _INSTANCE);
  16         21  
  16         769  
23 16     16   65 use Scalar::Util qw(blessed weaken);
  16         21  
  16         12676  
24              
25             our $VERSION = '1.412';
26              
27             my %oplist = (
28             '=' => 'Equal',
29             '<>' => 'NotEqual',
30             'AND' => 'And',
31             'OR' => 'Or',
32             '<=' => 'LowerEqual',
33             '>=' => 'GreaterEqual',
34             '<' => 'Lower',
35             '>' => 'Greater',
36             'LIKE' => 'Like',
37             'RLIKE' => 'Rlike',
38             'CLIKE' => 'Clike',
39             'IN' => 'Contains',
40             'BETWEEN' => 'Between',
41             'IS' => 'Is',
42             );
43              
44             sub new
45             {
46 868     868 0 961 my ( $class, $owner ) = @_;
47 868         1623 my $self = bless(
48             {
49             OWNER => $owner,
50             },
51             $class
52             );
53              
54 868         2107 weaken( $self->{OWNER} );
55              
56 868         1797 return $self;
57             }
58              
59             my %opClasses;
60              
61             sub _getOpClass($)
62             {
63 272     272   282 my ( $self, $op ) = @_;
64 272 100       485 unless ( defined( $opClasses{$op} ) )
65             {
66 39         48 my $opBase = 'SQL::Statement::Operation';
67 39         116 my $opDialect = join( '::', $opBase, $self->{OWNER}->{dialect}, $oplist{$op} );
68             $opClasses{$op} =
69 39 100       445 $opDialect->isa($opBase) ? $opDialect : join( '::', $opBase, $oplist{$op} );
70             }
71              
72 272         359 return $opClasses{$op};
73             }
74              
75             sub buildCondition
76             {
77 2276     2276 1 1954 my ( $self, $pred ) = @_;
78 2276         1483 my $term;
79              
80 2276 100       5710 if ( _ARRAY0($pred) )
    100          
    100          
    50          
81             {
82 30         30 $term = [ map { $self->buildCondition($_) } @{$pred} ];
  85         109  
  30         37  
83             }
84             elsif ( defined( $pred->{op} ) )
85             {
86 329         438 my $op = uc( $pred->{op} );
87 329 100 66     961 if ( $op eq 'USER_DEFINED' && !$pred->{arg2} )
    100          
    50          
88             {
89 56         158 $term = SQL::Statement::ConstantTerm->new( $self->{OWNER}, $pred->{arg1}->{value} );
90             }
91             elsif ( defined( $oplist{$op} ) )
92             {
93 272         438 my $cn = $self->_getOpClass($op);
94 272         549 my $left = $self->buildCondition( $pred->{arg1} );
95 272         399 my $right = $self->buildCondition( $pred->{arg2} );
96 272         1049 $term = $cn->new( $self->{OWNER}, $op, $left, $right );
97             }
98             elsif ( defined( $self->{OWNER}->{opts}->{function_names}->{$op} ) )
99             {
100 1         6 my $left = $self->buildCondition( $pred->{arg1} );
101 1         3 my $right = $self->buildCondition( $pred->{arg2} );
102              
103             $term = SQL::Statement::Function::UserFunc->new(
104             $self->{OWNER}, $op,
105 1         10 $self->{OWNER}->{opts}->{function_names}->{$op},
106             [ $left, $right ]
107             );
108             }
109             else
110             {
111 0         0 return $self->{OWNER}->do_err( sprintf( q{Unknown operation '%s'}, $pred->{op} ) );
112             }
113              
114 329 100       617 if ( $pred->{neg} )
115             {
116 25         84 $term = SQL::Statement::Operation::Neg->new( $self->{OWNER}, 'NOT', $term );
117             }
118             }
119             elsif ( defined( $pred->{type} ) )
120             {
121 1915         2440 my $type = uc( $pred->{type} );
122 1915 100       5460 if ( $type =~ m/^(?:STRING|NUMBER|BOOLEAN)$/ )
    100          
    100          
    100          
    50          
123             {
124 1093         2542 $term = SQL::Statement::ConstantTerm->new( $self->{OWNER}, $pred->{value} );
125             }
126             elsif ( $type eq 'NULL' )
127             {
128 24         57 $term = SQL::Statement::ConstantTerm->new( $self->{OWNER}, undef );
129             }
130             elsif ( $type eq 'COLUMN' )
131             {
132 439         1196 $term = SQL::Statement::ColumnValue->new( $self->{OWNER}, $pred->{value} );
133             }
134             elsif ( $type eq 'PLACEHOLDER' )
135             {
136 28         130 $term = SQL::Statement::Placeholder->new( $self->{OWNER}, $pred->{argnum} );
137             }
138             elsif ( $type eq 'FUNCTION' )
139             {
140 331 50       261 my @params = map { blessed($_) ? $_ : $self->buildCondition($_) } @{ $pred->{value} };
  457         1115  
  331         491  
141              
142 331 100       1015 if ( $pred->{name} eq 'numeric_exp' )
    100          
    100          
    100          
143             {
144 41         138 $term = SQL::Statement::Function::NumericEval->new( $self->{OWNER}, $pred->{str}, \@params );
145             }
146             elsif ( $pred->{name} eq 'str_concat' )
147             {
148 7         51 $term = SQL::Statement::Function::StrConcat->new( $self->{OWNER}, \@params );
149             }
150             elsif ( $pred->{name} eq 'TRIM' )
151             {
152 10         55 $term = SQL::Statement::Function::Trim->new( $self->{OWNER}, $pred->{trim_spec}, $pred->{trim_char}, \@params );
153             }
154             elsif ( $pred->{name} eq 'SUBSTRING' )
155             {
156 3         7 my $start = $self->buildCondition( $pred->{start} );
157             my $length = $self->buildCondition( $pred->{length} )
158 3 100       14 if ( _HASH( $pred->{length} ) );
159 3         21 $term = SQL::Statement::Function::SubString->new( $self->{OWNER}, $start, $length, \@params );
160             }
161             else
162             {
163 270         856 $term = SQL::Statement::Function::UserFunc->new( $self->{OWNER}, $pred->{name}, $pred->{subname}, \@params );
164             }
165             }
166             else
167             {
168 0         0 return $self->{OWNER}->do_err( sprintf( q{Unknown type '%s'}, $pred->{type} ) );
169             }
170             }
171             elsif ( defined( _INSTANCE( $pred, 'SQL::Statement::Term' ) ) )
172             {
173 0         0 return $pred;
174             }
175             else
176             {
177 2         8 return $self->{OWNER}->do_err( sprintf( q~Unknown predicate '{%s}'~, Dumper($pred) ) );
178             }
179              
180 2274         3224 return $term;
181             }
182              
183             sub DESTROY
184             {
185 866     866   824 my $self = $_[0];
186 866         3220 undef $self->{OWNER};
187             }
188              
189             =pod
190              
191             =head1 NAME
192              
193             SQL::Statement::TermFactory - Factory for SQL::Statement::Term instances
194              
195             =head1 SYNOPSIS
196              
197             my $termFactory = SQL::Statement::TermFactory->new($stmt);
198             my $whereTerms = $termFactory->buildCondition( $stmt->{where_clause} );
199             my $col = $termFactory->buildCondition( $stmt->{col_obj}->{$name}->{content} );
200              
201             =head1 DESCRIPTION
202              
203             This package implements a factory to create type and operation based terms.
204             Those terms are used to access data from the table(s) - either when evaluating
205             the where clause or returning column data.
206              
207             The concept of a factory can be studied in I by the Gang of
208             Four. The concept of using polymorphism instead of conditions is suggested by
209             Martin Fowler in his book I.
210              
211             =head1 METHODS
212              
213             =head2 buildCondition
214              
215             Builds a condition object from a given (part of a) where clause. This method
216             calls itself recursively for I.
217              
218             =head1 AUTHOR AND COPYRIGHT
219              
220             Copyright (c) 2001,2005 by Jeff Zucker: jzuckerATcpan.org
221             Copyright (c) 2009-2017 by Jens Rehsack: rehsackATcpan.org
222              
223             All rights reserved.
224              
225             You may distribute this module under the terms of either the GNU
226             General Public License or the Artistic License, as specified in
227             the Perl README file.
228              
229             =cut
230              
231             1;