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.
37 $class->new_result(@_) if ref $class;
38 my ($source, $attrs) = @_;
39 #use Data::Dumper; warn Dumper(@_);
40 $attrs = { %{ $attrs || {} } };
42 my $alias = ($attrs->{alias} ||= 'me');
43 if (!$attrs->{select}) {
44 my @cols = ($attrs->{cols}
45 ? @{delete $attrs->{cols}}
46 : $source->result_class->_select_columns);
47 $attrs->{select} = [ map { m/\./ ? $_ : "${alias}.$_" } @cols ];
49 $attrs->{as} ||= [ map { m/^$alias\.(.*)$/ ? $1 : $_ } @{$attrs->{select}} ];
50 #use Data::Dumper; warn Dumper(@{$attrs}{qw/select as/});
51 $attrs->{from} ||= [ { $alias => $source->from } ];
52 if (my $join = delete $attrs->{join}) {
53 foreach my $j (ref $join eq 'ARRAY'
54 ? (@{$join}) : ($join)) {
55 if (ref $j eq 'HASH') {
56 $seen{$_} = 1 foreach keys %$j;
61 push(@{$attrs->{from}}, $source->result_class->_resolve_join($join, $attrs->{alias}));
63 $attrs->{group_by} ||= $attrs->{select} if delete $attrs->{distinct};
64 foreach my $pre (@{delete $attrs->{prefetch} || []}) {
65 push(@{$attrs->{from}}, $source->result_class->_resolve_join($pre, $attrs->{alias}))
69 $source->result_class->_relationships->{$pre}->{class}->columns;
70 push(@{$attrs->{select}}, @pre);
71 push(@{$attrs->{as}}, @pre);
74 $attrs->{rows} ||= 10;
75 $attrs->{offset} ||= 0;
76 $attrs->{offset} += ($attrs->{rows} * ($attrs->{page} - 1));
80 cond => $attrs->{where},
81 from => $attrs->{from},
83 page => delete $attrs->{page},
92 my @obj = $rs->search({ foo => 3 }); # "... WHERE foo = 3"
93 my $new_rs = $rs->search({ foo => 3 });
95 If you need to pass in additional attributes but no additional condition,
96 call it as ->search(undef, \%attrs);
98 my @all = $class->search({}, { cols => [qw/foo bar/] }); # "SELECT foo, bar FROM $class_table"
105 #use Data::Dumper;warn Dumper(@_);
107 my $attrs = { %{$self->{attrs}} };
108 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
109 $attrs = { %$attrs, %{ pop(@_) } };
112 my $where = (@_ ? ((@_ == 1 || ref $_[0] eq "HASH") ? shift : {@_}) : undef());
113 if (defined $where) {
114 $where = (defined $attrs->{where}
115 ? { '-and' => [ $where, $attrs->{where} ] }
117 $attrs->{where} = $where;
120 my $rs = (ref $self)->new($self->{source}, $attrs);
122 return (wantarray ? $rs->all : $rs);
125 =head2 search_literal
126 my @obj = $rs->search_literal($literal_where_cond, @bind);
127 my $new_rs = $rs->search_literal($literal_where_cond, @bind);
129 Pass a literal chunk of SQL to be added to the conditional part of the
135 my ($self, $cond, @vals) = @_;
136 my $attrs = (ref $vals[$#vals] eq 'HASH' ? { %{ pop(@vals) } } : {});
137 $attrs->{bind} = [ @{$self->{attrs}{bind}||[]}, @vals ];
138 return $self->search(\$cond, $attrs);
141 =head2 find(@colvalues), find(\%cols)
143 Finds a row based on its primary key(s).
148 my ($self, @vals) = @_;
149 my $attrs = (@vals > 1 && ref $vals[$#vals] eq 'HASH' ? pop(@vals) : {});
150 my @pk = $self->{source}->primary_columns;
151 #use Data::Dumper; warn Dumper($attrs, @vals, @pk);
152 $self->{source}->result_class->throw( "Can't find unless primary columns are defined" )
155 if (ref $vals[0] eq 'HASH') {
157 } elsif (@pk == @vals) {
159 @{$query}{@pk} = @vals;
163 #warn Dumper($query);
164 # Useless -> disabled
165 #$self->{source}->result_class->throw( "Can't find unless all primary keys are specified" )
166 # unless (keys %$query >= @pk); # If we check 'em we run afoul of uc/lc
167 # column names etc. Not sure what to do yet
168 return $self->search($query)->next;
171 =head2 search_related
173 $rs->search_related('relname', $cond?, $attrs?);
178 my ($self, $rel, @rest) = @_;
179 my $rel_obj = $self->{source}->result_class->_relationships->{$rel};
180 $self->{source}->result_class->throw(
181 "No such relationship ${rel} in search_related")
183 my $r_class = $self->{source}->result_class->resolve_class($rel_obj->{class});
184 my $source = $r_class->result_source;
185 $source = bless({ %{$source} }, ref $source || $source);
186 $source->storage($self->{source}->storage);
187 $source->result_class($r_class);
188 my $rs = $self->search(undef, { join => $rel });
189 #use Data::Dumper; warn Dumper($rs);
190 return $source->resultset_class->new(
191 $source, { %{$rs->{attrs}},
200 Returns a storage-driven cursor to the given resultset.
206 my ($source, $attrs) = @{$self}{qw/source attrs/};
207 $attrs = { %$attrs };
208 return $self->{cursor}
209 ||= $source->storage->select($self->{from}, $attrs->{select},
210 $attrs->{where},$attrs);
215 Identical to search except defaults to 'LIKE' instead of '=' in condition
222 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
225 my $query = ref $_[0] eq "HASH" ? { %{shift()} }: {@_};
226 $query->{$_} = { 'like' => $query->{$_} } for keys %$query;
227 return $class->search($query, { %$attrs });
230 =head2 slice($first, $last)
232 Returns a subset of elements from the resultset.
237 my ($self, $min, $max) = @_;
238 my $attrs = { %{ $self->{attrs} || {} } };
239 $attrs->{offset} ||= 0;
240 $attrs->{offset} += $min;
241 $attrs->{rows} = ($max ? ($max - $min + 1) : 1);
242 my $slice = (ref $self)->new($self->{source}, $attrs);
243 return (wantarray ? $slice->all : $slice);
248 Returns the next element in the resultset (undef is there is none).
254 my @row = $self->cursor->next;
255 return unless (@row);
256 return $self->_construct_object(@row);
259 sub _construct_object {
260 my ($self, @row) = @_;
261 my @cols = @{ $self->{attrs}{as} };
262 #warn "@cols -> @row";
264 foreach my $col (@cols) {
265 if ($col =~ /([^\.]+)\.([^\.]+)/) {
266 $pre{$1}[0]{$2} = shift @row;
268 $me{$col} = shift @row;
271 my $new = $self->{source}->result_class->inflate_result(\%me, \%pre);
272 $new = $self->{attrs}{record_filter}->($new)
273 if exists $self->{attrs}{record_filter};
279 Performs an SQL C<COUNT> with the same query as the resultset was built
280 with to find the number of elements. If passed arguments, does a search
281 on the resultset and counts the results of that.
287 return $self->search(@_)->count if @_ && defined $_[0];
288 die "Unable to ->count with a GROUP BY" if defined $self->{attrs}{group_by};
289 unless (defined $self->{count}) {
290 my $attrs = { %{ $self->{attrs} },
291 select => { 'count' => '*' },
293 # offset, order by and page are not needed to count
294 delete $attrs->{$_} for qw/rows offset order_by page pager/;
296 ($self->{count}) = (ref $self)->new($self->{source}, $attrs)->cursor->next;
298 return 0 unless $self->{count};
299 my $count = $self->{count};
300 $count -= $self->{attrs}{offset} if $self->{attrs}{offset};
301 $count = $self->{attrs}{rows} if
302 ($self->{attrs}{rows} && $self->{attrs}{rows} < $count);
308 Calls search_literal with the passed arguments, then count.
312 sub count_literal { shift->search_literal(@_)->count; }
316 Returns all elements in the resultset. Called implictly if the resultset
317 is returned in list context.
323 return map { $self->_construct_object(@$_); }
329 Resets the resultset's cursor, so you can iterate through the elements again.
335 $self->cursor->reset;
341 Resets the resultset and returns the first element.
346 return $_[0]->reset->next;
351 Deletes all elements in the resultset.
357 $_->delete for $self->all;
361 *delete_all = \&delete; # Yeah, yeah, yeah ...
365 Returns a L<Data::Page> object for the current resultset. Only makes
366 sense for queries with page turned on.
372 my $attrs = $self->{attrs};
373 die "Can't create pager for non-paged rs" unless $self->{page};
374 $attrs->{rows} ||= 10;
376 return $self->{pager} ||= Data::Page->new(
377 $self->{count}, $attrs->{rows}, $self->{page});
380 =head2 page($page_num)
382 Returns a new resultset for the specified page.
387 my ($self, $page) = @_;
388 my $attrs = { %{$self->{attrs}} };
389 $attrs->{page} = $page;
390 return (ref $self)->new($self->{source}, $attrs);
393 =head2 new_result(\%vals)
395 Creates a result in the resultset's result class
400 my ($self, $values) = @_;
401 $self->{source}->result_class->throw( "new_result needs a hash" )
402 unless (ref $values eq 'HASH');
403 $self->{source}->result_class->throw( "Can't abstract implicit construct, condition not a hash" )
404 if ($self->{cond} && !(ref $self->{cond} eq 'HASH'));
406 my $alias = $self->{attrs}{alias};
407 foreach my $key (keys %{$self->{cond}||{}}) {
408 $new{$1} = $self->{cond}{$key} if ($key =~ m/^(?:$alias\.)?([^\.]+)$/);
410 return $self->{source}->result_class->new(\%new);
413 =head2 create(\%vals)
415 Inserts a record into the resultset and returns the object
417 Effectively a shortcut for ->new_result(\%vals)->insert
422 my ($self, $attrs) = @_;
423 $self->{source}->result_class->throw( "create needs a hashref" ) unless ref $attrs eq 'HASH';
424 return $self->new_result($attrs)->insert;
429 The resultset takes various attributes that modify its behavior.
430 Here's an overview of them:
434 Which column(s) to order the results by. This is currently passed
435 through directly to SQL, so you can give e.g. C<foo DESC> for a
438 =head2 cols (arrayref)
440 Shortcut to request a particular set of columns to be retrieved - adds
441 'me.' onto the start of any column without a '.' in it and sets 'select'
442 from that, then auto-populates 'as' from 'select' as normal
444 =head2 select (arrayref)
446 Indicates which columns should be selected from the storage
450 Indicates column names for object inflation
454 Contains a list of relationships that should be joined for this query. Can also
455 contain a hash reference to refer to that relation's relations. So, if one column
456 in your class C<belongs_to> foo and another C<belongs_to> bar, you can do
457 C<< join => [qw/ foo bar /] >> to join both (and e.g. use them for C<order_by>).
458 If a foo contains many margles and you want to join those too, you can do
459 C<< join => { foo => 'margle' } >>. If you want to fetch the columns from the
460 related table as well, see C<prefetch> below.
464 Contains a list of relationships that should be fetched along with the main
465 query (when they are accessed afterwards they will have already been
466 "prefetched"). This is useful for when you know you will need the related
467 object(s), because it saves a query. Currently limited to prefetching
468 one relationship deep, so unlike C<join>, prefetch must be an arrayref.
472 This attribute can contain a arrayref of elements. Each element can be another
473 arrayref, to nest joins, or it can be a hash which represents the two sides
476 NOTE: Use this on your own risk. This allows you to shoot your foot off!
480 For a paged resultset, specifies which page to retrieve. Leave unset
481 for an unpaged resultset.
485 For a paged resultset, how many rows per page
489 A list of columns to group by (note that 'count' doesn't work on grouped
494 Set to 1 to group by all columns