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);
140 =item slice <first> <last>
142 return a number of elements from the given resultset.
147 my ($self, $min, $max) = @_;
148 my $attrs = { %{ $self->{attrs} || {} } };
149 $self->{source}->throw("Can't slice without where") unless $attrs->{where};
150 $attrs->{offset} = $min;
151 $attrs->{rows} = ($max ? ($max - $min + 1) : 1);
152 my $slice = $self->new($self->{source}, $attrs);
153 return (wantarray ? $slice->all : $slice);
158 Returns the next element in this resultset.
164 my @row = $self->cursor->next;
165 return unless (@row);
166 return $self->_construct_object(@row);
169 sub _construct_object {
170 my ($self, @row) = @_;
171 my @cols = @{ $self->{attrs}{cols} };
173 @cols = grep { /\(/ or ! /\./ } @cols;
175 unless ($self->{attrs}{prefetch}) {
176 $new = $self->{source}->_row_to_object(\@cols, \@row);
178 my @main = splice(@row, 0, scalar @cols);
179 $new = $self->{source}->_row_to_object(\@cols, \@main);
180 PRE: foreach my $pre (@{$self->{attrs}{prefetch}}) {
181 my $rel_obj = $self->{source}->_relationships->{$pre};
182 my $pre_class = $self->{source}->resolve_class($rel_obj->{class});
183 my @pre_cols = $pre_class->_select_columns;
184 my @vals = splice(@row, 0, scalar @pre_cols);
185 my $fetched = $pre_class->_row_to_object(\@pre_cols, \@vals);
186 $self->{source}->throw("No accessor for prefetched $pre")
187 unless defined $rel_obj->{attrs}{accessor};
188 if ($rel_obj->{attrs}{accessor} eq 'single') {
189 foreach my $pri ($rel_obj->{class}->primary_columns) {
190 unless (defined $fetched->get_column($pri)) {
195 $new->{_relationship_data}{$pre} = $fetched;
196 } elsif ($rel_obj->{attrs}{accessor} eq 'filter') {
197 $new->{_inflated_column}{$pre} = $fetched;
199 $self->{source}->throw("Don't know how to store prefetched $pre");
203 $new = $self->{attrs}{record_filter}->($new)
204 if exists $self->{attrs}{record_filter};
210 Performs an SQL count with the same query as the resultset was built
211 with to find the number of elements. If passed arguments, does a search
212 on the resultset and counts the results of that.
218 return $self->search(@_)->count if @_ && defined $_[0];
219 my $attrs = { %{ $self->{attrs} } };
220 unless ($self->{count}) {
221 # offset and order by are not needed to count
222 delete $attrs->{$_} for qw/offset order_by/;
224 my @cols = 'COUNT(*)';
225 $self->{count} = $self->{source}->storage->select_single(
226 $self->{from}, \@cols, $self->{cond}, $attrs);
228 return 0 unless $self->{count};
229 return $self->{pager}->entries_on_this_page if ($self->{pager});
230 return ( $attrs->{rows} && $attrs->{rows} < $self->{count} )
237 Calls search_literal with the passed arguments, then count
241 sub count_literal { shift->search_literal(@_)->count; }
245 Returns all elements in the resultset. Is called implictly if the search
246 method is used in list context.
252 return map { $self->_construct_object(@$_); }
258 Reset this resultset's cursor, so you can iterate through the elements again.
264 $self->cursor->reset;
270 resets the resultset and returns the first element.
275 return $_[0]->reset->next;
280 Deletes all elements in the resultset.
286 $_->delete for $self->all;
290 *delete_all = \&delete; # Yeah, yeah, yeah ...
294 Returns a L<Data::Page> object for the current resultset. Only makes
295 sense for queries with page turned on.
301 my $attrs = $self->{attrs};
302 delete $attrs->{offset};
303 my $rows_per_page = delete $attrs->{rows} || 10;
304 $self->{pager} ||= Data::Page->new(
305 $self->count, $rows_per_page, $attrs->{page} || 1);
306 $attrs->{rows} = $rows_per_page;
307 return $self->{pager};
312 Returns a new resultset representing a given page.
317 my ($self, $page) = @_;
318 my $attrs = $self->{attrs};
319 $attrs->{page} = $page;
320 return $self->new($self->{source}, $attrs);
327 The resultset is responsible for handling the various attributes that
328 can be passed in with the search functions. Here's an overview of them:
334 Which column to order the results by.
338 Which cols should be retrieved on the first search.
342 Contains a list of relations that should be joined for this query. Can also
343 contain a hash referece to refer to that relation's relations.
347 This attribute can contain a arrayref of elements. each element can be another
348 arrayref, to nest joins, or it can be a hash which represents the two sides
351 *NOTE* Use this on your own risk. This allows you to shoot your foot off!
355 Should the resultset be paged? This can also be enabled by using the
360 For paged resultsset, how many rows per page
364 For paged resultsset, which page to start on.