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 if (!$attrs->{select}) {
42 my @cols = ($attrs->{cols}
43 ? @{delete $attrs->{cols}}
44 : $source->result_class->_select_columns);
45 $attrs->{select} = [ map { m/\./ ? $_ : "me.$_" } @cols ];
47 $attrs->{as} ||= [ map { m/^me\.(.*)$/ ? $1 : $_ } @{$attrs->{select}} ];
48 #use Data::Dumper; warn Dumper(@{$attrs}{qw/select as/});
49 $attrs->{from} ||= [ { 'me' => $source->name } ];
51 foreach my $j (ref $attrs->{join} eq 'ARRAY'
52 ? (@{$attrs->{join}}) : ($attrs->{join})) {
53 if (ref $j eq 'HASH') {
54 $seen{$_} = 1 foreach keys %$j;
59 push(@{$attrs->{from}}, $source->result_class->_resolve_join($attrs->{join}, 'me'));
61 $attrs->{group_by} ||= $attrs->{select} if delete $attrs->{distinct};
62 foreach my $pre (@{$attrs->{prefetch} || []}) {
63 push(@{$attrs->{from}}, $source->result_class->_resolve_join($pre, 'me'))
67 $source->result_class->_relationships->{$pre}->{class}->columns;
68 push(@{$attrs->{select}}, @pre);
69 push(@{$attrs->{as}}, @pre);
73 cond => $attrs->{where},
74 from => $attrs->{from},
79 $new->pager if $attrs->{page};
85 my @obj = $rs->search({ foo => 3 }); # "... WHERE foo = 3"
86 my $new_rs = $rs->search({ foo => 3 });
88 If you need to pass in additional attributes but no additional condition,
89 call it as ->search(undef, \%attrs);
91 my @all = $class->search({}, { cols => [qw/foo bar/] }); # "SELECT foo, bar FROM $class_table"
98 #use Data::Dumper;warn Dumper(@_);
100 my $attrs = { %{$self->{attrs}} };
101 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
102 $attrs = { %{ pop(@_) } };
105 my $where = ((@_ == 1 || ref $_[0] eq "HASH") ? shift : {@_});
106 if (defined $where) {
107 $where = (defined $attrs->{where}
108 ? { '-and' => [ $where, $attrs->{where} ] }
110 $attrs->{where} = $where;
113 my $rs = $self->new($self->{source}, $attrs);
115 return (wantarray ? $rs->all : $rs);
118 =head2 search_literal
119 my @obj = $rs->search_literal($literal_where_cond, @bind);
120 my $new_rs = $rs->search_literal($literal_where_cond, @bind);
122 Pass a literal chunk of SQL to be added to the conditional part of the
128 my ($self, $cond, @vals) = @_;
129 my $attrs = (ref $vals[$#vals] eq 'HASH' ? { %{ pop(@vals) } } : {});
130 $attrs->{bind} = [ @{$self->{attrs}{bind}||[]}, @vals ];
131 return $self->search(\$cond, $attrs);
136 Returns a storage-driven cursor to the given resultset.
142 my ($source, $attrs) = @{$self}{qw/source attrs/};
143 if ($attrs->{page}) {
144 $attrs->{rows} = $self->pager->entries_per_page;
145 $attrs->{offset} = $self->pager->skipped;
147 return $self->{cursor}
148 ||= $source->storage->select($self->{from}, $attrs->{select},
149 $attrs->{where},$attrs);
154 Identical to search except defaults to 'LIKE' instead of '=' in condition
161 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
164 my $query = ref $_[0] eq "HASH" ? { %{shift()} }: {@_};
165 $query->{$_} = { 'like' => $query->{$_} } for keys %$query;
166 return $class->search($query, { %$attrs });
169 =head2 slice($first, $last)
171 Returns a subset of elements from the resultset.
176 my ($self, $min, $max) = @_;
177 my $attrs = { %{ $self->{attrs} || {} } };
178 $self->{source}->result_class->throw("Can't slice without where") unless $attrs->{where};
179 $attrs->{offset} = $min;
180 $attrs->{rows} = ($max ? ($max - $min + 1) : 1);
181 my $slice = $self->new($self->{source}, $attrs);
182 return (wantarray ? $slice->all : $slice);
187 Returns the next element in the resultset (undef is there is none).
193 my @row = $self->cursor->next;
194 return unless (@row);
195 return $self->_construct_object(@row);
198 sub _construct_object {
199 my ($self, @row) = @_;
200 my @cols = @{ $self->{attrs}{as} };
201 #warn "@cols -> @row";
202 @cols = grep { /\(/ or ! /\./ } @cols;
204 unless ($self->{attrs}{prefetch}) {
205 $new = $self->{source}->result_class->_row_to_object(\@cols, \@row);
207 my @main = splice(@row, 0, scalar @cols);
208 $new = $self->{source}->result_class->_row_to_object(\@cols, \@main);
209 PRE: foreach my $pre (@{$self->{attrs}{prefetch}}) {
210 my $rel_obj = $self->{source}->result_class->_relationships->{$pre};
211 my $pre_class = $self->{source}->result_class->resolve_class($rel_obj->{class});
212 my @pre_cols = $pre_class->_select_columns;
213 my @vals = splice(@row, 0, scalar @pre_cols);
214 my $fetched = $pre_class->_row_to_object(\@pre_cols, \@vals);
215 $self->{source}->result_class->throw("No accessor for prefetched $pre")
216 unless defined $rel_obj->{attrs}{accessor};
217 if ($rel_obj->{attrs}{accessor} eq 'single') {
218 foreach my $pri ($rel_obj->{class}->primary_columns) {
219 unless (defined $fetched->get_column($pri)) {
224 $new->{_relationship_data}{$pre} = $fetched;
225 } elsif ($rel_obj->{attrs}{accessor} eq 'filter') {
226 $new->{_inflated_column}{$pre} = $fetched;
228 $self->{source}->result_class->throw("Don't know how to store prefetched $pre");
232 $new = $self->{attrs}{record_filter}->($new)
233 if exists $self->{attrs}{record_filter};
239 Performs an SQL C<COUNT> with the same query as the resultset was built
240 with to find the number of elements. If passed arguments, does a search
241 on the resultset and counts the results of that.
247 return $self->search(@_)->count if @_ && defined $_[0];
248 die "Unable to ->count with a GROUP BY" if defined $self->{attrs}{group_by};
249 unless ($self->{count}) {
250 my $attrs = { %{ $self->{attrs} },
251 select => { 'count' => '*' },
253 # offset and order by are not needed to count, page, join and prefetch
254 # will get in the way (add themselves to from again ...)
255 delete $attrs->{$_} for qw/offset order_by page join prefetch/;
257 my @cols = 'COUNT(*)';
258 ($self->{count}) = $self->search(undef, $attrs)->cursor->next;
260 return 0 unless $self->{count};
261 return $self->{pager}->entries_on_this_page if ($self->{pager});
262 return ( $self->{attrs}->{rows} && $self->{attrs}->{rows} < $self->{count} )
263 ? $self->{attrs}->{rows}
269 Calls search_literal with the passed arguments, then count.
273 sub count_literal { shift->search_literal(@_)->count; }
277 Returns all elements in the resultset. Called implictly if the resultset
278 is returned in list context.
284 return map { $self->_construct_object(@$_); }
290 Resets the resultset's cursor, so you can iterate through the elements again.
296 $self->cursor->reset;
302 Resets the resultset and returns the first element.
307 return $_[0]->reset->next;
312 Deletes all elements in the resultset.
318 $_->delete for $self->all;
322 *delete_all = \&delete; # Yeah, yeah, yeah ...
326 Returns a L<Data::Page> object for the current resultset. Only makes
327 sense for queries with page turned on.
333 my $attrs = $self->{attrs};
334 delete $attrs->{offset};
335 my $rows_per_page = delete $attrs->{rows} || 10;
336 $self->{pager} ||= Data::Page->new(
337 $self->count, $rows_per_page, $attrs->{page} || 1);
338 $attrs->{rows} = $rows_per_page;
339 return $self->{pager};
342 =head2 page($page_num)
344 Returns a new resultset for the specified page.
349 my ($self, $page) = @_;
350 my $attrs = $self->{attrs};
351 $attrs->{page} = $page;
352 return $self->new($self->{source}, $attrs);
357 The resultset takes various attributes that modify its behavior.
358 Here's an overview of them:
362 Which column(s) to order the results by. This is currently passed
363 through directly to SQL, so you can give e.g. C<foo DESC> for a
366 =head2 cols (arrayref)
368 Shortcut to request a particular set of columns to be retrieved - adds
369 'me.' onto the start of any column without a '.' in it and sets 'select'
370 from that, then auto-populates 'as' from 'select' as normal
372 =head2 select (arrayref)
374 Indicates which columns should be selected from the storage
378 Indicates column names for object inflation
382 Contains a list of relationships that should be joined for this query. Can also
383 contain a hash reference to refer to that relation's relations. So, if one column
384 in your class C<belongs_to> foo and another C<belongs_to> bar, you can do
385 C<< join => [qw/ foo bar /] >> to join both (and e.g. use them for C<order_by>).
386 If a foo contains many margles and you want to join those too, you can do
387 C<< join => { foo => 'margle' } >>. If you want to fetch the columns from the
388 related table as well, see C<prefetch> below.
392 Contains a list of relationships that should be fetched along with the main
393 query (when they are accessed afterwards they will have already been
394 "prefetched"). This is useful for when you know you will need the related
395 object(s), because it saves a query. Currently limited to prefetching
396 one relationship deep, so unlike C<join>, prefetch must be an arrayref.
400 This attribute can contain a arrayref of elements. Each element can be another
401 arrayref, to nest joins, or it can be a hash which represents the two sides
404 NOTE: Use this on your own risk. This allows you to shoot your foot off!
408 For a paged resultset, specifies which page to retrieve. Leave unset
409 for an unpaged resultset.
413 For a paged resultset, how many rows per page
417 A list of columns to group by (note that 'count' doesn't work on grouped
422 Set to 1 to group by all columns