1 package DBIx::Class::ResultSet;
13 DBIx::Class::ResultSet - Responsible for fetching and creating resultset.
17 my $rs = MyApp::DB::Class->search(registered => 1);
18 my @rows = MyApp::DB::Class->search(foo => 'bar');
22 The resultset is also known as an iterator. It is responsible for handling
23 queries that may return an arbitrary number of rows, e.g. via C<search>
24 or a C<has_many> relationship.
28 =head2 new($source, \%$attrs)
30 The resultset constructor. Takes a source object (usually a DBIx::Class::Table)
31 and an attribute hash (see below for more information on attributes). Does
32 not perform any queries -- these are executed as needed by the other methods.
38 return $class->new_result(@_) if ref $class;
39 my ($source, $attrs) = @_;
40 #use Data::Dumper; warn Dumper(@_);
41 $attrs = Storable::dclone($attrs || {}); # { %{ $attrs || {} } };
43 my $alias = ($attrs->{alias} ||= 'me');
44 if (!$attrs->{select}) {
45 my @cols = ($attrs->{cols}
46 ? @{delete $attrs->{cols}}
47 : $source->result_class->_select_columns);
48 $attrs->{select} = [ map { m/\./ ? $_ : "${alias}.$_" } @cols ];
50 $attrs->{as} ||= [ map { m/^$alias\.(.*)$/ ? $1 : $_ } @{$attrs->{select}} ];
51 #use Data::Dumper; warn Dumper(@{$attrs}{qw/select as/});
52 $attrs->{from} ||= [ { $alias => $source->from } ];
53 if (my $join = delete $attrs->{join}) {
54 foreach my $j (ref $join eq 'ARRAY'
55 ? (@{$join}) : ($join)) {
56 if (ref $j eq 'HASH') {
57 $seen{$_} = 1 foreach keys %$j;
62 push(@{$attrs->{from}}, $source->resolve_join($join, $attrs->{alias}));
64 $attrs->{group_by} ||= $attrs->{select} if delete $attrs->{distinct};
65 foreach my $pre (@{delete $attrs->{prefetch} || []}) {
66 push(@{$attrs->{from}}, $source->resolve_join($pre, $attrs->{alias}))
70 $source->related_source($pre)->columns;
71 push(@{$attrs->{select}}, @pre);
72 push(@{$attrs->{as}}, @pre);
75 $attrs->{rows} ||= 10;
76 $attrs->{offset} ||= 0;
77 $attrs->{offset} += ($attrs->{rows} * ($attrs->{page} - 1));
81 cond => $attrs->{where},
82 from => $attrs->{from},
84 page => delete $attrs->{page},
93 my @obj = $rs->search({ foo => 3 }); # "... WHERE foo = 3"
94 my $new_rs = $rs->search({ foo => 3 });
96 If you need to pass in additional attributes but no additional condition,
97 call it as ->search(undef, \%attrs);
99 my @all = $class->search({}, { cols => [qw/foo bar/] }); # "SELECT foo, bar FROM $class_table"
106 #use Data::Dumper;warn Dumper(@_);
108 my $attrs = { %{$self->{attrs}} };
109 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
110 $attrs = { %$attrs, %{ pop(@_) } };
113 my $where = (@_ ? ((@_ == 1 || ref $_[0] eq "HASH") ? shift : {@_}) : undef());
114 if (defined $where) {
115 $where = (defined $attrs->{where}
117 [ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
118 $where, $attrs->{where} ] }
120 $attrs->{where} = $where;
123 my $rs = (ref $self)->new($self->{source}, $attrs);
125 return (wantarray ? $rs->all : $rs);
128 =head2 search_literal
129 my @obj = $rs->search_literal($literal_where_cond, @bind);
130 my $new_rs = $rs->search_literal($literal_where_cond, @bind);
132 Pass a literal chunk of SQL to be added to the conditional part of the
138 my ($self, $cond, @vals) = @_;
139 my $attrs = (ref $vals[$#vals] eq 'HASH' ? { %{ pop(@vals) } } : {});
140 $attrs->{bind} = [ @{$self->{attrs}{bind}||[]}, @vals ];
141 return $self->search(\$cond, $attrs);
144 =head2 find(@colvalues), find(\%cols)
146 Finds a row based on its primary key(s).
151 my ($self, @vals) = @_;
152 my $attrs = (@vals > 1 && ref $vals[$#vals] eq 'HASH' ? pop(@vals) : {});
153 my @pk = $self->{source}->primary_columns;
154 #use Data::Dumper; warn Dumper($attrs, @vals, @pk);
155 $self->{source}->result_class->throw( "Can't find unless primary columns are defined" )
158 if (ref $vals[0] eq 'HASH') {
160 } elsif (@pk == @vals) {
162 @{$query}{@pk} = @vals;
166 #warn Dumper($query);
167 # Useless -> disabled
168 #$self->{source}->result_class->throw( "Can't find unless all primary keys are specified" )
169 # unless (keys %$query >= @pk); # If we check 'em we run afoul of uc/lc
170 # column names etc. Not sure what to do yet
171 return $self->search($query)->next;
174 =head2 search_related
176 $rs->search_related('relname', $cond?, $attrs?);
181 my ($self, $rel, @rest) = @_;
182 my $rel_obj = $self->{source}->relationship_info($rel);
183 $self->{source}->result_class->throw(
184 "No such relationship ${rel} in search_related")
186 my $rs = $self->search(undef, { join => $rel });
187 return $self->{source}->schema->resultset($rel_obj->{class}
198 Returns a storage-driven cursor to the given resultset.
204 my ($source, $attrs) = @{$self}{qw/source attrs/};
205 $attrs = { %$attrs };
206 return $self->{cursor}
207 ||= $source->storage->select($self->{from}, $attrs->{select},
208 $attrs->{where},$attrs);
213 Identical to search except defaults to 'LIKE' instead of '=' in condition
220 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
223 my $query = ref $_[0] eq "HASH" ? { %{shift()} }: {@_};
224 $query->{$_} = { 'like' => $query->{$_} } for keys %$query;
225 return $class->search($query, { %$attrs });
228 =head2 slice($first, $last)
230 Returns a subset of elements from the resultset.
235 my ($self, $min, $max) = @_;
236 my $attrs = { %{ $self->{attrs} || {} } };
237 $attrs->{offset} ||= 0;
238 $attrs->{offset} += $min;
239 $attrs->{rows} = ($max ? ($max - $min + 1) : 1);
240 my $slice = (ref $self)->new($self->{source}, $attrs);
241 return (wantarray ? $slice->all : $slice);
246 Returns the next element in the resultset (undef is there is none).
252 my @row = $self->cursor->next;
253 return unless (@row);
254 return $self->_construct_object(@row);
257 sub _construct_object {
258 my ($self, @row) = @_;
259 my @cols = @{ $self->{attrs}{as} };
260 #warn "@cols -> @row";
262 foreach my $col (@cols) {
263 if ($col =~ /([^\.]+)\.([^\.]+)/) {
264 $pre{$1}[0]{$2} = shift @row;
266 $me{$col} = shift @row;
269 my $new = $self->{source}->result_class->inflate_result(\%me, \%pre);
270 $new = $self->{attrs}{record_filter}->($new)
271 if exists $self->{attrs}{record_filter};
277 Performs an SQL C<COUNT> with the same query as the resultset was built
278 with to find the number of elements. If passed arguments, does a search
279 on the resultset and counts the results of that.
285 return $self->search(@_)->count if @_ && defined $_[0];
286 die "Unable to ->count with a GROUP BY" if defined $self->{attrs}{group_by};
287 unless (defined $self->{count}) {
288 my $attrs = { %{ $self->{attrs} },
289 select => { 'count' => '*' },
291 # offset, order by and page are not needed to count. record_filter is cdbi
292 delete $attrs->{$_} for qw/rows offset order_by page pager record_filter/;
294 ($self->{count}) = (ref $self)->new($self->{source}, $attrs)->cursor->next;
296 return 0 unless $self->{count};
297 my $count = $self->{count};
298 $count -= $self->{attrs}{offset} if $self->{attrs}{offset};
299 $count = $self->{attrs}{rows} if
300 ($self->{attrs}{rows} && $self->{attrs}{rows} < $count);
306 Calls search_literal with the passed arguments, then count.
310 sub count_literal { shift->search_literal(@_)->count; }
314 Returns all elements in the resultset. Called implictly if the resultset
315 is returned in list context.
321 return map { $self->_construct_object(@$_); }
327 Resets the resultset's cursor, so you can iterate through the elements again.
333 $self->cursor->reset;
339 Resets the resultset and returns the first element.
344 return $_[0]->reset->next;
349 Deletes all elements in the resultset.
355 $_->delete for $self->all;
359 *delete_all = \&delete; # Yeah, yeah, yeah ...
363 Returns a L<Data::Page> object for the current resultset. Only makes
364 sense for queries with page turned on.
370 my $attrs = $self->{attrs};
371 die "Can't create pager for non-paged rs" unless $self->{page};
372 $attrs->{rows} ||= 10;
374 return $self->{pager} ||= Data::Page->new(
375 $self->{count}, $attrs->{rows}, $self->{page});
378 =head2 page($page_num)
380 Returns a new resultset for the specified page.
385 my ($self, $page) = @_;
386 my $attrs = { %{$self->{attrs}} };
387 $attrs->{page} = $page;
388 return (ref $self)->new($self->{source}, $attrs);
391 =head2 new_result(\%vals)
393 Creates a result in the resultset's result class
398 my ($self, $values) = @_;
399 $self->{source}->result_class->throw( "new_result needs a hash" )
400 unless (ref $values eq 'HASH');
401 $self->{source}->result_class->throw( "Can't abstract implicit construct, condition not a hash" )
402 if ($self->{cond} && !(ref $self->{cond} eq 'HASH'));
404 my $alias = $self->{attrs}{alias};
405 foreach my $key (keys %{$self->{cond}||{}}) {
406 $new{$1} = $self->{cond}{$key} if ($key =~ m/^(?:$alias\.)?([^\.]+)$/);
408 return $self->{source}->result_class->new(\%new);
411 =head2 create(\%vals)
413 Inserts a record into the resultset and returns the object
415 Effectively a shortcut for ->new_result(\%vals)->insert
420 my ($self, $attrs) = @_;
421 $self->{source}->result_class->throw( "create needs a hashref" ) unless ref $attrs eq 'HASH';
422 return $self->new_result($attrs)->insert;
425 =head2 find_or_create(\%vals)
427 $class->find_or_create({ key => $val, ... });
429 Searches for a record matching the search condition; if it doesn't find one,
430 creates one and returns that instead.
436 my $hash = ref $_[0] eq "HASH" ? shift: {@_};
437 my $exists = $self->find($hash);
438 return defined($exists) ? $exists : $self->create($hash);
443 The resultset takes various attributes that modify its behavior.
444 Here's an overview of them:
448 Which column(s) to order the results by. This is currently passed
449 through directly to SQL, so you can give e.g. C<foo DESC> for a
452 =head2 cols (arrayref)
454 Shortcut to request a particular set of columns to be retrieved - adds
455 'me.' onto the start of any column without a '.' in it and sets 'select'
456 from that, then auto-populates 'as' from 'select' as normal
458 =head2 select (arrayref)
460 Indicates which columns should be selected from the storage
464 Indicates column names for object inflation
468 Contains a list of relationships that should be joined for this query. Can also
469 contain a hash reference to refer to that relation's relations. So, if one column
470 in your class C<belongs_to> foo and another C<belongs_to> bar, you can do
471 C<< join => [qw/ foo bar /] >> to join both (and e.g. use them for C<order_by>).
472 If a foo contains many margles and you want to join those too, you can do
473 C<< join => { foo => 'margle' } >>. If you want to fetch the columns from the
474 related table as well, see C<prefetch> below.
478 Contains a list of relationships that should be fetched along with the main
479 query (when they are accessed afterwards they will have already been
480 "prefetched"). This is useful for when you know you will need the related
481 object(s), because it saves a query. Currently limited to prefetching
482 one relationship deep, so unlike C<join>, prefetch must be an arrayref.
486 This attribute can contain a arrayref of elements. Each element can be another
487 arrayref, to nest joins, or it can be a hash which represents the two sides
490 NOTE: Use this on your own risk. This allows you to shoot your foot off!
494 For a paged resultset, specifies which page to retrieve. Leave unset
495 for an unpaged resultset.
499 For a paged resultset, how many rows per page
503 A list of columns to group by (note that 'count' doesn't work on grouped
508 Set to 1 to group by all columns