1 package DBIx::Class::ResultSet;
12 use base qw/DBIx::Class/;
13 __PACKAGE__->load_components(qw/AccessorGroup/);
14 __PACKAGE__->mk_group_accessors('simple' => 'result_source');
18 DBIx::Class::ResultSet - Responsible for fetching and creating resultset.
22 my $rs = $schema->resultset('User')->search(registered => 1);
23 my @rows = $schema->resultset('Foo')->search(bar => 'baz');
27 The resultset is also known as an iterator. It is responsible for handling
28 queries that may return an arbitrary number of rows, e.g. via L</search>
29 or a C<has_many> relationship.
31 In the examples below, the following table classes are used:
33 package MyApp::Schema::Artist;
34 use base qw/DBIx::Class/;
35 __PACKAGE__->table('artist');
36 __PACKAGE__->add_columns(qw/artistid name/);
37 __PACKAGE__->set_primary_key('artistid');
38 __PACKAGE__->has_many(cds => 'MyApp::Schema::CD');
41 package MyApp::Schema::CD;
42 use base qw/DBIx::Class/;
43 __PACKAGE__->table('artist');
44 __PACKAGE__->add_columns(qw/cdid artist title year/);
45 __PACKAGE__->set_primary_key('cdid');
46 __PACKAGE__->belongs_to(artist => 'MyApp::Schema::Artist');
53 =head3 Arguments: ($source, \%$attrs)
55 The resultset constructor. Takes a source object (usually a
56 L<DBIx::Class::ResultSourceProxy::Table>) and an attribute hash (see L</ATRRIBUTES>
57 below). Does not perform any queries -- these are executed as needed by the
60 Generally you won't need to construct a resultset manually. You'll
61 automatically get one from e.g. a L</search> called in scalar context:
63 my $rs = $schema->resultset('CD')->search({ title => '100th Window' });
69 return $class->new_result(@_) if ref $class;
70 my ($source, $attrs) = @_;
71 #use Data::Dumper; warn Dumper($attrs);
72 $attrs = Storable::dclone($attrs || {}); # { %{ $attrs || {} } };
74 my $alias = ($attrs->{alias} ||= 'me');
75 if ($attrs->{cols} || !$attrs->{select}) {
76 delete $attrs->{as} if $attrs->{cols};
77 my @cols = ($attrs->{cols}
78 ? @{delete $attrs->{cols}}
80 $attrs->{select} = [ map { m/\./ ? $_ : "${alias}.$_" } @cols ];
82 $attrs->{as} ||= [ map { m/^$alias\.(.*)$/ ? $1 : $_ } @{$attrs->{select}} ];
83 if (my $include = delete $attrs->{include_columns}) {
84 push(@{$attrs->{select}}, @$include);
85 push(@{$attrs->{as}}, map { m/([^\.]+)$/; $1; } @$include);
87 #use Data::Dumper; warn Dumper(@{$attrs}{qw/select as/});
88 $attrs->{from} ||= [ { $alias => $source->from } ];
89 $attrs->{seen_join} ||= {};
90 if (my $join = delete $attrs->{join}) {
91 foreach my $j (ref $join eq 'ARRAY'
92 ? (@{$join}) : ($join)) {
93 if (ref $j eq 'HASH') {
94 $seen{$_} = 1 foreach keys %$j;
99 push(@{$attrs->{from}}, $source->resolve_join($join, $attrs->{alias}, $attrs->{seen_join}));
101 $attrs->{group_by} ||= $attrs->{select} if delete $attrs->{distinct};
103 if (my $prefetch = delete $attrs->{prefetch}) {
104 foreach my $p (ref $prefetch eq 'ARRAY'
105 ? (@{$prefetch}) : ($prefetch)) {
106 if( ref $p eq 'HASH' ) {
107 foreach my $key (keys %$p) {
108 push(@{$attrs->{from}}, $source->resolve_join($p, $attrs->{alias}))
113 push(@{$attrs->{from}}, $source->resolve_join($p, $attrs->{alias}))
116 my @prefetch = $source->resolve_prefetch($p, $attrs->{alias});
118 push(@{$attrs->{select}}, map { $_->[0] } @prefetch);
119 push(@{$attrs->{as}}, map { $_->[1] } @prefetch);
123 if ($attrs->{page}) {
124 $attrs->{rows} ||= 10;
125 $attrs->{offset} ||= 0;
126 $attrs->{offset} += ($attrs->{rows} * ($attrs->{page} - 1));
129 result_source => $source,
130 cond => $attrs->{where},
131 from => $attrs->{from},
133 page => delete $attrs->{page},
136 bless ($new, $class);
142 my @obj = $rs->search({ foo => 3 }); # "... WHERE foo = 3"
143 my $new_rs = $rs->search({ foo => 3 });
145 If you need to pass in additional attributes but no additional condition,
146 call it as C<search({}, \%attrs);>.
148 # "SELECT foo, bar FROM $class_table"
149 my @all = $class->search({}, { cols => [qw/foo bar/] });
156 #use Data::Dumper;warn Dumper(@_);
158 my $attrs = { %{$self->{attrs}} };
159 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
160 $attrs = { %$attrs, %{ pop(@_) } };
163 my $where = (@_ ? ((@_ == 1 || ref $_[0] eq "HASH") ? shift : {@_}) : undef());
164 if (defined $where) {
165 $where = (defined $attrs->{where}
167 [ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
168 $where, $attrs->{where} ] }
170 $attrs->{where} = $where;
173 my $rs = (ref $self)->new($self->result_source, $attrs);
175 return (wantarray ? $rs->all : $rs);
178 =head2 search_literal
180 my @obj = $rs->search_literal($literal_where_cond, @bind);
181 my $new_rs = $rs->search_literal($literal_where_cond, @bind);
183 Pass a literal chunk of SQL to be added to the conditional part of the
189 my ($self, $cond, @vals) = @_;
190 my $attrs = (ref $vals[$#vals] eq 'HASH' ? { %{ pop(@vals) } } : {});
191 $attrs->{bind} = [ @{$self->{attrs}{bind}||[]}, @vals ];
192 return $self->search(\$cond, $attrs);
197 =head3 Arguments: (@colvalues) | (\%cols, \%attrs?)
199 Finds a row based on its primary key or unique constraint. For example:
201 my $cd = $schema->resultset('CD')->find(5);
203 Also takes an optional C<key> attribute, to search by a specific key or unique
204 constraint. For example:
206 my $cd = $schema->resultset('CD')->find_or_create(
208 artist => 'Massive Attack',
209 title => 'Mezzanine',
211 { key => 'artist_title' }
214 See also L</find_or_create> and L</update_or_create>.
219 my ($self, @vals) = @_;
220 my $attrs = (@vals > 1 && ref $vals[$#vals] eq 'HASH' ? pop(@vals) : {});
222 my @cols = $self->result_source->primary_columns;
223 if (exists $attrs->{key}) {
224 my %uniq = $self->result_source->unique_constraints;
225 $self->( "Unknown key " . $attrs->{key} . " on " . $self->name )
226 unless exists $uniq{$attrs->{key}};
227 @cols = @{ $uniq{$attrs->{key}} };
229 #use Data::Dumper; warn Dumper($attrs, @vals, @cols);
230 $self->throw_exception( "Can't find unless a primary key or unique constraint is defined" )
234 if (ref $vals[0] eq 'HASH') {
235 $query = { %{$vals[0]} };
236 } elsif (@cols == @vals) {
238 @{$query}{@cols} = @vals;
242 foreach (keys %$query) {
244 $query->{$self->{attrs}{alias}.'.'.$_} = delete $query->{$_};
246 #warn Dumper($query);
247 return $self->search($query,$attrs)->next;
250 =head2 search_related
252 $rs->search_related('relname', $cond?, $attrs?);
254 Search the specified relationship. Optionally specify a condition for matching
260 my ($self, $rel, @rest) = @_;
261 my $rel_obj = $self->result_source->relationship_info($rel);
262 $self->throw_exception(
263 "No such relationship ${rel} in search_related")
265 my $rs = $self->search(undef, { join => $rel });
266 my $alias = ($rs->{attrs}{seen_join}{$rel} > 1
267 ? join('_', $rel, $rs->{attrs}{seen_join}{$rel})
269 return $self->result_source->schema->resultset($rel_obj->{class}
280 Returns a storage-driven cursor to the given resultset.
286 my ($attrs) = $self->{attrs};
287 $attrs = { %$attrs };
288 return $self->{cursor}
289 ||= $self->result_source->storage->select($self->{from}, $attrs->{select},
290 $attrs->{where},$attrs);
295 Perform a search, but use C<LIKE> instead of equality as the condition. Note
296 that this is simply a convenience method; you most likely want to use
297 L</search> with specific operators.
299 For more information, see L<DBIx::Class::Manual::Cookbook>.
306 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
309 my $query = ref $_[0] eq "HASH" ? { %{shift()} }: {@_};
310 $query->{$_} = { 'like' => $query->{$_} } for keys %$query;
311 return $class->search($query, { %$attrs });
316 =head3 Arguments: ($first, $last)
318 Returns a subset of elements from the resultset.
323 my ($self, $min, $max) = @_;
324 my $attrs = { %{ $self->{attrs} || {} } };
325 $attrs->{offset} ||= 0;
326 $attrs->{offset} += $min;
327 $attrs->{rows} = ($max ? ($max - $min + 1) : 1);
328 my $slice = (ref $self)->new($self->result_source, $attrs);
329 return (wantarray ? $slice->all : $slice);
334 Returns the next element in the resultset (C<undef> is there is none).
336 Can be used to efficiently iterate over records in the resultset:
338 my $rs = $schema->resultset('CD')->search({});
339 while (my $cd = $rs->next) {
347 my @row = $self->cursor->next;
348 # warn Dumper(\@row); use Data::Dumper;
349 return unless (@row);
350 return $self->_construct_object(@row);
353 sub _construct_object {
354 my ($self, @row) = @_;
355 my @as = @{ $self->{attrs}{as} };
356 #warn "@cols -> @row";
357 my $info = [ {}, {} ];
358 foreach my $as (@as) {
360 my @parts = split(/\./, $as);
361 my $col = pop(@parts);
362 foreach my $p (@parts) {
363 $target = $target->[1]->{$p} ||= [];
365 $target->[0]->{$col} = shift @row;
367 #use Data::Dumper; warn Dumper(\@as, $info);
368 my $new = $self->result_source->result_class->inflate_result(
369 $self->result_source, @$info);
370 $new = $self->{attrs}{record_filter}->($new)
371 if exists $self->{attrs}{record_filter};
377 Returns a reference to the result source for this recordset.
384 Performs an SQL C<COUNT> with the same query as the resultset was built
385 with to find the number of elements. If passed arguments, does a search
386 on the resultset and counts the results of that.
388 Note: When using C<count> with C<group_by>, L<DBIX::Class> emulates C<GROUP BY>
389 using C<COUNT( DISTINCT( columns ) )>. Some databases (notably SQLite) do
390 not support C<DISTINCT> with multiple columns. If you are using such a
391 database, you should only use columns from the main table in your C<group_by>
398 return $self->search(@_)->count if @_ && defined $_[0];
399 unless (defined $self->{count}) {
401 my $select = { 'count' => '*' };
402 if( $group_by = delete $self->{attrs}{group_by} ) {
403 my @distinct = (ref $group_by ? @$group_by : ($group_by));
404 # todo: try CONCAT for multi-column pk
405 my @pk = $self->result_source->primary_columns;
406 if( scalar(@pk) == 1 ) {
408 my $alias = $self->{attrs}{alias};
409 my $re = qr/^($alias\.)?$pk$/;
410 foreach my $column ( @distinct) {
411 if( $column =~ $re ) {
412 @distinct = ( $column );
418 $select = { count => { 'distinct' => \@distinct } };
419 #use Data::Dumper; die Dumper $select;
422 my $attrs = { %{ $self->{attrs} },
425 # offset, order by and page are not needed to count. record_filter is cdbi
426 delete $attrs->{$_} for qw/rows offset order_by page pager record_filter/;
428 ($self->{count}) = (ref $self)->new($self->result_source, $attrs)->cursor->next;
429 $self->{attrs}{group_by} = $group_by;
431 return 0 unless $self->{count};
432 my $count = $self->{count};
433 $count -= $self->{attrs}{offset} if $self->{attrs}{offset};
434 $count = $self->{attrs}{rows} if
435 ($self->{attrs}{rows} && $self->{attrs}{rows} < $count);
441 Calls L</search_literal> with the passed arguments, then L</count>.
445 sub count_literal { shift->search_literal(@_)->count; }
449 Returns all elements in the resultset. Called implictly if the resultset
450 is returned in list context.
456 return map { $self->_construct_object(@$_); }
462 Resets the resultset's cursor, so you can iterate through the elements again.
468 $self->cursor->reset;
474 Resets the resultset and returns the first element.
479 return $_[0]->reset->next;
484 =head3 Arguments: (\%values)
486 Sets the specified columns in the resultset to the supplied values.
491 my ($self, $values) = @_;
492 $self->throw_exception("Values for update must be a hash") unless ref $values eq 'HASH';
493 return $self->result_source->storage->update(
494 $self->result_source->from, $values, $self->{cond});
499 =head3 Arguments: (\%values)
501 Fetches all objects and updates them one at a time. Note that C<update_all>
502 will run cascade triggers while L</update> will not.
507 my ($self, $values) = @_;
508 $self->throw_exception("Values for update must be a hash") unless ref $values eq 'HASH';
509 foreach my $obj ($self->all) {
510 $obj->set_columns($values)->update;
517 Deletes the contents of the resultset from its result source.
524 $self->throw_exception("Can't delete on resultset with condition unless hash or array")
525 unless (ref($self->{cond}) eq 'HASH' || ref($self->{cond}) eq 'ARRAY');
526 if (ref $self->{cond} eq 'ARRAY') {
527 $del = [ map { my %hash;
528 foreach my $key (keys %{$_}) {
530 $hash{$1} = $_->{$key};
531 }; \%hash; } @{$self->{cond}} ];
532 } elsif ((keys %{$self->{cond}})[0] eq '-and') {
533 $del->{-and} = [ map { my %hash;
534 foreach my $key (keys %{$_}) {
536 $hash{$1} = $_->{$key};
537 }; \%hash; } @{$self->{cond}{-and}} ];
539 foreach my $key (keys %{$self->{cond}}) {
541 $del->{$1} = $self->{cond}{$key};
544 $self->result_source->storage->delete($self->result_source->from, $del);
550 Fetches all objects and deletes them one at a time. Note that C<delete_all>
551 will run cascade triggers while L</delete> will not.
557 $_->delete for $self->all;
563 Returns a L<Data::Page> object for the current resultset. Only makes
564 sense for queries with a C<page> attribute.
570 my $attrs = $self->{attrs};
571 $self->throw_exception("Can't create pager for non-paged rs") unless $self->{page};
572 $attrs->{rows} ||= 10;
574 return $self->{pager} ||= Data::Page->new(
575 $self->{count}, $attrs->{rows}, $self->{page});
580 =head3 Arguments: ($page_num)
582 Returns a new resultset for the specified page.
587 my ($self, $page) = @_;
588 my $attrs = { %{$self->{attrs}} };
589 $attrs->{page} = $page;
590 return (ref $self)->new($self->result_source, $attrs);
595 =head3 Arguments: (\%vals)
597 Creates a result in the resultset's result class.
602 my ($self, $values) = @_;
603 $self->throw_exception( "new_result needs a hash" )
604 unless (ref $values eq 'HASH');
605 $self->throw_exception( "Can't abstract implicit construct, condition not a hash" )
606 if ($self->{cond} && !(ref $self->{cond} eq 'HASH'));
608 my $alias = $self->{attrs}{alias};
609 foreach my $key (keys %{$self->{cond}||{}}) {
610 $new{$1} = $self->{cond}{$key} if ($key =~ m/^(?:$alias\.)?([^\.]+)$/);
612 my $obj = $self->result_source->result_class->new(\%new);
613 $obj->result_source($self->result_source) if $obj->can('result_source');
619 =head3 Arguments: (\%vals)
621 Inserts a record into the resultset and returns the object.
623 Effectively a shortcut for C<< ->new_result(\%vals)->insert >>.
628 my ($self, $attrs) = @_;
629 $self->throw_exception( "create needs a hashref" ) unless ref $attrs eq 'HASH';
630 return $self->new_result($attrs)->insert;
633 =head2 find_or_create
635 =head3 Arguments: (\%vals, \%attrs?)
637 $class->find_or_create({ key => $val, ... });
639 Searches for a record matching the search condition; if it doesn't find one,
640 creates one and returns that instead.
642 my $cd = $schema->resultset('CD')->find_or_create({
644 artist => 'Massive Attack',
645 title => 'Mezzanine',
649 Also takes an optional C<key> attribute, to search by a specific key or unique
650 constraint. For example:
652 my $cd = $schema->resultset('CD')->find_or_create(
654 artist => 'Massive Attack',
655 title => 'Mezzanine',
657 { key => 'artist_title' }
660 See also L</find> and L</update_or_create>.
666 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
667 my $hash = ref $_[0] eq "HASH" ? shift : {@_};
668 my $exists = $self->find($hash, $attrs);
669 return defined($exists) ? $exists : $self->create($hash);
672 =head2 update_or_create
674 $class->update_or_create({ key => $val, ... });
676 First, search for an existing row matching one of the unique constraints
677 (including the primary key) on the source of this resultset. If a row is
678 found, update it with the other given column values. Otherwise, create a new
681 Takes an optional C<key> attribute to search on a specific unique constraint.
684 # In your application
685 my $cd = $schema->resultset('CD')->update_or_create(
687 artist => 'Massive Attack',
688 title => 'Mezzanine',
691 { key => 'artist_title' }
694 If no C<key> is specified, it searches on all unique constraints defined on the
695 source, including the primary key.
697 If the C<key> is specified as C<primary>, search only on the primary key.
699 See also L</find> and L</find_or_create>.
703 sub update_or_create {
706 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
707 my $hash = ref $_[0] eq "HASH" ? shift : {@_};
709 my %unique_constraints = $self->result_source->unique_constraints;
710 my @constraint_names = (exists $attrs->{key}
712 : keys %unique_constraints);
715 foreach my $name (@constraint_names) {
716 my @unique_cols = @{ $unique_constraints{$name} };
718 map { $_ => $hash->{$_} }
719 grep { exists $hash->{$_} }
722 push @unique_hashes, \%unique_hash
723 if (scalar keys %unique_hash == scalar @unique_cols);
727 if (@unique_hashes) {
728 $row = $self->search(\@unique_hashes, { rows => 1 })->first;
730 $row->set_columns($hash);
736 $row = $self->create($hash);
742 =head2 throw_exception
744 See Schema's throw_exception
748 sub throw_exception {
750 $self->result_source->schema->throw_exception(@_);
755 The resultset takes various attributes that modify its behavior. Here's an
760 Which column(s) to order the results by. This is currently passed through
761 directly to SQL, so you can give e.g. C<foo DESC> for a descending order.
765 =head3 Arguments: (arrayref)
767 Shortcut to request a particular set of columns to be retrieved. Adds
768 C<me.> onto the start of any column without a C<.> in it and sets C<select>
769 from that, then auto-populates C<as> from C<select> as normal.
771 =head2 include_columns
773 =head3 Arguments: (arrayref)
775 Shortcut to include additional columns in the returned results - for example
777 { include_columns => ['foo.name'], join => ['foo'] }
779 would add a 'name' column to the information passed to object inflation
783 =head3 Arguments: (arrayref)
785 Indicates which columns should be selected from the storage. You can use
786 column names, or in the case of RDBMS back ends, function or stored procedure
789 $rs = $schema->resultset('Foo')->search(
794 { count => 'column_to_count' },
795 { sum => 'column_to_sum' }
800 When you use function/stored procedure names and do not supply an C<as>
801 attribute, the column names returned are storage-dependent. E.g. MySQL would
802 return a column named C<count(column_to_count)> in the above example.
806 =head3 Arguments: (arrayref)
808 Indicates column names for object inflation. This is used in conjunction with
809 C<select>, usually when C<select> contains one or more function or stored
812 $rs = $schema->resultset('Foo')->search(
817 { count => 'column2' }
819 as => [qw/ column1 column2_count /]
823 my $foo = $rs->first(); # get the first Foo
825 If the object against which the search is performed already has an accessor
826 matching a column name specified in C<as>, the value can be retrieved using
827 the accessor as normal:
829 my $column1 = $foo->column1();
831 If on the other hand an accessor does not exist in the object, you need to
832 use C<get_column> instead:
834 my $column2_count = $foo->get_column('column2_count');
836 You can create your own accessors if required - see
837 L<DBIx::Class::Manual::Cookbook> for details.
841 Contains a list of relationships that should be joined for this query. For
844 # Get CDs by Nine Inch Nails
845 my $rs = $schema->resultset('CD')->search(
846 { 'artist.name' => 'Nine Inch Nails' },
850 Can also contain a hash reference to refer to the other relation's relations.
853 package MyApp::Schema::Track;
854 use base qw/DBIx::Class/;
855 __PACKAGE__->table('track');
856 __PACKAGE__->add_columns(qw/trackid cd position title/);
857 __PACKAGE__->set_primary_key('trackid');
858 __PACKAGE__->belongs_to(cd => 'MyApp::Schema::CD');
861 # In your application
862 my $rs = $schema->resultset('Artist')->search(
863 { 'track.title' => 'Teardrop' },
865 join => { cd => 'track' },
866 order_by => 'artist.name',
870 If the same join is supplied twice, it will be aliased to <rel>_2 (and
871 similarly for a third time). For e.g.
873 my $rs = $schema->resultset('Artist')->search(
874 { 'cds.title' => 'Foo',
875 'cds_2.title' => 'Bar' },
876 { join => [ qw/cds cds/ ] });
878 will return a set of all artists that have both a cd with title Foo and a cd
881 If you want to fetch related objects from other tables as well, see C<prefetch>
886 =head3 Arguments: arrayref/hashref
888 Contains one or more relationships that should be fetched along with the main
889 query (when they are accessed afterwards they will have already been
890 "prefetched"). This is useful for when you know you will need the related
891 objects, because it saves at least one query:
893 my $rs = $schema->resultset('Tag')->search(
902 The initial search results in SQL like the following:
904 SELECT tag.*, cd.*, artist.* FROM tag
905 JOIN cd ON tag.cd = cd.cdid
906 JOIN artist ON cd.artist = artist.artistid
908 L<DBIx::Class> has no need to go back to the database when we access the
909 C<cd> or C<artist> relationships, which saves us two SQL statements in this
912 Simple prefetches will be joined automatically, so there is no need
913 for a C<join> attribute in the above search. If you're prefetching to
914 depth (e.g. { cd => { artist => 'label' } or similar), you'll need to
915 specify the join as well.
917 C<prefetch> can be used with the following relationship types: C<belongs_to>,
918 C<has_one> (or if you're using C<add_relationship>, any relationship declared
919 with an accessor type of 'single' or 'filter').
923 =head3 Arguments: (arrayref)
925 The C<from> attribute gives you manual control over the C<FROM> clause of SQL
926 statements generated by L<DBIx::Class>, allowing you to express custom C<JOIN>
929 NOTE: Use this on your own risk. This allows you to shoot off your foot!
930 C<join> will usually do what you need and it is strongly recommended that you
931 avoid using C<from> unless you cannot achieve the desired result using C<join>.
933 In simple terms, C<from> works as follows:
936 { <alias> => <table>, -join-type => 'inner|left|right' }
937 [] # nested JOIN (optional)
938 { <table.column> = <foreign_table.foreign_key> }
944 ON <table.column> = <foreign_table.foreign_key>
946 An easy way to follow the examples below is to remember the following:
948 Anything inside "[]" is a JOIN
949 Anything inside "{}" is a condition for the enclosing JOIN
951 The following examples utilize a "person" table in a family tree application.
952 In order to express parent->child relationships, this table is self-joined:
954 # Person->belongs_to('father' => 'Person');
955 # Person->belongs_to('mother' => 'Person');
957 C<from> can be used to nest joins. Here we return all children with a father,
958 then search against all mothers of those children:
960 $rs = $schema->resultset('Person')->search(
963 alias => 'mother', # alias columns in accordance with "from"
965 { mother => 'person' },
968 { child => 'person' },
970 { father => 'person' },
971 { 'father.person_id' => 'child.father_id' }
974 { 'mother.person_id' => 'child.mother_id' }
981 # SELECT mother.* FROM person mother
985 # ON ( father.person_id = child.father_id )
987 # ON ( mother.person_id = child.mother_id )
989 The type of any join can be controlled manually. To search against only people
990 with a father in the person table, we could explicitly use C<INNER JOIN>:
992 $rs = $schema->resultset('Person')->search(
995 alias => 'child', # alias columns in accordance with "from"
997 { child => 'person' },
999 { father => 'person', -join-type => 'inner' },
1000 { 'father.id' => 'child.father_id' }
1007 # SELECT child.* FROM person child
1008 # INNER JOIN person father ON child.father_id = father.id
1012 For a paged resultset, specifies which page to retrieve. Leave unset
1013 for an unpaged resultset.
1017 For a paged resultset, how many rows per page:
1021 Can also be used to simulate an SQL C<LIMIT>.
1025 =head3 Arguments: (arrayref)
1027 A arrayref of columns to group by. Can include columns of joined tables.
1029 group_by => [qw/ column1 column2 ... /]
1033 Set to 1 to group by all columns.
1035 For more examples of using these attributes, see
1036 L<DBIx::Class::Manual::Cookbook>.