1 package DBIx::Class::ResultSet;
12 DBIX::Class::ResultSet - Responsible for fetching and creating resultset.
16 $rs=MyApp::DB::Class->search(registered=>1);
20 The resultset is also known as an iterator.
26 =item new <db_class> <attrs>
28 The resultset constructor. Takes a db class and an
29 attribute hash (see below for more info on attributes)
34 my ($class, $db_class, $attrs) = @_;
35 #use Data::Dumper; warn Dumper(@_);
36 $class = ref $class if ref $class;
37 $attrs = { %{ $attrs || {} } };
39 $attrs->{cols} ||= [ map { "me.$_" } $db_class->_select_columns ];
40 $attrs->{from} ||= [ { 'me' => $db_class->_table_name } ];
42 foreach my $j (ref $attrs->{join} eq 'ARRAY'
43 ? (@{$attrs->{join}}) : ($attrs->{join})) {
44 if (ref $j eq 'HASH') {
45 $seen{$_} = 1 foreach keys %$j;
50 push(@{$attrs->{from}}, $db_class->_resolve_join($attrs->{join}, 'me'));
52 foreach my $pre (@{$attrs->{prefetch} || []}) {
53 push(@{$attrs->{from}}, $db_class->_resolve_join($pre, 'me'))
55 push(@{$attrs->{cols}},
57 $db_class->_relationships->{$pre}->{class}->_select_columns);
61 cols => $attrs->{cols},
62 cond => $attrs->{where},
63 from => $attrs->{from},
68 $new->pager if ($attrs->{page});
74 my @obj = $rs->search({ foo => 3 }); # "... WHERE foo = 3"
75 my $new_rs = $rs->search({ foo => 3 });
77 If you need to pass in additional attributes but no additional condition,
78 call it as ->search(undef, \%attrs);
80 my @all = $class->search({}, { cols => [qw/foo bar/] }); # "SELECT foo, bar FROM $class_table"
87 #use Data::Dumper;warn Dumper(@_);
89 my $attrs = { %{$self->{attrs}} };
90 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
91 $attrs = { %{ pop(@_) } };
94 my $where = ((@_ == 1 || ref $_[0] eq "HASH") ? shift : {@_});
96 $where = (defined $attrs->{where}
97 ? { '-and' => [ $where, $attrs->{where} ] }
99 $attrs->{where} = $where;
102 my $rs = $self->new($self->{source}, $attrs);
104 return (wantarray ? $rs->all : $rs);
108 my @obj = $rs->search_literal($literal_where_cond, @bind);
109 my $new_rs = $rs->search_literal($literal_where_cond, @bind);
111 Pass a literal chunk of SQL to be added to the conditional part of the
116 my ($self, $cond, @vals) = @_;
117 my $attrs = (ref $vals[$#vals] eq 'HASH' ? { %{ pop(@vals) } } : {});
118 $attrs->{bind} = [ @{$self->{attrs}{bind}||[]}, @vals ];
119 return $self->search(\$cond, $attrs);
124 Return a storage driven cursor to the given resultset.
130 my ($source, $attrs) = @{$self}{qw/source attrs/};
131 if ($attrs->{page}) {
132 $attrs->{rows} = $self->pager->entries_per_page;
133 $attrs->{offset} = $self->pager->skipped;
135 return $self->{cursor}
136 ||= $source->storage->select($self->{from}, $self->{cols},
137 $attrs->{where},$attrs);
142 Identical to search except defaults to 'LIKE' instead of '=' in condition
149 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
152 my $query = ref $_[0] eq "HASH" ? { %{shift()} }: {@_};
153 $query->{$_} = { 'like' => $query->{$_} } for keys %$query;
154 return $class->search($query, { %$attrs });
157 =item slice <first> <last>
159 return a number of elements from the given resultset.
164 my ($self, $min, $max) = @_;
165 my $attrs = { %{ $self->{attrs} || {} } };
166 $self->{source}->throw("Can't slice without where") unless $attrs->{where};
167 $attrs->{offset} = $min;
168 $attrs->{rows} = ($max ? ($max - $min + 1) : 1);
169 my $slice = $self->new($self->{source}, $attrs);
170 return (wantarray ? $slice->all : $slice);
175 Returns the next element in this resultset.
181 my @row = $self->cursor->next;
182 return unless (@row);
183 return $self->_construct_object(@row);
186 sub _construct_object {
187 my ($self, @row) = @_;
188 my @cols = @{ $self->{attrs}{cols} };
190 @cols = grep { /\(/ or ! /\./ } @cols;
192 unless ($self->{attrs}{prefetch}) {
193 $new = $self->{source}->_row_to_object(\@cols, \@row);
195 my @main = splice(@row, 0, scalar @cols);
196 $new = $self->{source}->_row_to_object(\@cols, \@main);
197 PRE: foreach my $pre (@{$self->{attrs}{prefetch}}) {
198 my $rel_obj = $self->{source}->_relationships->{$pre};
199 my $pre_class = $self->{source}->resolve_class($rel_obj->{class});
200 my @pre_cols = $pre_class->_select_columns;
201 my @vals = splice(@row, 0, scalar @pre_cols);
202 my $fetched = $pre_class->_row_to_object(\@pre_cols, \@vals);
203 $self->{source}->throw("No accessor for prefetched $pre")
204 unless defined $rel_obj->{attrs}{accessor};
205 if ($rel_obj->{attrs}{accessor} eq 'single') {
206 foreach my $pri ($rel_obj->{class}->primary_columns) {
207 unless (defined $fetched->get_column($pri)) {
212 $new->{_relationship_data}{$pre} = $fetched;
213 } elsif ($rel_obj->{attrs}{accessor} eq 'filter') {
214 $new->{_inflated_column}{$pre} = $fetched;
216 $self->{source}->throw("Don't know how to store prefetched $pre");
220 $new = $self->{attrs}{record_filter}->($new)
221 if exists $self->{attrs}{record_filter};
227 Performs an SQL count with the same query as the resultset was built
228 with to find the number of elements. If passed arguments, does a search
229 on the resultset and counts the results of that.
235 return $self->search(@_)->count if @_ && defined $_[0];
236 my $attrs = { %{ $self->{attrs} } };
237 unless ($self->{count}) {
238 # offset and order by are not needed to count
239 delete $attrs->{$_} for qw/offset order_by/;
241 my @cols = 'COUNT(*)';
242 $self->{count} = $self->{source}->storage->select_single(
243 $self->{from}, \@cols, $self->{cond}, $attrs);
245 return 0 unless $self->{count};
246 return $self->{pager}->entries_on_this_page if ($self->{pager});
247 return ( $attrs->{rows} && $attrs->{rows} < $self->{count} )
254 Calls search_literal with the passed arguments, then count
258 sub count_literal { shift->search_literal(@_)->count; }
262 Returns all elements in the resultset. Is called implictly if the search
263 method is used in list context.
269 return map { $self->_construct_object(@$_); }
275 Reset this resultset's cursor, so you can iterate through the elements again.
281 $self->cursor->reset;
287 resets the resultset and returns the first element.
292 return $_[0]->reset->next;
297 Deletes all elements in the resultset.
303 $_->delete for $self->all;
307 *delete_all = \&delete; # Yeah, yeah, yeah ...
311 Returns a L<Data::Page> object for the current resultset. Only makes
312 sense for queries with page turned on.
318 my $attrs = $self->{attrs};
319 delete $attrs->{offset};
320 my $rows_per_page = delete $attrs->{rows} || 10;
321 $self->{pager} ||= Data::Page->new(
322 $self->count, $rows_per_page, $attrs->{page} || 1);
323 $attrs->{rows} = $rows_per_page;
324 return $self->{pager};
329 Returns a new resultset representing a given page.
334 my ($self, $page) = @_;
335 my $attrs = $self->{attrs};
336 $attrs->{page} = $page;
337 return $self->new($self->{source}, $attrs);
344 The resultset is responsible for handling the various attributes that
345 can be passed in with the search functions. Here's an overview of them:
351 Which column to order the results by.
355 Which cols should be retrieved on the first search.
359 Contains a list of relations that should be joined for this query. Can also
360 contain a hash referece to refer to that relation's relations.
364 This attribute can contain a arrayref of elements. each element can be another
365 arrayref, to nest joins, or it can be a hash which represents the two sides
368 *NOTE* Use this on your own risk. This allows you to shoot your foot off!
372 Should the resultset be paged? This can also be enabled by using the
377 For paged resultsset, how many rows per page
381 For paged resultsset, which page to start on.