1 package DBIx::Class::ResultSet;
13 DBIx::Class::ResultSet - Responsible for fetching and creating resultset.
17 my $rs = MyApp::DB::Class->search(registered => 1);
18 my @rows = MyApp::DB::Class->search(foo => 'bar');
22 The resultset is also known as an iterator. It is responsible for handling
23 queries that may return an arbitrary number of rows, e.g. via C<search>
24 or a C<has_many> relationship.
28 =head2 new($source, \%$attrs)
30 The resultset constructor. Takes a source object (usually a DBIx::Class::Table)
31 and an attribute hash (see below for more information on attributes). Does
32 not perform any queries -- these are executed as needed by the other methods.
38 $class->new_result(@_) if ref $class;
39 my ($source, $attrs) = @_;
40 #use Data::Dumper; warn Dumper(@_);
41 $attrs = Storable::dclone($attrs || {}); # { %{ $attrs || {} } };
43 my $alias = ($attrs->{alias} ||= 'me');
44 if (!$attrs->{select}) {
45 my @cols = ($attrs->{cols}
46 ? @{delete $attrs->{cols}}
47 : $source->result_class->_select_columns);
48 $attrs->{select} = [ map { m/\./ ? $_ : "${alias}.$_" } @cols ];
50 $attrs->{as} ||= [ map { m/^$alias\.(.*)$/ ? $1 : $_ } @{$attrs->{select}} ];
51 #use Data::Dumper; warn Dumper(@{$attrs}{qw/select as/});
52 $attrs->{from} ||= [ { $alias => $source->from } ];
53 if (my $join = delete $attrs->{join}) {
54 foreach my $j (ref $join eq 'ARRAY'
55 ? (@{$join}) : ($join)) {
56 if (ref $j eq 'HASH') {
57 $seen{$_} = 1 foreach keys %$j;
62 push(@{$attrs->{from}}, $source->resolve_join($join, $attrs->{alias}));
64 $attrs->{group_by} ||= $attrs->{select} if delete $attrs->{distinct};
65 foreach my $pre (@{delete $attrs->{prefetch} || []}) {
66 push(@{$attrs->{from}}, $source->resolve_join($pre, $attrs->{alias}))
70 $source->result_class->relationship_info($pre)->{class}->columns;
71 push(@{$attrs->{select}}, @pre);
72 push(@{$attrs->{as}}, @pre);
75 $attrs->{rows} ||= 10;
76 $attrs->{offset} ||= 0;
77 $attrs->{offset} += ($attrs->{rows} * ($attrs->{page} - 1));
81 cond => $attrs->{where},
82 from => $attrs->{from},
84 page => delete $attrs->{page},
93 my @obj = $rs->search({ foo => 3 }); # "... WHERE foo = 3"
94 my $new_rs = $rs->search({ foo => 3 });
96 If you need to pass in additional attributes but no additional condition,
97 call it as ->search(undef, \%attrs);
99 my @all = $class->search({}, { cols => [qw/foo bar/] }); # "SELECT foo, bar FROM $class_table"
106 #use Data::Dumper;warn Dumper(@_);
108 my $attrs = { %{$self->{attrs}} };
109 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
110 $attrs = { %$attrs, %{ pop(@_) } };
113 my $where = (@_ ? ((@_ == 1 || ref $_[0] eq "HASH") ? shift : {@_}) : undef());
114 if (defined $where) {
115 $where = (defined $attrs->{where}
116 ? { '-and' => [ $where, $attrs->{where} ] }
118 $attrs->{where} = $where;
121 my $rs = (ref $self)->new($self->{source}, $attrs);
123 return (wantarray ? $rs->all : $rs);
126 =head2 search_literal
127 my @obj = $rs->search_literal($literal_where_cond, @bind);
128 my $new_rs = $rs->search_literal($literal_where_cond, @bind);
130 Pass a literal chunk of SQL to be added to the conditional part of the
136 my ($self, $cond, @vals) = @_;
137 my $attrs = (ref $vals[$#vals] eq 'HASH' ? { %{ pop(@vals) } } : {});
138 $attrs->{bind} = [ @{$self->{attrs}{bind}||[]}, @vals ];
139 return $self->search(\$cond, $attrs);
142 =head2 find(@colvalues), find(\%cols)
144 Finds a row based on its primary key(s).
149 my ($self, @vals) = @_;
150 my $attrs = (@vals > 1 && ref $vals[$#vals] eq 'HASH' ? pop(@vals) : {});
151 my @pk = $self->{source}->primary_columns;
152 #use Data::Dumper; warn Dumper($attrs, @vals, @pk);
153 $self->{source}->result_class->throw( "Can't find unless primary columns are defined" )
156 if (ref $vals[0] eq 'HASH') {
158 } elsif (@pk == @vals) {
160 @{$query}{@pk} = @vals;
164 #warn Dumper($query);
165 # Useless -> disabled
166 #$self->{source}->result_class->throw( "Can't find unless all primary keys are specified" )
167 # unless (keys %$query >= @pk); # If we check 'em we run afoul of uc/lc
168 # column names etc. Not sure what to do yet
169 return $self->search($query)->next;
172 =head2 search_related
174 $rs->search_related('relname', $cond?, $attrs?);
179 my ($self, $rel, @rest) = @_;
180 my $rel_obj = $self->{source}->result_class->relationship_info($rel);
181 $self->{source}->result_class->throw(
182 "No such relationship ${rel} in search_related")
184 my $rs = $self->search(undef, { join => $rel });
185 return $self->{source}->schema->resultset($rel_obj->{class}
196 Returns a storage-driven cursor to the given resultset.
202 my ($source, $attrs) = @{$self}{qw/source attrs/};
203 $attrs = { %$attrs };
204 return $self->{cursor}
205 ||= $source->storage->select($self->{from}, $attrs->{select},
206 $attrs->{where},$attrs);
211 Identical to search except defaults to 'LIKE' instead of '=' in condition
218 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
221 my $query = ref $_[0] eq "HASH" ? { %{shift()} }: {@_};
222 $query->{$_} = { 'like' => $query->{$_} } for keys %$query;
223 return $class->search($query, { %$attrs });
226 =head2 slice($first, $last)
228 Returns a subset of elements from the resultset.
233 my ($self, $min, $max) = @_;
234 my $attrs = { %{ $self->{attrs} || {} } };
235 $attrs->{offset} ||= 0;
236 $attrs->{offset} += $min;
237 $attrs->{rows} = ($max ? ($max - $min + 1) : 1);
238 my $slice = (ref $self)->new($self->{source}, $attrs);
239 return (wantarray ? $slice->all : $slice);
244 Returns the next element in the resultset (undef is there is none).
250 my @row = $self->cursor->next;
251 return unless (@row);
252 return $self->_construct_object(@row);
255 sub _construct_object {
256 my ($self, @row) = @_;
257 my @cols = @{ $self->{attrs}{as} };
258 #warn "@cols -> @row";
260 foreach my $col (@cols) {
261 if ($col =~ /([^\.]+)\.([^\.]+)/) {
262 $pre{$1}[0]{$2} = shift @row;
264 $me{$col} = shift @row;
267 my $new = $self->{source}->result_class->inflate_result(\%me, \%pre);
268 $new = $self->{attrs}{record_filter}->($new)
269 if exists $self->{attrs}{record_filter};
275 Performs an SQL C<COUNT> with the same query as the resultset was built
276 with to find the number of elements. If passed arguments, does a search
277 on the resultset and counts the results of that.
283 return $self->search(@_)->count if @_ && defined $_[0];
284 die "Unable to ->count with a GROUP BY" if defined $self->{attrs}{group_by};
285 unless (defined $self->{count}) {
286 my $attrs = { %{ $self->{attrs} },
287 select => { 'count' => '*' },
289 # offset, order by and page are not needed to count. record_filter is cdbi
290 delete $attrs->{$_} for qw/rows offset order_by page pager record_filter/;
292 ($self->{count}) = (ref $self)->new($self->{source}, $attrs)->cursor->next;
294 return 0 unless $self->{count};
295 my $count = $self->{count};
296 $count -= $self->{attrs}{offset} if $self->{attrs}{offset};
297 $count = $self->{attrs}{rows} if
298 ($self->{attrs}{rows} && $self->{attrs}{rows} < $count);
304 Calls search_literal with the passed arguments, then count.
308 sub count_literal { shift->search_literal(@_)->count; }
312 Returns all elements in the resultset. Called implictly if the resultset
313 is returned in list context.
319 return map { $self->_construct_object(@$_); }
325 Resets the resultset's cursor, so you can iterate through the elements again.
331 $self->cursor->reset;
337 Resets the resultset and returns the first element.
342 return $_[0]->reset->next;
347 Deletes all elements in the resultset.
353 $_->delete for $self->all;
357 *delete_all = \&delete; # Yeah, yeah, yeah ...
361 Returns a L<Data::Page> object for the current resultset. Only makes
362 sense for queries with page turned on.
368 my $attrs = $self->{attrs};
369 die "Can't create pager for non-paged rs" unless $self->{page};
370 $attrs->{rows} ||= 10;
372 return $self->{pager} ||= Data::Page->new(
373 $self->{count}, $attrs->{rows}, $self->{page});
376 =head2 page($page_num)
378 Returns a new resultset for the specified page.
383 my ($self, $page) = @_;
384 my $attrs = { %{$self->{attrs}} };
385 $attrs->{page} = $page;
386 return (ref $self)->new($self->{source}, $attrs);
389 =head2 new_result(\%vals)
391 Creates a result in the resultset's result class
396 my ($self, $values) = @_;
397 $self->{source}->result_class->throw( "new_result needs a hash" )
398 unless (ref $values eq 'HASH');
399 $self->{source}->result_class->throw( "Can't abstract implicit construct, condition not a hash" )
400 if ($self->{cond} && !(ref $self->{cond} eq 'HASH'));
402 my $alias = $self->{attrs}{alias};
403 foreach my $key (keys %{$self->{cond}||{}}) {
404 $new{$1} = $self->{cond}{$key} if ($key =~ m/^(?:$alias\.)?([^\.]+)$/);
406 return $self->{source}->result_class->new(\%new);
409 =head2 create(\%vals)
411 Inserts a record into the resultset and returns the object
413 Effectively a shortcut for ->new_result(\%vals)->insert
418 my ($self, $attrs) = @_;
419 $self->{source}->result_class->throw( "create needs a hashref" ) unless ref $attrs eq 'HASH';
420 return $self->new_result($attrs)->insert;
423 =head2 find_or_create(\%vals)
425 $class->find_or_create({ key => $val, ... });
427 Searches for a record matching the search condition; if it doesn't find one,
428 creates one and returns that instead.
434 my $hash = ref $_[0] eq "HASH" ? shift: {@_};
435 my $exists = $self->find($hash);
436 return defined($exists) ? $exists : $self->create($hash);
441 The resultset takes various attributes that modify its behavior.
442 Here's an overview of them:
446 Which column(s) to order the results by. This is currently passed
447 through directly to SQL, so you can give e.g. C<foo DESC> for a
450 =head2 cols (arrayref)
452 Shortcut to request a particular set of columns to be retrieved - adds
453 'me.' onto the start of any column without a '.' in it and sets 'select'
454 from that, then auto-populates 'as' from 'select' as normal
456 =head2 select (arrayref)
458 Indicates which columns should be selected from the storage
462 Indicates column names for object inflation
466 Contains a list of relationships that should be joined for this query. Can also
467 contain a hash reference to refer to that relation's relations. So, if one column
468 in your class C<belongs_to> foo and another C<belongs_to> bar, you can do
469 C<< join => [qw/ foo bar /] >> to join both (and e.g. use them for C<order_by>).
470 If a foo contains many margles and you want to join those too, you can do
471 C<< join => { foo => 'margle' } >>. If you want to fetch the columns from the
472 related table as well, see C<prefetch> below.
476 Contains a list of relationships that should be fetched along with the main
477 query (when they are accessed afterwards they will have already been
478 "prefetched"). This is useful for when you know you will need the related
479 object(s), because it saves a query. Currently limited to prefetching
480 one relationship deep, so unlike C<join>, prefetch must be an arrayref.
484 This attribute can contain a arrayref of elements. Each element can be another
485 arrayref, to nest joins, or it can be a hash which represents the two sides
488 NOTE: Use this on your own risk. This allows you to shoot your foot off!
492 For a paged resultset, specifies which page to retrieve. Leave unset
493 for an unpaged resultset.
497 For a paged resultset, how many rows per page
501 A list of columns to group by (note that 'count' doesn't work on grouped
506 Set to 1 to group by all columns