File Coverage

blib/lib/SQL/String.pm
Criterion Covered Total %
statement 57 64 89.0
branch 18 24 75.0
condition 8 13 61.5
subroutine 14 15 93.3
pod 7 7 100.0
total 104 123 84.5


line stmt bran cond sub pod time code
1             package SQL::String;
2              
3             =pod
4              
5             =head1 NAME
6              
7             SQL::String - An object representation of a chunk of SQL
8              
9             =head1 SYNOPSIS
10              
11             I hate SQL::
12             Guess what SQL::Snippit is
13             a not very useful library. I've looked at that.
14             "A snippit of SQL"? NO! A giant complex library and storage and frameworks and junk
15             That's all I want
16             Every decent name I could take for a simple little tied-param chunk of SQL is taken by a "giant framework"
17             Alias: the reason is because SQL does not lend itself to small helpful modules
18             It's like CGI all over again :)
19             hehe
20             alias: dunno if you want to make your own big framework
21             I have my own big framework :)
22             heh
23             I just want some nice little toys to clean it up a bit
24             aha! Nobody has taken SQL::String yet
25             It's mine I tellses you! My own... my precious...
26              
27             =head1 DESCRIPTION
28              
29             SQL::String is a simple object class that lets you create "chunks" of SQL
30             that intrinsicly have their parameters attached to them.
31              
32             Quite a few standard SQL queries won't need this, you create your main
33             select statement once, and then provide the parameters different for each
34             call.
35              
36             However, several types of queries can benefit from this. In particular,
37             the creation of large and complex search queries can be tricky to build
38             what might be 1000 character of SQL and keep track of all the required
39             parameters (short of doing them in a named form, with all the problems
40             of namespace management that entails).
41              
42             SQL::String solves this problem by embedding the parameters into the SQL.
43              
44             A SQL::String object exists as a reference to an array containing the SQL,
45             and a number of parameters intended to be used with it.
46              
47             More usefully, SQL::String overloads concatonation so that you can still
48             use a SQL::String object naturally is if it was just SQL.
49              
50             Once you have created your large complex query, you simple split out the
51             SQL and parameters parts and hand them off to DBI normally.
52              
53             Although SQL::String WILL check to make sure that the SQL is a simple string
54             of at least one character, it makes no judgements whatsoever about the
55             parameters. C, references, objects, everything is legal.
56              
57             This enables custom database backends that do translation of non-DBI
58             parameters normally.
59              
60             =head2 Overloads
61              
62             SQL::String objects ALWAYS evaluate as true, stringify to just the SQL,
63             and act properly in concatination, merging in other parameters in the
64             correct order as expected.
65              
66             The concatination is completely interpolation-safe. That is you can do
67             something like the following.
68              
69             my $sql = SQL::String( 'foo = ?', 10 );
70             $sql = "select * from table where $sql";
71              
72             =head2 Sub-classing
73              
74             Due to the nature of it's internal design, for the time being you are
75             forbidden to sub-class SQL::String.
76              
77             There are some future issues relating to internal structure and XS
78             acceleration that have not been resolved.
79              
80             =head1 METHODS
81              
82             =cut
83              
84 2     2   23325 use 5.005;
  2         7  
  2         79  
85 2     2   12 use strict;
  2         3  
  2         70  
86 2     2   22 use Carp ();
  2         4  
  2         206  
87             use overload 'bool' => sub () { 1 },
88 0     0   0 'eq' => sub { $_[0]->[0] eq $_[1] },
89 2         21 '""' => 'sql',
90             '.' => '_concat',
91             '.=' => 'concat',
92 2     2   1624 '=' => 'clone';
  2         1128  
93              
94 2     2   259 use vars qw{$VERSION};
  2         4  
  2         147  
95             BEGIN {
96 2     2   1315 $VERSION = '0.02';
97             }
98              
99              
100              
101              
102              
103             #####################################################################
104             # Constructor
105              
106             =pod
107              
108             =head2 new $sql [, $param, $param, $param ]
109              
110             The C constructor takes a fragment of SQL and zero or more parameters
111             and creates a new SQL::String object.
112              
113             Returns a new SQL::String object, or C if the SQL argument is not a
114             simple (defined, non-reference, and with non-zero length) string.
115              
116             =cut
117              
118             sub new {
119 19 50   19 1 2847 my $class = ref $_[0] ? ref shift : shift;
120 19 100       85 my $self = (ref $_[0] eq 'ARRAY') ? shift : [ @_ ];
121 19 100 100     217 defined $self->[0] and ! ref $self->[0] and CORE::length $self->[0] or return undef;
      66        
122 14         57 bless $self, $class;
123             }
124              
125             =pod
126              
127             =head2 sql
128              
129             The C accessor provides direct access to the SQL within the object.
130              
131             =cut
132              
133 22     22 1 13233 sub sql { $_[0]->[0] }
134              
135             =pod
136              
137             =head2 params
138              
139             The C method returns a list of the zero or more SQL parameters.
140              
141             When called in scalar context, it returns the number of parameters.
142              
143             =cut
144              
145             sub params {
146 6 100   6 1 23 return $#{$_[0]} unless wantarray;
  3         9  
147 3         5 my @params = @{$_[0]};
  3         9  
148 3         6 shift @params;
149 3         11 @params;
150             }
151              
152             =pod
153              
154             =head2 params_ref
155              
156             The C method also returns the SQL parameters, but as a
157             reference to an ARRAY.
158              
159             =cut
160              
161             sub params_ref {
162 16     16 1 3451 my @params = @{$_[0]};
  16         79  
163 16         135 shift @params;
164 16         94 \@params;
165             }
166              
167             =pod
168              
169             =head2 stable
170              
171             The C method can be used to double-check that the SQL::String object
172             contains a matching number of placeholders and parameters. At this time,
173             only '?' placeholders are recommended in SQL::String objects.
174              
175             Returns true if the number of placeholders match the number of parameters,
176             or false otherwise (in the same way as the == operator).
177              
178             =cut
179              
180             sub stable {
181 3     3 1 2227 my $self = shift;
182 3         27 my $placeholders =()= $self->[0] =~ /(\?)/g;
183 3         8 my $params = $#$self;
184 3         16 $placeholders == $params;
185             }
186              
187              
188              
189              
190              
191             #####################################################################
192             # Overloaded Concatination
193              
194             =pod
195              
196             =head2 clone
197              
198             Make a copy of the SQL::String object. The C function does NOT
199             deep copy the parameters, so you will end up with references to the
200             same refs if you are using refs or objects in the params list.
201              
202             Returns a new and identical SQL::String object with shared param refs.
203              
204             =cut
205              
206             sub clone {
207 9     9 1 17 my $self = shift;
208 9         53 bless [ @$self ], ref $self;
209             }
210              
211             # This is likely to be by FAR the most common operation
212              
213             =pod
214              
215             =head2 concat $string | \@array | $SQLString
216              
217             The C method contatonates another string or SQL::String object
218             to the end of the current object.
219              
220             It takes only a single parameter and behaves in the following way
221              
222             - If passed C, throws the same warning as for a normal undef
223             concatonation.
224              
225             - If passed a zero-length or simple string, concatonates it normally.
226              
227             - If passed another SQL::String object, joins both the SQL and parameter
228             lists in the way you would expect, retaining the correct order of
229             placeholders and parameters. To make the process faster, the SQL::String
230             argument will be probably be destroyed in the process.
231              
232             - If passed an ARRAY reference it will be treated as a SQL::String object,
233             with the first element as a SQL string and the rest as parameters, as with
234             the SQL::String parameter above.
235              
236             - If passed any other type of reference of object, will die with an
237             appropriate error message.
238              
239             In all cases, it returns the same object as a convenience.
240              
241             =cut
242              
243             sub concat {
244 12     12 1 533 my $self = shift;
245 12         25 my $right = shift;
246              
247             # The argument is undef
248 12 100 50     609 defined $right or Carp::carp('Use of uninitialized value in concatenation (.) or string') and return $self;
249              
250             # Add a plain string
251 9         21 my $reftype = ref $right;
252 9 100       25 unless ( $reftype ) {
253 5         14 $self->[0] .= $right;
254 5         18 return $self;
255             }
256              
257             # A plain ARRAY or another SQL::String
258 4 50 33     37 if ( $reftype eq 'ARRAY' or $reftype eq 'SQL::String' ) {
259 4         11 $self->[0] .= shift @$right;
260 4         11 push @$self, @$right;
261              
262 4         16 return $self;
263             }
264              
265             # Something unknown, because we don't allow subclasses.
266 0         0 Carp::croak("Tried to SQL::String::concat an illegal object ($reftype)");
267             }
268              
269             sub _concat {
270 6 50   6   1918 return shift->concat(shift) unless defined $_[2];
271 6 100       27 return shift->clone->concat(shift) unless $_[2];
272              
273             # Handle the reversed case ourselves
274 3         9 my $self = shift->clone;
275 3         6 my $left = shift;
276              
277             # The argument is undef
278 3 100 50     214 defined $left or Carp::carp('Use of uninitialized value in concatenation (.) or string') and return $self;
279              
280             # Add a plain string
281 2         5 my $reftype = ref $left;
282 2 50       7 unless ( $reftype ) {
283 2         8 $self->[0] = $left . $self->[0];
284 2         8 return $self;
285             }
286              
287             # A plain ARRAY (it can't be another SQL::String this time)
288 0 0         if ( $reftype eq 'ARRAY' ) {
289 0           $self->[0] = shift(@$left) . $self->[0];
290 0           unshift @$self, @$left;
291 0           return $self;
292             }
293              
294             # Something unknown, because we don't allow subclasses.
295 0           Carp::croak("Tried to SQL::String::concat an illegal object ($reftype)");
296             }
297              
298             1;
299              
300             ### Keeping this for future uses... it was delicate and tricky to create
301             ### $self->[0] .= ' ' unless substr($sql, 0, 1) eq ' ' or substr($self->[0], -1, 1) eq ' ';
302              
303             =pod
304              
305             =head1 TO DO
306              
307             - Write a faster XS version?
308              
309             - Change param handling to Params::Util
310              
311             - Make use of bytes and potentially unicode
312              
313             - Test to see if if would be better to include the params in their own
314             ARRAY reference.
315              
316             =head1 SUPPORT
317              
318             Bugs should be submitted via the CPAN bug tracker, located at
319              
320             L
321              
322             For other issues, contact the author
323              
324             =head1 AUTHOR
325              
326             Adam Kennedy Eadamk@cpan.orgE
327              
328             Thank you to Phase N Australia (L) for permitting the
329             open sourcing and release of this distribution.
330              
331             =head1 COPYRIGHT
332              
333             Copyright 2004 - 2008 Adam Kennedy.
334              
335             This program is free software; you can redistribute
336             it and/or modify it under the same terms as Perl itself.
337              
338             The full text of the license can be found in the
339             LICENSE file included with this module.
340              
341             =cut