Minor doc cleanup and more examples
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / ResultSet.pm
1 package DBIx::Class::ResultSet;
2
3 use strict;
4 use warnings;
5 use Carp qw/croak/;
6 use overload
7         '0+'     => 'count',
8         'bool'   => sub { 1; },
9         fallback => 1;
10 use Data::Page;
11 use Storable;
12
13 =head1 NAME
14
15 DBIx::Class::ResultSet - Responsible for fetching and creating resultset.
16
17 =head1 SYNOPSIS
18
19   my $rs   = $schema->resultset('User')->search(registered => 1);
20   my @rows = $schema->resultset('Foo')->search(bar => 'baz');
21
22 =head1 DESCRIPTION
23
24 The resultset is also known as an iterator. It is responsible for handling
25 queries that may return an arbitrary number of rows, e.g. via L</search>
26 or a C<has_many> relationship.
27
28 In the examples below, the following table classes are used:
29
30   package MyApp::Schema::Artist;
31   use base qw/DBIx::Class/;
32   __PACKAGE__->table('artist');
33   __PACKAGE__->add_columns(qw/artistid name/);
34   __PACKAGE__->set_primary_key('artistid');
35   __PACKAGE__->has_many(cds => 'MyApp::Schema::CD');
36   1;
37
38   package MyApp::Schema::CD;
39   use base qw/DBIx::Class/;
40   __PACKAGE__->table('artist');
41   __PACKAGE__->add_columns(qw/cdid artist title year/);
42   __PACKAGE__->set_primary_key('cdid');
43   __PACKAGE__->belongs_to(artist => 'MyApp::Schema::Artist');
44   1;
45
46 =head1 METHODS
47
48 =head2 new($source, \%$attrs)
49
50 The resultset constructor. Takes a source object (usually a
51 L<DBIx::Class::TableInstance>) and an attribute hash (see L</ATRRIBUTES>
52 below).  Does not perform any queries -- these are executed as needed by the
53 other methods.
54
55 Generally you won't need to construct a resultset manually.  You'll
56 automatically get one from e.g. a L</search> called in scalar context:
57
58   my $rs = $schema->resultset('CD')->search({ title => '100th Window' });
59
60 =cut
61
62 sub new {
63   my $class = shift;
64   return $class->new_result(@_) if ref $class;
65   my ($source, $attrs) = @_;
66   #use Data::Dumper; warn Dumper($attrs);
67   $attrs = Storable::dclone($attrs || {}); # { %{ $attrs || {} } };
68   my %seen;
69   my $alias = ($attrs->{alias} ||= 'me');
70   if ($attrs->{cols} || !$attrs->{select}) {
71     delete $attrs->{as} if $attrs->{cols};
72     my @cols = ($attrs->{cols}
73                  ? @{delete $attrs->{cols}}
74                  : $source->columns);
75     $attrs->{select} = [ map { m/\./ ? $_ : "${alias}.$_" } @cols ];
76   }
77   $attrs->{as} ||= [ map { m/^$alias\.(.*)$/ ? $1 : $_ } @{$attrs->{select}} ];
78   #use Data::Dumper; warn Dumper(@{$attrs}{qw/select as/});
79   $attrs->{from} ||= [ { $alias => $source->from } ];
80   if (my $join = delete $attrs->{join}) {
81     foreach my $j (ref $join eq 'ARRAY'
82               ? (@{$join}) : ($join)) {
83       if (ref $j eq 'HASH') {
84         $seen{$_} = 1 foreach keys %$j;
85       } else {
86         $seen{$j} = 1;
87       }
88     }
89     push(@{$attrs->{from}}, $source->resolve_join($join, $attrs->{alias}));
90   }
91   $attrs->{group_by} ||= $attrs->{select} if delete $attrs->{distinct};
92   foreach my $pre (@{delete $attrs->{prefetch} || []}) {
93     push(@{$attrs->{from}}, $source->resolve_join($pre, $attrs->{alias}))
94       unless $seen{$pre};
95     my @pre = 
96       map { "$pre.$_" }
97       $source->related_source($pre)->columns;
98     push(@{$attrs->{select}}, @pre);
99     push(@{$attrs->{as}}, @pre);
100   }
101   if ($attrs->{page}) {
102     $attrs->{rows} ||= 10;
103     $attrs->{offset} ||= 0;
104     $attrs->{offset} += ($attrs->{rows} * ($attrs->{page} - 1));
105   }
106   my $new = {
107     source => $source,
108     cond => $attrs->{where},
109     from => $attrs->{from},
110     count => undef,
111     page => delete $attrs->{page},
112     pager => undef,
113     attrs => $attrs };
114   bless ($new, $class);
115   return $new;
116 }
117
118 =head2 search
119
120   my @obj    = $rs->search({ foo => 3 }); # "... WHERE foo = 3"
121   my $new_rs = $rs->search({ foo => 3 });
122
123 If you need to pass in additional attributes but no additional condition,
124 call it as C<search({}, \%attrs);>.
125
126   # "SELECT foo, bar FROM $class_table"
127   my @all = $class->search({}, { cols => [qw/foo bar/] });
128
129 =cut
130
131 sub search {
132   my $self = shift;
133
134   #use Data::Dumper;warn Dumper(@_);
135
136   my $attrs = { %{$self->{attrs}} };
137   if (@_ > 1 && ref $_[$#_] eq 'HASH') {
138     $attrs = { %$attrs, %{ pop(@_) } };
139   }
140
141   my $where = (@_ ? ((@_ == 1 || ref $_[0] eq "HASH") ? shift : {@_}) : undef());
142   if (defined $where) {
143     $where = (defined $attrs->{where}
144                 ? { '-and' =>
145                     [ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
146                         $where, $attrs->{where} ] }
147                 : $where);
148     $attrs->{where} = $where;
149   }
150
151   my $rs = (ref $self)->new($self->{source}, $attrs);
152
153   return (wantarray ? $rs->all : $rs);
154 }
155
156 =head2 search_literal
157
158   my @obj    = $rs->search_literal($literal_where_cond, @bind);
159   my $new_rs = $rs->search_literal($literal_where_cond, @bind);
160
161 Pass a literal chunk of SQL to be added to the conditional part of the
162 resultset.
163
164 =cut
165                                                          
166 sub search_literal {
167   my ($self, $cond, @vals) = @_;
168   my $attrs = (ref $vals[$#vals] eq 'HASH' ? { %{ pop(@vals) } } : {});
169   $attrs->{bind} = [ @{$self->{attrs}{bind}||[]}, @vals ];
170   return $self->search(\$cond, $attrs);
171 }
172
173 =head2 find(@colvalues), find(\%cols, \%attrs?)
174
175 Finds a row based on its primary key or unique constraint. For example:
176
177   my $cd = $schema->resultset('CD')->find(5);
178
179 Also takes an optional C<key> attribute, to search by a specific key or unique
180 constraint. For example:
181
182   my $cd = $schema->resultset('CD')->find_or_create(
183     {
184       artist => 'Massive Attack',
185       title  => 'Mezzanine',
186     },
187     { key => 'artist_title' }
188   );
189
190 See also L</find_or_create> and L</update_or_create>.
191
192 =cut
193
194 sub find {
195   my ($self, @vals) = @_;
196   my $attrs = (@vals > 1 && ref $vals[$#vals] eq 'HASH' ? pop(@vals) : {});
197
198   my @cols = $self->{source}->primary_columns;
199   if (exists $attrs->{key}) {
200     my %uniq = $self->{source}->unique_constraints;
201     $self->( "Unknown key " . $attrs->{key} . " on " . $self->name )
202       unless exists $uniq{$attrs->{key}};
203     @cols = @{ $uniq{$attrs->{key}} };
204   }
205   #use Data::Dumper; warn Dumper($attrs, @vals, @cols);
206   $self->{source}->result_class->throw( "Can't find unless a primary key or unique constraint is defined" )
207     unless @cols;
208
209   my $query;
210   if (ref $vals[0] eq 'HASH') {
211     $query = $vals[0];
212   } elsif (@cols == @vals) {
213     $query = {};
214     @{$query}{@cols} = @vals;
215   } else {
216     $query = {@vals};
217   }
218   #warn Dumper($query);
219   # Useless -> disabled
220   #$self->{source}->result_class->throw( "Can't find unless all primary keys are specified" )
221   #  unless (keys %$query >= @pk); # If we check 'em we run afoul of uc/lc
222                                   # column names etc. Not sure what to do yet
223   return $self->search($query)->next;
224 }
225
226 =head2 search_related
227
228   $rs->search_related('relname', $cond?, $attrs?);
229
230 Search the specified relationship. Optionally specify a condition for matching
231 records.
232
233 =cut
234
235 sub search_related {
236   my ($self, $rel, @rest) = @_;
237   my $rel_obj = $self->{source}->relationship_info($rel);
238   $self->{source}->result_class->throw(
239     "No such relationship ${rel} in search_related")
240       unless $rel_obj;
241   my $rs = $self->search(undef, { join => $rel });
242   return $self->{source}->schema->resultset($rel_obj->{class}
243            )->search( undef,
244              { %{$rs->{attrs}},
245                alias => $rel,
246                select => undef(),
247                as => undef() }
248            )->search(@rest);
249 }
250
251 =head2 cursor
252
253 Returns a storage-driven cursor to the given resultset.
254
255 =cut
256
257 sub cursor {
258   my ($self) = @_;
259   my ($source, $attrs) = @{$self}{qw/source attrs/};
260   $attrs = { %$attrs };
261   return $self->{cursor}
262     ||= $source->storage->select($self->{from}, $attrs->{select},
263           $attrs->{where},$attrs);
264 }
265
266 =head2 search_like
267
268 Perform a search, but use C<LIKE> instead of equality as the condition. Note
269 that this is simply a convenience method; you most likely want to use
270 L</search> with specific operators.
271
272 For more information, see L<DBIx::Class::Manual::Cookbook>.
273
274 =cut
275
276 sub search_like {
277   my $class    = shift;
278   my $attrs = { };
279   if (@_ > 1 && ref $_[$#_] eq 'HASH') {
280     $attrs = pop(@_);
281   }
282   my $query    = ref $_[0] eq "HASH" ? { %{shift()} }: {@_};
283   $query->{$_} = { 'like' => $query->{$_} } for keys %$query;
284   return $class->search($query, { %$attrs });
285 }
286
287 =head2 slice($first, $last)
288
289 Returns a subset of elements from the resultset.
290
291 =cut
292
293 sub slice {
294   my ($self, $min, $max) = @_;
295   my $attrs = { %{ $self->{attrs} || {} } };
296   $attrs->{offset} ||= 0;
297   $attrs->{offset} += $min;
298   $attrs->{rows} = ($max ? ($max - $min + 1) : 1);
299   my $slice = (ref $self)->new($self->{source}, $attrs);
300   return (wantarray ? $slice->all : $slice);
301 }
302
303 =head2 next
304
305 Returns the next element in the resultset (C<undef> is there is none).
306
307 Can be used to efficiently iterate over records in the resultset:
308
309   my $rs = $schema->resultset('CD')->search({});
310   while (my $cd = $rs->next) {
311     print $cd->title;
312   }
313
314 =cut
315
316 sub next {
317   my ($self) = @_;
318   my @row = $self->cursor->next;
319 #  warn Dumper(\@row); use Data::Dumper;
320   return unless (@row);
321   return $self->_construct_object(@row);
322 }
323
324 sub _construct_object {
325   my ($self, @row) = @_;
326   my @cols = @{ $self->{attrs}{as} };
327   #warn "@cols -> @row";
328   my (%me, %pre);
329   foreach my $col (@cols) {
330     if ($col =~ /([^\.]+)\.([^\.]+)/) {
331       $pre{$1}[0]{$2} = shift @row;
332     } else {
333       $me{$col} = shift @row;
334     }
335   }
336   my $new = $self->{source}->result_class->inflate_result(
337               $self->{source}, \%me, \%pre);
338   $new = $self->{attrs}{record_filter}->($new)
339     if exists $self->{attrs}{record_filter};
340   return $new;
341 }
342
343 =head2 count
344
345 Performs an SQL C<COUNT> with the same query as the resultset was built
346 with to find the number of elements. If passed arguments, does a search
347 on the resultset and counts the results of that.
348
349 =cut
350
351 sub count {
352   my $self = shift;
353   return $self->search(@_)->count if @_ && defined $_[0];
354   croak "Unable to ->count with a GROUP BY" if defined $self->{attrs}{group_by};
355   unless (defined $self->{count}) {
356     my $attrs = { %{ $self->{attrs} },
357                   select => { 'count' => '*' },
358                   as => [ 'count' ] };
359     # offset, order by and page are not needed to count. record_filter is cdbi
360     delete $attrs->{$_} for qw/rows offset order_by page pager record_filter/;
361         
362     ($self->{count}) = (ref $self)->new($self->{source}, $attrs)->cursor->next;
363   }
364   return 0 unless $self->{count};
365   my $count = $self->{count};
366   $count -= $self->{attrs}{offset} if $self->{attrs}{offset};
367   $count = $self->{attrs}{rows} if
368     ($self->{attrs}{rows} && $self->{attrs}{rows} < $count);
369   return $count;
370 }
371
372 =head2 count_literal
373
374 Calls L</search_literal> with the passed arguments, then L</count>.
375
376 =cut
377
378 sub count_literal { shift->search_literal(@_)->count; }
379
380 =head2 all
381
382 Returns all elements in the resultset. Called implictly if the resultset
383 is returned in list context.
384
385 =cut
386
387 sub all {
388   my ($self) = @_;
389   return map { $self->_construct_object(@$_); }
390            $self->cursor->all;
391 }
392
393 =head2 reset
394
395 Resets the resultset's cursor, so you can iterate through the elements again.
396
397 =cut
398
399 sub reset {
400   my ($self) = @_;
401   $self->cursor->reset;
402   return $self;
403 }
404
405 =head2 first
406
407 Resets the resultset and returns the first element.
408
409 =cut
410
411 sub first {
412   return $_[0]->reset->next;
413 }
414
415 =head2 update(\%values)
416
417 Sets the specified columns in the resultset to the supplied values.
418
419 =cut
420
421 sub update {
422   my ($self, $values) = @_;
423   croak "Values for update must be a hash" unless ref $values eq 'HASH';
424   return $self->{source}->storage->update(
425            $self->{source}->from, $values, $self->{cond});
426 }
427
428 =head2 update_all(\%values)
429
430 Fetches all objects and updates them one at a time.  Note that C<update_all>
431 will run cascade triggers while L</update> will not.
432
433 =cut
434
435 sub update_all {
436   my ($self, $values) = @_;
437   croak "Values for update must be a hash" unless ref $values eq 'HASH';
438   foreach my $obj ($self->all) {
439     $obj->set_columns($values)->update;
440   }
441   return 1;
442 }
443
444 =head2 delete
445
446 Deletes the contents of the resultset from its result source.
447
448 =cut
449
450 sub delete {
451   my ($self) = @_;
452   $self->{source}->storage->delete($self->{source}->from, $self->{cond});
453   return 1;
454 }
455
456 =head2 delete_all
457
458 Fetches all objects and deletes them one at a time.  Note that C<delete_all>
459 will run cascade triggers while L</delete> will not.
460
461 =cut
462
463 sub delete_all {
464   my ($self) = @_;
465   $_->delete for $self->all;
466   return 1;
467 }
468
469 =head2 pager
470
471 Returns a L<Data::Page> object for the current resultset. Only makes
472 sense for queries with a C<page> attribute.
473
474 =cut
475
476 sub pager {
477   my ($self) = @_;
478   my $attrs = $self->{attrs};
479   croak "Can't create pager for non-paged rs" unless $self->{page};
480   $attrs->{rows} ||= 10;
481   $self->count;
482   return $self->{pager} ||= Data::Page->new(
483     $self->{count}, $attrs->{rows}, $self->{page});
484 }
485
486 =head2 page($page_num)
487
488 Returns a new resultset for the specified page.
489
490 =cut
491
492 sub page {
493   my ($self, $page) = @_;
494   my $attrs = { %{$self->{attrs}} };
495   $attrs->{page} = $page;
496   return (ref $self)->new($self->{source}, $attrs);
497 }
498
499 =head2 new_result(\%vals)
500
501 Creates a result in the resultset's result class.
502
503 =cut
504
505 sub new_result {
506   my ($self, $values) = @_;
507   $self->{source}->result_class->throw( "new_result needs a hash" )
508     unless (ref $values eq 'HASH');
509   $self->{source}->result_class->throw( "Can't abstract implicit construct, condition not a hash" )
510     if ($self->{cond} && !(ref $self->{cond} eq 'HASH'));
511   my %new = %$values;
512   my $alias = $self->{attrs}{alias};
513   foreach my $key (keys %{$self->{cond}||{}}) {
514     $new{$1} = $self->{cond}{$key} if ($key =~ m/^(?:$alias\.)?([^\.]+)$/);
515   }
516   my $obj = $self->{source}->result_class->new(\%new);
517   $obj->result_source($self->{source}) if $obj->can('result_source');
518   $obj;
519 }
520
521 =head2 create(\%vals)
522
523 Inserts a record into the resultset and returns the object.
524
525 Effectively a shortcut for C<< ->new_result(\%vals)->insert >>.
526
527 =cut
528
529 sub create {
530   my ($self, $attrs) = @_;
531   $self->{source}->result_class->throw( "create needs a hashref" ) unless ref $attrs eq 'HASH';
532   return $self->new_result($attrs)->insert;
533 }
534
535 =head2 find_or_create(\%vals, \%attrs?)
536
537   $class->find_or_create({ key => $val, ... });
538
539 Searches for a record matching the search condition; if it doesn't find one,    
540 creates one and returns that instead.                                           
541
542   my $cd = $schema->resultset('CD')->find_or_create({
543     cdid   => 5,
544     artist => 'Massive Attack',
545     title  => 'Mezzanine',
546     year   => 2005,
547   });
548
549 Also takes an optional C<key> attribute, to search by a specific key or unique
550 constraint. For example:
551
552   my $cd = $schema->resultset('CD')->find_or_create(
553     {
554       artist => 'Massive Attack',
555       title  => 'Mezzanine',
556     },
557     { key => 'artist_title' }
558   );
559
560 See also L</find> and L</update_or_create>.
561
562 =cut
563
564 sub find_or_create {
565   my $self     = shift;
566   my $attrs    = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
567   my $hash     = ref $_[0] eq "HASH" ? shift : {@_};
568   my $exists   = $self->find($hash, $attrs);
569   return defined($exists) ? $exists : $self->create($hash);
570 }
571
572 =head2 update_or_create
573
574   $class->update_or_create({ key => $val, ... });
575
576 First, search for an existing row matching one of the unique constraints
577 (including the primary key) on the source of this resultset.  If a row is
578 found, update it with the other given column values.  Otherwise, create a new
579 row.
580
581 Takes an optional C<key> attribute to search on a specific unique constraint.
582 For example:
583
584   # In your application
585   my $cd = $schema->resultset('CD')->update_or_create(
586     {
587       artist => 'Massive Attack',
588       title  => 'Mezzanine',
589       year   => 1998,
590     },
591     { key => 'artist_title' }
592   );
593
594 If no C<key> is specified, it searches on all unique constraints defined on the
595 source, including the primary key.
596
597 If the C<key> is specified as C<primary>, search only on the primary key.
598
599 See also L</find> and L</find_or_create>.
600
601 =cut
602
603 sub update_or_create {
604   my $self = shift;
605
606   my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
607   my $hash  = ref $_[0] eq "HASH" ? shift : {@_};
608
609   my %unique_constraints = $self->{source}->unique_constraints;
610   my @constraint_names   = (exists $attrs->{key}
611                             ? ($attrs->{key})
612                             : keys %unique_constraints);
613
614   my @unique_hashes;
615   foreach my $name (@constraint_names) {
616     my @unique_cols = @{ $unique_constraints{$name} };
617     my %unique_hash =
618       map  { $_ => $hash->{$_} }
619       grep { exists $hash->{$_} }
620       @unique_cols;
621
622     push @unique_hashes, \%unique_hash
623       if (scalar keys %unique_hash == scalar @unique_cols);
624   }
625
626   my $row;
627   if (@unique_hashes) {
628     $row = $self->search(\@unique_hashes, { rows => 1 })->first;
629     if ($row) {
630       $row->set_columns($hash);
631       $row->update;
632     }
633   }
634
635   unless ($row) {
636     $row = $self->create($hash);
637   }
638
639   return $row;
640 }
641
642 =head1 ATTRIBUTES
643
644 The resultset takes various attributes that modify its behavior. Here's an
645 overview of them:
646
647 =head2 order_by
648
649 Which column(s) to order the results by. This is currently passed through
650 directly to SQL, so you can give e.g. C<foo DESC> for a descending order.
651
652 =head2 cols (arrayref)
653
654 Shortcut to request a particular set of columns to be retrieved.  Adds
655 C<me.> onto the start of any column without a C<.> in it and sets C<select>
656 from that, then auto-populates C<as> from C<select> as normal.
657
658 =head2 select (arrayref)
659
660 Indicates which columns should be selected from the storage.
661
662 =head2 as (arrayref)
663
664 Indicates column names for object inflation.
665
666 =head2 join
667
668 Contains a list of relationships that should be joined for this query.  For
669 example:
670
671   # Get CDs by Nine Inch Nails
672   my $rs = $schema->resultset('CD')->search(
673     { 'artist.name' => 'Nine Inch Nails' },
674     { join => 'artist' }
675   );
676
677 Can also contain a hash reference to refer to the other relation's relations.
678 For example:
679
680   package MyApp::Schema::Track;
681   use base qw/DBIx::Class/;
682   __PACKAGE__->table('track');
683   __PACKAGE__->add_columns(qw/trackid cd position title/);
684   __PACKAGE__->set_primary_key('trackid');
685   __PACKAGE__->belongs_to(cd => 'MyApp::Schema::CD');
686   1;
687
688   # In your application
689   my $rs = $schema->resultset('Artist')->search(
690     { 'track.title' => 'Teardrop' },
691     {
692       join     => { cd => 'track' },
693       order_by => 'artist.name',
694     }
695   );
696
697 If you want to fetch the columns from the related table as well, see
698 C<prefetch> below.
699
700 =head2 prefetch
701
702 Contains a list of relationships that should be fetched along with the main 
703 query (when they are accessed afterwards they will have already been
704 "prefetched").  This is useful for when you know you will need the related
705 objects, because it saves a query.  Currently limited to prefetching
706 one relationship deep, so unlike C<join>, prefetch must be an arrayref.
707
708 =head2 from 
709
710 This attribute can contain a arrayref of elements.  Each element can be another
711 arrayref, to nest joins, or it can be a hash which represents the two sides
712 of the join. 
713
714 NOTE: Use this on your own risk.  This allows you to shoot off your foot!
715
716 =head2 page
717
718 For a paged resultset, specifies which page to retrieve.  Leave unset
719 for an unpaged resultset.
720
721 =head2 rows
722
723 For a paged resultset, how many rows per page.  Can also be used to simulate an
724 SQL C<LIMIT>.
725
726 =head2 group_by (arrayref)
727
728 A arrayref of columns to group by (note that L</count> doesn't work on grouped
729 resultsets).
730
731   group_by => [qw/ column1 column2 ... /]
732
733 =head2 distinct
734
735 Set to 1 to group by all columns.
736
737 For more examples of using these attributes, see
738 L<DBIx::Class::Manual::Cookbook>.
739
740 =cut
741
742 1;