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   109 use strict;
  16         31  
  16         504  
14 16     16   82 use warnings FATAL => "all";
  16         31  
  16         457  
15              
16 16     16   6797 use SQL::Statement::Term ();
  16         42  
  16         341  
17 16     16   7786 use SQL::Statement::Operation ();
  16         45  
  16         364  
18 16     16   7201 use SQL::Statement::Placeholder ();
  16         37  
  16         327  
19 16     16   7100 use SQL::Statement::Function ();
  16         68  
  16         467  
20              
21 16     16   8000 use Data::Dumper;
  16         75067  
  16         1099  
22 16     16   117 use Params::Util qw(_HASH _ARRAY0 _INSTANCE);
  16         32  
  16         800  
23 16     16   91 use Scalar::Util qw(blessed weaken);
  16         30  
  16         15015  
24              
25             our $VERSION = '1.414';
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 1711 my ( $class, $owner ) = @_;
47 872         2244 my $self = bless(
48             {
49             OWNER => $owner,
50             },
51             $class
52             );
53              
54 872         3103 weaken( $self->{OWNER} );
55              
56 872         2083 return $self;
57             }
58              
59             my %opClasses;
60              
61             sub _getOpClass($)
62             {
63 272     272   480 my ( $self, $op ) = @_;
64 272 100       620 unless ( defined( $opClasses{$op} ) )
65             {
66 39         76 my $opBase = 'SQL::Statement::Operation';
67 39         164 my $opDialect = join( '::', $opBase, $self->{OWNER}->{dialect}, $oplist{$op} );
68             $opClasses{$op} =
69 39 100       533 $opDialect->isa($opBase) ? $opDialect : join( '::', $opBase, $oplist{$op} );
70             }
71              
72 272         576 return $opClasses{$op};
73             }
74              
75             sub buildCondition
76             {
77 2276     2276 1 3858 my ( $self, $pred ) = @_;
78 2276         2946 my $term;
79              
80 2276 100       6512 if ( _ARRAY0($pred) )
    100          
    100          
    50          
81             {
82 30         43 $term = [ map { $self->buildCondition($_) } @{$pred} ];
  85         141  
  30         56  
83             }
84             elsif ( defined( $pred->{op} ) )
85             {
86 329         659 my $op = uc( $pred->{op} );
87 329 100 66     1138 if ( $op eq 'USER_DEFINED' && !$pred->{arg2} )
    100          
    50          
88             {
89 56         157 $term = SQL::Statement::ConstantTerm->new( $self->{OWNER}, $pred->{arg1}->{value} );
90             }
91             elsif ( defined( $oplist{$op} ) )
92             {
93 272         612 my $cn = $self->_getOpClass($op);
94 272         697 my $left = $self->buildCondition( $pred->{arg1} );
95 272         543 my $right = $self->buildCondition( $pred->{arg2} );
96 272         1486 $term = $cn->new( $self->{OWNER}, $op, $left, $right );
97             }
98             elsif ( defined( $self->{OWNER}->{opts}->{function_names}->{$op} ) )
99             {
100 1         8 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         11 $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       751 if ( $pred->{neg} )
115             {
116 25         77 $term = SQL::Statement::Operation::Neg->new( $self->{OWNER}, 'NOT', $term );
117             }
118             }
119             elsif ( defined( $pred->{type} ) )
120             {
121 1915         3846 my $type = uc( $pred->{type} );
122 1915 100       7167 if ( $type =~ m/^(?:STRING|NUMBER|BOOLEAN)$/ )
    100          
    100          
    100          
    50          
123             {
124 1093         3280 $term = SQL::Statement::ConstantTerm->new( $self->{OWNER}, $pred->{value} );
125             }
126             elsif ( $type eq 'NULL' )
127             {
128 24         83 $term = SQL::Statement::ConstantTerm->new( $self->{OWNER}, undef );
129             }
130             elsif ( $type eq 'COLUMN' )
131             {
132 439         1458 $term = SQL::Statement::ColumnValue->new( $self->{OWNER}, $pred->{value} );
133             }
134             elsif ( $type eq 'PLACEHOLDER' )
135             {
136 28         149 $term = SQL::Statement::Placeholder->new( $self->{OWNER}, $pred->{argnum} );
137             }
138             elsif ( $type eq 'FUNCTION' )
139             {
140 331 50       508 my @params = map { blessed($_) ? $_ : $self->buildCondition($_) } @{ $pred->{value} };
  457         1379  
  331         737  
141              
142 331 100       1317 if ( $pred->{name} eq 'numeric_exp' )
    100          
    100          
    100          
143             {
144 41         197 $term = SQL::Statement::Function::NumericEval->new( $self->{OWNER}, $pred->{str}, \@params );
145             }
146             elsif ( $pred->{name} eq 'str_concat' )
147             {
148 7         68 $term = SQL::Statement::Function::StrConcat->new( $self->{OWNER}, \@params );
149             }
150             elsif ( $pred->{name} eq 'TRIM' )
151             {
152 10         58 $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         9 my $start = $self->buildCondition( $pred->{start} );
157             my $length = $self->buildCondition( $pred->{length} )
158 3 100       13 if ( _HASH( $pred->{length} ) );
159 3         24 $term = SQL::Statement::Function::SubString->new( $self->{OWNER}, $start, $length, \@params );
160             }
161             else
162             {
163 270         1119 $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         9 return $self->{OWNER}->do_err( sprintf( q~Unknown predicate '{%s}'~, Dumper($pred) ) );
178             }
179              
180 2274         4678 return $term;
181             }
182              
183             sub DESTROY
184             {
185 870     870   1428 my $self = $_[0];
186 870         6783 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;