1 package DBIx::Class::ResultSet;
9 use Carp::Clan qw/^DBIx::Class/;
12 use DBIx::Class::ResultSetColumn;
13 use base qw/DBIx::Class/;
15 __PACKAGE__->load_components(qw/AccessorGroup/);
16 __PACKAGE__->mk_group_accessors('simple' => qw/result_source result_class/);
20 DBIx::Class::ResultSet - Responsible for fetching and creating resultset.
24 my $rs = $schema->resultset('User')->search(registered => 1);
25 my @rows = $schema->resultset('CD')->search(year => 2005);
29 The resultset is also known as an iterator. It is responsible for handling
30 queries that may return an arbitrary number of rows, e.g. via L</search>
31 or a C<has_many> relationship.
33 In the examples below, the following table classes are used:
35 package MyApp::Schema::Artist;
36 use base qw/DBIx::Class/;
37 __PACKAGE__->load_components(qw/Core/);
38 __PACKAGE__->table('artist');
39 __PACKAGE__->add_columns(qw/artistid name/);
40 __PACKAGE__->set_primary_key('artistid');
41 __PACKAGE__->has_many(cds => 'MyApp::Schema::CD');
44 package MyApp::Schema::CD;
45 use base qw/DBIx::Class/;
46 __PACKAGE__->load_components(qw/Core/);
47 __PACKAGE__->table('cd');
48 __PACKAGE__->add_columns(qw/cdid artist title year/);
49 __PACKAGE__->set_primary_key('cdid');
50 __PACKAGE__->belongs_to(artist => 'MyApp::Schema::Artist');
59 =item Arguments: $source, \%$attrs
61 =item Return Value: $rs
65 The resultset constructor. Takes a source object (usually a
66 L<DBIx::Class::ResultSourceProxy::Table>) and an attribute hash (see
67 L</ATTRIBUTES> below). Does not perform any queries -- these are
68 executed as needed by the other methods.
70 Generally you won't need to construct a resultset manually. You'll
71 automatically get one from e.g. a L</search> called in scalar context:
73 my $rs = $schema->resultset('CD')->search({ title => '100th Window' });
75 IMPORTANT: If called on an object, proxies to new_result instead so
77 my $cd = $schema->resultset('CD')->new({ title => 'Spoon' });
79 will return a CD object, not a ResultSet.
85 return $class->new_result(@_) if ref $class;
87 my ($source, $attrs) = @_;
89 $attrs = { %{$attrs||{}} };
92 $attrs->{rows} ||= 10;
93 $attrs->{offset} ||= 0;
94 $attrs->{offset} += ($attrs->{rows} * ($attrs->{page} - 1));
97 $attrs->{alias} ||= 'me';
100 result_source => $source,
101 result_class => $attrs->{result_class} || $source->result_class,
102 cond => $attrs->{where},
117 =item Arguments: $cond, \%attrs?
119 =item Return Value: $resultset (scalar context), @row_objs (list context)
123 my @cds = $cd_rs->search({ year => 2001 }); # "... WHERE year = 2001"
124 my $new_rs = $cd_rs->search({ year => 2005 });
126 my $new_rs = $cd_rs->search([ { year => 2005 }, { year => 2004 } ]);
127 # year = 2005 OR year = 2004
129 If you need to pass in additional attributes but no additional condition,
130 call it as C<search(undef, \%attrs)>.
132 # "SELECT name, artistid FROM $artist_table"
133 my @all_artists = $schema->resultset('Artist')->search(undef, {
134 columns => [qw/name artistid/],
137 For a list of attributes that can be passed to C<search>, see L</ATTRIBUTES>. For more examples of using this function, see L<Searching|DBIx::Class::Manual::Cookbook/Searching>.
143 my $rs = $self->search_rs( @_ );
144 return (wantarray ? $rs->all : $rs);
151 =item Arguments: $cond, \%attrs?
153 =item Return Value: $resultset
157 This method does the same exact thing as search() except it will
158 always return a resultset, even in list context.
167 unless (@_) { # no search, effectively just a clone
168 $rows = $self->get_cache;
172 $attrs = pop(@_) if @_ > 1 and ref $_[$#_] eq 'HASH';
173 my $our_attrs = { %{$self->{attrs}} };
174 my $having = delete $our_attrs->{having};
175 my $where = delete $our_attrs->{where};
177 my $new_attrs = { %{$our_attrs}, %{$attrs} };
179 # merge new attrs into inherited
180 foreach my $key (qw/join prefetch/) {
181 next unless exists $attrs->{$key};
182 $new_attrs->{$key} = $self->_merge_attr($our_attrs->{$key}, $attrs->{$key});
187 (@_ == 1 || ref $_[0] eq "HASH")
189 (ref $_[0] eq 'HASH')
191 (keys %{ $_[0] } > 0)
199 ? $self->throw_exception("Odd number of arguments to search")
206 if (defined $where) {
207 $new_attrs->{where} = (
208 defined $new_attrs->{where}
211 ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_
212 } $where, $new_attrs->{where}
219 $new_attrs->{where} = (
220 defined $new_attrs->{where}
223 ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_
224 } $cond, $new_attrs->{where}
230 if (defined $having) {
231 $new_attrs->{having} = (
232 defined $new_attrs->{having}
235 ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_
236 } $having, $new_attrs->{having}
242 my $rs = (ref $self)->new($self->result_source, $new_attrs);
244 $rs->set_cache($rows);
249 =head2 search_literal
253 =item Arguments: $sql_fragment, @bind_values
255 =item Return Value: $resultset (scalar context), @row_objs (list context)
259 my @cds = $cd_rs->search_literal('year = ? AND title = ?', qw/2001 Reload/);
260 my $newrs = $artist_rs->search_literal('name = ?', 'Metallica');
262 Pass a literal chunk of SQL to be added to the conditional part of the
268 my ($self, $cond, @vals) = @_;
269 my $attrs = (ref $vals[$#vals] eq 'HASH' ? { %{ pop(@vals) } } : {});
270 $attrs->{bind} = [ @{$self->{attrs}{bind}||[]}, @vals ];
271 return $self->search(\$cond, $attrs);
278 =item Arguments: @values | \%cols, \%attrs?
280 =item Return Value: $row_object
284 Finds a row based on its primary key or unique constraint. For example, to find
285 a row by its primary key:
287 my $cd = $schema->resultset('CD')->find(5);
289 You can also find a row by a specific unique constraint using the C<key>
290 attribute. For example:
292 my $cd = $schema->resultset('CD')->find('Massive Attack', 'Mezzanine', {
293 key => 'cd_artist_title'
296 Additionally, you can specify the columns explicitly by name:
298 my $cd = $schema->resultset('CD')->find(
300 artist => 'Massive Attack',
301 title => 'Mezzanine',
303 { key => 'cd_artist_title' }
306 If the C<key> is specified as C<primary>, it searches only on the primary key.
308 If no C<key> is specified, it searches on all unique constraints defined on the
309 source, including the primary key.
311 If your table does not have a primary key, you B<must> provide a value for the
312 C<key> attribute matching one of the unique constraints on the source.
314 See also L</find_or_create> and L</update_or_create>. For information on how to
315 declare unique constraints, see
316 L<DBIx::Class::ResultSource/add_unique_constraint>.
322 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
324 # Default to the primary key, but allow a specific key
325 my @cols = exists $attrs->{key}
326 ? $self->result_source->unique_constraint_columns($attrs->{key})
327 : $self->result_source->primary_columns;
328 $self->throw_exception(
329 "Can't find unless a primary key is defined or unique constraint is specified"
332 # Parse out a hashref from input
334 if (ref $_[0] eq 'HASH') {
335 $input_query = { %{$_[0]} };
337 elsif (@_ == @cols) {
339 @{$input_query}{@cols} = @_;
342 # Compatibility: Allow e.g. find(id => $value)
343 carp "Find by key => value deprecated; please use a hashref instead";
347 my (%related, $info);
349 foreach my $key (keys %$input_query) {
350 if (ref($input_query->{$key})
351 && ($info = $self->result_source->relationship_info($key))) {
352 my $rel_q = $self->result_source->resolve_condition(
353 $info->{cond}, delete $input_query->{$key}, $key
355 die "Can't handle OR join condition in find" if ref($rel_q) eq 'ARRAY';
356 @related{keys %$rel_q} = values %$rel_q;
359 if (my @keys = keys %related) {
360 @{$input_query}{@keys} = values %related;
363 my @unique_queries = $self->_unique_queries($input_query, $attrs);
365 # Build the final query: Default to the disjunction of the unique queries,
366 # but allow the input query in case the ResultSet defines the query or the
367 # user is abusing find
368 my $alias = exists $attrs->{alias} ? $attrs->{alias} : $self->{attrs}{alias};
369 my $query = @unique_queries
370 ? [ map { $self->_add_alias($_, $alias) } @unique_queries ]
371 : $self->_add_alias($input_query, $alias);
375 my $rs = $self->search($query, $attrs);
376 return keys %{$rs->_resolved_attrs->{collapse}} ? $rs->next : $rs->single;
379 return keys %{$self->_resolved_attrs->{collapse}}
380 ? $self->search($query)->next
381 : $self->single($query);
387 # Add the specified alias to the specified query hash. A copy is made so the
388 # original query is not modified.
391 my ($self, $query, $alias) = @_;
393 my %aliased = %$query;
394 foreach my $col (grep { ! m/\./ } keys %aliased) {
395 $aliased{"$alias.$col"} = delete $aliased{$col};
403 # Build a list of queries which satisfy unique constraints.
405 sub _unique_queries {
406 my ($self, $query, $attrs) = @_;
408 my @constraint_names = exists $attrs->{key}
410 : $self->result_source->unique_constraint_names;
412 my $where = $self->_collapse_cond($self->{attrs}{where} || {});
413 my $num_where = scalar keys %$where;
416 foreach my $name (@constraint_names) {
417 my @unique_cols = $self->result_source->unique_constraint_columns($name);
418 my $unique_query = $self->_build_unique_query($query, \@unique_cols);
420 my $num_cols = scalar @unique_cols;
421 my $num_query = scalar keys %$unique_query;
423 my $total = $num_query + $num_where;
424 if ($num_query && ($num_query == $num_cols || $total == $num_cols)) {
425 # The query is either unique on its own or is unique in combination with
426 # the existing where clause
427 push @unique_queries, $unique_query;
431 return @unique_queries;
434 # _build_unique_query
436 # Constrain the specified query hash based on the specified column names.
438 sub _build_unique_query {
439 my ($self, $query, $unique_cols) = @_;
442 map { $_ => $query->{$_} }
443 grep { exists $query->{$_} }
448 =head2 search_related
452 =item Arguments: $rel, $cond, \%attrs?
454 =item Return Value: $new_resultset
458 $new_rs = $cd_rs->search_related('artist', {
462 Searches the specified relationship, optionally specifying a condition and
463 attributes for matching records. See L</ATTRIBUTES> for more information.
468 return shift->related_resultset(shift)->search(@_);
475 =item Arguments: none
477 =item Return Value: $cursor
481 Returns a storage-driven cursor to the given resultset. See
482 L<DBIx::Class::Cursor> for more information.
489 my $attrs = { %{$self->_resolved_attrs} };
490 return $self->{cursor}
491 ||= $self->result_source->storage->select($attrs->{from}, $attrs->{select},
492 $attrs->{where},$attrs);
499 =item Arguments: $cond?
501 =item Return Value: $row_object?
505 my $cd = $schema->resultset('CD')->single({ year => 2001 });
507 Inflates the first result without creating a cursor if the resultset has
508 any records in it; if not returns nothing. Used by L</find> as an optimisation.
510 Can optionally take an additional condition *only* - this is a fast-code-path
511 method; if you need to add extra joins or similar call ->search and then
512 ->single without a condition on the $rs returned from that.
517 my ($self, $where) = @_;
518 my $attrs = { %{$self->_resolved_attrs} };
520 if (defined $attrs->{where}) {
523 [ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
524 $where, delete $attrs->{where} ]
527 $attrs->{where} = $where;
531 # XXX: Disabled since it doesn't infer uniqueness in all cases
532 # unless ($self->_is_unique_query($attrs->{where})) {
533 # carp "Query not guaranteed to return a single row"
534 # . "; please declare your unique constraints or use search instead";
537 my @data = $self->result_source->storage->select_single(
538 $attrs->{from}, $attrs->{select},
539 $attrs->{where}, $attrs
542 return (@data ? ($self->_construct_object(@data))[0] : ());
547 # Try to determine if the specified query is guaranteed to be unique, based on
548 # the declared unique constraints.
550 sub _is_unique_query {
551 my ($self, $query) = @_;
553 my $collapsed = $self->_collapse_query($query);
554 my $alias = $self->{attrs}{alias};
556 foreach my $name ($self->result_source->unique_constraint_names) {
557 my @unique_cols = map {
559 } $self->result_source->unique_constraint_columns($name);
561 # Count the values for each unique column
562 my %seen = map { $_ => 0 } @unique_cols;
564 foreach my $key (keys %$collapsed) {
565 my $aliased = $key =~ /\./ ? $key : "$alias.$key";
566 next unless exists $seen{$aliased}; # Additional constraints are okay
567 $seen{$aliased} = scalar keys %{ $collapsed->{$key} };
570 # If we get 0 or more than 1 value for a column, it's not necessarily unique
571 return 1 unless grep { $_ != 1 } values %seen;
579 # Recursively collapse the query, accumulating values for each column.
581 sub _collapse_query {
582 my ($self, $query, $collapsed) = @_;
586 if (ref $query eq 'ARRAY') {
587 foreach my $subquery (@$query) {
588 next unless ref $subquery; # -or
589 # warn "ARRAY: " . Dumper $subquery;
590 $collapsed = $self->_collapse_query($subquery, $collapsed);
593 elsif (ref $query eq 'HASH') {
594 if (keys %$query and (keys %$query)[0] eq '-and') {
595 foreach my $subquery (@{$query->{-and}}) {
596 # warn "HASH: " . Dumper $subquery;
597 $collapsed = $self->_collapse_query($subquery, $collapsed);
601 # warn "LEAF: " . Dumper $query;
602 foreach my $col (keys %$query) {
603 my $value = $query->{$col};
604 $collapsed->{$col}{$value}++;
616 =item Arguments: $cond?
618 =item Return Value: $resultsetcolumn
622 my $max_length = $rs->get_column('length')->max;
624 Returns a L<DBIx::Class::ResultSetColumn> instance for a column of the ResultSet.
629 my ($self, $column) = @_;
630 my $new = DBIx::Class::ResultSetColumn->new($self, $column);
638 =item Arguments: $cond, \%attrs?
640 =item Return Value: $resultset (scalar context), @row_objs (list context)
644 # WHERE title LIKE '%blue%'
645 $cd_rs = $rs->search_like({ title => '%blue%'});
647 Performs a search, but uses C<LIKE> instead of C<=> as the condition. Note
648 that this is simply a convenience method. You most likely want to use
649 L</search> with specific operators.
651 For more information, see L<DBIx::Class::Manual::Cookbook>.
657 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
658 my $query = ref $_[0] eq 'HASH' ? { %{shift()} }: {@_};
659 $query->{$_} = { 'like' => $query->{$_} } for keys %$query;
660 return $class->search($query, { %$attrs });
667 =item Arguments: $first, $last
669 =item Return Value: $resultset (scalar context), @row_objs (list context)
673 Returns a resultset or object list representing a subset of elements from the
674 resultset slice is called on. Indexes are from 0, i.e., to get the first
677 my ($one, $two, $three) = $rs->slice(0, 2);
682 my ($self, $min, $max) = @_;
683 my $attrs = {}; # = { %{ $self->{attrs} || {} } };
684 $attrs->{offset} = $self->{attrs}{offset} || 0;
685 $attrs->{offset} += $min;
686 $attrs->{rows} = ($max ? ($max - $min + 1) : 1);
687 return $self->search(undef(), $attrs);
688 #my $slice = (ref $self)->new($self->result_source, $attrs);
689 #return (wantarray ? $slice->all : $slice);
696 =item Arguments: none
698 =item Return Value: $result?
702 Returns the next element in the resultset (C<undef> is there is none).
704 Can be used to efficiently iterate over records in the resultset:
706 my $rs = $schema->resultset('CD')->search;
707 while (my $cd = $rs->next) {
711 Note that you need to store the resultset object, and call C<next> on it.
712 Calling C<< resultset('Table')->next >> repeatedly will always return the
713 first record from the resultset.
719 if (my $cache = $self->get_cache) {
720 $self->{all_cache_position} ||= 0;
721 return $cache->[$self->{all_cache_position}++];
723 if ($self->{attrs}{cache}) {
724 $self->{all_cache_position} = 1;
725 return ($self->all)[0];
727 if ($self->{stashed_objects}) {
728 my $obj = shift(@{$self->{stashed_objects}});
729 delete $self->{stashed_objects} unless @{$self->{stashed_objects}};
733 exists $self->{stashed_row}
734 ? @{delete $self->{stashed_row}}
735 : $self->cursor->next
737 return unless (@row);
738 my ($row, @more) = $self->_construct_object(@row);
739 $self->{stashed_objects} = \@more if @more;
743 sub _construct_object {
744 my ($self, @row) = @_;
745 my $info = $self->_collapse_result($self->{_attrs}{as}, \@row);
746 my @new = $self->result_class->inflate_result($self->result_source, @$info);
747 @new = $self->{_attrs}{record_filter}->(@new)
748 if exists $self->{_attrs}{record_filter};
752 sub _collapse_result {
753 my ($self, $as, $row, $prefix) = @_;
758 foreach my $this_as (@$as) {
759 my $val = shift @copy;
760 if (defined $prefix) {
761 if ($this_as =~ m/^\Q${prefix}.\E(.+)$/) {
763 $remain =~ /^(?:(.*)\.)?([^.]+)$/;
764 $const{$1||''}{$2} = $val;
767 $this_as =~ /^(?:(.*)\.)?([^.]+)$/;
768 $const{$1||''}{$2} = $val;
772 my $alias = $self->{attrs}{alias};
773 my $info = [ {}, {} ];
774 foreach my $key (keys %const) {
775 if (length $key && $key ne $alias) {
777 my @parts = split(/\./, $key);
778 foreach my $p (@parts) {
779 $target = $target->[1]->{$p} ||= [];
781 $target->[0] = $const{$key};
783 $info->[0] = $const{$key};
788 if (defined $prefix) {
790 m/^\Q${prefix}.\E(.+)$/ ? ($1) : ()
791 } keys %{$self->{_attrs}{collapse}}
793 @collapse = keys %{$self->{_attrs}{collapse}};
797 my ($c) = sort { length $a <=> length $b } @collapse;
799 foreach my $p (split(/\./, $c)) {
800 $target = $target->[1]->{$p} ||= [];
802 my $c_prefix = (defined($prefix) ? "${prefix}.${c}" : $c);
803 my @co_key = @{$self->{_attrs}{collapse}{$c_prefix}};
804 my $tree = $self->_collapse_result($as, $row, $c_prefix);
805 my %co_check = map { ($_, $tree->[0]->{$_}); } @co_key;
811 !defined($tree->[0]->{$_}) || $co_check{$_} ne $tree->[0]->{$_}
816 last unless (@raw = $self->cursor->next);
817 $row = $self->{stashed_row} = \@raw;
818 $tree = $self->_collapse_result($as, $row, $c_prefix);
820 @$target = (@final ? @final : [ {}, {} ]);
821 # single empty result to indicate an empty prefetched has_many
824 #print "final info: " . Dumper($info);
832 =item Arguments: $result_source?
834 =item Return Value: $result_source
838 An accessor for the primary ResultSource object from which this ResultSet
845 =item Arguments: $result_class?
847 =item Return Value: $result_class
851 An accessor for the class to use when creating row objects. Defaults to
852 C<< result_source->result_class >> - which in most cases is the name of the
853 L<"table"|DBIx::Class::Manual::Glossary/"ResultSource"> class.
862 =item Arguments: $cond, \%attrs??
864 =item Return Value: $count
868 Performs an SQL C<COUNT> with the same query as the resultset was built
869 with to find the number of elements. If passed arguments, does a search
870 on the resultset and counts the results of that.
872 Note: When using C<count> with C<group_by>, L<DBIX::Class> emulates C<GROUP BY>
873 using C<COUNT( DISTINCT( columns ) )>. Some databases (notably SQLite) do
874 not support C<DISTINCT> with multiple columns. If you are using such a
875 database, you should only use columns from the main table in your C<group_by>
882 return $self->search(@_)->count if @_ and defined $_[0];
883 return scalar @{ $self->get_cache } if $self->get_cache;
884 my $count = $self->_count;
885 return 0 unless $count;
887 $count -= $self->{attrs}{offset} if $self->{attrs}{offset};
888 $count = $self->{attrs}{rows} if
889 $self->{attrs}{rows} and $self->{attrs}{rows} < $count;
893 sub _count { # Separated out so pager can get the full count
895 my $select = { count => '*' };
897 my $attrs = { %{$self->_resolved_attrs} };
898 if (my $group_by = delete $attrs->{group_by}) {
899 delete $attrs->{having};
900 my @distinct = (ref $group_by ? @$group_by : ($group_by));
901 # todo: try CONCAT for multi-column pk
902 my @pk = $self->result_source->primary_columns;
904 my $alias = $attrs->{alias};
905 foreach my $column (@distinct) {
906 if ($column =~ qr/^(?:\Q${alias}.\E)?$pk[0]$/) {
907 @distinct = ($column);
913 $select = { count => { distinct => \@distinct } };
916 $attrs->{select} = $select;
917 $attrs->{as} = [qw/count/];
919 # offset, order by and page are not needed to count. record_filter is cdbi
920 delete $attrs->{$_} for qw/rows offset order_by page pager record_filter/;
922 my $tmp_rs = (ref $self)->new($self->result_source, $attrs);
923 my ($count) = $tmp_rs->cursor->next;
931 =item Arguments: $sql_fragment, @bind_values
933 =item Return Value: $count
937 Counts the results in a literal query. Equivalent to calling L</search_literal>
938 with the passed arguments, then L</count>.
942 sub count_literal { shift->search_literal(@_)->count; }
948 =item Arguments: none
950 =item Return Value: @objects
954 Returns all elements in the resultset. Called implicitly if the resultset
955 is returned in list context.
961 return @{ $self->get_cache } if $self->get_cache;
965 # TODO: don't call resolve here
966 if (keys %{$self->_resolved_attrs->{collapse}}) {
967 # if ($self->{attrs}{prefetch}) {
968 # Using $self->cursor->all is really just an optimisation.
969 # If we're collapsing has_many prefetches it probably makes
970 # very little difference, and this is cleaner than hacking
971 # _construct_object to survive the approach
972 my @row = $self->cursor->next;
974 push(@obj, $self->_construct_object(@row));
975 @row = (exists $self->{stashed_row}
976 ? @{delete $self->{stashed_row}}
977 : $self->cursor->next);
980 @obj = map { $self->_construct_object(@$_) } $self->cursor->all;
983 $self->set_cache(\@obj) if $self->{attrs}{cache};
991 =item Arguments: none
993 =item Return Value: $self
997 Resets the resultset's cursor, so you can iterate through the elements again.
1003 delete $self->{_attrs} if exists $self->{_attrs};
1004 $self->{all_cache_position} = 0;
1005 $self->cursor->reset;
1013 =item Arguments: none
1015 =item Return Value: $object?
1019 Resets the resultset and returns an object for the first result (if the
1020 resultset returns anything).
1025 return $_[0]->reset->next;
1028 # _cond_for_update_delete
1030 # update/delete require the condition to be modified to handle
1031 # the differing SQL syntax available. This transforms the $self->{cond}
1032 # appropriately, returning the new condition.
1034 sub _cond_for_update_delete {
1035 my ($self, $full_cond) = @_;
1038 $full_cond ||= $self->{cond};
1039 # No-op. No condition, we're updating/deleting everything
1040 return $cond unless ref $full_cond;
1042 if (ref $full_cond eq 'ARRAY') {
1046 foreach my $key (keys %{$_}) {
1048 $hash{$1} = $_->{$key};
1054 elsif (ref $full_cond eq 'HASH') {
1055 if ((keys %{$full_cond})[0] eq '-and') {
1058 my @cond = @{$full_cond->{-and}};
1059 for (my $i = 0; $i < @cond; $i++) {
1060 my $entry = $cond[$i];
1063 if (ref $entry eq 'HASH') {
1064 $hash = $self->_cond_for_update_delete($entry);
1067 $entry =~ /([^.]+)$/;
1068 $hash->{$1} = $cond[++$i];
1071 push @{$cond->{-and}}, $hash;
1075 foreach my $key (keys %{$full_cond}) {
1077 $cond->{$1} = $full_cond->{$key};
1082 $self->throw_exception(
1083 "Can't update/delete on resultset with condition unless hash or array"
1095 =item Arguments: \%values
1097 =item Return Value: $storage_rv
1101 Sets the specified columns in the resultset to the supplied values in a
1102 single query. Return value will be true if the update succeeded or false
1103 if no records were updated; exact type of success value is storage-dependent.
1108 my ($self, $values) = @_;
1109 $self->throw_exception("Values for update must be a hash")
1110 unless ref $values eq 'HASH';
1112 my $cond = $self->_cond_for_update_delete;
1114 return $self->result_source->storage->update(
1115 $self->result_source->from, $values, $cond
1123 =item Arguments: \%values
1125 =item Return Value: 1
1129 Fetches all objects and updates them one at a time. Note that C<update_all>
1130 will run DBIC cascade triggers, while L</update> will not.
1135 my ($self, $values) = @_;
1136 $self->throw_exception("Values for update must be a hash")
1137 unless ref $values eq 'HASH';
1138 foreach my $obj ($self->all) {
1139 $obj->set_columns($values)->update;
1148 =item Arguments: none
1150 =item Return Value: 1
1154 Deletes the contents of the resultset from its result source. Note that this
1155 will not run DBIC cascade triggers. See L</delete_all> if you need triggers
1156 to run. See also L<DBIx::Class::Row/delete>.
1163 my $cond = $self->_cond_for_update_delete;
1165 $self->result_source->storage->delete($self->result_source->from, $cond);
1173 =item Arguments: none
1175 =item Return Value: 1
1179 Fetches all objects and deletes them one at a time. Note that C<delete_all>
1180 will run DBIC cascade triggers, while L</delete> will not.
1186 $_->delete for $self->all;
1194 =item Arguments: none
1196 =item Return Value: $pager
1200 Return Value a L<Data::Page> object for the current resultset. Only makes
1201 sense for queries with a C<page> attribute.
1207 my $attrs = $self->{attrs};
1208 $self->throw_exception("Can't create pager for non-paged rs")
1209 unless $self->{attrs}{page};
1210 $attrs->{rows} ||= 10;
1211 return $self->{pager} ||= Data::Page->new(
1212 $self->_count, $attrs->{rows}, $self->{attrs}{page});
1219 =item Arguments: $page_number
1221 =item Return Value: $rs
1225 Returns a resultset for the $page_number page of the resultset on which page
1226 is called, where each page contains a number of rows equal to the 'rows'
1227 attribute set on the resultset (10 by default).
1232 my ($self, $page) = @_;
1233 return (ref $self)->new($self->result_source, { %{$self->{attrs}}, page => $page });
1240 =item Arguments: \%vals
1242 =item Return Value: $object
1246 Creates an object in the resultset's result class and returns it.
1251 my ($self, $values) = @_;
1252 $self->throw_exception( "new_result needs a hash" )
1253 unless (ref $values eq 'HASH');
1254 $self->throw_exception(
1255 "Can't abstract implicit construct, condition not a hash"
1256 ) if ($self->{cond} && !(ref $self->{cond} eq 'HASH'));
1258 my $alias = $self->{attrs}{alias};
1259 my $collapsed_cond = $self->{cond} ? $self->_collapse_cond($self->{cond}) : {};
1261 %{ $self->_remove_alias($values, $alias) },
1262 %{ $self->_remove_alias($collapsed_cond, $alias) },
1263 -result_source => $self->result_source,
1266 my $obj = $self->result_class->new(\%new);
1272 # Recursively collapse the condition.
1274 sub _collapse_cond {
1275 my ($self, $cond, $collapsed) = @_;
1279 if (ref $cond eq 'ARRAY') {
1280 foreach my $subcond (@$cond) {
1281 next unless ref $subcond; # -or
1282 # warn "ARRAY: " . Dumper $subcond;
1283 $collapsed = $self->_collapse_cond($subcond, $collapsed);
1286 elsif (ref $cond eq 'HASH') {
1287 if (keys %$cond and (keys %$cond)[0] eq '-and') {
1288 foreach my $subcond (@{$cond->{-and}}) {
1289 # warn "HASH: " . Dumper $subcond;
1290 $collapsed = $self->_collapse_cond($subcond, $collapsed);
1294 # warn "LEAF: " . Dumper $cond;
1295 foreach my $col (keys %$cond) {
1296 my $value = $cond->{$col};
1297 $collapsed->{$col} = $value;
1307 # Remove the specified alias from the specified query hash. A copy is made so
1308 # the original query is not modified.
1311 my ($self, $query, $alias) = @_;
1313 my %orig = %{ $query || {} };
1316 foreach my $key (keys %orig) {
1318 $unaliased{$key} = $orig{$key};
1321 $unaliased{$1} = $orig{$key}
1322 if $key =~ m/^(?:\Q$alias\E\.)?([^.]+)$/;
1332 =item Arguments: \%vals, \%attrs?
1334 =item Return Value: $object
1338 Find an existing record from this resultset. If none exists, instantiate a new
1339 result object and return it. The object will not be saved into your storage
1340 until you call L<DBIx::Class::Row/insert> on it.
1342 If you want objects to be saved immediately, use L</find_or_create> instead.
1348 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
1349 my $hash = ref $_[0] eq 'HASH' ? shift : {@_};
1350 my $exists = $self->find($hash, $attrs);
1351 return defined $exists ? $exists : $self->new_result($hash);
1358 =item Arguments: \%vals
1360 =item Return Value: $object
1364 Inserts a record into the resultset and returns the object representing it.
1366 Effectively a shortcut for C<< ->new_result(\%vals)->insert >>.
1371 my ($self, $attrs) = @_;
1372 $self->throw_exception( "create needs a hashref" )
1373 unless ref $attrs eq 'HASH';
1374 return $self->new_result($attrs)->insert;
1377 =head2 find_or_create
1381 =item Arguments: \%vals, \%attrs?
1383 =item Return Value: $object
1387 $class->find_or_create({ key => $val, ... });
1389 Tries to find a record based on its primary key or unique constraint; if none
1390 is found, creates one and returns that instead.
1392 my $cd = $schema->resultset('CD')->find_or_create({
1394 artist => 'Massive Attack',
1395 title => 'Mezzanine',
1399 Also takes an optional C<key> attribute, to search by a specific key or unique
1400 constraint. For example:
1402 my $cd = $schema->resultset('CD')->find_or_create(
1404 artist => 'Massive Attack',
1405 title => 'Mezzanine',
1407 { key => 'cd_artist_title' }
1410 See also L</find> and L</update_or_create>. For information on how to declare
1411 unique constraints, see L<DBIx::Class::ResultSource/add_unique_constraint>.
1415 sub find_or_create {
1417 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
1418 my $hash = ref $_[0] eq 'HASH' ? shift : {@_};
1419 my $exists = $self->find($hash, $attrs);
1420 return defined $exists ? $exists : $self->create($hash);
1423 =head2 update_or_create
1427 =item Arguments: \%col_values, { key => $unique_constraint }?
1429 =item Return Value: $object
1433 $class->update_or_create({ col => $val, ... });
1435 First, searches for an existing row matching one of the unique constraints
1436 (including the primary key) on the source of this resultset. If a row is
1437 found, updates it with the other given column values. Otherwise, creates a new
1440 Takes an optional C<key> attribute to search on a specific unique constraint.
1443 # In your application
1444 my $cd = $schema->resultset('CD')->update_or_create(
1446 artist => 'Massive Attack',
1447 title => 'Mezzanine',
1450 { key => 'cd_artist_title' }
1453 If no C<key> is specified, it searches on all unique constraints defined on the
1454 source, including the primary key.
1456 If the C<key> is specified as C<primary>, it searches only on the primary key.
1458 See also L</find> and L</find_or_create>. For information on how to declare
1459 unique constraints, see L<DBIx::Class::ResultSource/add_unique_constraint>.
1463 sub update_or_create {
1465 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
1466 my $cond = ref $_[0] eq 'HASH' ? shift : {@_};
1468 my $row = $self->find($cond, $attrs);
1470 $row->update($cond);
1474 return $self->create($cond);
1481 =item Arguments: none
1483 =item Return Value: \@cache_objects?
1487 Gets the contents of the cache for the resultset, if the cache is set.
1499 =item Arguments: \@cache_objects
1501 =item Return Value: \@cache_objects
1505 Sets the contents of the cache for the resultset. Expects an arrayref
1506 of objects of the same class as those produced by the resultset. Note that
1507 if the cache is set the resultset will return the cached objects rather
1508 than re-querying the database even if the cache attr is not set.
1513 my ( $self, $data ) = @_;
1514 $self->throw_exception("set_cache requires an arrayref")
1515 if defined($data) && (ref $data ne 'ARRAY');
1516 $self->{all_cache} = $data;
1523 =item Arguments: none
1525 =item Return Value: []
1529 Clears the cache for the resultset.
1534 shift->set_cache(undef);
1537 =head2 related_resultset
1541 =item Arguments: $relationship_name
1543 =item Return Value: $resultset
1547 Returns a related resultset for the supplied relationship name.
1549 $artist_rs = $schema->resultset('CD')->related_resultset('Artist');
1553 sub related_resultset {
1554 my ($self, $rel) = @_;
1556 $self->{related_resultsets} ||= {};
1557 return $self->{related_resultsets}{$rel} ||= do {
1558 my $rel_obj = $self->result_source->relationship_info($rel);
1560 $self->throw_exception(
1561 "search_related: result source '" . $self->result_source->name .
1562 "' has no such relationship $rel")
1565 my ($from,$seen) = $self->_resolve_from($rel);
1567 my $join_count = $seen->{$rel};
1568 my $alias = ($join_count > 1 ? join('_', $rel, $join_count) : $rel);
1570 $self->result_source->schema->resultset($rel_obj->{class})->search_rs(
1572 %{$self->{attrs}||{}},
1578 where => $self->{cond},
1586 my ($self, $extra_join) = @_;
1587 my $source = $self->result_source;
1588 my $attrs = $self->{attrs};
1590 my $from = $attrs->{from}
1591 || [ { $attrs->{alias} => $source->from } ];
1593 my $seen = { %{$attrs->{seen_join}||{}} };
1595 my $join = ($attrs->{join}
1596 ? [ $attrs->{join}, $extra_join ]
1600 ($join ? $source->resolve_join($join, $attrs->{alias}, $seen) : ()),
1603 return ($from,$seen);
1606 sub _resolved_attrs {
1608 return $self->{_attrs} if $self->{_attrs};
1610 my $attrs = { %{$self->{attrs}||{}} };
1611 my $source = $self->{result_source};
1612 my $alias = $attrs->{alias};
1614 $attrs->{columns} ||= delete $attrs->{cols} if exists $attrs->{cols};
1615 if ($attrs->{columns}) {
1616 delete $attrs->{as};
1617 } elsif (!$attrs->{select}) {
1618 $attrs->{columns} = [ $source->columns ];
1623 ? (ref $attrs->{select} eq 'ARRAY'
1624 ? [ @{$attrs->{select}} ]
1625 : [ $attrs->{select} ])
1626 : [ map { m/\./ ? $_ : "${alias}.$_" } @{delete $attrs->{columns}} ]
1630 ? (ref $attrs->{as} eq 'ARRAY'
1631 ? [ @{$attrs->{as}} ]
1633 : [ map { m/^\Q${alias}.\E(.+)$/ ? $1 : $_ } @{$attrs->{select}} ]
1637 if ($adds = delete $attrs->{include_columns}) {
1638 $adds = [$adds] unless ref $adds eq 'ARRAY';
1639 push(@{$attrs->{select}}, @$adds);
1640 push(@{$attrs->{as}}, map { m/([^.]+)$/; $1 } @$adds);
1642 if ($adds = delete $attrs->{'+select'}) {
1643 $adds = [$adds] unless ref $adds eq 'ARRAY';
1644 push(@{$attrs->{select}},
1645 map { /\./ || ref $_ ? $_ : "${alias}.$_" } @$adds);
1647 if (my $adds = delete $attrs->{'+as'}) {
1648 $adds = [$adds] unless ref $adds eq 'ARRAY';
1649 push(@{$attrs->{as}}, @$adds);
1652 $attrs->{from} ||= [ { 'me' => $source->from } ];
1654 if (exists $attrs->{join} || exists $attrs->{prefetch}) {
1655 my $join = delete $attrs->{join} || {};
1657 if (defined $attrs->{prefetch}) {
1658 $join = $self->_merge_attr(
1659 $join, $attrs->{prefetch}
1663 $attrs->{from} = # have to copy here to avoid corrupting the original
1666 $source->resolve_join($join, $alias, { %{$attrs->{seen_join}||{}} })
1670 $attrs->{group_by} ||= $attrs->{select} if delete $attrs->{distinct};
1671 if ($attrs->{order_by}) {
1672 $attrs->{order_by} = (ref($attrs->{order_by}) eq 'ARRAY'
1673 ? [ @{$attrs->{order_by}} ]
1674 : [ $attrs->{order_by} ]);
1676 $attrs->{order_by} = [];
1679 my $collapse = $attrs->{collapse} || {};
1680 if (my $prefetch = delete $attrs->{prefetch}) {
1681 $prefetch = $self->_merge_attr({}, $prefetch);
1683 my $seen = $attrs->{seen_join} || {};
1684 foreach my $p (ref $prefetch eq 'ARRAY' ? @$prefetch : ($prefetch)) {
1685 # bring joins back to level of current class
1686 my @prefetch = $source->resolve_prefetch(
1687 $p, $alias, $seen, \@pre_order, $collapse
1689 push(@{$attrs->{select}}, map { $_->[0] } @prefetch);
1690 push(@{$attrs->{as}}, map { $_->[1] } @prefetch);
1692 push(@{$attrs->{order_by}}, @pre_order);
1694 $attrs->{collapse} = $collapse;
1696 return $self->{_attrs} = $attrs;
1700 my ($self, $a, $b) = @_;
1701 return $b unless defined($a);
1702 return $a unless defined($b);
1704 if (ref $b eq 'HASH' && ref $a eq 'HASH') {
1705 foreach my $key (keys %{$b}) {
1706 if (exists $a->{$key}) {
1707 $a->{$key} = $self->_merge_attr($a->{$key}, $b->{$key});
1709 $a->{$key} = $b->{$key};
1714 $a = [$a] unless ref $a eq 'ARRAY';
1715 $b = [$b] unless ref $b eq 'ARRAY';
1719 foreach my $x ($a, $b) {
1720 foreach my $element (@{$x}) {
1721 if (ref $element eq 'HASH') {
1722 $hash = $self->_merge_attr($hash, $element);
1723 } elsif (ref $element eq 'ARRAY') {
1724 push(@array, @{$element});
1726 push(@array, $element) unless $b == $x
1727 && grep { $_ eq $element } @array;
1732 @array = grep { !exists $hash->{$_} } @array;
1734 return keys %{$hash}
1743 =head2 throw_exception
1745 See L<DBIx::Class::Schema/throw_exception> for details.
1749 sub throw_exception {
1751 $self->result_source->schema->throw_exception(@_);
1754 # XXX: FIXME: Attributes docs need clearing up
1758 The resultset takes various attributes that modify its behavior. Here's an
1765 =item Value: ($order_by | \@order_by)
1769 Which column(s) to order the results by. This is currently passed
1770 through directly to SQL, so you can give e.g. C<year DESC> for a
1771 descending order on the column `year'.
1773 Please note that if you have quoting enabled (see
1774 L<DBIx::Class::Storage/quote_char>) you will need to do C<\'year DESC' > to
1775 specify an order. (The scalar ref causes it to be passed as raw sql to the DB,
1776 so you will need to manually quote things as appropriate.)
1782 =item Value: \@columns
1786 Shortcut to request a particular set of columns to be retrieved. Adds
1787 C<me.> onto the start of any column without a C<.> in it and sets C<select>
1788 from that, then auto-populates C<as> from C<select> as normal. (You may also
1789 use the C<cols> attribute, as in earlier versions of DBIC.)
1791 =head2 include_columns
1795 =item Value: \@columns
1799 Shortcut to include additional columns in the returned results - for example
1801 $schema->resultset('CD')->search(undef, {
1802 include_columns => ['artist.name'],
1806 would return all CDs and include a 'name' column to the information
1807 passed to object inflation. Note that the 'artist' is the name of the
1808 column (or relationship) accessor, and 'name' is the name of the column
1809 accessor in the related table.
1815 =item Value: \@select_columns
1819 Indicates which columns should be selected from the storage. You can use
1820 column names, or in the case of RDBMS back ends, function or stored procedure
1823 $rs = $schema->resultset('Employee')->search(undef, {
1826 { count => 'employeeid' },
1831 When you use function/stored procedure names and do not supply an C<as>
1832 attribute, the column names returned are storage-dependent. E.g. MySQL would
1833 return a column named C<count(employeeid)> in the above example.
1839 Indicates additional columns to be selected from storage. Works the same as
1840 L<select> but adds columns to the selection.
1848 Indicates additional column names for those added via L<+select>.
1856 =item Value: \@inflation_names
1860 Indicates column names for object inflation. This is used in conjunction with
1861 C<select>, usually when C<select> contains one or more function or stored
1864 $rs = $schema->resultset('Employee')->search(undef, {
1867 { count => 'employeeid' }
1869 as => ['name', 'employee_count'],
1872 my $employee = $rs->first(); # get the first Employee
1874 If the object against which the search is performed already has an accessor
1875 matching a column name specified in C<as>, the value can be retrieved using
1876 the accessor as normal:
1878 my $name = $employee->name();
1880 If on the other hand an accessor does not exist in the object, you need to
1881 use C<get_column> instead:
1883 my $employee_count = $employee->get_column('employee_count');
1885 You can create your own accessors if required - see
1886 L<DBIx::Class::Manual::Cookbook> for details.
1888 Please note: This will NOT insert an C<AS employee_count> into the SQL
1889 statement produced, it is used for internal access only. Thus
1890 attempting to use the accessor in an C<order_by> clause or similar
1891 will fail miserably.
1893 To get around this limitation, you can supply literal SQL to your
1894 C<select> attibute that contains the C<AS alias> text, eg:
1896 select => [\'myfield AS alias']
1902 =item Value: ($rel_name | \@rel_names | \%rel_names)
1906 Contains a list of relationships that should be joined for this query. For
1909 # Get CDs by Nine Inch Nails
1910 my $rs = $schema->resultset('CD')->search(
1911 { 'artist.name' => 'Nine Inch Nails' },
1912 { join => 'artist' }
1915 Can also contain a hash reference to refer to the other relation's relations.
1918 package MyApp::Schema::Track;
1919 use base qw/DBIx::Class/;
1920 __PACKAGE__->table('track');
1921 __PACKAGE__->add_columns(qw/trackid cd position title/);
1922 __PACKAGE__->set_primary_key('trackid');
1923 __PACKAGE__->belongs_to(cd => 'MyApp::Schema::CD');
1926 # In your application
1927 my $rs = $schema->resultset('Artist')->search(
1928 { 'track.title' => 'Teardrop' },
1930 join => { cd => 'track' },
1931 order_by => 'artist.name',
1935 You need to use the relationship (not the table) name in conditions,
1936 because they are aliased as such. The current table is aliased as "me", so
1937 you need to use me.column_name in order to avoid ambiguity. For example:
1939 # Get CDs from 1984 with a 'Foo' track
1940 my $rs = $schema->resultset('CD')->search(
1943 'tracks.name' => 'Foo'
1945 { join => 'tracks' }
1948 If the same join is supplied twice, it will be aliased to <rel>_2 (and
1949 similarly for a third time). For e.g.
1951 my $rs = $schema->resultset('Artist')->search({
1952 'cds.title' => 'Down to Earth',
1953 'cds_2.title' => 'Popular',
1955 join => [ qw/cds cds/ ],
1958 will return a set of all artists that have both a cd with title 'Down
1959 to Earth' and a cd with title 'Popular'.
1961 If you want to fetch related objects from other tables as well, see C<prefetch>
1968 =item Value: ($rel_name | \@rel_names | \%rel_names)
1972 Contains one or more relationships that should be fetched along with the main
1973 query (when they are accessed afterwards they will have already been
1974 "prefetched"). This is useful for when you know you will need the related
1975 objects, because it saves at least one query:
1977 my $rs = $schema->resultset('Tag')->search(
1986 The initial search results in SQL like the following:
1988 SELECT tag.*, cd.*, artist.* FROM tag
1989 JOIN cd ON tag.cd = cd.cdid
1990 JOIN artist ON cd.artist = artist.artistid
1992 L<DBIx::Class> has no need to go back to the database when we access the
1993 C<cd> or C<artist> relationships, which saves us two SQL statements in this
1996 Simple prefetches will be joined automatically, so there is no need
1997 for a C<join> attribute in the above search. If you're prefetching to
1998 depth (e.g. { cd => { artist => 'label' } or similar), you'll need to
1999 specify the join as well.
2001 C<prefetch> can be used with the following relationship types: C<belongs_to>,
2002 C<has_one> (or if you're using C<add_relationship>, any relationship declared
2003 with an accessor type of 'single' or 'filter').
2013 Makes the resultset paged and specifies the page to retrieve. Effectively
2014 identical to creating a non-pages resultset and then calling ->page($page)
2017 If L<rows> attribute is not specified it defualts to 10 rows per page.
2027 Specifes the maximum number of rows for direct retrieval or the number of
2028 rows per page if the page attribute or method is used.
2034 =item Value: $offset
2038 Specifies the (zero-based) row number for the first row to be returned, or the
2039 of the first row of the first page if paging is used.
2045 =item Value: \@columns
2049 A arrayref of columns to group by. Can include columns of joined tables.
2051 group_by => [qw/ column1 column2 ... /]
2057 =item Value: $condition
2061 HAVING is a select statement attribute that is applied between GROUP BY and
2062 ORDER BY. It is applied to the after the grouping calculations have been
2065 having => { 'count(employee)' => { '>=', 100 } }
2071 =item Value: (0 | 1)
2075 Set to 1 to group by all columns.
2081 Adds to the WHERE clause.
2083 # only return rows WHERE deleted IS NULL for all searches
2084 __PACKAGE__->resultset_attributes({ where => { deleted => undef } }); )
2086 Can be overridden by passing C<{ where => undef }> as an attribute
2093 Set to 1 to cache search results. This prevents extra SQL queries if you
2094 revisit rows in your ResultSet:
2096 my $resultset = $schema->resultset('Artist')->search( undef, { cache => 1 } );
2098 while( my $artist = $resultset->next ) {
2102 $rs->first; # without cache, this would issue a query
2104 By default, searches are not cached.
2106 For more examples of using these attributes, see
2107 L<DBIx::Class::Manual::Cookbook>.
2113 =item Value: \@from_clause
2117 The C<from> attribute gives you manual control over the C<FROM> clause of SQL
2118 statements generated by L<DBIx::Class>, allowing you to express custom C<JOIN>
2121 NOTE: Use this on your own risk. This allows you to shoot off your foot!
2123 C<join> will usually do what you need and it is strongly recommended that you
2124 avoid using C<from> unless you cannot achieve the desired result using C<join>.
2125 And we really do mean "cannot", not just tried and failed. Attempting to use
2126 this because you're having problems with C<join> is like trying to use x86
2127 ASM because you've got a syntax error in your C. Trust us on this.
2129 Now, if you're still really, really sure you need to use this (and if you're
2130 not 100% sure, ask the mailing list first), here's an explanation of how this
2133 The syntax is as follows -
2136 { <alias1> => <table1> },
2138 { <alias2> => <table2>, -join_type => 'inner|left|right' },
2139 [], # nested JOIN (optional)
2140 { <table1.column1> => <table2.column2>, ... (more conditions) },
2142 # More of the above [ ] may follow for additional joins
2149 ON <table1.column1> = <table2.column2>
2150 <more joins may follow>
2152 An easy way to follow the examples below is to remember the following:
2154 Anything inside "[]" is a JOIN
2155 Anything inside "{}" is a condition for the enclosing JOIN
2157 The following examples utilize a "person" table in a family tree application.
2158 In order to express parent->child relationships, this table is self-joined:
2160 # Person->belongs_to('father' => 'Person');
2161 # Person->belongs_to('mother' => 'Person');
2163 C<from> can be used to nest joins. Here we return all children with a father,
2164 then search against all mothers of those children:
2166 $rs = $schema->resultset('Person')->search(
2169 alias => 'mother', # alias columns in accordance with "from"
2171 { mother => 'person' },
2174 { child => 'person' },
2176 { father => 'person' },
2177 { 'father.person_id' => 'child.father_id' }
2180 { 'mother.person_id' => 'child.mother_id' }
2187 # SELECT mother.* FROM person mother
2190 # JOIN person father
2191 # ON ( father.person_id = child.father_id )
2193 # ON ( mother.person_id = child.mother_id )
2195 The type of any join can be controlled manually. To search against only people
2196 with a father in the person table, we could explicitly use C<INNER JOIN>:
2198 $rs = $schema->resultset('Person')->search(
2201 alias => 'child', # alias columns in accordance with "from"
2203 { child => 'person' },
2205 { father => 'person', -join_type => 'inner' },
2206 { 'father.id' => 'child.father_id' }
2213 # SELECT child.* FROM person child
2214 # INNER JOIN person father ON child.father_id = father.id