1 package DBIx::Class::ResultSet;
12 DBIx::Class::ResultSet - Responsible for fetching and creating resultset.
16 my $rs = MyApp::DB::Class->search(registered => 1);
17 my @rows = MyApp::DB::Class->search(foo => 'bar');
21 The resultset is also known as an iterator. It is responsible for handling
22 queries that may return an arbitrary number of rows, e.g. via C<search>
23 or a C<has_many> relationship.
27 =head2 new($source, \%$attrs)
29 The resultset constructor. Takes a source object (usually a DBIx::Class::Table)
30 and an attribute hash (see below for more information on attributes). Does
31 not perform any queries -- these are executed as needed by the other methods.
36 my ($class, $source, $attrs) = @_;
37 #use Data::Dumper; warn Dumper(@_);
38 $class = ref $class if ref $class;
39 $attrs = { %{ $attrs || {} } };
41 my $alias = ($attrs->{alias} ||= 'me');
42 if (!$attrs->{select}) {
43 my @cols = ($attrs->{cols}
44 ? @{delete $attrs->{cols}}
45 : $source->result_class->_select_columns);
46 $attrs->{select} = [ map { m/\./ ? $_ : "${alias}.$_" } @cols ];
48 $attrs->{as} ||= [ map { m/^$alias\.(.*)$/ ? $1 : $_ } @{$attrs->{select}} ];
49 #use Data::Dumper; warn Dumper(@{$attrs}{qw/select as/});
50 $attrs->{from} ||= [ { $alias => $source->name } ];
51 if (my $join = delete $attrs->{join}) {
52 foreach my $j (ref $join eq 'ARRAY'
53 ? (@{$join}) : ($join)) {
54 if (ref $j eq 'HASH') {
55 $seen{$_} = 1 foreach keys %$j;
60 push(@{$attrs->{from}}, $source->result_class->_resolve_join($join, $attrs->{alias}));
62 $attrs->{group_by} ||= $attrs->{select} if delete $attrs->{distinct};
63 foreach my $pre (@{delete $attrs->{prefetch} || []}) {
64 push(@{$attrs->{from}}, $source->result_class->_resolve_join($pre, $attrs->{alias}))
68 $source->result_class->_relationships->{$pre}->{class}->columns;
69 push(@{$attrs->{select}}, @pre);
70 push(@{$attrs->{as}}, @pre);
73 $attrs->{rows} ||= 10;
74 $attrs->{offset} ||= 0;
75 $attrs->{offset} += ($attrs->{rows} * ($attrs->{page} - 1));
79 cond => $attrs->{where},
80 from => $attrs->{from},
85 #$new->pager if $attrs->{page};
91 my @obj = $rs->search({ foo => 3 }); # "... WHERE foo = 3"
92 my $new_rs = $rs->search({ foo => 3 });
94 If you need to pass in additional attributes but no additional condition,
95 call it as ->search(undef, \%attrs);
97 my @all = $class->search({}, { cols => [qw/foo bar/] }); # "SELECT foo, bar FROM $class_table"
104 #use Data::Dumper;warn Dumper(@_);
106 my $attrs = { %{$self->{attrs}} };
107 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
108 $attrs = { %$attrs, %{ pop(@_) } };
111 my $where = (@_ ? ((@_ == 1 || ref $_[0] eq "HASH") ? shift : {@_}) : undef());
112 if (defined $where) {
113 $where = (defined $attrs->{where}
114 ? { '-and' => [ $where, $attrs->{where} ] }
116 $attrs->{where} = $where;
119 my $rs = $self->new($self->{source}, $attrs);
121 return (wantarray ? $rs->all : $rs);
124 =head2 search_literal
125 my @obj = $rs->search_literal($literal_where_cond, @bind);
126 my $new_rs = $rs->search_literal($literal_where_cond, @bind);
128 Pass a literal chunk of SQL to be added to the conditional part of the
134 my ($self, $cond, @vals) = @_;
135 my $attrs = (ref $vals[$#vals] eq 'HASH' ? { %{ pop(@vals) } } : {});
136 $attrs->{bind} = [ @{$self->{attrs}{bind}||[]}, @vals ];
137 return $self->search(\$cond, $attrs);
140 =head2 search_related
142 $rs->search_related('relname', $cond?, $attrs?);
147 my ($self, $rel, @rest) = @_;
148 my $rel_obj = $self->{source}->result_class->_relationships->{$rel};
149 $self->{source}->result_class->throw(
150 "No such relationship ${rel} in search_related")
152 my $r_class = $self->{source}->result_class->resolve_class($rel_obj->{class});
153 my $source = $r_class->result_source;
154 $source = bless({ %{$source} }, ref $source || $source);
155 $source->storage($self->{source}->storage);
156 $source->result_class($r_class);
157 my $rs = $self->search(undef, { join => $rel });
158 #use Data::Dumper; warn Dumper($rs);
159 return $source->resultset_class->new(
160 $source, { %{$rs->{attrs}},
169 Returns a storage-driven cursor to the given resultset.
175 my ($source, $attrs) = @{$self}{qw/source attrs/};
176 $attrs = { %$attrs };
177 return $self->{cursor}
178 ||= $source->storage->select($self->{from}, $attrs->{select},
179 $attrs->{where},$attrs);
184 Identical to search except defaults to 'LIKE' instead of '=' in condition
191 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
194 my $query = ref $_[0] eq "HASH" ? { %{shift()} }: {@_};
195 $query->{$_} = { 'like' => $query->{$_} } for keys %$query;
196 return $class->search($query, { %$attrs });
199 =head2 slice($first, $last)
201 Returns a subset of elements from the resultset.
206 my ($self, $min, $max) = @_;
207 my $attrs = { %{ $self->{attrs} || {} } };
208 $attrs->{offset} ||= 0;
209 $attrs->{offset} += $min;
210 $attrs->{rows} = ($max ? ($max - $min + 1) : 1);
211 my $slice = $self->new($self->{source}, $attrs);
212 return (wantarray ? $slice->all : $slice);
217 Returns the next element in the resultset (undef is there is none).
223 my @row = $self->cursor->next;
224 return unless (@row);
225 return $self->_construct_object(@row);
228 sub _construct_object {
229 my ($self, @row) = @_;
230 my @cols = @{ $self->{attrs}{as} };
231 #warn "@cols -> @row";
233 foreach my $col (@cols) {
234 if ($col =~ /([^\.]+)\.([^\.]+)/) {
235 $pre{$1}[0]{$2} = shift @row;
237 $me{$col} = shift @row;
240 my $new = $self->{source}->result_class->inflate_result(\%me, \%pre);
241 $new = $self->{attrs}{record_filter}->($new)
242 if exists $self->{attrs}{record_filter};
248 Performs an SQL C<COUNT> with the same query as the resultset was built
249 with to find the number of elements. If passed arguments, does a search
250 on the resultset and counts the results of that.
256 return $self->search(@_)->count if @_ && defined $_[0];
257 die "Unable to ->count with a GROUP BY" if defined $self->{attrs}{group_by};
258 unless (defined $self->{count}) {
259 my $attrs = { %{ $self->{attrs} },
260 select => { 'count' => '*' },
262 # offset, order by and page are not needed to count
263 delete $attrs->{$_} for qw/rows offset order_by page pager/;
265 ($self->{count}) = $self->new($self->{source}, $attrs)->cursor->next;
267 return 0 unless $self->{count};
268 my $count = $self->{count};
269 $count -= $self->{attrs}{offset} if $self->{attrs}{offset};
270 $count = $self->{attrs}{rows} if
271 ($self->{attrs}{rows} && $self->{attrs}{rows} < $count);
277 Calls search_literal with the passed arguments, then count.
281 sub count_literal { shift->search_literal(@_)->count; }
285 Returns all elements in the resultset. Called implictly if the resultset
286 is returned in list context.
292 return map { $self->_construct_object(@$_); }
298 Resets the resultset's cursor, so you can iterate through the elements again.
304 $self->cursor->reset;
310 Resets the resultset and returns the first element.
315 return $_[0]->reset->next;
320 Deletes all elements in the resultset.
326 $_->delete for $self->all;
330 *delete_all = \&delete; # Yeah, yeah, yeah ...
334 Returns a L<Data::Page> object for the current resultset. Only makes
335 sense for queries with page turned on.
341 my $attrs = $self->{attrs};
342 die "Can't create pager for non-paged rs" unless $attrs->{page};
343 $attrs->{rows} ||= 10;
345 return $self->{pager} ||= Data::Page->new(
346 $self->{count}, $attrs->{rows}, $attrs->{page});
349 =head2 page($page_num)
351 Returns a new resultset for the specified page.
356 my ($self, $page) = @_;
357 my $attrs = { %{$self->{attrs}} };
358 $attrs->{page} = $page;
359 return $self->new($self->{source}, $attrs);
364 The resultset takes various attributes that modify its behavior.
365 Here's an overview of them:
369 Which column(s) to order the results by. This is currently passed
370 through directly to SQL, so you can give e.g. C<foo DESC> for a
373 =head2 cols (arrayref)
375 Shortcut to request a particular set of columns to be retrieved - adds
376 'me.' onto the start of any column without a '.' in it and sets 'select'
377 from that, then auto-populates 'as' from 'select' as normal
379 =head2 select (arrayref)
381 Indicates which columns should be selected from the storage
385 Indicates column names for object inflation
389 Contains a list of relationships that should be joined for this query. Can also
390 contain a hash reference to refer to that relation's relations. So, if one column
391 in your class C<belongs_to> foo and another C<belongs_to> bar, you can do
392 C<< join => [qw/ foo bar /] >> to join both (and e.g. use them for C<order_by>).
393 If a foo contains many margles and you want to join those too, you can do
394 C<< join => { foo => 'margle' } >>. If you want to fetch the columns from the
395 related table as well, see C<prefetch> below.
399 Contains a list of relationships that should be fetched along with the main
400 query (when they are accessed afterwards they will have already been
401 "prefetched"). This is useful for when you know you will need the related
402 object(s), because it saves a query. Currently limited to prefetching
403 one relationship deep, so unlike C<join>, prefetch must be an arrayref.
407 This attribute can contain a arrayref of elements. Each element can be another
408 arrayref, to nest joins, or it can be a hash which represents the two sides
411 NOTE: Use this on your own risk. This allows you to shoot your foot off!
415 For a paged resultset, specifies which page to retrieve. Leave unset
416 for an unpaged resultset.
420 For a paged resultset, how many rows per page
424 A list of columns to group by (note that 'count' doesn't work on grouped
429 Set to 1 to group by all columns