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;
427 =head2 find_or_create(\%vals)
429 $class->find_or_create({ key => $val, ... });
431 Searches for a record matching the search condition; if it doesn't find one,
432 creates one and returns that instead.
438 my $hash = ref $_[0] eq "HASH" ? shift: {@_};
439 my $exists = $self->find($hash);
440 return defined($exists) ? $exists : $self->create($hash);
445 The resultset takes various attributes that modify its behavior.
446 Here's an overview of them:
450 Which column(s) to order the results by. This is currently passed
451 through directly to SQL, so you can give e.g. C<foo DESC> for a
454 =head2 cols (arrayref)
456 Shortcut to request a particular set of columns to be retrieved - adds
457 'me.' onto the start of any column without a '.' in it and sets 'select'
458 from that, then auto-populates 'as' from 'select' as normal
460 =head2 select (arrayref)
462 Indicates which columns should be selected from the storage
466 Indicates column names for object inflation
470 Contains a list of relationships that should be joined for this query. Can also
471 contain a hash reference to refer to that relation's relations. So, if one column
472 in your class C<belongs_to> foo and another C<belongs_to> bar, you can do
473 C<< join => [qw/ foo bar /] >> to join both (and e.g. use them for C<order_by>).
474 If a foo contains many margles and you want to join those too, you can do
475 C<< join => { foo => 'margle' } >>. If you want to fetch the columns from the
476 related table as well, see C<prefetch> below.
480 Contains a list of relationships that should be fetched along with the main
481 query (when they are accessed afterwards they will have already been
482 "prefetched"). This is useful for when you know you will need the related
483 object(s), because it saves a query. Currently limited to prefetching
484 one relationship deep, so unlike C<join>, prefetch must be an arrayref.
488 This attribute can contain a arrayref of elements. Each element can be another
489 arrayref, to nest joins, or it can be a hash which represents the two sides
492 NOTE: Use this on your own risk. This allows you to shoot your foot off!
496 For a paged resultset, specifies which page to retrieve. Leave unset
497 for an unpaged resultset.
501 For a paged resultset, how many rows per page
505 A list of columns to group by (note that 'count' doesn't work on grouped
510 Set to 1 to group by all columns