File Coverage

blib/lib/Jifty/DBI/Collection.pm
Criterion Covered Total %
statement 555 669 82.9
branch 223 330 67.5
condition 83 151 54.9
subroutine 71 86 82.5
pod 51 51 100.0
total 983 1287 76.3


line stmt bran cond sub pod time code
1             package Jifty::DBI::Collection;
2              
3 13     13   40875 use warnings;
  13         20  
  13         346  
4 13     13   45 use strict;
  13         12  
  13         324  
5 13     13   2114 use Scalar::Defer qw/lazy/;
  13         78398  
  13         78  
6 13     13   872 use Scalar::Util qw/weaken/;
  13         16  
  13         943  
7             use overload (
8 435     435   25591 '@{}' => \&items_array_ref,
9             '<>' => \&next,
10             bool => sub {shift},
11 13         103 fallback => 1
12 13     13   51 );
  13         18  
13              
14             =head1 NAME
15              
16             Jifty::DBI::Collection - Encapsulate SQL queries and rows in simple
17             perl objects
18              
19             =head1 SYNOPSIS
20              
21             use Jifty::DBI::Collection;
22              
23             package My::ThingCollection;
24             use base qw/Jifty::DBI::Collection/;
25              
26             package My::Thing;
27             use Jifty::DBI::Schema;
28             use Jifty::DBI::Record schema {
29             column column_1 => type is 'text';
30             };
31              
32             package main;
33              
34             use Jifty::DBI::Handle;
35             my $handle = Jifty::DBI::Handle->new();
36             $handle->connect( driver => 'SQLite', database => "my_test_db" );
37              
38             my $collection = My::ThingCollection->new( handle => $handle );
39              
40             $collection->limit( column => "column_1", value => "matchstring" );
41              
42             while ( my $record = $collection->next ) {
43             print $record->id;
44             }
45              
46             =head1 DESCRIPTION
47              
48             This module provides an object-oriented mechanism for retrieving and
49             updating data in a DBI-accessible database.
50              
51             In order to use this module, you should create a subclass of
52             L and a subclass of L for
53             each table that you wish to access. (See the documentation of
54             L for more information on subclassing it.)
55              
56             Your L subclass must override L,
57             and probably should override at least L also; at the very
58             least, L should probably call L and L to
59             set the database handle (a L object) and table
60             name for the class -- see the L for an example.
61              
62              
63             =cut
64              
65 13     13   937 use vars qw($VERSION);
  13         23  
  13         434  
66              
67 13     13   5330 use Data::Page;
  13         67564  
  13         77  
68 13     13   6677 use Clone;
  13         25072  
  13         555  
69 13     13   65 use Carp qw/croak/;
  13         15  
  13         478  
70 13     13   53 use base qw/Class::Accessor::Fast/;
  13         14  
  13         71210  
71             __PACKAGE__->mk_accessors(qw/pager prefetch_related derived _handle _is_limited rows_per_page/);
72              
73             =head1 METHODS
74              
75             =head2 new
76              
77             Creates a new L object and immediately calls
78             L with the same parameters that were passed to L. If
79             you haven't overridden L<_init> in your subclass, this means that you
80             should pass in a L (or one of its subclasses) like
81             this:
82              
83             my $collection = My::Jifty::DBI::Subclass->new( handle => $handle );
84              
85             However, if your subclass overrides L you do not need to take
86             a handle argument, as long as your subclass takes care of calling the
87             L method somehow. This is useful if you want all of your
88             L objects to use a shared global handle and don't want to
89             have to explicitly pass it in each time, for example.
90              
91             =cut
92              
93             sub new {
94 230     230 1 53798 my $proto = shift;
95 230   66     696 my $class = ref($proto) || $proto;
96 230         234 my $self = {};
97 230         400 bless( $self, $class );
98 230 100       353 $self->record_class( $proto->record_class ) if ref $proto;
99 230         360 $self->_init(@_);
100 230         976 return ($self);
101             }
102              
103             =head2 _init
104              
105             This method is called by L with whatever arguments were passed to
106             L. By default, it takes a C object as a
107             C argument and calls L with that.
108              
109             =cut
110              
111             sub _init {
112 230     230   254 my $self = shift;
113 230         528 my %args = (
114             handle => undef,
115             derived => undef,
116             @_
117             );
118 230 50       787 $self->_handle( $args{'handle'} ) if ( $args{'handle'} );
119 230 100       2086 $self->derived( $args{'derived'} ) if ( $args{'derived'} );
120 230         408 $self->table( $self->record_class->table() );
121 230         543 $self->clean_slate(%args);
122             }
123              
124             sub _init_pager {
125 296     296   243 my $self = shift;
126 296         798 return $self->pager( Data::Page->new(0, 10, 1) );
127             }
128              
129             =head2 clean_slate
130              
131             This completely erases all the data in the object. It's useful if a
132             subclass is doing funky stuff to keep track of a search and wants to
133             reset the object's data without losing its own data; it's probably
134             cleaner to accomplish that in a different way, though.
135              
136             =cut
137              
138             sub clean_slate {
139 296     296 1 7040 my $self = shift;
140 296         443 my %args = (@_);
141 296         432 $self->redo_search();
142 296         407 $self->_init_pager();
143 296         8954 $self->{'itemscount'} = 0;
144 296         403 $self->{'tables'} = "";
145 296         493 $self->{'auxillary_tables'} = "";
146 296         289 $self->{'where_clause'} = "";
147 296         412 $self->{'limit_clause'} = "";
148 296         308 $self->{'order'} = "";
149 296         276 $self->{'alias_count'} = 0;
150 296         301 $self->{'first_row'} = 0;
151              
152 296         1267 delete $self->{$_} for qw(
153             items
154             joins
155             raw_rows
156             count_all
157             subclauses
158             restrictions
159             _open_parens
160             criteria_count
161             );
162              
163 296         570 $self->rows_per_page(0);
164 296         1214 $self->implicit_clauses(%args);
165 296         506 $self->_is_limited(0);
166             }
167              
168             =head2 implicit_clauses
169              
170             Called by L to set up any implicit clauses that the
171             collection B has. Defaults to doing nothing. Is passed the
172             paramhash passed into L.
173              
174             =cut
175              
176 296     296 1 228 sub implicit_clauses { }
177              
178             =head2 _handle [DBH]
179              
180             Get or set this object's L object.
181              
182             =cut
183              
184             =head2 _do_search
185              
186             This internal private method actually executes the search on the
187             database; it is called automatically the first time that you actually
188             need results (such as a call to L).
189              
190             =cut
191              
192             sub _do_search {
193 48     48   57 my $self = shift;
194              
195 48         119 my $query_string = $self->build_select_query();
196              
197             # If we're about to redo the search, we need an empty set of items
198 48         1001 delete $self->{'items'};
199              
200 48         95 my $records = $self->_handle->simple_query($query_string);
201 48 50       110 return 0 unless $records;
202 48         57 my @names = @{ $records->{NAME_lc} };
  48         748  
203 48         137 my $data = {};
204              
205 48 100       56 my @tables = map { $_->{alias} } values %{ $self->prefetch_related || {} };
  3         25  
  48         130  
206              
207 48 100       426 unless ( @tables ) {
208 45         781 while ( my $row = $records->fetchrow_hashref() ) {
209             $row->{ substr($_, 5) } = delete $row->{ $_ }
210 130         1197 foreach grep rindex($_, "main_", 0) == 0, keys %$row;
211 130         297 my $item = $self->new_item;
212 130         320 $item->load_from_hash($row, fast => 1);
213 130         250 $self->add_record($item);
214             }
215 45 50       189 if ( $records->err ) {
216 0         0 $self->{'must_redo_search'} = 0;
217             }
218              
219 45         119 return $self->_record_count;
220             }
221              
222 3         3 my @order;
223 3         5 my $i = 1;
224 3         60 while ( my $base_row = $records->fetchrow_hashref() ) {
225 18         23 my $main_pkey = $base_row->{ $names[0] };
226 18 50       29 $main_pkey = 'unique-'.$i++ if $self->{group_by};
227 18 100 100     61 push @order, $main_pkey
228             unless ( $order[0] && $order[-1] eq $main_pkey );
229              
230             # let's chop the row into subrows;
231 18         20 foreach my $table ('main', @tables) {
232 36         34 my %tmp = ();
233 36         111 for my $k( grep rindex($_, $table ."_", 0) == 0, keys %$base_row ) {
234 90         139 $tmp{ substr($k, length($table)+1) } = $base_row->{ $k };
235             }
236 36 50 33     375 $data->{$main_pkey}{$table}{ $base_row->{ $table . '_id' } || $main_pkey }
237             = \%tmp if keys %tmp;
238             }
239             }
240              
241 3         7 foreach my $row_id (@order) {
242 10         8 my $item;
243 10         10 foreach my $row ( values %{ $data->{$row_id}->{'main'} } ) {
  10         22  
244 10         24 $item = $self->new_item();
245 10         23 $item->load_from_hash($row, fast => 1);
246             }
247 10         9 foreach my $alias ( grep { $_ ne 'main' } keys %{ $data->{$row_id} } )
  20         28  
  10         22  
248             {
249              
250 10         14 my $related_rows = $data->{$row_id}->{$alias};
251 10         24 my ( $class, $col_name )
252             = $self->class_and_column_for_alias($alias);
253 10 50       15 next unless $class;
254              
255 17         20 my @rows = sort { $a->{id} <=> $b->{id} }
  18         33  
256 10         18 grep { $_->{id} } values %$related_rows;
257              
258 10 100       90 if ( $class->isa('Jifty::DBI::Collection') ) {
    50          
259 4         9 my $collection = $class->new( $self->_new_collection_args,
260             derived => 1 );
261 4         7 foreach my $row (@rows) {
262 12         14 my $entry = $collection->new_item;
263 12         26 $entry->load_from_hash($row, fast => 1);
264 12         21 $collection->add_record($entry);
265             }
266              
267 4         13 $item->prefetched( $col_name => $collection );
268             } elsif ( $class->isa('Jifty::DBI::Record') ) {
269 6 50       9 warn "Multiple rows returned for $class in prefetch"
270             if @rows > 1;
271 6         7 my $entry = $class->new( $self->_new_record_args );
272 6 50       16 $entry->load_from_hash( shift(@rows), fast => 1 ) if @rows;
273 6         12 $item->prefetched( $col_name => $entry );
274             } else {
275 0         0 Carp::cluck(
276             "Asked to prefetch $alias as a $class. Don't know how to handle $class"
277             );
278             }
279             }
280 10         19 $self->add_record($item);
281              
282             }
283 3 50       19 if ( $records->err ) {
284 0         0 $self->{'must_redo_search'} = 0;
285             }
286              
287 3         9 return $self->_record_count;
288             }
289              
290             sub _new_record_args {
291 192     192   168 my $self = shift;
292 192         373 return ( handle => $self->_handle );
293             }
294              
295             sub _new_collection_args {
296 5     5   6 my $self = shift;
297 5         8 return ( handle => $self->_handle );
298             }
299              
300             =head2 add_record RECORD
301              
302             Adds a record object to this collection.
303              
304             This method automatically sets our "must redo search" flag to 0 and our "we have limits" flag to 1.
305              
306             Without those two flags, counting the number of items wouldn't work.
307              
308             =cut
309              
310             sub add_record {
311 152     152 1 140 my $self = shift;
312 152         115 my $record = shift;
313 152         291 $self->_is_limited(1);
314 152         614 $self->{'must_redo_search'} = 0;
315 152         120 push @{ $self->{'items'} }, $record;
  152         2711  
316             }
317              
318             =head2 _record_count
319              
320             This private internal method returns the number of
321             L objects saved as a result of the last query.
322              
323             =cut
324              
325             sub _record_count {
326 240     240   1697 my $self = shift;
327 240 100       502 return 0 unless defined $self->{'items'};
328 220         162 return scalar @{ $self->{'items'} };
  220         876  
329             }
330              
331             =head2 _do_count
332              
333             This internal private method actually executes a counting operation on
334             the database; it is used by L and L.
335              
336             =cut
337              
338             sub _do_count {
339 78     78   84 my $self = shift;
340 78   50     218 my $all = shift || 0;
341              
342 78         166 my $query_string = $self->build_select_count_query();
343 78         144 my $records = $self->_handle->simple_query($query_string);
344 78 50       164 return 0 unless $records;
345              
346 78         858 my @row = $records->fetchrow_array();
347 78 50       351 return 0 if $records->err;
348              
349 78 50       251 $self->{ $all ? 'count_all' : 'raw_rows' } = $row[0];
350              
351 78         779 return ( $row[0] );
352             }
353              
354             =head2 _apply_limits STATEMENTREF
355              
356             This routine takes a reference to a scalar containing an SQL
357             statement. It massages the statement to limit the returned rows to
358             only C<< $self->rows_per_page >> rows, skipping C<< $self->first_row >>
359             rows. (That is, if rows are numbered starting from 0, row number
360             C<< $self->first_row >> will be the first row returned.) Note that it
361             probably makes no sense to set these variables unless you are also
362             enforcing an ordering on the rows (with L, say).
363              
364             =cut
365              
366             sub _apply_limits {
367 246     246   210 my $self = shift;
368 246         185 my $statementref = shift;
369 246         433 $self->_handle->apply_limits( $statementref, $self->rows_per_page,
370             $self->first_row );
371              
372             }
373              
374             =head2 _distinct_query STATEMENTREF
375              
376             This routine takes a reference to a scalar containing an SQL
377             statement. It massages the statement to ensure a distinct result set
378             is returned.
379              
380             =cut
381              
382             sub _distinct_query {
383 5     5   5 my $self = shift;
384 5         4 my $statementref = shift;
385 5         12 $self->_handle->distinct_query( $statementref, $self );
386             }
387              
388             =head2 _build_joins
389              
390             Build up all of the joins we need to perform this query.
391              
392             =cut
393              
394             sub _build_joins {
395 328     328   250 my $self = shift;
396              
397 328         513 return ( $self->_handle->_build_joins($self) );
398              
399             }
400              
401             =head2 _is_joined
402              
403             Returns true if this collection will be joining multiple tables
404             together.
405              
406             =cut
407              
408             sub _is_joined {
409 333     333   5763 my $self = shift;
410 333 100 100     680 if ( $self->{'joins'} && keys %{ $self->{'joins'} } ) {
  325         785  
411 19         59 return (1);
412             } else {
413 314         797 return 0;
414             }
415             }
416              
417             =head2 _is_distinctly_joined
418              
419             Returns true if this collection is joining multiple table, but is
420             joining other table's distinct fields, hence resulting in distinct
421             resultsets. The behaviour is undefined if called on a non-joining
422             collection.
423              
424             =cut
425              
426             sub _is_distinctly_joined {
427 18     18   19 my $self = shift;
428 18 50       48 if ( $self->{'joins'} ) {
429 18         14 for ( values %{ $self->{'joins'} } ) {
  18         33  
430 18 100       65 return 0 unless $_->{is_distinct};
431             }
432              
433 4         13 return 1;
434             }
435             }
436              
437             =head2 _is_limited
438              
439             If we've limited down this search, return true. Otherwise, return
440             false.
441              
442             C<1> means "we have limits"
443             C<-1> means "we should return all rows. We want no where clause"
444             C<0> means "no limits have been applied yet.
445              
446             =cut
447              
448             =head2 build_select_query
449              
450             Builds a query string for a "SELECT rows from Tables" statement for
451             this collection
452              
453             =cut
454              
455             sub build_select_query {
456 246     246 1 471 my $self = shift;
457              
458 246 50       409 return "" if $self->derived;
459              
460             # The initial SELECT or SELECT DISTINCT is decided later
461              
462 246         909 my $query_string = $self->_build_joins . " ";
463              
464 246 50       457 if ( $self->_is_limited ) {
465 246         964 $query_string .= $self->_where_clause . " ";
466             }
467 246 100       409 if ( $self->distinct_required ) {
468              
469             # DISTINCT query only required for multi-table selects
470 5         20 $self->_distinct_query( \$query_string );
471             } else {
472 241         370 $query_string
473             = "SELECT " . $self->query_columns . " FROM $query_string";
474 241         409 $query_string .= $self->_group_clause;
475 241         316 $query_string .= $self->_order_clause;
476             }
477              
478 246         423 $self->_apply_limits( \$query_string );
479              
480 246         1088 return ($query_string)
481              
482             }
483              
484             =head2 query_columns
485              
486             The columns that the query would load for result items. By default
487             it's everything.
488              
489             =cut
490              
491             sub query_columns {
492 246     246 1 200 my $self = shift;
493              
494 246         245 my @cols = ();
495 246 100 66     1295 if ( $self->{columns} and @{ $self->{columns} } ) {
  3         17  
496 3         7 push @cols, @{ $self->{columns} };
  3         9  
497             } else {
498 243         338 push @cols, $self->_qualified_record_columns( 'main' => $self->record_class );
499             }
500 246 100       237 my %prefetch_related = %{ $self->prefetch_related || {} };
  246         456  
501 246         1704 foreach my $alias ( keys %prefetch_related ) {
502 3         6 my $class = $prefetch_related{$alias}{class};
503              
504 3         4 my $reference;
505 3 100       23 if ( $class->isa('Jifty::DBI::Collection') ) {
    50          
506 2         4 $reference = $class->record_class;
507             } elsif ( $class->isa('Jifty::DBI::Record') ) {
508 1         2 $reference = $class;
509             }
510              
511 3         5 my $only_cols = $prefetch_related{$alias}{columns};
512              
513 3         5 push @cols, $self->_qualified_record_columns( $alias => $reference, $only_cols );
514             }
515 246         817 return CORE::join( ', ', @cols );
516             }
517              
518             =head2 class_and_column_for_alias
519              
520             Takes the alias you've assigned to a prefetched related
521             object. Returns the class of the column we've declared that alias
522             prefetches.
523              
524             =cut
525              
526             sub class_and_column_for_alias {
527 10     10 1 9 my $self = shift;
528 10         8 my $alias = shift;
529 10 50       7 my %prefetch = %{ $self->prefetch_related || {} };
  10         18  
530 10         48 my $related = $prefetch{$alias};
531 10 50       16 return unless $related;
532              
533 10         21 return $related->{class}, $related->{name};
534             }
535              
536             sub _qualified_record_columns {
537 246     246   203 my $self = shift;
538 246         349 my $alias = shift;
539 246         184 my $item = shift;
540 246         190 my $only_cols = shift;
541 246   66     544 my @columns = map { $_->name } grep { !$_->virtual && !$_->computed } $item->columns;
  998         3635  
  1016         6789  
542 246 50       956 if ($only_cols) {
543 0         0 my %wanted = map { +($_ => 1) } @{ $only_cols };
  0         0  
  0         0  
544 0         0 @columns = grep { $wanted{$_} } @columns;
  0         0  
545             }
546 246         237 return map {$alias ."." . $_ ." as ". $alias ."_". $_} @columns
  998         1583  
547             }
548              
549             =head2 prefetch PARAMHASH
550              
551             Prefetches properties of a related table, in the same query. Possible
552             keys in the paramhash are:
553              
554             =over
555              
556             =item name
557              
558             This argument is required; it specifies the name of the collection or
559             record that is to be prefetched. If the name matches a column with a
560             C relationship, the other arguments can be inferred, and
561             this is the only parameter which needs to be passed.
562              
563             It is possible to pass values for C which are not real columns
564             in the model; these, while they won't be accessible by calling
565             C<< $record-> I >> on records in this collection, will
566             still be accessible by calling C<< $record->prefetched( I ) >>.
567              
568             =item reference
569              
570             Specifies the series of column names to traverse to extract the
571             information. For instance, if groups referred to multiple users, and
572             users referred to multiple phone numbers, then providing
573             C would do the two necessary joins to produce a phone
574             collection for all users in each group.
575              
576             This option defaults to the name, and is irrelevant if an C is
577             provided.
578              
579             =item alias
580              
581             Specifies an alias which has already been joined to this collection as
582             the source of the prefetched data. C will also need to be
583             specified.
584              
585             =item class
586              
587             Specifies the class of the data to preload. This is only necessary if
588             C is provided, and C is not the name of a column which
589             provides C information.
590              
591             =back
592              
593             For backwards compatibility, C can instead be called with
594             C and C as its two arguments, instead of a paramhash.
595              
596             =cut
597              
598             sub prefetch {
599 3     3 1 25 my $self = shift;
600              
601             # Back-compat
602 3 100 66     20 if ( @_ and $self->{joins}{ $_[0] } ) {
603              
604             # First argument appears to be an alias
605 1         4 @_ = ( alias => $_[0], name => $_[1] );
606             }
607              
608 3         13 my %args = (
609             alias => undef,
610             name => undef,
611             class => undef,
612             reference => undef,
613             columns => undef,
614             @_,
615             );
616              
617 3 50       8 die "Must at least provide name to prefetch"
618             unless $args{name};
619              
620             # Reference defaults to name
621 3   33     16 $args{reference} ||= $args{name};
622              
623             # If we don't have an alias, do the join
624 3 100       8 if ( not $args{alias} ) {
625 2         14 my ( $class, @columns )
626             = $self->find_class( split /\./, $args{reference} );
627 2         4 $args{class} = ref $class;
628 2         23 ( $args{alias} ) = $self->resolve_join(@columns);
629             }
630              
631 3 100       9 if ( not $args{class} ) {
632              
633             # Check the column
634 1         3 my $column = $self->record_class->column( $args{name} );
635 1 50       6 $args{class} = $column->refers_to if $column;
636              
637 1 50       6 die "Don't know class" unless $args{class};
638             }
639              
640             # Check that the class is a Jifty::DBI::Record or Jifty::DBI::Collection
641 3 50 66     27 unless ( UNIVERSAL::isa( $args{class}, "Jifty::DBI::Record" )
642             or UNIVERSAL::isa( $args{class}, "Jifty::DBI::Collection" ) )
643             {
644 0         0 warn
645             "Class ($args{class}) isn't a Jifty::DBI::Record or Jifty::DBI::Collection";
646 0         0 return undef;
647             }
648              
649 3 50       15 $self->prefetch_related( {} ) unless $self->prefetch_related;
650 3         31 $self->prefetch_related->{ $args{alias} } = {};
651             $self->prefetch_related->{ $args{alias} }{$_} = $args{$_}
652 3         18 for qw/alias class name columns/;
653              
654             # Return the alias, in case we made it
655 3         50 return $args{alias};
656             }
657              
658             =head2 find_column NAMES
659              
660             Tales a chained list of column names, where all but the last element
661             is the name of a column on the previous class which refers to the next
662             collection or record. Returns a list of L objects
663             for the list.
664              
665             =cut
666              
667             sub find_column {
668 0     0 1 0 my $self = shift;
669 0         0 my @names = @_;
670              
671 0         0 my $last = pop @names;
672 0         0 my ( $class, @columns ) = $self->find_class(@names);
673 0 0       0 $class = $class->record_class
674             if UNIVERSAL::isa( $class, "Jifty::DBI::Collection" );
675 0         0 my $column = $class->column($last);
676 0 0       0 die "$class has no column '$last'" unless $column;
677 0         0 return @columns, $column;
678             }
679              
680             =head2 find_class NAMES
681              
682             Tales a chained list of column names, where each element is the name
683             of a column on the previous class which refers to the next collection
684             or record. Returns an instance of the ending class, followed by the
685             list of L objects traversed to get there.
686              
687             =cut
688              
689             sub find_class {
690 2     2 1 2 my $self = shift;
691 2         3 my @names = @_;
692              
693 2         3 my @res;
694 2         1 my $object = $self;
695 2         4 my $itemclass = $self->record_class;
696 2         5 while ( my $name = shift @names ) {
697 2         6 my $column = $itemclass->column($name);
698 2 50       5 die "$itemclass has no column '$name'" unless $column;
699              
700 2         2 push @res, $column;
701              
702 2         4 my $classname = $column->refers_to;
703 2 50       10 unless ($classname) {
704 0         0 die "column '$name' of $itemclass is not a reference";
705             }
706              
707 2 100       12 if ( UNIVERSAL::isa( $classname, 'Jifty::DBI::Collection' ) ) {
    50          
708 1         3 $object = $classname->new( $self->_new_collection_args );
709 1         2 $itemclass = $object->record_class;
710             } elsif ( UNIVERSAL::isa( $classname, 'Jifty::DBI::Record' ) ) {
711 1         2 $object = $classname->new( $self->_new_record_args );
712 1         3 $itemclass = $classname;
713             } else {
714 0         0 die
715             "Column '$name' refers to '$classname' which is not record or collection";
716             }
717             }
718              
719 2         4 return $object, @res;
720             }
721              
722             =head2 resolve_join COLUMNS
723              
724             Takes a chained list of L objects, and performs
725             the requisite joins to join all of them. Returns the alias of the
726             last join.
727              
728             =cut
729              
730             sub resolve_join {
731 2     2 1 3 my $self = shift;
732 2         3 my @chain = @_;
733              
734 2         3 my $last_alias = 'main';
735              
736 2         3 foreach my $column (@chain) {
737 2         7 my $name = $column->name;
738              
739 2         9 my $classname = $column->refers_to;
740 2 50       8 unless ($classname) {
741 0         0 die "column '$name' of is not a reference";
742             }
743              
744 2 100       11 if ( UNIVERSAL::isa( $classname, 'Jifty::DBI::Collection' ) ) {
    50          
745 1         2 my $right_alias = $self->new_alias($classname->record_class);
746 1   50     4 $self->join(
747             type => 'left',
748             alias1 => $last_alias,
749             column1 => 'id',
750             alias2 => $right_alias,
751             column2 => $column->by || 'id',
752             is_distinct => 1,
753             );
754 1         2 $last_alias = $right_alias;
755             } elsif ( UNIVERSAL::isa( $classname, 'Jifty::DBI::Record' ) ) {
756 1         5 my $right_alias = $self->new_alias($classname);
757 1   50     3 $self->join(
758             type => 'left',
759             alias1 => $last_alias,
760             column1 => $name,
761             alias2 => $right_alias,
762             column2 => $column->by || 'id',
763             is_distinct => 1,
764             );
765 1         3 $last_alias = $right_alias;
766             } else {
767 0         0 die
768             "Column '$name' refers to '$classname' which is not record or collection";
769             }
770             }
771 2         9 return $last_alias;
772             }
773              
774             =head2 distinct_required
775              
776             Returns true if Jifty::DBI expects that this result set will end up
777             with repeated rows and should be "condensed" down to a single row for
778             each unique primary key.
779              
780             Out of the box, this method returns true if you've joined to another table.
781             To add additional logic, feel free to override this method in your subclass.
782              
783             XXX TODO: it should be possible to create a better heuristic than the simple
784             "is it joined?" question we're asking now. Something along the lines of "are we
785             joining this table to something that is not the other table's primary key"
786              
787             =cut
788              
789             sub distinct_required {
790 324     324 1 263 my $self = shift;
791 324 100       440 return ( $self->_is_joined ? !$self->_is_distinctly_joined : 0 );
792             }
793              
794             =head2 build_select_count_query
795              
796             Builds a SELECT statement to find the number of rows this collection
797             would find.
798              
799             =cut
800              
801             sub build_select_count_query {
802 78     78 1 94 my $self = shift;
803              
804 78 50       146 return "" if $self->derived;
805              
806 78         328 my $query_string = $self->_build_joins . " ";
807              
808 78 50       155 if ( $self->_is_limited ) {
809 78         342 $query_string .= $self->_where_clause . " ";
810             }
811              
812             # DISTINCT query only required for multi-table selects
813 78 100 100     175 if ( $self->distinct_required or $self->prefetch_related ) {
814 11         32 $query_string = $self->_handle->distinct_count( \$query_string );
815             } else {
816 67         299 $query_string = "SELECT count(main.id) FROM " . $query_string;
817             }
818              
819 78         143 return ($query_string);
820             }
821              
822             =head2 do_search
823              
824             C usually does searches "lazily". That is, it
825             does a C on the fly the first time you ask
826             for results that would need one or the other. Sometimes, you need to
827             display a count of results found before you iterate over a collection,
828             but you know you're about to do that too. To save a bit of wear and tear
829             on your database, call C before that C.
830              
831             =cut
832              
833             sub do_search {
834 0     0 1 0 my $self = shift;
835 0 0       0 return if $self->derived;
836 0 0       0 $self->_do_search() if $self->{'must_redo_search'};
837              
838             }
839              
840             =head2 next
841              
842             Returns the next row from the set as an object of the type defined by
843             sub new_item. When the complete set has been iterated through,
844             returns undef and resets the search such that the following call to
845             L will start over with the first item retrieved from the
846             database.
847              
848             You may also call this method via the built-in iterator syntax.
849             The two lines below are equivalent:
850              
851             while ($_ = $collection->next) { ... }
852              
853             while (<$collection>) { ... }
854              
855             =cut
856              
857             sub next {
858 83     83 1 1958 my $self = shift;
859              
860 83         159 my $item = $self->peek;
861              
862 83 100       181 if ( $self->{'itemscount'} < $self->_record_count ) {
863 65         108 $self->{'itemscount'}++;
864             } else { #we've gone through the whole list. reset the count.
865 18         40 $self->goto_first_item();
866             }
867              
868 83         223 return ($item);
869             }
870              
871             =head2 peek
872              
873             Exactly the same as next, only it doesn't move the iterator.
874              
875             =cut
876              
877             sub peek {
878 91     91 1 95 my $self = shift;
879              
880 91 100       196 return (undef) unless ( $self->_is_limited );
881              
882 83 100       555 $self->_do_search() if $self->{'must_redo_search'};
883              
884 83 100       199 if ( $self->{'itemscount'} < $self->_record_count )
885             { #return the next item
886 67         120 my $item = ( $self->{'items'}[ $self->{'itemscount'} ] );
887 67         99 return ($item);
888             } else { #no more items!
889 16         33 return (undef);
890             }
891             }
892              
893             =head2 goto_first_item
894              
895             Starts the recordset counter over from the first item. The next time
896             you call L, you'll get the first item returned by the database,
897             as if you'd just started iterating through the result set.
898              
899             =cut
900              
901             sub goto_first_item {
902 59     59 1 66 my $self = shift;
903 59         151 $self->goto_item(0);
904             }
905              
906             =head2 goto_item
907              
908             Takes an integer, n. Sets the record counter to n. the next time you
909             call L, you'll get the nth item.
910              
911             =cut
912              
913             sub goto_item {
914 65     65 1 80 my $self = shift;
915 65         65 my $item = shift;
916 65         115 $self->{'itemscount'} = $item;
917             }
918              
919             =head2 first
920              
921             Returns the first item
922              
923             =cut
924              
925             sub first {
926 35     35 1 1868 my $self = shift;
927 35         260 $self->goto_first_item();
928 35         83 return ( $self->next );
929             }
930              
931             =head2 last
932              
933             Returns the last item
934              
935             =cut
936              
937             sub last {
938 6     6 1 10 my $self = shift;
939 6         13 $self->goto_item( ( $self->count ) - 1 );
940 6         10 return ( $self->next );
941             }
942              
943             =head2 distinct_column_values
944              
945             Takes a column name and returns distinct values of the column.
946             Only values in the current collection are returned.
947              
948             Optional arguments are C and C to limit number of
949             values returned and it makes sense to sort results.
950              
951             $col->distinct_column_values('column');
952              
953             $col->distinct_column_values(column => 'column');
954              
955             $col->distinct_column_values('column', max => 10, sort => 'asc');
956              
957             =cut
958              
959             sub distinct_column_values {
960 4     4 1 881 my $self = shift;
961 4 50       24 my %args = (
962             column => undef,
963             sort => undef,
964             max => undef,
965             @_%2 ? (column => @_) : (@_)
966             );
967              
968 4 50       14 return () if $self->derived;
969              
970 4         29 my $query_string = $self->_build_joins;
971 4 50       8 if ( $self->_is_limited ) {
972 0         0 $query_string .= ' '. $self->_where_clause . " ";
973             }
974              
975 4         19 my $column = 'main.'. $args{'column'};
976 4         6 $query_string = 'SELECT DISTINCT '. $column .' FROM '. $query_string;
977              
978 4 100       8 if ( $args{'sort'} ) {
979 3 100       15 $query_string .= ' ORDER BY '. $column
980             .' '. ($args{'sort'} =~ /^des/i ? 'DESC' : 'ASC');
981             }
982              
983 4 50       27 my $sth = $self->_handle->simple_query( $query_string ) or return;
984 4         6 my $value;
985 4 50       25 $sth->bind_col(1, \$value) or return;
986 4         4 my @col;
987 4 100       8 if ($args{max}) {
988 1   66     38 push @col, $value while 0 < $args{max}-- && $sth->fetch;
989             } else {
990 3         79 push @col, $value while $sth->fetch;
991             }
992 4         85 return @col;
993             }
994              
995             =head2 items_array_ref
996              
997             Return a reference to an array containing all objects found by this
998             search.
999              
1000             You may also call this method via the built-in array dereference syntax.
1001             The two lines below are equivalent:
1002              
1003             for (@{$collection->items_array_ref}) { ... }
1004              
1005             for (@$collection) { ... }
1006              
1007             =cut
1008              
1009             sub items_array_ref {
1010 8     8 1 1626 my $self = shift;
1011              
1012             # If we're not limited, return an empty array
1013 8 100       17 return [] unless $self->_is_limited;
1014              
1015             # Do a search if we need to.
1016 6 100       41 $self->_do_search() if $self->{'must_redo_search'};
1017              
1018             # If we've got any items in the array, return them. Otherwise,
1019             # return an empty array
1020 6   50     24 return ( $self->{'items'} || [] );
1021             }
1022              
1023             =head2 new_item
1024              
1025             Should return a new object of the correct type for the current collection.
1026             L method is used to determine class of the object.
1027              
1028             Each record class at least once is loaded using require. This method is
1029             called each time a record fetched so load attempts are cached to avoid
1030             penalties. If you're sure that all record classes are loaded before
1031             first use then you can override this method.
1032              
1033             =cut
1034              
1035             { my %cache = ();
1036             sub new_item {
1037 185     185 1 337 my $self = shift;
1038 185         264 my $class = $self->record_class();
1039              
1040 185 50       285 die "Jifty::DBI::Collection needs to be subclassed; override new_item\n"
1041             unless $class;
1042              
1043 185 100       324 unless ( exists $cache{$class} ) {
1044 9         111 $class->require;
1045 9         122 $cache{$class} = undef;
1046             }
1047 185         346 return $class->new( $self->_new_record_args );
1048             } }
1049              
1050             =head2 record_class
1051              
1052             Returns the record class which this is a collection of; override this
1053             to subclass. Or, pass it the name of a class as an argument after
1054             creating a C object to create an 'anonymous'
1055             collection class.
1056              
1057             If you haven't specified a record class, this returns a best guess at
1058             the name of the record class for this collection.
1059              
1060             It uses a simple heuristic to determine the record class name -- It
1061             chops "Collection" or "s" off its own name. If you want to name your
1062             records and collections differently, go right ahead, but don't say we
1063             didn't warn you.
1064              
1065             =cut
1066              
1067             sub record_class {
1068 948     948 1 804 my $self = shift;
1069 948 100 100     3896 if (@_) {
    100          
1070 2 50       7 $self->{record_class} = shift if (@_);
1071 2 50       6 $self->{record_class} = ref $self->{record_class}
1072             if ref $self->{record_class};
1073             } elsif ( not ref $self or not $self->{record_class} ) {
1074 231   66     1065 my $class = ref($self) || $self;
1075 231 50       1092 $class =~ s/(?
1076             || die "Can't guess record class from $class";
1077 231 100       424 return $class unless ref $self;
1078 228         383 $self->{record_class} = $class;
1079             }
1080 945         2231 return $self->{record_class};
1081             }
1082              
1083             =head2 redo_search
1084              
1085             Takes no arguments. Tells Jifty::DBI::Collection that the next time
1086             it is asked for a record, it should re-execute the query.
1087              
1088             =cut
1089              
1090             sub redo_search {
1091 597     597 1 3670 my $self = shift;
1092 597         765 $self->{'must_redo_search'} = 1;
1093 597         1857 delete $self->{$_} for qw(items raw_rows count_all);
1094 597         810 $self->{'itemscount'} = 0;
1095             }
1096              
1097             =head2 unlimit
1098              
1099             Unlimit clears all restrictions on this collection and resets
1100             it to a "default" pristine state. Note, in particular, that
1101             this means C will erase ordering and grouping
1102             metadata. To find all rows without resetting this metadata,
1103             use the C method.
1104              
1105             =cut
1106              
1107             sub unlimit {
1108 7     7 1 3235 my $self = shift;
1109              
1110 7         19 $self->clean_slate();
1111 7         40 $self->_is_limited(-1);
1112             }
1113              
1114             =head2 find_all_rows
1115              
1116             C instructs this collection class to return all rows in
1117             the table. (It removes the WHERE clause from your query).
1118              
1119             =cut
1120              
1121             sub find_all_rows {
1122 0     0 1 0 my $self = shift;
1123 0         0 $self->_is_limited(-1);
1124             }
1125              
1126             =head2 limit
1127              
1128             Takes a hash of parameters with the following keys:
1129              
1130             =over 4
1131              
1132             =item table
1133              
1134             Can be set to something different than this table if a join is
1135             wanted (that means we can't do recursive joins as for now).
1136              
1137             =item alias
1138              
1139             Unless alias is set, the join criteria will be taken from EXT_LINKcolumn
1140             and INT_LINKcolumn and added to the criteria. If alias is set, new
1141             criteria about the foreign table will be added.
1142              
1143             =item column
1144              
1145             Column to be checked against.
1146              
1147             =item value
1148              
1149             Should always be set and will always be quoted. If the value is a
1150             subclass of Jifty::DBI::Object, the value will be interpreted to be
1151             the object's id.
1152              
1153             =item operator
1154              
1155             operator is the SQL operator to use for this phrase. Possible choices include:
1156              
1157             =over 4
1158              
1159             =item "="
1160              
1161             =item "!="
1162              
1163             Any other standard SQL comparison operators that your underlying
1164             database supports are also valid.
1165              
1166             =item "LIKE"
1167              
1168             =item "NOT LIKE"
1169              
1170             =item "MATCHES"
1171              
1172             MATCHES is like LIKE, except it surrounds the value with % signs.
1173              
1174             =item "starts_with"
1175              
1176             starts_with is like LIKE, except it only appends a % at the end of the string
1177              
1178             =item "ends_with"
1179              
1180             ends_with is like LIKE, except it prepends a % to the beginning of the string
1181              
1182             =item "IN"
1183              
1184             IN matches a column within a set of values. The value specified in the limit
1185             should be an array reference of values.
1186              
1187             =item "IS"
1188              
1189             =item "IS NOT"
1190              
1191             This is useful for when you wish to match columns that contain NULL (or ones that don't). Use this operator and a value of "NULL".
1192              
1193             =back
1194              
1195             =item escape
1196              
1197             If you need to escape wildcard characters (usually _ or %) in the value *explicitly* with
1198             "ESCAPE", set the escape character here. Note that backslashes may require special treatment
1199             (e.g. Postgres dislikes \ or \\ in queries unless we use the E'' syntax).
1200              
1201             =item entry_aggregator
1202              
1203             Can be AND or OR (or anything else valid to aggregate two clauses in SQL)
1204              
1205             =item case_sensitive
1206              
1207             on some databases, such as postgres, setting case_sensitive to 1 will make
1208             this search case sensitive. Note that this flag is ignored if the column
1209             is numeric.
1210              
1211             =back
1212              
1213             =cut
1214              
1215             sub limit {
1216 279     279 1 7463 my $self = shift;
1217 279         1421 my %args = (
1218             table => undef,
1219             alias => undef,
1220             column => undef,
1221             value => undef,
1222             quote_value => 1,
1223             entry_aggregator => 'or',
1224             case_sensitive => undef,
1225             operator => '=',
1226             escape => undef,
1227             subclause => undef,
1228             leftjoin => undef,
1229             @_ # get the real argumentlist
1230             );
1231              
1232 279 50       552 return if $self->derived;
1233              
1234             #If we're performing a left join, we really want the alias to be the
1235             #left join criterion.
1236              
1237 279 50 33     1413 if ( ( defined $args{'leftjoin'} )
1238             && ( not defined $args{'alias'} ) )
1239             {
1240 0         0 $args{'alias'} = $args{'leftjoin'};
1241             }
1242              
1243             # {{{ if there's no alias set, we need to set it
1244              
1245 279 100       440 unless ( defined $args{'alias'} ) {
1246              
1247             #if the table we're looking at is the same as the main table
1248 271 50 33     545 if ( !defined $args{'table'} || $args{'table'} eq $self->table ) {
1249              
1250             # TODO this code assumes no self joins on that table.
1251             # if someone can name a case where we'd want to do that,
1252             # I'll change it.
1253              
1254 271         315 $args{'alias'} = 'main';
1255             }
1256              
1257             else {
1258 0         0 $args{'alias'} = $self->new_alias( $args{'table'} );
1259             }
1260             }
1261              
1262             # }}}
1263              
1264             # $column_obj is undefined when the table2 argument to the join is a table
1265             # name and not a collection model class. In that case, the class key
1266             # doesn't exist for the join.
1267 279 50 66     949 my $class
1268             = $self->{joins}{ $args{alias} }
1269             && $self->{joins}{ $args{alias} }{class}
1270             ? $self->{joins}{ $args{alias} }{class}
1271             ->new( $self->_new_collection_args )
1272             : $self;
1273 279         391 my $column_obj = $class->record_class->column( $args{column} );
1274              
1275 279 100 100     848 $self->new_item->_apply_input_filters(
      66        
1276             column => $column_obj,
1277             value_ref => \$args{'value'},
1278             ) if $column_obj && $column_obj->encode_on_select && $args{operator} !~ /IS/;
1279              
1280             # Ensure that the column has nothing fishy going on. We can't
1281             # simply check $column_obj's truth because joins mostly join by
1282             # table name, not class, and we don't track table_name -> class.
1283 279 50       1633 if ($args{column} =~ /\W/) {
1284 0         0 warn "Possible SQL injection on column '$args{column}' in limit at @{[join(',',(caller)[1,2])]}\n";
  0         0  
1285 0         0 %args = (
1286             %args,
1287             column => 'id',
1288             operator => '<',
1289             value => 0,
1290             );
1291             }
1292 279 50       1249 if ($args{operator} !~ /^(=|<|>|!=|<>|<=|>=
1293             |(NOT\s*)?LIKE
1294             |(NOT\s*)?(STARTS|ENDS)_?WITH
1295             |(NOT\s*)?MATCHES
1296             |IS(\s*NOT)?
1297             |IN)$/ix) {
1298 0         0 warn "Unknown operator '$args{operator}' in limit at @{[join(',',(caller)[1,2])]}\n";
  0         0  
1299 0         0 %args = (
1300             %args,
1301             column => 'id',
1302             operator => '<',
1303             value => 0,
1304             );
1305             }
1306              
1307              
1308             # Set this to the name of the column and the alias, unless we've been
1309             # handed a subclause name
1310 279 50       628 my $qualified_column
1311             = $args{'alias'}
1312             ? $args{'alias'} . "." . $args{'column'}
1313             : $args{'column'};
1314 279   66     734 my $clause_id = $args{'subclause'} || $qualified_column;
1315              
1316              
1317             # make passing in an object DTRT
1318 279         276 my $value_ref = ref( $args{value} );
1319 279 100       392 if ($value_ref) {
1320 31 100 66     112 if ( ( $value_ref ne 'ARRAY' )
    50          
1321             && $args{value}->isa('Jifty::DBI::Record') )
1322             {
1323 2 50 33     8 my $by = (defined $column_obj and defined $column_obj->by)
1324             ? $column_obj->by
1325             : 'id';
1326 2         18 $args{value} = $args{value}->$by;
1327             } elsif ( $value_ref eq 'ARRAY' ) {
1328              
1329             # Don't modify the original reference, it isn't polite
1330 29         29 $args{value} = [ @{ $args{value} } ];
  29         66  
1331 62 100 66     174 map {
1332 29         46 my $by = (defined $column_obj and defined $column_obj->by)
1333             ? $column_obj->by
1334             : 'id';
1335 62 100 66     341 $_ = (
1336             ( ref $_ && $_->isa('Jifty::DBI::Record') )
1337             ? ( $_->$by )
1338             : $_
1339             )
1340 29         31 } @{ $args{value} };
1341             }
1342             }
1343              
1344             #since we're changing the search criteria, we need to redo the search
1345 279         410 $self->redo_search();
1346              
1347             #If it's a like, we supply the %s around the search term
1348 279 100       885 if ( $args{'operator'} =~ /MATCHES/i ) {
    100          
    100          
1349 25         46 $args{'value'} = "%" . $args{'value'} . "%";
1350             } elsif ( $args{'operator'} =~ /STARTS_?WITH/i ) {
1351 17         30 $args{'value'} = $args{'value'} . "%";
1352             } elsif ( $args{'operator'} =~ /ENDS_?WITH/i ) {
1353 17         27 $args{'value'} = "%" . $args{'value'};
1354             }
1355 279         536 $args{'operator'} =~ s/(?:MATCHES|ENDS_?WITH|STARTS_?WITH)/LIKE/i;
1356              
1357             # Force the value to NULL (non-quoted) if the operator is IS.
1358 279 100       606 if ($args{'operator'} =~ /^IS(\s*NOT)?$/i) {
1359 54         53 $args{'quote_value'} = 0;
1360 54         58 $args{'value'} = 'NULL';
1361             }
1362              
1363             # Quote the value
1364 279 100       396 if ( $args{'quote_value'} ) {
1365 223 100       287 if ( $value_ref eq 'ARRAY' ) {
1366 29         23 map { $_ = $self->_handle->quote_value($_) } @{ $args{'value'} };
  62         97  
  29         42  
1367             } else {
1368 194         375 $args{'value'} = $self->_handle->quote_value( $args{'value'} );
1369             }
1370             }
1371              
1372 279 100       440 if ( $args{'escape'} ) {
1373 4         8 $args{'escape'} = 'ESCAPE ' . $self->_handle->quote_value( $args{escape} );
1374             }
1375              
1376             # If we're trying to get a leftjoin restriction, lets set
1377             # $restriction to point there. otherwise, lets construct normally
1378              
1379 279         207 my $restriction;
1380 279 50       399 if ( $args{'leftjoin'} ) {
1381 0   0     0 $restriction
1382             = $self->{'joins'}{ $args{'leftjoin'} }{'criteria'}{$clause_id}
1383             ||= [];
1384             } else {
1385 279   100     1203 $restriction = $self->{'restrictions'}{$clause_id} ||= [];
1386             }
1387              
1388             # If it's a new value or we're overwriting this sort of restriction,
1389              
1390 279 100 66     863 if ( defined $args{'value'} && $args{'quote_value'} ) {
1391 223         179 my $case_sensitive = 0;
1392 223 100       390 if ( defined $args{'case_sensitive'} ) {
    100          
1393 114         99 $case_sensitive = $args{'case_sensitive'};
1394             }
1395             elsif ( $column_obj ) {
1396 103         215 $case_sensitive = $column_obj->case_sensitive;
1397             }
1398             # don't worry about case for numeric columns_in_db
1399             # only be case insensitive when we KNOW it's a text
1400 223 100 100     1148 if ( $column_obj && !$case_sensitive && !$column_obj->is_string ) {
      100        
1401 68         62 $case_sensitive = 1;
1402             }
1403              
1404 223 100 66     494 if ( !$case_sensitive && $self->_handle->case_sensitive ) {
1405 67         116 ( $qualified_column, $args{'operator'}, $args{'value'} )
1406             = $self->_handle->_make_clause_case_insensitive(
1407             $qualified_column, $args{'operator'}, $args{'value'} );
1408             }
1409             }
1410              
1411 279 100       443 if ( $value_ref eq 'ARRAY' ) {
1412 29 50       96 croak
1413             'Limits with an array ref are only allowed with operator \'IN\' or \'=\''
1414             unless $args{'operator'} =~ /^(IN|=)$/i;
1415 29         30 $args{'value'} = '( ' . join( ',', @{ $args{'value'} } ) . ' )';
  29         78  
1416 29         43 $args{'operator'} = 'IN';
1417             }
1418              
1419 279         770 my $clause = {
1420             column => $qualified_column,
1421             operator => $args{'operator'},
1422             value => $args{'value'},
1423             escape => $args{'escape'},
1424             };
1425              
1426             # Juju because this should come _AFTER_ the EA
1427 279         236 my @prefix;
1428 279 100       567 if ( $self->{'_open_parens'}{$clause_id} ) {
1429 1         3 @prefix = ('(') x delete $self->{'_open_parens'}{$clause_id};
1430             }
1431              
1432 279 100 50     1127 if ( lc( $args{'entry_aggregator'} || "" ) eq 'none' || !@$restriction ) {
      66        
1433 274         419 @$restriction = ( @prefix, $clause );
1434             } else {
1435 5         11 push @$restriction, $args{'entry_aggregator'}, @prefix, $clause;
1436             }
1437              
1438             # We're now limited. people can do searches.
1439              
1440 279         538 $self->_is_limited(1);
1441              
1442 279 50       1159 if ( defined( $args{'alias'} ) ) {
1443 279         780 return ( $args{'alias'} );
1444             } else {
1445 0         0 return (1);
1446             }
1447             }
1448              
1449             =head2 open_paren CLAUSE
1450              
1451             Places an open parenthesis at the current location in the given C.
1452             Note that this can be used for Deep Magic, and has a high likelihood
1453             of allowing you to construct malformed SQL queries. Its interface
1454             will probably change in the near future, but its presence allows for
1455             arbitrarily complex queries.
1456              
1457             Here's an example, to construct a SQL WHERE clause roughly equivalent to (depending on your SQL dialect):
1458              
1459             parent = 12 AND task_type = 'action'
1460             AND (status = 'open'
1461             OR (status = 'done'
1462             AND completed_on >= '2008-06-26 11:39:22'))
1463              
1464             You can use sub-clauses and C and C as follows:
1465              
1466             $col->limit( column => 'parent', value => 12 );
1467             $col->limit( column => 'task_type', value => 'action' );
1468              
1469             $col->open_paren("my_clause");
1470              
1471             $col->limit( subclause => "my_clause", column => 'status', value => 'open' );
1472              
1473             $col->open_paren("my_clause");
1474              
1475             $col->limit( subclause => "my_clause", column => 'status',
1476             value => 'done', entry_aggregator => 'OR' );
1477             $col->limit( subclause => "my_clause", column => 'completed_on',
1478             operator => '>=', value => '2008-06-26 11:39:22' );
1479              
1480             $col->close_paren("my_clause");
1481              
1482             $col->close_paren("my_clause");
1483              
1484             Where the C<"my_clause"> can be any name you choose.
1485              
1486             =cut
1487              
1488             sub open_paren {
1489 1     1 1 7 my ( $self, $clause ) = @_;
1490 1         3 $self->{_open_parens}{$clause}++;
1491             }
1492              
1493             =head2 close_paren CLAUSE
1494              
1495             Places a close parenthesis at the current location in the given C.
1496             Note that this can be used for Deep Magic, and has a high likelihood
1497             of allowing you to construct malformed SQL queries. Its interface
1498             will probably change in the near future, but its presence allows for
1499             arbitrarily complex queries.
1500              
1501             =cut
1502              
1503             # Immediate Action
1504             sub close_paren {
1505 1     1 1 6 my ( $self, $clause ) = @_;
1506 1   50     4 my $restriction = $self->{'restrictions'}{$clause} ||= [];
1507 1         2 push @$restriction, ')';
1508             }
1509              
1510             sub _add_subclause {
1511 0     0   0 my $self = shift;
1512 0         0 my $clauseid = shift;
1513 0         0 my $subclause = shift;
1514              
1515 0         0 $self->{'subclauses'}{"$clauseid"} = $subclause;
1516              
1517             }
1518              
1519             sub _where_clause {
1520 324     324   277 my $self = shift;
1521 324         266 my $where_clause = '';
1522              
1523             # Go through all the generic restrictions and build up the
1524             # "generic_restrictions" subclause. That's the only one that the
1525             # collection builds itself. Arguably, the abstraction should be
1526             # better, but I don't really see where to put it.
1527 324         411 $self->_compile_generic_restrictions();
1528              
1529             #Go through all restriction types. Build the where clause from the
1530             #Various subclauses.
1531              
1532 324         1414 my @subclauses = grep defined && length,
1533 324   66     238 values %{ $self->{'subclauses'} };
1534              
1535 324 100       779 $where_clause = " WHERE " . CORE::join( ' AND ', @subclauses )
1536             if (@subclauses);
1537              
1538 324         528 return ($where_clause);
1539              
1540             }
1541              
1542             #Compile the restrictions to a WHERE Clause
1543              
1544             sub _compile_generic_restrictions {
1545 324     324   243 my $self = shift;
1546              
1547 324         494 delete $self->{'subclauses'}{'generic_restrictions'};
1548              
1549             # Go through all the restrictions of this type. Buld up the generic subclause
1550 324         233 my $result = '';
1551 324   33     343 foreach my $restriction ( grep $_ && @$_,
  324         1501  
1552             values %{ $self->{'restrictions'} } )
1553             {
1554 312 100       420 $result .= ' AND ' if $result;
1555 312         307 $result .= '(';
1556 312         319 foreach my $entry (@$restriction) {
1557 328 100       457 unless ( ref $entry ) {
1558 10         14 $result .= ' ' . $entry . ' ';
1559             } else {
1560 1272         1613 $result .= join ' ',
1561 318         421 grep {defined}
1562 318         308 @{$entry}{qw(column operator value escape)};
1563             }
1564             }
1565 312         388 $result .= ')';
1566             }
1567 324         671 return ( $self->{'subclauses'}{'generic_restrictions'} = $result );
1568             }
1569              
1570             # set $self->{$type .'_clause'} to new value
1571             # redo_search only if new value is really new
1572             sub _set_clause {
1573 0     0   0 my $self = shift;
1574 0         0 my ( $type, $value ) = @_;
1575 0         0 $type .= '_clause';
1576 0 0 0     0 if ( ( $self->{$type} || '' ) ne ( $value || '' ) ) {
      0        
1577 0         0 $self->redo_search;
1578             }
1579 0         0 $self->{$type} = $value;
1580             }
1581              
1582             # stub for back-compat
1583             sub _quote_value {
1584 0     0   0 my $self = shift;
1585 0         0 return $self->_handle->quote_value(@_);
1586             }
1587              
1588             =head2 order_by_cols DEPRECATED
1589              
1590             *DEPRECATED*. Use C method.
1591              
1592             =cut
1593              
1594             sub order_by_cols {
1595 0     0 1 0 require Carp;
1596 0         0 Carp::cluck("order_by_cols is deprecated, use order_by method");
1597 0         0 goto &order_by;
1598             }
1599              
1600             =head2 order_by EMPTY|HASH|ARRAY_OF_HASHES
1601              
1602             Orders the returned results by column(s) and/or function(s) on column(s).
1603              
1604             Takes a paramhash of C, C and C
1605             or C and C.
1606             C defaults to main.
1607             C defaults to ASC(ending), DES(cending) is also a valid value.
1608             C and C have no default values.
1609              
1610             Use C instead of C and C to order by
1611             the function value. Note that if you want use a column as argument of
1612             the function then you have to build correct reference with alias
1613             in the C format.
1614              
1615             If you specify C and C, the column (and C) will be
1616             wrapped in the function. This is useful for simple functions like C or
1617             C.
1618              
1619             Use array of hashes to order by many columns/functions.
1620              
1621             Calling this I the ordering, it doesn't refine it. If you want to keep
1622             previous ordering, use C.
1623              
1624             The results would be unordered if method called without arguments.
1625              
1626             Returns the current list of columns.
1627              
1628             =cut
1629              
1630             sub order_by {
1631 7     7 1 32 my $self = shift;
1632 7 50       47 return if $self->derived;
1633 7 100       162 if (@_) {
1634 6         12 $self->{'order_by'} = [];
1635 6         29 $self->add_order_by(@_);
1636             }
1637 7   50     26 return ( $self->{'order_by'} || [] );
1638             }
1639              
1640             =head2 add_order_by EMPTY|HASH|ARRAY_OF_HASHES
1641              
1642             Same as order_by, except it will not reset the ordering you have already set.
1643              
1644             =cut
1645              
1646             sub add_order_by {
1647 8     8 1 22 my $self = shift;
1648 8 50       24 return if $self->derived;
1649 8 50       42 if (@_) {
1650 8         14 my @args = @_;
1651              
1652 8 100       40 unless ( UNIVERSAL::isa( $args[0], 'HASH' ) ) {
1653 7         19 @args = {@args};
1654             }
1655 8   50     9 push @{ $self->{'order_by'} ||= [] }, @args;
  8         25  
1656 8         833 $self->redo_search();
1657             }
1658 8   50     25 return ( $self->{'order_by'} || [] );
1659             }
1660              
1661             =head2 clear_order_by
1662              
1663             Clears whatever would normally get set in the ORDER BY clause.
1664              
1665             =cut
1666              
1667             sub clear_order_by {
1668 1     1 1 1 my $self = shift;
1669              
1670 1         3 $self->{'order_by'} = [];
1671             }
1672              
1673             =head2 _order_clause
1674              
1675             returns the ORDER BY clause for the search.
1676              
1677             =cut
1678              
1679             sub _order_clause {
1680 256     256   224 my $self = shift;
1681              
1682 256 100       565 return '' unless $self->{'order_by'};
1683              
1684 13         16 my $clause = '';
1685 13         14 foreach my $row ( @{ $self->{'order_by'} } ) {
  13         21  
1686              
1687 29         78 my %rowhash = (
1688             alias => 'main',
1689             column => undef,
1690             order => 'ASC',
1691             %$row
1692             );
1693 29 100       69 if ( $rowhash{'order'} =~ /^des/i ) {
1694 12         13 $rowhash{'order'} = "DESC";
1695             } else {
1696 17         18 $rowhash{'order'} = "ASC";
1697             }
1698              
1699 29 100 100     130 if ( $rowhash{'function'} and not defined $rowhash{'column'} ) {
    50 33        
1700 6 100       9 $clause .= ( $clause ? ", " : " " );
1701 6         8 $clause .= $rowhash{'function'} . ' ';
1702 6         9 $clause .= $rowhash{'order'};
1703              
1704             } elsif ( ( defined $rowhash{'alias'} )
1705             and ( $rowhash{'column'} ) )
1706             {
1707 23 50       74 if ($rowhash{'column'} =~ /\W/) {
1708 0         0 warn "Possible SQL injection in column '$rowhash{column}' in order_by\n";
1709 0         0 next;
1710             }
1711              
1712 23 100       32 $clause .= ( $clause ? ", " : " " );
1713 23 100       35 $clause .= $rowhash{'function'} . "(" if $rowhash{'function'};
1714 23 100       39 $clause .= $rowhash{'alias'} . "." if $rowhash{'alias'};
1715 23         21 $clause .= $rowhash{'column'};
1716 23 100       54 $clause .= ")" if $rowhash{'function'};
1717 23         44 $clause .= " " . $rowhash{'order'};
1718             }
1719             }
1720 13 100       37 $clause = " ORDER BY$clause " if $clause;
1721 13         34 return $clause;
1722             }
1723              
1724             =head2 group_by_cols DEPRECATED
1725              
1726             *DEPRECATED*. Use group_by method.
1727              
1728             =cut
1729              
1730             sub group_by_cols {
1731 0     0 1 0 require Carp;
1732 0         0 Carp::cluck("group_by_cols is deprecated, use group_by method");
1733 0         0 goto &group_by;
1734             }
1735              
1736             =head2 group_by EMPTY|HASH|ARRAY_OF_HASHES
1737              
1738             Groups the search results by column(s) and/or function(s) on column(s).
1739              
1740             Takes a paramhash of C and C or C.
1741             C defaults to main.
1742             C and C have no default values.
1743              
1744             Use C instead of C and C to group by
1745             the function value. Note that if you want use a column as argument
1746             of the function then you have to build correct reference with alias
1747             in the C format.
1748              
1749             Use array of hashes to group by many columns/functions.
1750              
1751             The method is EXPERIMENTAL and subject to change.
1752              
1753             =cut
1754              
1755             sub group_by {
1756 2     2 1 28 my $self = shift;
1757              
1758 2 50       9 return if $self->derived;
1759 2         19 my @args = @_;
1760              
1761 2 50       14 unless ( UNIVERSAL::isa( $args[0], 'HASH' ) ) {
1762 2         7 @args = {@args};
1763             }
1764 2         7 $self->{'group_by'} = \@args;
1765 2         6 $self->redo_search();
1766             }
1767              
1768             =head2 _group_clause
1769              
1770             Private function to return the "GROUP BY" clause for this query.
1771              
1772             =cut
1773              
1774             sub _group_clause {
1775 247     247   217 my $self = shift;
1776 247 100       545 return '' unless $self->{'group_by'};
1777              
1778 3         5 my $row;
1779             my $clause;
1780              
1781 3         4 foreach $row ( @{ $self->{'group_by'} } ) {
  3         7  
1782 3         12 my %rowhash = (
1783             alias => 'main',
1784              
1785             column => undef,
1786             %$row
1787             );
1788 3 50 33     32 if ( $rowhash{'function'} ) {
    50          
1789 0 0       0 $clause .= ( $clause ? ", " : " " );
1790 0         0 $clause .= $rowhash{'function'};
1791              
1792             } elsif ( ( $rowhash{'alias'} )
1793             and ( $rowhash{'column'} ) )
1794             {
1795 3 50       11 if ($rowhash{'column'} =~ /\W/) {
1796 0         0 warn "Possible SQL injection in column '$rowhash{column}' in group_by\n";
1797 0         0 next;
1798             }
1799              
1800 3 50       7 $clause .= ( $clause ? ", " : " " );
1801 3         7 $clause .= $rowhash{'alias'} . ".";
1802 3         10 $clause .= $rowhash{'column'};
1803             }
1804             }
1805 3 50       7 if ($clause) {
1806 3         8 return " GROUP BY" . $clause . " ";
1807             } else {
1808 0         0 return '';
1809             }
1810             }
1811              
1812             =head2 new_alias table_OR_CLASS
1813              
1814             Takes the name of a table or a Jifty::DBI::Record subclass.
1815             Returns the string of a new Alias for that table, which can be used
1816             to Join tables or to limit what gets found by
1817             a search.
1818              
1819             =cut
1820              
1821             sub new_alias {
1822 5     5 1 6 my $self = shift;
1823 5   50     14 my $refers_to = shift || die "Missing parameter";
1824 5         5 my $table;
1825 5         5 my $class = undef;
1826 5 100       27 if ( $refers_to->can('table') ) {
1827 2         4 $table = $refers_to->table;
1828 2         8 $class = $refers_to;
1829             } else {
1830 3         3 $table = $refers_to;
1831             }
1832              
1833 5         12 my $alias = $self->_get_alias($table);
1834              
1835 5 100       29 $self->{'joins'}{$alias} = {
1836             alias => $alias,
1837             table => $table,
1838             type => 'CROSS',
1839             ( $class ? ( class => $class ) : () ),
1840             alias_string => " CROSS JOIN $table $alias ",
1841             };
1842              
1843 5         12 return $alias;
1844             }
1845              
1846             # _get_alias is a private function which takes an tablename and
1847             # returns a new alias for that table without adding something to
1848             # self->{'joins'}. This function is used by new_alias and the
1849             # as-yet-unnamed left join code
1850              
1851             sub _get_alias {
1852 14     14   15 my $self = shift;
1853 14         12 my $table = shift;
1854              
1855 14         49 return $table . "_" . ++$self->{'alias_count'};
1856             }
1857              
1858             =head2 join
1859              
1860             Join instructs Jifty::DBI::Collection to join two tables.
1861              
1862             The standard form takes a paramhash with keys C, C, C
1863             and C. C and C are column aliases obtained from
1864             $self->new_alias or a $self->limit. C and C are the columns
1865             in C and C that should be linked, respectively. For this
1866             type of join, this method has no return value.
1867              
1868             Supplying the parameter C => 'left' causes Join to perform a left
1869             join. in this case, it takes C, C, C and
1870             C. Because of the way that left joins work, this method needs a
1871             table for the second column rather than merely an alias. For this type
1872             of join, it will return the alias generated by the join.
1873              
1874             The parameter C defaults C<=>, but you can specify other
1875             operators to join with.
1876              
1877             Passing a true value for the C parameter allows one to
1878             specify that, despite the join, the original table's rows are will all
1879             still be distinct.
1880              
1881             Instead of C/C, it's possible to specify expression, to join
1882             C/C on an arbitrary expression.
1883              
1884             =cut
1885              
1886             sub join {
1887 12     12 1 580 my $self = shift;
1888 12         65 my %args = (
1889             type => 'normal',
1890             column1 => undef,
1891             alias1 => 'main',
1892             table2 => undef,
1893             column2 => undef,
1894             alias2 => undef,
1895             @_
1896             );
1897              
1898 12 50       39 return if $self->derived;
1899 12         71 $self->_handle->join( collection => $self, %args );
1900              
1901             }
1902              
1903             =head2 set_page_info [per_page => NUMBER,] [current_page => NUMBER]
1904              
1905             Sets the current page (one-based) and number of items per page on the
1906             pager object, and pulls the number of elements from the collection.
1907             This both sets up the collection's L object so that you
1908             can use its calculations, and sets the L
1909             C and C so that queries return values from
1910             the selected page.
1911              
1912             If a C of C is passed, then paging is basically disabled
1913             (by setting C to the number of entries, and C to 1)
1914              
1915             =cut
1916              
1917             sub set_page_info {
1918 0     0 1 0 my $self = shift;
1919 0         0 my %args = (
1920             per_page => 0,
1921             current_page => 1, # 1-based
1922             @_
1923             );
1924 0 0       0 return if $self->derived;
1925              
1926 0         0 my $weakself = $self;
1927 0         0 weaken($weakself);
1928              
1929 0     0   0 my $total_entries = lazy { $weakself->count_all };
  0         0  
1930              
1931 0 0       0 if ($args{'current_page'} eq 'all') {
1932 0         0 $args{'current_page'} = 1;
1933 0         0 $args{'per_page'} = $total_entries;
1934             }
1935              
1936 0         0 $self->pager->total_entries($total_entries)
1937             ->entries_per_page( $args{'per_page'} )
1938             ->current_page( $args{'current_page'} );
1939              
1940 0         0 $self->rows_per_page( $args{'per_page'} );
1941              
1942             # We're not using $pager->first because it automatically does a count_all
1943             # to correctly return '0' for empty collections
1944 0         0 $self->first_row( ( $args{'current_page'} - 1 ) * $args{'per_page'} + 1 );
1945              
1946             }
1947              
1948             =head2 rows_per_page
1949              
1950             limits the number of rows returned by the database. Optionally, takes
1951             an integer which restricts the # of rows returned in a result Returns
1952             the number of rows the database should display.
1953              
1954             =cut
1955              
1956             =head2 first_row
1957              
1958             Get or set the first row of the result set the database should return.
1959             Takes an optional single integer argument. Returns the currently set
1960             integer first row that the database should return.
1961              
1962              
1963             =cut
1964              
1965             # returns the first row
1966             sub first_row {
1967 246     246 1 1099 my $self = shift;
1968 246 50       358 if (@_) {
1969 0         0 $self->{'first_row'} = shift;
1970              
1971             #SQL starts counting at 0
1972 0         0 $self->{'first_row'}--;
1973              
1974             #gotta redo the search if changing pages
1975 0         0 $self->redo_search();
1976             }
1977 246         622 return ( $self->{'first_row'} );
1978             }
1979              
1980             =head2 _items_counter
1981              
1982             Returns the current position in the record set.
1983              
1984             =cut
1985              
1986             sub _items_counter {
1987 10     10   9 my $self = shift;
1988 10         17 return $self->{'itemscount'};
1989             }
1990              
1991             =head2 count
1992              
1993             Returns the number of records in the set.
1994              
1995             =cut
1996              
1997             sub count {
1998 119     119 1 1294 my $self = shift;
1999              
2000             # An unlimited search returns no tickets
2001 119 100       217 return 0 unless ( $self->_is_limited );
2002              
2003             # If we haven't actually got all objects loaded in memory, we
2004             # really just want to do a quick count from the database.
2005 106 100       489 if ( $self->{'must_redo_search'} ) {
2006              
2007             # If we haven't already asked the database for the row count, do that
2008 82 100       269 $self->_do_count unless ( $self->{'raw_rows'} );
2009              
2010             #Report back the raw # of rows in the database
2011 82         343 return ( $self->{'raw_rows'} );
2012             }
2013              
2014             # If we have loaded everything from the DB we have an
2015             # accurate count already.
2016             else {
2017 24         35 return $self->_record_count;
2018             }
2019             }
2020              
2021             =head2 count_all
2022              
2023             Returns the total number of potential records in the set, ignoring any
2024             limit_clause.
2025              
2026             =cut
2027              
2028             # 22:24 [Robrt(500@outer.space)] It has to do with Caching.
2029             # 22:25 [Robrt(500@outer.space)] The documentation says it ignores the limit.
2030             # 22:25 [Robrt(500@outer.space)] But I don't believe thats true.
2031             # 22:26 [msg(Robrt)] yeah. I
2032             # 22:26 [msg(Robrt)] yeah. I'm not convinced it does anything useful right now
2033             # 22:26 [msg(Robrt)] especially since until a week ago, it was setting one variable and returning another
2034             # 22:27 [Robrt(500@outer.space)] I remember.
2035             # 22:27 [Robrt(500@outer.space)] It had to do with which Cached value was returned.
2036             # 22:27 [msg(Robrt)] (given that every time we try to explain it, we get it Wrong)
2037             # 22:27 [Robrt(500@outer.space)] Because Count can return a different number than actual NumberOfResults
2038             # 22:28 [msg(Robrt)] in what case?
2039             # 22:28 [Robrt(500@outer.space)] count_all _always_ used the return value of _do_count(), as opposed to Count which would return the cached number of
2040             # results returned.
2041             # 22:28 [Robrt(500@outer.space)] IIRC, if you do a search with a limit, then raw_rows will == limit.
2042             # 22:31 [msg(Robrt)] ah.
2043             # 22:31 [msg(Robrt)] that actually makes sense
2044             # 22:31 [Robrt(500@outer.space)] You should paste this conversation into the count_all docs.
2045             # 22:31 [msg(Robrt)] perhaps I'll create a new method that _actually_ do that.
2046             # 22:32 [msg(Robrt)] since I'm not convinced it's been doing that correctly
2047              
2048             sub count_all {
2049 0     0 1 0 my $self = shift;
2050              
2051             # An unlimited search returns no tickets
2052 0 0       0 return 0 unless ( $self->_is_limited );
2053              
2054             # If we haven't actually got all objects loaded in memory, we
2055             # really just want to do a quick count from the database.
2056 0 0 0     0 if ( $self->{'must_redo_search'} || !$self->{'count_all'} ) {
2057              
2058             # If we haven't already asked the database for the row count, do that
2059 0 0       0 $self->_do_count(1) unless ( $self->{'count_all'} );
2060              
2061             #Report back the raw # of rows in the database
2062 0         0 return ( $self->{'count_all'} );
2063             }
2064              
2065             # If we have loaded everything from the DB we have an
2066             # accurate count already.
2067             else {
2068 0         0 return $self->_record_count;
2069             }
2070             }
2071              
2072             =head2 is_last
2073              
2074             Returns true if the current row is the last record in the set.
2075              
2076             =cut
2077              
2078             sub is_last {
2079 18     18 1 2750 my $self = shift;
2080              
2081 18 100       51 return undef unless $self->count;
2082              
2083 10 100       22 if ( $self->_items_counter == $self->count ) {
2084 6         18 return (1);
2085             } else {
2086 4         13 return (0);
2087             }
2088             }
2089              
2090             =head2 DEBUG
2091              
2092             Gets/sets the DEBUG flag.
2093              
2094             =cut
2095              
2096             sub DEBUG {
2097 0     0 1 0 my $self = shift;
2098 0 0       0 if (@_) {
2099 0         0 $self->{'DEBUG'} = shift;
2100             }
2101 0         0 return ( $self->{'DEBUG'} );
2102             }
2103              
2104             =head2 column
2105              
2106             Normally a collection object contains record objects populated with all columns
2107             in the database, but you can restrict the records to only contain some
2108             particular columns, by calling the C method once for each column you
2109             are interested in.
2110              
2111             Takes a hash of parameters; the C, C and C keys means
2112             the same as in the C method. A special C key may contain
2113             one of several possible kinds of expressions:
2114              
2115             =over 4
2116              
2117             =item C
2118              
2119             Same as C.
2120              
2121             =item Expression with C in it
2122              
2123             The C is substituted with the column name, then passed verbatim to the
2124             underlying C
2125              
2126             =item Expression with C<(> in it
2127              
2128             The expression is passed verbatim to the underlying C
2129              
2130             =item Any other expression
2131              
2132             The expression is taken to be a function name. For example, C means
2133             the same thing as C.
2134              
2135             =back
2136              
2137             =cut
2138              
2139             sub column {
2140 3     3 1 21 my $self = shift;
2141 3         18 my %args = (
2142             table => undef,
2143             alias => undef,
2144             column => undef,
2145             function => undef,
2146             @_
2147             );
2148              
2149 3   33     14 my $table = $args{table} || do {
2150             if ( my $alias = $args{alias} ) {
2151             $alias =~ s/_\d+$//;
2152             $alias;
2153             } else {
2154             $self->table;
2155             }
2156             };
2157              
2158 3   50     26 my $name = ( $args{alias} || 'main' ) . '.' . $args{column};
2159 3 50       13 if ( my $func = $args{function} ) {
2160 0 0       0 if ( $func =~ /^DISTINCT\s*COUNT$/i ) {
    0          
    0          
2161 0         0 $name = "COUNT(DISTINCT $name)";
2162             }
2163              
2164             # If we want to substitute
2165             elsif ( $func =~ /\?/ ) {
2166 0         0 $name =~ s/\?/$name/g;
2167             }
2168              
2169             # If we want to call a simple function on the column
2170             elsif ( $func !~ /\(/ ) {
2171 0         0 $name = "\U$func\E($name)";
2172             } else {
2173 0         0 $name = $func;
2174             }
2175              
2176             }
2177              
2178 3   50     6 my $column = "col" . @{ $self->{columns} ||= [] };
  3         29  
2179 3 50 33     16 $column = $args{column} if $table eq $self->table and !$args{alias};
2180 3   50     30 $column = ( $args{'alias'} || 'main' ) . "_" . $column;
2181 3         4 push @{ $self->{columns} }, "$name AS \L$column";
  3         18  
2182 3         10 return $column;
2183             }
2184              
2185             =head2 columns LIST
2186              
2187             Specify that we want to load only the columns in LIST, which should be
2188             a list of column names.
2189              
2190             =cut
2191              
2192             sub columns {
2193 1     1 1 6 my $self = shift;
2194 1         5 $self->column( column => $_ ) for @_;
2195             }
2196              
2197             =head2 columns_in_db table
2198              
2199             Return a list of columns in table, in lowercase.
2200              
2201             TODO: Why are they in lowercase?
2202              
2203             =cut
2204              
2205             sub columns_in_db {
2206 0     0 1 0 my $self = shift;
2207 0         0 my $table = shift;
2208              
2209 0         0 my $dbh = $self->_handle->dbh;
2210              
2211             # TODO: memoize this
2212              
2213 0         0 return map lc( $_->[0] ), @{ (
2214 0 0 0     0 eval {
      0        
2215 0         0 $dbh->column_info( '', '', $table, '' )->fetchall_arrayref( [3] );
2216             }
2217             || $dbh->selectall_arrayref("DESCRIBE $table;")
2218             || $dbh->selectall_arrayref("DESCRIBE \u$table;")
2219             || []
2220             ) };
2221             }
2222              
2223             =head2 has_column { table => undef, column => undef }
2224              
2225             Returns true if table has column column.
2226             Return false otherwise
2227              
2228             =cut
2229              
2230             sub has_column {
2231 0     0 1 0 my $self = shift;
2232 0         0 my %args = (
2233             column => undef,
2234             table => undef,
2235             @_
2236             );
2237              
2238 0 0       0 my $table = $args{table} or die;
2239 0 0       0 my $column = $args{column} or die;
2240 0         0 return grep { $_ eq $column } $self->columns_in_db($table);
  0         0  
2241             }
2242              
2243             =head2 table [table]
2244              
2245             If called with an argument, sets this collection's table.
2246              
2247             Always returns this collection's table.
2248              
2249             =cut
2250              
2251             sub table {
2252 559     559 1 1285 my $self = shift;
2253 559 100       1173 $self->{table} = shift if (@_);
2254 559         1166 return $self->{table};
2255             }
2256              
2257             =head2 clone
2258              
2259             Returns copy of the current object with all search restrictions.
2260              
2261             =cut
2262              
2263             sub clone {
2264 2     2 1 15 my $self = shift;
2265              
2266 2         5 my $obj = bless {}, ref($self);
2267 2         25 %$obj = %$self;
2268              
2269 2         20 $obj->redo_search(); # clean out the object of data
2270              
2271             $obj->{$_} = Clone::clone( $obj->{$_} )
2272 2         12 for grep exists $self->{$_}, $self->_cloned_attributes;
2273 2         6 return $obj;
2274             }
2275              
2276             =head2 _cloned_attributes
2277              
2278             Returns list of the object's fields that should be copied.
2279              
2280             If your subclass store references in the object that should be copied while
2281             cloning then you probably want override this method and add own values to
2282             the list.
2283              
2284             =cut
2285              
2286             sub _cloned_attributes {
2287 2     2   13 return qw(
2288             joins
2289             subclauses
2290             restrictions
2291             );
2292             }
2293              
2294             =head2 each CALLBACK
2295              
2296             Executes the callback for each item in the collection. The callback receives as
2297             arguments each record, its zero-based index, and the collection. The return
2298             value of C is the original collection.
2299              
2300             If the callback returns zero, the iteration ends.
2301              
2302             =cut
2303              
2304             sub each {
2305 0     0 1   my $self = shift;
2306 0           my $cb = shift;
2307              
2308 0           my $idx = 0;
2309 0           $self->goto_first_item;
2310              
2311 0           while (my $record = $self->next) {
2312 0           my $ret = $cb->($record, $idx++, $self);
2313 0 0 0       last if defined($ret) && !$ret;
2314             }
2315              
2316 0           return $self;
2317             }
2318              
2319             1;
2320             __END__