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-2020 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   120 use strict;
  16         33  
  16         535  
14 16     16   90 use warnings FATAL => "all";
  16         30  
  16         502  
15              
16 16     16   7487 use SQL::Statement::Term ();
  16         46  
  16         382  
17 16     16   8453 use SQL::Statement::Operation ();
  16         48  
  16         455  
18 16     16   7540 use SQL::Statement::Placeholder ();
  16         46  
  16         350  
19 16     16   7778 use SQL::Statement::Function ();
  16         75  
  16         501  
20              
21 16     16   8361 use Data::Dumper;
  16         82294  
  16         1194  
22 16     16   124 use Params::Util qw(_HASH _ARRAY0 _INSTANCE);
  16         33  
  16         858  
23 16     16   97 use Scalar::Util qw(blessed weaken);
  16         33  
  16         16712  
24              
25             our $VERSION = '1.413_001';
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 872     872 0 1955 my ( $class, $owner ) = @_;
47 872         2377 my $self = bless(
48             {
49             OWNER => $owner,
50             },
51             $class
52             );
53              
54 872         3474 weaken( $self->{OWNER} );
55              
56 872         2360 return $self;
57             }
58              
59             my %opClasses;
60              
61             sub _getOpClass($)
62             {
63 272     272   520 my ( $self, $op ) = @_;
64 272 100       675 unless ( defined( $opClasses{$op} ) )
65             {
66 39         79 my $opBase = 'SQL::Statement::Operation';
67 39         182 my $opDialect = join( '::', $opBase, $self->{OWNER}->{dialect}, $oplist{$op} );
68             $opClasses{$op} =
69 39 100       538 $opDialect->isa($opBase) ? $opDialect : join( '::', $opBase, $oplist{$op} );
70             }
71              
72 272         618 return $opClasses{$op};
73             }
74              
75             sub buildCondition
76             {
77 2276     2276 1 4174 my ( $self, $pred ) = @_;
78 2276         3119 my $term;
79              
80 2276 100       6987 if ( _ARRAY0($pred) )
    100          
    100          
    50          
81             {
82 30         55 $term = [ map { $self->buildCondition($_) } @{$pred} ];
  85         174  
  30         63  
83             }
84             elsif ( defined( $pred->{op} ) )
85             {
86 329         719 my $op = uc( $pred->{op} );
87 329 100 66     1187 if ( $op eq 'USER_DEFINED' && !$pred->{arg2} )
    100          
    50          
88             {
89 56         210 $term = SQL::Statement::ConstantTerm->new( $self->{OWNER}, $pred->{arg1}->{value} );
90             }
91             elsif ( defined( $oplist{$op} ) )
92             {
93 272         678 my $cn = $self->_getOpClass($op);
94 272         1207 my $left = $self->buildCondition( $pred->{arg1} );
95 272         619 my $right = $self->buildCondition( $pred->{arg2} );
96 272         1402 $term = $cn->new( $self->{OWNER}, $op, $left, $right );
97             }
98             elsif ( defined( $self->{OWNER}->{opts}->{function_names}->{$op} ) )
99             {
100 1         10 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       821 if ( $pred->{neg} )
115             {
116 25         92 $term = SQL::Statement::Operation::Neg->new( $self->{OWNER}, 'NOT', $term );
117             }
118             }
119             elsif ( defined( $pred->{type} ) )
120             {
121 1915         4088 my $type = uc( $pred->{type} );
122 1915 100       7478 if ( $type =~ m/^(?:STRING|NUMBER|BOOLEAN)$/ )
    100          
    100          
    100          
    50          
123             {
124 1093         3477 $term = SQL::Statement::ConstantTerm->new( $self->{OWNER}, $pred->{value} );
125             }
126             elsif ( $type eq 'NULL' )
127             {
128 24         90 $term = SQL::Statement::ConstantTerm->new( $self->{OWNER}, undef );
129             }
130             elsif ( $type eq 'COLUMN' )
131             {
132 439         1513 $term = SQL::Statement::ColumnValue->new( $self->{OWNER}, $pred->{value} );
133             }
134             elsif ( $type eq 'PLACEHOLDER' )
135             {
136 28         186 $term = SQL::Statement::Placeholder->new( $self->{OWNER}, $pred->{argnum} );
137             }
138             elsif ( $type eq 'FUNCTION' )
139             {
140 331 50       574 my @params = map { blessed($_) ? $_ : $self->buildCondition($_) } @{ $pred->{value} };
  457         1537  
  331         758  
141              
142 331 100       1418 if ( $pred->{name} eq 'numeric_exp' )
    100          
    100          
    100          
143             {
144 41         180 $term = SQL::Statement::Function::NumericEval->new( $self->{OWNER}, $pred->{str}, \@params );
145             }
146             elsif ( $pred->{name} eq 'str_concat' )
147             {
148 7         65 $term = SQL::Statement::Function::StrConcat->new( $self->{OWNER}, \@params );
149             }
150             elsif ( $pred->{name} eq 'TRIM' )
151             {
152 10         68 $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         12 my $start = $self->buildCondition( $pred->{start} );
157             my $length = $self->buildCondition( $pred->{length} )
158 3 100       19 if ( _HASH( $pred->{length} ) );
159 3         28 $term = SQL::Statement::Function::SubString->new( $self->{OWNER}, $start, $length, \@params );
160             }
161             else
162             {
163 270         1244 $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         13 return $self->{OWNER}->do_err( sprintf( q~Unknown predicate '{%s}'~, Dumper($pred) ) );
178             }
179              
180 2274         5087 return $term;
181             }
182              
183             sub DESTROY
184             {
185 870     870   1607 my $self = $_[0];
186 870         4169 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-2020 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;