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($attrs);
41 $attrs = Storable::dclone($attrs || {}); # { %{ $attrs || {} } };
44 # wrong! we cannot delete select/as because it will interfere with the count() method. need to just set alias correctly in the first instance
46 if( $attrs->{from} && $attrs->{alias} eq 'me' ) {
47 my @keys = keys( %{$attrs->{from}->[0]} );
48 $attrs->{alias} = $keys[0];
49 delete $attrs->{select};
54 # alias should be set in accordance with from if alias is not defined or = "me"
55 # could also alter the line below instead, i.e. use alias if defined, then get from "from", then class->table, then "me" as a last resort.
57 my $alias = ($attrs->{alias} ||= 'me');
58 if (!$attrs->{select}) {
59 my @cols = ($attrs->{cols}
60 ? @{delete $attrs->{cols}}
61 : $source->result_class->_select_columns);
62 $attrs->{select} = [ map { m/\./ ? $_ : "${alias}.$_" } @cols ];
64 $attrs->{as} ||= [ map { m/^$alias\.(.*)$/ ? $1 : $_ } @{$attrs->{select}} ];
65 #use Data::Dumper; warn Dumper(@{$attrs}{qw/select as/});
66 $attrs->{from} ||= [ { $alias => $source->from } ];
67 if (my $join = delete $attrs->{join}) {
68 foreach my $j (ref $join eq 'ARRAY'
69 ? (@{$join}) : ($join)) {
70 if (ref $j eq 'HASH') {
71 $seen{$_} = 1 foreach keys %$j;
76 push(@{$attrs->{from}}, $source->resolve_join($join, $attrs->{alias}));
78 $attrs->{group_by} ||= $attrs->{select} if delete $attrs->{distinct};
79 foreach my $pre (@{delete $attrs->{prefetch} || []}) {
80 push(@{$attrs->{from}}, $source->resolve_join($pre, $attrs->{alias}))
84 $source->related_source($pre)->columns;
85 push(@{$attrs->{select}}, @pre);
86 push(@{$attrs->{as}}, @pre);
89 $attrs->{rows} ||= 10;
90 $attrs->{offset} ||= 0;
91 $attrs->{offset} += ($attrs->{rows} * ($attrs->{page} - 1));
95 cond => $attrs->{where},
96 from => $attrs->{from},
98 page => delete $attrs->{page},
101 bless ($new, $class);
107 my @obj = $rs->search({ foo => 3 }); # "... WHERE foo = 3"
108 my $new_rs = $rs->search({ foo => 3 });
110 If you need to pass in additional attributes but no additional condition,
111 call it as ->search(undef, \%attrs);
113 my @all = $class->search({}, { cols => [qw/foo bar/] }); # "SELECT foo, bar FROM $class_table"
120 #use Data::Dumper;warn Dumper(@_);
122 my $attrs = { %{$self->{attrs}} };
123 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
124 $attrs = { %$attrs, %{ pop(@_) } };
127 my $where = (@_ ? ((@_ == 1 || ref $_[0] eq "HASH") ? shift : {@_}) : undef());
128 if (defined $where) {
129 $where = (defined $attrs->{where}
131 [ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
132 $where, $attrs->{where} ] }
134 $attrs->{where} = $where;
137 my $rs = (ref $self)->new($self->{source}, $attrs);
139 return (wantarray ? $rs->all : $rs);
142 =head2 search_literal
143 my @obj = $rs->search_literal($literal_where_cond, @bind);
144 my $new_rs = $rs->search_literal($literal_where_cond, @bind);
146 Pass a literal chunk of SQL to be added to the conditional part of the
152 my ($self, $cond, @vals) = @_;
153 my $attrs = (ref $vals[$#vals] eq 'HASH' ? { %{ pop(@vals) } } : {});
154 $attrs->{bind} = [ @{$self->{attrs}{bind}||[]}, @vals ];
155 return $self->search(\$cond, $attrs);
158 =head2 find(@colvalues), find(\%cols)
160 Finds a row based on its primary key(s).
165 my ($self, @vals) = @_;
166 my $attrs = (@vals > 1 && ref $vals[$#vals] eq 'HASH' ? pop(@vals) : {});
167 my @pk = $self->{source}->primary_columns;
168 #use Data::Dumper; warn Dumper($attrs, @vals, @pk);
169 $self->{source}->result_class->throw( "Can't find unless primary columns are defined" )
172 if (ref $vals[0] eq 'HASH') {
174 } elsif (@pk == @vals) {
176 @{$query}{@pk} = @vals;
180 #warn Dumper($query);
181 # Useless -> disabled
182 #$self->{source}->result_class->throw( "Can't find unless all primary keys are specified" )
183 # unless (keys %$query >= @pk); # If we check 'em we run afoul of uc/lc
184 # column names etc. Not sure what to do yet
185 return $self->search($query)->next;
188 =head2 search_related
190 $rs->search_related('relname', $cond?, $attrs?);
195 my ($self, $rel, @rest) = @_;
196 my $rel_obj = $self->{source}->relationship_info($rel);
197 $self->{source}->result_class->throw(
198 "No such relationship ${rel} in search_related")
200 my $rs = $self->search(undef, { join => $rel });
201 return $self->{source}->schema->resultset($rel_obj->{class}
212 Returns a storage-driven cursor to the given resultset.
218 my ($source, $attrs) = @{$self}{qw/source attrs/};
219 $attrs = { %$attrs };
220 return $self->{cursor}
221 ||= $source->storage->select($self->{from}, $attrs->{select},
222 $attrs->{where},$attrs);
227 Identical to search except defaults to 'LIKE' instead of '=' in condition
234 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
237 my $query = ref $_[0] eq "HASH" ? { %{shift()} }: {@_};
238 $query->{$_} = { 'like' => $query->{$_} } for keys %$query;
239 return $class->search($query, { %$attrs });
242 =head2 slice($first, $last)
244 Returns a subset of elements from the resultset.
249 my ($self, $min, $max) = @_;
250 my $attrs = { %{ $self->{attrs} || {} } };
251 $attrs->{offset} ||= 0;
252 $attrs->{offset} += $min;
253 $attrs->{rows} = ($max ? ($max - $min + 1) : 1);
254 my $slice = (ref $self)->new($self->{source}, $attrs);
255 return (wantarray ? $slice->all : $slice);
260 Returns the next element in the resultset (undef is there is none).
266 my @row = $self->cursor->next;
267 return unless (@row);
268 return $self->_construct_object(@row);
271 sub _construct_object {
272 my ($self, @row) = @_;
273 my @cols = @{ $self->{attrs}{as} };
274 #warn "@cols -> @row";
276 foreach my $col (@cols) {
277 if ($col =~ /([^\.]+)\.([^\.]+)/) {
278 $pre{$1}[0]{$2} = shift @row;
280 $me{$col} = shift @row;
283 my $new = $self->{source}->result_class->inflate_result(
284 $self->{source}, \%me, \%pre);
285 $new = $self->{attrs}{record_filter}->($new)
286 if exists $self->{attrs}{record_filter};
292 Performs an SQL C<COUNT> with the same query as the resultset was built
293 with to find the number of elements. If passed arguments, does a search
294 on the resultset and counts the results of that.
300 return $self->search(@_)->count if @_ && defined $_[0];
301 die "Unable to ->count with a GROUP BY" if defined $self->{attrs}{group_by};
302 unless (defined $self->{count}) {
303 my $attrs = { %{ $self->{attrs} },
304 select => { 'count' => '*' },
306 # offset, order by and page are not needed to count. record_filter is cdbi
307 delete $attrs->{$_} for qw/rows offset order_by page pager record_filter/;
309 ($self->{count}) = (ref $self)->new($self->{source}, $attrs)->cursor->next;
311 return 0 unless $self->{count};
312 my $count = $self->{count};
313 $count -= $self->{attrs}{offset} if $self->{attrs}{offset};
314 $count = $self->{attrs}{rows} if
315 ($self->{attrs}{rows} && $self->{attrs}{rows} < $count);
321 Calls search_literal with the passed arguments, then count.
325 sub count_literal { shift->search_literal(@_)->count; }
329 Returns all elements in the resultset. Called implictly if the resultset
330 is returned in list context.
336 return map { $self->_construct_object(@$_); }
342 Resets the resultset's cursor, so you can iterate through the elements again.
348 $self->cursor->reset;
354 Resets the resultset and returns the first element.
359 return $_[0]->reset->next;
362 =head2 update(\%values)
364 Sets the specified columns in the resultset to the supplied values
369 my ($self, $values) = @_;
370 die "Values for update must be a hash" unless ref $values eq 'HASH';
371 return $self->{source}->storage->update(
372 $self->{source}->from, $values, $self->{cond});
375 =head2 update_all(\%values)
377 Fetches all objects and updates them one at a time. ->update_all will run
378 cascade triggers, ->update will not.
383 my ($self, $values) = @_;
384 die "Values for update must be a hash" unless ref $values eq 'HASH';
385 foreach my $obj ($self->all) {
386 $obj->set_columns($values)->update;
393 Deletes the contents of the resultset from its result source.
399 $self->{source}->storage->delete($self->{source}->from, $self->{cond});
405 Fetches all objects and deletes them one at a time. ->delete_all will run
406 cascade triggers, ->delete will not.
412 $_->delete for $self->all;
418 Returns a L<Data::Page> object for the current resultset. Only makes
419 sense for queries with page turned on.
425 my $attrs = $self->{attrs};
426 die "Can't create pager for non-paged rs" unless $self->{page};
427 $attrs->{rows} ||= 10;
429 return $self->{pager} ||= Data::Page->new(
430 $self->{count}, $attrs->{rows}, $self->{page});
433 =head2 page($page_num)
435 Returns a new resultset for the specified page.
440 my ($self, $page) = @_;
441 my $attrs = { %{$self->{attrs}} };
442 $attrs->{page} = $page;
443 return (ref $self)->new($self->{source}, $attrs);
446 =head2 new_result(\%vals)
448 Creates a result in the resultset's result class
453 my ($self, $values) = @_;
454 $self->{source}->result_class->throw( "new_result needs a hash" )
455 unless (ref $values eq 'HASH');
456 $self->{source}->result_class->throw( "Can't abstract implicit construct, condition not a hash" )
457 if ($self->{cond} && !(ref $self->{cond} eq 'HASH'));
459 my $alias = $self->{attrs}{alias};
460 foreach my $key (keys %{$self->{cond}||{}}) {
461 $new{$1} = $self->{cond}{$key} if ($key =~ m/^(?:$alias\.)?([^\.]+)$/);
463 my $obj = $self->{source}->result_class->new(\%new);
464 $obj->result_source($self->{source}) if $obj->can('result_source');
468 =head2 create(\%vals)
470 Inserts a record into the resultset and returns the object
472 Effectively a shortcut for ->new_result(\%vals)->insert
477 my ($self, $attrs) = @_;
478 $self->{source}->result_class->throw( "create needs a hashref" ) unless ref $attrs eq 'HASH';
479 return $self->new_result($attrs)->insert;
482 =head2 find_or_create(\%vals)
484 $class->find_or_create({ key => $val, ... });
486 Searches for a record matching the search condition; if it doesn't find one,
487 creates one and returns that instead.
493 my $hash = ref $_[0] eq "HASH" ? shift: {@_};
494 my $exists = $self->find($hash);
495 return defined($exists) ? $exists : $self->create($hash);
500 The resultset takes various attributes that modify its behavior.
501 Here's an overview of them:
505 Which column(s) to order the results by. This is currently passed
506 through directly to SQL, so you can give e.g. C<foo DESC> for a
509 =head2 cols (arrayref)
511 Shortcut to request a particular set of columns to be retrieved - adds
512 'me.' onto the start of any column without a '.' in it and sets 'select'
513 from that, then auto-populates 'as' from 'select' as normal
515 =head2 select (arrayref)
517 Indicates which columns should be selected from the storage
521 Indicates column names for object inflation
525 Contains a list of relationships that should be joined for this query. Can also
526 contain a hash reference to refer to that relation's relations. So, if one column
527 in your class C<belongs_to> foo and another C<belongs_to> bar, you can do
528 C<< join => [qw/ foo bar /] >> to join both (and e.g. use them for C<order_by>).
529 If a foo contains many margles and you want to join those too, you can do
530 C<< join => { foo => 'margle' } >>. If you want to fetch the columns from the
531 related table as well, see C<prefetch> below.
535 Contains a list of relationships that should be fetched along with the main
536 query (when they are accessed afterwards they will have already been
537 "prefetched"). This is useful for when you know you will need the related
538 object(s), because it saves a query. Currently limited to prefetching
539 one relationship deep, so unlike C<join>, prefetch must be an arrayref.
543 This attribute can contain a arrayref of elements. Each element can be another
544 arrayref, to nest joins, or it can be a hash which represents the two sides
547 NOTE: Use this on your own risk. This allows you to shoot your foot off!
551 For a paged resultset, specifies which page to retrieve. Leave unset
552 for an unpaged resultset.
556 For a paged resultset, how many rows per page
558 =head2 group_by (listref)
560 A listref of columns to group by (note that 'count' doesn't work on grouped
563 group_by => [qw/ column1 column2 ... /]
567 Set to 1 to group by all columns