Docs!
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / ResultSet.pm
CommitLineData
89c0a5a2 1package DBIx::Class::ResultSet;
2
3use strict;
4use warnings;
5use overload
ebaefbc2 6 '0+' => \&count,
a910dc57 7 'bool' => sub { 1; },
89c0a5a2 8 fallback => 1;
3c5b25c5 9use Data::Page;
ea20d0fd 10use Storable;
bcd26419 11use Scalar::Util qw/weaken/;
89c0a5a2 12
701da8c4 13use base qw/DBIx::Class/;
14__PACKAGE__->load_components(qw/AccessorGroup/);
a50bcd52 15__PACKAGE__->mk_group_accessors('simple' => qw/result_source result_class/);
701da8c4 16
ee38fa40 17=head1 NAME
18
bfab575a 19DBIx::Class::ResultSet - Responsible for fetching and creating resultset.
ee38fa40 20
bfab575a 21=head1 SYNOPSIS
ee38fa40 22
a33df5d4 23 my $rs = $schema->resultset('User')->search(registered => 1);
24d67825 24 my @rows = $schema->resultset('CD')->search(year => 2005);
ee38fa40 25
26=head1 DESCRIPTION
27
bfab575a 28The resultset is also known as an iterator. It is responsible for handling
a33df5d4 29queries that may return an arbitrary number of rows, e.g. via L</search>
bfab575a 30or a C<has_many> relationship.
ee38fa40 31
a33df5d4 32In the examples below, the following table classes are used:
33
34 package MyApp::Schema::Artist;
35 use base qw/DBIx::Class/;
f4409169 36 __PACKAGE__->load_components(qw/Core/);
a33df5d4 37 __PACKAGE__->table('artist');
38 __PACKAGE__->add_columns(qw/artistid name/);
39 __PACKAGE__->set_primary_key('artistid');
40 __PACKAGE__->has_many(cds => 'MyApp::Schema::CD');
41 1;
42
43 package MyApp::Schema::CD;
44 use base qw/DBIx::Class/;
f4409169 45 __PACKAGE__->load_components(qw/Core/);
46 __PACKAGE__->table('cd');
a33df5d4 47 __PACKAGE__->add_columns(qw/cdid artist title year/);
48 __PACKAGE__->set_primary_key('cdid');
49 __PACKAGE__->belongs_to(artist => 'MyApp::Schema::Artist');
50 1;
51
ee38fa40 52=head1 METHODS
53
87c4e602 54=head2 new
55
27f01d1f 56=over 4
57
58=item Arguments: ($source, \%$attrs)
59
60=back
ee38fa40 61
a33df5d4 62The resultset constructor. Takes a source object (usually a
aa1088bf 63L<DBIx::Class::ResultSourceProxy::Table>) and an attribute hash (see
64L</ATTRIBUTES> below). Does not perform any queries -- these are
65executed as needed by the other methods.
a33df5d4 66
67Generally you won't need to construct a resultset manually. You'll
68automatically get one from e.g. a L</search> called in scalar context:
69
70 my $rs = $schema->resultset('CD')->search({ title => '100th Window' });
ee38fa40 71
72=cut
73
89c0a5a2 74sub new {
fea3d045 75 my $class = shift;
f9db5527 76 return $class->new_result(@_) if ref $class;
5e8b1b2a 77
fea3d045 78 my ($source, $attrs) = @_;
bcd26419 79 weaken $source;
ea20d0fd 80 $attrs = Storable::dclone($attrs || {}); # { %{ $attrs || {} } };
bcd26419 81 #use Data::Dumper; warn Dumper($attrs);
6aeb9185 82 my $alias = ($attrs->{alias} ||= 'me');
5e8b1b2a 83
84 $attrs->{columns} ||= delete $attrs->{cols} if $attrs->{cols};
1c258fc1 85 delete $attrs->{as} if $attrs->{columns};
5e8b1b2a 86 $attrs->{columns} ||= [ $source->columns ] unless $attrs->{select};
aa1088bf 87 $attrs->{select} = [
88 map { m/\./ ? $_ : "${alias}.$_" } @{delete $attrs->{columns}}
89 ] if $attrs->{columns};
90 $attrs->{as} ||= [
91 map { m/^\Q$alias.\E(.+)$/ ? $1 : $_ } @{$attrs->{select}}
92 ];
5ac6a044 93 if (my $include = delete $attrs->{include_columns}) {
94 push(@{$attrs->{select}}, @$include);
223aea40 95 push(@{$attrs->{as}}, map { m/([^.]+)$/; $1; } @$include);
5ac6a044 96 }
976f3686 97 #use Data::Dumper; warn Dumper(@{$attrs}{qw/select as/});
5e8b1b2a 98
fea3d045 99 $attrs->{from} ||= [ { $alias => $source->from } ];
8fab5eef 100 $attrs->{seen_join} ||= {};
5e8b1b2a 101 my %seen;
b52e9bf8 102 if (my $join = delete $attrs->{join}) {
5e8b1b2a 103 foreach my $j (ref $join eq 'ARRAY' ? @$join : ($join)) {
c7ce65e6 104 if (ref $j eq 'HASH') {
105 $seen{$_} = 1 foreach keys %$j;
106 } else {
107 $seen{$j} = 1;
108 }
109 }
aa1088bf 110 push(@{$attrs->{from}}, $source->resolve_join(
111 $join, $attrs->{alias}, $attrs->{seen_join})
112 );
c7ce65e6 113 }
5e8b1b2a 114
54540863 115 $attrs->{group_by} ||= $attrs->{select} if delete $attrs->{distinct};
aa1088bf 116 $attrs->{order_by} = [ $attrs->{order_by} ] if
117 $attrs->{order_by} and !ref($attrs->{order_by});
a86b1efe 118 $attrs->{order_by} ||= [];
119
555af3d9 120 my $collapse = $attrs->{collapse} || {};
b3e8ac9b 121 if (my $prefetch = delete $attrs->{prefetch}) {
0f66a01b 122 my @pre_order;
5e8b1b2a 123 foreach my $p (ref $prefetch eq 'ARRAY' ? @$prefetch : ($prefetch)) {
124 if ( ref $p eq 'HASH' ) {
b3e8ac9b 125 foreach my $key (keys %$p) {
126 push(@{$attrs->{from}}, $source->resolve_join($p, $attrs->{alias}))
127 unless $seen{$key};
128 }
5e8b1b2a 129 } else {
b3e8ac9b 130 push(@{$attrs->{from}}, $source->resolve_join($p, $attrs->{alias}))
131 unless $seen{$p};
132 }
a86b1efe 133 my @prefetch = $source->resolve_prefetch(
0f66a01b 134 $p, $attrs->{alias}, {}, \@pre_order, $collapse);
489709af 135 push(@{$attrs->{select}}, map { $_->[0] } @prefetch);
136 push(@{$attrs->{as}}, map { $_->[1] } @prefetch);
b3e8ac9b 137 }
0f66a01b 138 push(@{$attrs->{order_by}}, @pre_order);
fef5d100 139 }
555af3d9 140 $attrs->{collapse} = $collapse;
5e8b1b2a 141# use Data::Dumper; warn Dumper($collapse) if keys %{$collapse};
555af3d9 142
6aeb9185 143 if ($attrs->{page}) {
144 $attrs->{rows} ||= 10;
145 $attrs->{offset} ||= 0;
146 $attrs->{offset} += ($attrs->{rows} * ($attrs->{page} - 1));
147 }
0f66a01b 148
5e8b1b2a 149 bless {
701da8c4 150 result_source => $source,
a50bcd52 151 result_class => $attrs->{result_class} || $source->result_class,
89c0a5a2 152 cond => $attrs->{where},
0a3c5b43 153 from => $attrs->{from},
0f66a01b 154 collapse => $collapse,
3c5b25c5 155 count => undef,
93b004d3 156 page => delete $attrs->{page},
3c5b25c5 157 pager => undef,
5e8b1b2a 158 attrs => $attrs
159 }, $class;
89c0a5a2 160}
161
bfab575a 162=head2 search
0a3c5b43 163
b2f17732 164=over 4
165
166=item Arguments: (\%cond?, \%attrs?)
167
168=item Returns: $resultset (scalar context), @row_objs (list context)
169
170=back
171
172 my @cds = $cd_rs->search({ year => 2001 }); # "... WHERE year = 2001"
173 my $new_rs = $cd_rs->search({ year => 2005 });
87f0da6a 174
6009260a 175If you need to pass in additional attributes but no additional condition,
5e8b1b2a 176call it as C<search(undef, \%attrs);>.
87f0da6a 177
24d67825 178 # "SELECT name, artistid FROM $artist_table"
179 my @all_artists = $schema->resultset('Artist')->search(undef, {
180 columns => [qw/name artistid/],
181 });
0a3c5b43 182
183=cut
184
185sub search {
186 my $self = shift;
187
ff7bb7a1 188 my $rs;
189 if( @_ ) {
190
191 my $attrs = { %{$self->{attrs}} };
8839560b 192 my $having = delete $attrs->{having};
223aea40 193 $attrs = { %$attrs, %{ pop(@_) } } if @_ > 1 and ref $_[$#_] eq 'HASH';
6009260a 194
3e0e9e27 195 my $where = (@_
196 ? ((@_ == 1 || ref $_[0] eq "HASH")
197 ? shift
198 : ((@_ % 2)
199 ? $self->throw_exception(
200 "Odd number of arguments to search")
201 : {@_}))
202 : undef());
ff7bb7a1 203 if (defined $where) {
223aea40 204 $attrs->{where} = (defined $attrs->{where}
ad3d2d7c 205 ? { '-and' =>
206 [ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
207 $where, $attrs->{where} ] }
0a3c5b43 208 : $where);
ff7bb7a1 209 }
0a3c5b43 210
8839560b 211 if (defined $having) {
223aea40 212 $attrs->{having} = (defined $attrs->{having}
8839560b 213 ? { '-and' =>
214 [ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
215 $having, $attrs->{having} ] }
216 : $having);
8839560b 217 }
218
ff7bb7a1 219 $rs = (ref $self)->new($self->result_source, $attrs);
220 }
221 else {
222 $rs = $self;
223aea40 223 $rs->reset;
ff7bb7a1 224 }
0a3c5b43 225 return (wantarray ? $rs->all : $rs);
226}
227
87f0da6a 228=head2 search_literal
229
b2f17732 230=over 4
231
232=item Arguments: ($literal_cond, @bind?)
233
234=item Returns: $resultset (scalar context), @row_objs (list context)
235
236=back
237
238 my @cds = $cd_rs->search_literal('year = ? AND title = ?', qw/2001 Reload/);
239 my $newrs = $artist_rs->search_literal('name = ?', 'Metallica');
6009260a 240
241Pass a literal chunk of SQL to be added to the conditional part of the
b2f17732 242resultset query.
6009260a 243
bfab575a 244=cut
fd9f5466 245
6009260a 246sub search_literal {
247 my ($self, $cond, @vals) = @_;
248 my $attrs = (ref $vals[$#vals] eq 'HASH' ? { %{ pop(@vals) } } : {});
249 $attrs->{bind} = [ @{$self->{attrs}{bind}||[]}, @vals ];
250 return $self->search(\$cond, $attrs);
251}
0a3c5b43 252
87c4e602 253=head2 find
254
27f01d1f 255=over 4
256
257=item Arguments: (@colvalues) | (\%cols, \%attrs?)
258
b2f17732 259=item Returns: $row_object
260
27f01d1f 261=back
87f0da6a 262
263Finds a row based on its primary key or unique constraint. For example:
264
87f0da6a 265 my $cd = $schema->resultset('CD')->find(5);
266
267Also takes an optional C<key> attribute, to search by a specific key or unique
268constraint. For example:
269
fd9f5466 270 my $cd = $schema->resultset('CD')->find(
87f0da6a 271 {
272 artist => 'Massive Attack',
273 title => 'Mezzanine',
274 },
275 { key => 'artist_title' }
276 );
277
a33df5d4 278See also L</find_or_create> and L</update_or_create>.
279
87f0da6a 280=cut
716b3d29 281
282sub find {
283 my ($self, @vals) = @_;
284 my $attrs = (@vals > 1 && ref $vals[$#vals] eq 'HASH' ? pop(@vals) : {});
87f0da6a 285
701da8c4 286 my @cols = $self->result_source->primary_columns;
87f0da6a 287 if (exists $attrs->{key}) {
701da8c4 288 my %uniq = $self->result_source->unique_constraints;
aa1088bf 289 $self->throw_exception(
290 "Unknown key $attrs->{key} on '" . $self->result_source->name . "'"
291 ) unless exists $uniq{$attrs->{key}};
87f0da6a 292 @cols = @{ $uniq{$attrs->{key}} };
293 }
294 #use Data::Dumper; warn Dumper($attrs, @vals, @cols);
aa1088bf 295 $self->throw_exception(
296 "Can't find unless a primary key or unique constraint is defined"
297 ) unless @cols;
87f0da6a 298
716b3d29 299 my $query;
300 if (ref $vals[0] eq 'HASH') {
01bc091e 301 $query = { %{$vals[0]} };
87f0da6a 302 } elsif (@cols == @vals) {
716b3d29 303 $query = {};
87f0da6a 304 @{$query}{@cols} = @vals;
716b3d29 305 } else {
306 $query = {@vals};
307 }
223aea40 308 foreach my $key (grep { ! m/\./ } keys %$query) {
309 $query->{"$self->{attrs}{alias}.$key"} = delete $query->{$key};
01bc091e 310 }
716b3d29 311 #warn Dumper($query);
8389d433 312
313 if (keys %$attrs) {
314 my $rs = $self->search($query,$attrs);
315 return keys %{$rs->{collapse}} ? $rs->next : $rs->single;
316 } else {
aa1088bf 317 return keys %{$self->{collapse}} ?
318 $self->search($query)->next :
319 $self->single($query);
8389d433 320 }
716b3d29 321}
322
b52e9bf8 323=head2 search_related
324
b2f17732 325=over 4
326
327=item Arguments: (\%cond?, \%attrs?)
328
329=item Returns: $new_resultset
b52e9bf8 330
b2f17732 331=back
332
333 $new_rs = $cd_rs->search_related('artist', {
334 name => 'Emo-R-Us',
335 });
336
337Search the specified relationship, optionally specify a condition and
338attributes for matching records. See L</ATTRIBUTES> for more information.
a33df5d4 339
b52e9bf8 340=cut
341
6aeb9185 342sub search_related {
64acc2bc 343 return shift->related_resultset(shift)->search(@_);
6aeb9185 344}
b52e9bf8 345
bfab575a 346=head2 cursor
ee38fa40 347
b2f17732 348=over 4
349
350=item Arguments: (none)
351
352=item Returns: $cursor
353
354=back
355
356Returns a storage-driven cursor to the given resultset. See
357L<DBIx::Class::Cursor> for more information.
ee38fa40 358
359=cut
360
73f58123 361sub cursor {
362 my ($self) = @_;
223aea40 363 my $attrs = { %{$self->{attrs}} };
73f58123 364 return $self->{cursor}
701da8c4 365 ||= $self->result_source->storage->select($self->{from}, $attrs->{select},
73f58123 366 $attrs->{where},$attrs);
367}
368
a04ab285 369=head2 single
370
b2f17732 371=over 4
372
373=item Arguments: (\%cond)
374
375=item Returns: $row_object
376
377=back
378
379 my $cd = $schema->resultset('CD')->single({ year => 2001 });
380
381Inflates the first result without creating a cursor.
a04ab285 382
383=cut
384
385sub single {
223aea40 386 my ($self, $where) = @_;
387 my $attrs = { %{$self->{attrs}} };
388 if ($where) {
a04ab285 389 if (defined $attrs->{where}) {
390 $attrs->{where} = {
223aea40 391 '-and' =>
392 [ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
393 $where, delete $attrs->{where} ]
a04ab285 394 };
395 } else {
223aea40 396 $attrs->{where} = $where;
a04ab285 397 }
398 }
399 my @data = $self->result_source->storage->select_single(
400 $self->{from}, $attrs->{select},
401 $attrs->{where},$attrs);
402 return (@data ? $self->_construct_object(@data) : ());
403}
404
405
87f0da6a 406=head2 search_like
407
b2f17732 408=over 4
409
410=item Arguments: (\%cond?, \%attrs?)
411
412=item Returns: $resultset (scalar context), @row_objs (list context)
413
414=back
415
416 # WHERE title LIKE '%blue%'
417 $cd_rs = $rs->search_like({ title => '%blue%'});
418
419Perform a search, but use C<LIKE> instead of C<=> as the condition. Note
420that this is simply a convenience method. You most likely want to use
a33df5d4 421L</search> with specific operators.
422
423For more information, see L<DBIx::Class::Manual::Cookbook>.
87f0da6a 424
425=cut
58a4bd18 426
427sub search_like {
223aea40 428 my $class = shift;
429 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
430 my $query = ref $_[0] eq 'HASH' ? { %{shift()} }: {@_};
58a4bd18 431 $query->{$_} = { 'like' => $query->{$_} } for keys %$query;
432 return $class->search($query, { %$attrs });
433}
434
87c4e602 435=head2 slice
436
27f01d1f 437=over 4
438
439=item Arguments: ($first, $last)
440
b2f17732 441=item Returns: $resultset (scalar context), @row_objs (list context)
442
27f01d1f 443=back
ee38fa40 444
bfab575a 445Returns a subset of elements from the resultset.
ee38fa40 446
447=cut
448
89c0a5a2 449sub slice {
450 my ($self, $min, $max) = @_;
451 my $attrs = { %{ $self->{attrs} || {} } };
6aeb9185 452 $attrs->{offset} ||= 0;
453 $attrs->{offset} += $min;
89c0a5a2 454 $attrs->{rows} = ($max ? ($max - $min + 1) : 1);
701da8c4 455 my $slice = (ref $self)->new($self->result_source, $attrs);
89c0a5a2 456 return (wantarray ? $slice->all : $slice);
457}
458
87f0da6a 459=head2 next
ee38fa40 460
a33df5d4 461Returns the next element in the resultset (C<undef> is there is none).
462
463Can be used to efficiently iterate over records in the resultset:
464
5e8b1b2a 465 my $rs = $schema->resultset('CD')->search;
a33df5d4 466 while (my $cd = $rs->next) {
467 print $cd->title;
468 }
ee38fa40 469
470=cut
471
89c0a5a2 472sub next {
473 my ($self) = @_;
223aea40 474 if (@{$self->{all_cache} || []}) {
64acc2bc 475 $self->{all_cache_position} ||= 0;
223aea40 476 return $self->{all_cache}->[$self->{all_cache_position}++];
64acc2bc 477 }
3e0e9e27 478 if ($self->{attrs}{cache}) {
0f66a01b 479 $self->{all_cache_position} = 1;
3e0e9e27 480 return ($self->all)[0];
481 }
aa1088bf 482 my @row = (exists $self->{stashed_row} ?
483 @{delete $self->{stashed_row}} :
484 $self->cursor->next
485 );
a953d8d9 486# warn Dumper(\@row); use Data::Dumper;
89c0a5a2 487 return unless (@row);
c7ce65e6 488 return $self->_construct_object(@row);
489}
490
491sub _construct_object {
492 my ($self, @row) = @_;
b3e8ac9b 493 my @as = @{ $self->{attrs}{as} };
223aea40 494
0f66a01b 495 my $info = $self->_collapse_result(\@as, \@row);
223aea40 496
a50bcd52 497 my $new = $self->result_class->inflate_result($self->result_source, @$info);
223aea40 498
33ce49d6 499 $new = $self->{attrs}{record_filter}->($new)
500 if exists $self->{attrs}{record_filter};
501 return $new;
89c0a5a2 502}
503
0f66a01b 504sub _collapse_result {
505 my ($self, $as, $row, $prefix) = @_;
506
507 my %const;
508
509 my @copy = @$row;
5a5bec6c 510 foreach my $this_as (@$as) {
511 my $val = shift @copy;
512 if (defined $prefix) {
513 if ($this_as =~ m/^\Q${prefix}.\E(.+)$/) {
514 my $remain = $1;
223aea40 515 $remain =~ /^(?:(.*)\.)?([^.]+)$/;
5a5bec6c 516 $const{$1||''}{$2} = $val;
517 }
518 } else {
223aea40 519 $this_as =~ /^(?:(.*)\.)?([^.]+)$/;
5a5bec6c 520 $const{$1||''}{$2} = $val;
0f66a01b 521 }
0f66a01b 522 }
523
0f66a01b 524 my $info = [ {}, {} ];
525 foreach my $key (keys %const) {
526 if (length $key) {
527 my $target = $info;
528 my @parts = split(/\./, $key);
529 foreach my $p (@parts) {
530 $target = $target->[1]->{$p} ||= [];
531 }
532 $target->[0] = $const{$key};
533 } else {
534 $info->[0] = $const{$key};
535 }
536 }
537
aa1088bf 538 my @collapse;
539 if (defined $prefix) {
540 @collapse = map {
541 m/^\Q${prefix}.\E(.+)$/ ? ($1) : ()
d2c26f3f 542 } keys %{$self->{collapse}}
aa1088bf 543 } else {
544 @collapse = keys %{$self->{collapse}};
d2c26f3f 545 };
aa1088bf 546
5a5bec6c 547 if (@collapse) {
548 my ($c) = sort { length $a <=> length $b } @collapse;
0f66a01b 549 my $target = $info;
0f66a01b 550 foreach my $p (split(/\./, $c)) {
5a5bec6c 551 $target = $target->[1]->{$p} ||= [];
0f66a01b 552 }
5a5bec6c 553 my $c_prefix = (defined($prefix) ? "${prefix}.${c}" : $c);
554 my @co_key = @{$self->{collapse}{$c_prefix}};
0f66a01b 555 my %co_check = map { ($_, $target->[0]->{$_}); } @co_key;
5a5bec6c 556 my $tree = $self->_collapse_result($as, $row, $c_prefix);
0f66a01b 557 my (@final, @raw);
5a5bec6c 558 while ( !(grep {
aa1088bf 559 !defined($tree->[0]->{$_}) ||
560 $co_check{$_} ne $tree->[0]->{$_}
5a5bec6c 561 } @co_key) ) {
0f66a01b 562 push(@final, $tree);
563 last unless (@raw = $self->cursor->next);
564 $row = $self->{stashed_row} = \@raw;
5a5bec6c 565 $tree = $self->_collapse_result($as, $row, $c_prefix);
566 #warn Data::Dumper::Dumper($tree, $row);
0f66a01b 567 }
223aea40 568 @$target = @final;
0f66a01b 569 }
570
0f66a01b 571 return $info;
572}
573
87c4e602 574=head2 result_source
701da8c4 575
576Returns a reference to the result source for this recordset.
577
578=cut
579
580
bfab575a 581=head2 count
ee38fa40 582
bfab575a 583Performs an SQL C<COUNT> with the same query as the resultset was built
6009260a 584with to find the number of elements. If passed arguments, does a search
585on the resultset and counts the results of that.
ee38fa40 586
bda4c2b8 587Note: When using C<count> with C<group_by>, L<DBIX::Class> emulates C<GROUP BY>
588using C<COUNT( DISTINCT( columns ) )>. Some databases (notably SQLite) do
589not support C<DISTINCT> with multiple columns. If you are using such a
590database, you should only use columns from the main table in your C<group_by>
591clause.
592
ee38fa40 593=cut
594
89c0a5a2 595sub count {
6009260a 596 my $self = shift;
223aea40 597 return $self->search(@_)->count if @_ and defined $_[0];
84e3c114 598 return scalar @{ $self->get_cache } if @{ $self->get_cache };
15c382be 599
84e3c114 600 my $count = $self->_count;
601 return 0 unless $count;
15c382be 602
6aeb9185 603 $count -= $self->{attrs}{offset} if $self->{attrs}{offset};
604 $count = $self->{attrs}{rows} if
223aea40 605 $self->{attrs}{rows} and $self->{attrs}{rows} < $count;
6aeb9185 606 return $count;
89c0a5a2 607}
608
84e3c114 609sub _count { # Separated out so pager can get the full count
610 my $self = shift;
611 my $select = { count => '*' };
612 my $attrs = { %{ $self->{attrs} } };
613 if (my $group_by = delete $attrs->{group_by}) {
614 delete $attrs->{having};
615 my @distinct = (ref $group_by ? @$group_by : ($group_by));
616 # todo: try CONCAT for multi-column pk
617 my @pk = $self->result_source->primary_columns;
618 if (@pk == 1) {
619 foreach my $column (@distinct) {
620 if ($column =~ qr/^(?:\Q$attrs->{alias}.\E)?$pk[0]$/) {
621 @distinct = ($column);
622 last;
623 }
624 }
625 }
626
627 $select = { count => { distinct => \@distinct } };
628 #use Data::Dumper; die Dumper $select;
629 }
630
631 $attrs->{select} = $select;
632 $attrs->{as} = [qw/count/];
633
634 # offset, order by and page are not needed to count. record_filter is cdbi
635 delete $attrs->{$_} for qw/rows offset order_by page pager record_filter/;
636
637 my ($count) = (ref $self)->new($self->result_source, $attrs)->cursor->next;
638 return $count;
639}
640
bfab575a 641=head2 count_literal
6009260a 642
b2f17732 643Counts the results in a literal query. Equivalent to calling L</search_literal>
644with the passed arguments, then L</count>.
6009260a 645
646=cut
647
648sub count_literal { shift->search_literal(@_)->count; }
649
bfab575a 650=head2 all
ee38fa40 651
880a1a0c 652Returns all elements in the resultset. Called implicitly if the resultset
bfab575a 653is returned in list context.
ee38fa40 654
655=cut
656
89c0a5a2 657sub all {
658 my ($self) = @_;
223aea40 659 return @{ $self->get_cache } if @{ $self->get_cache };
5a5bec6c 660
661 my @obj;
662
663 if (keys %{$self->{collapse}}) {
664 # Using $self->cursor->all is really just an optimisation.
665 # If we're collapsing has_many prefetches it probably makes
666 # very little difference, and this is cleaner than hacking
667 # _construct_object to survive the approach
5a5bec6c 668 $self->cursor->reset;
479ed423 669 my @row = $self->cursor->next;
670 while (@row) {
5a5bec6c 671 push(@obj, $self->_construct_object(@row));
479ed423 672 @row = (exists $self->{stashed_row}
673 ? @{delete $self->{stashed_row}}
674 : $self->cursor->next);
5a5bec6c 675 }
676 } else {
223aea40 677 @obj = map { $self->_construct_object(@$_) } $self->cursor->all;
64acc2bc 678 }
5a5bec6c 679
223aea40 680 $self->set_cache(\@obj) if $self->{attrs}{cache};
5a5bec6c 681 return @obj;
89c0a5a2 682}
683
bfab575a 684=head2 reset
ee38fa40 685
bfab575a 686Resets the resultset's cursor, so you can iterate through the elements again.
ee38fa40 687
688=cut
689
89c0a5a2 690sub reset {
691 my ($self) = @_;
64acc2bc 692 $self->{all_cache_position} = 0;
73f58123 693 $self->cursor->reset;
89c0a5a2 694 return $self;
695}
696
bfab575a 697=head2 first
ee38fa40 698
bfab575a 699Resets the resultset and returns the first element.
ee38fa40 700
701=cut
702
89c0a5a2 703sub first {
704 return $_[0]->reset->next;
705}
706
87c4e602 707=head2 update
708
27f01d1f 709=over 4
710
711=item Arguments: (\%values)
712
713=back
c01ab172 714
a33df5d4 715Sets the specified columns in the resultset to the supplied values.
c01ab172 716
717=cut
718
719sub update {
720 my ($self, $values) = @_;
aa1088bf 721 $self->throw_exception("Values for update must be a hash")
722 unless ref $values eq 'HASH';
701da8c4 723 return $self->result_source->storage->update(
27f01d1f 724 $self->result_source->from, $values, $self->{cond}
725 );
c01ab172 726}
727
87c4e602 728=head2 update_all
729
27f01d1f 730=over 4
731
732=item Arguments: (\%values)
733
734=back
c01ab172 735
a33df5d4 736Fetches all objects and updates them one at a time. Note that C<update_all>
737will run cascade triggers while L</update> will not.
c01ab172 738
739=cut
740
741sub update_all {
742 my ($self, $values) = @_;
aa1088bf 743 $self->throw_exception("Values for update must be a hash")
744 unless ref $values eq 'HASH';
c01ab172 745 foreach my $obj ($self->all) {
746 $obj->set_columns($values)->update;
747 }
748 return 1;
749}
750
bfab575a 751=head2 delete
ee38fa40 752
b2f17732 753Deletes the contents of the resultset from its result source. Note that this
754will not run cascade triggers. See L</delete_all> if you need triggers to run.
ee38fa40 755
756=cut
757
28927b50 758sub delete {
89c0a5a2 759 my ($self) = @_;
ca4b5ab7 760 my $del = {};
7ed3d6dc 761
762 if (!ref($self->{cond})) {
763
764 # No-op. No condition, we're deleting everything
765
766 } elsif (ref $self->{cond} eq 'ARRAY') {
767
ca4b5ab7 768 $del = [ map { my %hash;
769 foreach my $key (keys %{$_}) {
223aea40 770 $key =~ /([^.]+)$/;
ca4b5ab7 771 $hash{$1} = $_->{$key};
772 }; \%hash; } @{$self->{cond}} ];
7ed3d6dc 773
774 } elsif (ref $self->{cond} eq 'HASH') {
775
776 if ((keys %{$self->{cond}})[0] eq '-and') {
777
778 $del->{-and} = [ map { my %hash;
779 foreach my $key (keys %{$_}) {
780 $key =~ /([^.]+)$/;
781 $hash{$1} = $_->{$key};
782 }; \%hash; } @{$self->{cond}{-and}} ];
783
784 } else {
785
786 foreach my $key (keys %{$self->{cond}}) {
223aea40 787 $key =~ /([^.]+)$/;
7ed3d6dc 788 $del->{$1} = $self->{cond}{$key};
789 }
ca4b5ab7 790 }
27f01d1f 791
7ed3d6dc 792 } else {
793 $self->throw_exception(
27f01d1f 794 "Can't delete on resultset with condition unless hash or array"
795 );
ca4b5ab7 796 }
7ed3d6dc 797
ca4b5ab7 798 $self->result_source->storage->delete($self->result_source->from, $del);
89c0a5a2 799 return 1;
800}
801
c01ab172 802=head2 delete_all
803
a33df5d4 804Fetches all objects and deletes them one at a time. Note that C<delete_all>
805will run cascade triggers while L</delete> will not.
c01ab172 806
807=cut
808
809sub delete_all {
810 my ($self) = @_;
811 $_->delete for $self->all;
812 return 1;
813}
28927b50 814
bfab575a 815=head2 pager
ee38fa40 816
817Returns a L<Data::Page> object for the current resultset. Only makes
a33df5d4 818sense for queries with a C<page> attribute.
ee38fa40 819
820=cut
821
3c5b25c5 822sub pager {
823 my ($self) = @_;
824 my $attrs = $self->{attrs};
aa1088bf 825 $self->throw_exception("Can't create pager for non-paged rs")
826 unless $self->{page};
6aeb9185 827 $attrs->{rows} ||= 10;
6aeb9185 828 return $self->{pager} ||= Data::Page->new(
84e3c114 829 $self->_count, $attrs->{rows}, $self->{page});
3c5b25c5 830}
831
87c4e602 832=head2 page
833
27f01d1f 834=over 4
835
836=item Arguments: ($page_num)
837
838=back
ee38fa40 839
bfab575a 840Returns a new resultset for the specified page.
ee38fa40 841
842=cut
843
3c5b25c5 844sub page {
845 my ($self, $page) = @_;
6aeb9185 846 my $attrs = { %{$self->{attrs}} };
3c5b25c5 847 $attrs->{page} = $page;
701da8c4 848 return (ref $self)->new($self->result_source, $attrs);
fea3d045 849}
850
87c4e602 851=head2 new_result
852
27f01d1f 853=over 4
854
855=item Arguments: (\%vals)
856
857=back
fea3d045 858
87f0da6a 859Creates a result in the resultset's result class.
fea3d045 860
861=cut
862
863sub new_result {
864 my ($self, $values) = @_;
701da8c4 865 $self->throw_exception( "new_result needs a hash" )
fea3d045 866 unless (ref $values eq 'HASH');
aa1088bf 867 $self->throw_exception(
868 "Can't abstract implicit construct, condition not a hash"
869 ) if ($self->{cond} && !(ref $self->{cond} eq 'HASH'));
fea3d045 870 my %new = %$values;
871 my $alias = $self->{attrs}{alias};
872 foreach my $key (keys %{$self->{cond}||{}}) {
223aea40 873 $new{$1} = $self->{cond}{$key} if ($key =~ m/^(?:\Q${alias}.\E)?([^.]+)$/);
fea3d045 874 }
a50bcd52 875 my $obj = $self->result_class->new(\%new);
701da8c4 876 $obj->result_source($self->result_source) if $obj->can('result_source');
223aea40 877 return $obj;
fea3d045 878}
879
87c4e602 880=head2 create
881
27f01d1f 882=over 4
883
884=item Arguments: (\%vals)
885
886=back
fea3d045 887
87f0da6a 888Inserts a record into the resultset and returns the object.
fea3d045 889
a33df5d4 890Effectively a shortcut for C<< ->new_result(\%vals)->insert >>.
fea3d045 891
892=cut
893
894sub create {
895 my ($self, $attrs) = @_;
aa1088bf 896 $self->throw_exception( "create needs a hashref" )
897 unless ref $attrs eq 'HASH';
fea3d045 898 return $self->new_result($attrs)->insert;
3c5b25c5 899}
900
87c4e602 901=head2 find_or_create
902
27f01d1f 903=over 4
904
905=item Arguments: (\%vals, \%attrs?)
906
907=back
87f0da6a 908
909 $class->find_or_create({ key => $val, ... });
c2b15ecc 910
fd9f5466 911Searches for a record matching the search condition; if it doesn't find one,
912creates one and returns that instead.
87f0da6a 913
87f0da6a 914 my $cd = $schema->resultset('CD')->find_or_create({
915 cdid => 5,
916 artist => 'Massive Attack',
917 title => 'Mezzanine',
918 year => 2005,
919 });
920
921Also takes an optional C<key> attribute, to search by a specific key or unique
922constraint. For example:
923
924 my $cd = $schema->resultset('CD')->find_or_create(
925 {
926 artist => 'Massive Attack',
927 title => 'Mezzanine',
928 },
929 { key => 'artist_title' }
930 );
931
932See also L</find> and L</update_or_create>.
933
c2b15ecc 934=cut
935
936sub find_or_create {
937 my $self = shift;
87f0da6a 938 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
223aea40 939 my $hash = ref $_[0] eq 'HASH' ? shift : {@_};
87f0da6a 940 my $exists = $self->find($hash, $attrs);
223aea40 941 return defined $exists ? $exists : $self->create($hash);
c2b15ecc 942}
943
87f0da6a 944=head2 update_or_create
945
946 $class->update_or_create({ key => $val, ... });
947
948First, search for an existing row matching one of the unique constraints
949(including the primary key) on the source of this resultset. If a row is
950found, update it with the other given column values. Otherwise, create a new
951row.
952
953Takes an optional C<key> attribute to search on a specific unique constraint.
954For example:
955
956 # In your application
957 my $cd = $schema->resultset('CD')->update_or_create(
958 {
959 artist => 'Massive Attack',
960 title => 'Mezzanine',
961 year => 1998,
962 },
963 { key => 'artist_title' }
964 );
965
966If no C<key> is specified, it searches on all unique constraints defined on the
967source, including the primary key.
968
969If the C<key> is specified as C<primary>, search only on the primary key.
970
a33df5d4 971See also L</find> and L</find_or_create>.
972
87f0da6a 973=cut
974
975sub update_or_create {
976 my $self = shift;
87f0da6a 977 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
223aea40 978 my $hash = ref $_[0] eq 'HASH' ? shift : {@_};
87f0da6a 979
701da8c4 980 my %unique_constraints = $self->result_source->unique_constraints;
87f0da6a 981 my @constraint_names = (exists $attrs->{key}
982 ? ($attrs->{key})
983 : keys %unique_constraints);
984
985 my @unique_hashes;
986 foreach my $name (@constraint_names) {
987 my @unique_cols = @{ $unique_constraints{$name} };
988 my %unique_hash =
989 map { $_ => $hash->{$_} }
990 grep { exists $hash->{$_} }
991 @unique_cols;
992
993 push @unique_hashes, \%unique_hash
994 if (scalar keys %unique_hash == scalar @unique_cols);
995 }
996
87f0da6a 997 if (@unique_hashes) {
223aea40 998 my $row = $self->single(\@unique_hashes);
999 if (defined $row) {
87f0da6a 1000 $row->set_columns($hash);
1001 $row->update;
223aea40 1002 return $row;
87f0da6a 1003 }
1004 }
1005
223aea40 1006 return $self->create($hash);
87f0da6a 1007}
1008
64acc2bc 1009=head2 get_cache
1010
1011Gets the contents of the cache for the resultset.
1012
1013=cut
1014
1015sub get_cache {
223aea40 1016 shift->{all_cache} || [];
64acc2bc 1017}
1018
1019=head2 set_cache
1020
aa1088bf 1021Sets the contents of the cache for the resultset. Expects an arrayref
1022of objects of the same class as those produced by the resultset.
64acc2bc 1023
1024=cut
1025
1026sub set_cache {
1027 my ( $self, $data ) = @_;
1028 $self->throw_exception("set_cache requires an arrayref")
1029 if ref $data ne 'ARRAY';
a50bcd52 1030 my $result_class = $self->result_class;
64acc2bc 1031 foreach( @$data ) {
aa1088bf 1032 $self->throw_exception(
1033 "cannot cache object of type '$_', expected '$result_class'"
1034 ) if ref $_ ne $result_class;
64acc2bc 1035 }
1036 $self->{all_cache} = $data;
1037}
1038
1039=head2 clear_cache
1040
1041Clears the cache for the resultset.
1042
1043=cut
1044
1045sub clear_cache {
223aea40 1046 shift->set_cache([]);
64acc2bc 1047}
1048
1049=head2 related_resultset
1050
1051Returns a related resultset for the supplied relationship name.
1052
24d67825 1053 $artist_rs = $schema->resultset('CD')->related_resultset('Artist');
64acc2bc 1054
1055=cut
1056
1057sub related_resultset {
1058 my ( $self, $rel, @rest ) = @_;
1059 $self->{related_resultsets} ||= {};
223aea40 1060 return $self->{related_resultsets}{$rel} ||= do {
1061 #warn "fetching related resultset for rel '$rel'";
1062 my $rel_obj = $self->result_source->relationship_info($rel);
1063 $self->throw_exception(
1064 "search_related: result source '" . $self->result_source->name .
1065 "' has no such relationship ${rel}")
1066 unless $rel_obj; #die Dumper $self->{attrs};
1067
1068 my $rs = $self->search(undef, { join => $rel });
1069 my $alias = defined $rs->{attrs}{seen_join}{$rel}
1070 && $rs->{attrs}{seen_join}{$rel} > 1
1071 ? join('_', $rel, $rs->{attrs}{seen_join}{$rel})
1072 : $rel;
1073
64acc2bc 1074 $self->result_source->schema->resultset($rel_obj->{class}
1075 )->search( undef,
1076 { %{$rs->{attrs}},
1077 alias => $alias,
223aea40 1078 select => undef,
1079 as => undef }
1080 )->search(@rest);
1081 };
64acc2bc 1082}
1083
701da8c4 1084=head2 throw_exception
1085
1086See Schema's throw_exception
1087
1088=cut
1089
1090sub throw_exception {
1091 my $self=shift;
1092 $self->result_source->schema->throw_exception(@_);
1093}
1094
40dbc108 1095=head1 ATTRIBUTES
076652e8 1096
27f01d1f 1097XXX: FIXME: Attributes docs need clearing up
1098
a33df5d4 1099The resultset takes various attributes that modify its behavior. Here's an
1100overview of them:
bfab575a 1101
1102=head2 order_by
076652e8 1103
24d67825 1104Which column(s) to order the results by. This is currently passed
1105through directly to SQL, so you can give e.g. C<year DESC> for a
1106descending order on the column `year'.
076652e8 1107
5e8b1b2a 1108=head2 columns
87c4e602 1109
27f01d1f 1110=over 4
1111
1112=item Arguments: (\@columns)
1113
1114=back
976f3686 1115
a33df5d4 1116Shortcut to request a particular set of columns to be retrieved. Adds
1117C<me.> onto the start of any column without a C<.> in it and sets C<select>
5e8b1b2a 1118from that, then auto-populates C<as> from C<select> as normal. (You may also
1119use the C<cols> attribute, as in earlier versions of DBIC.)
976f3686 1120
87c4e602 1121=head2 include_columns
1122
27f01d1f 1123=over 4
1124
1125=item Arguments: (\@columns)
1126
1127=back
5ac6a044 1128
1129Shortcut to include additional columns in the returned results - for example
1130
24d67825 1131 $schema->resultset('CD')->search(undef, {
1132 include_columns => ['artist.name'],
1133 join => ['artist']
1134 });
5ac6a044 1135
24d67825 1136would return all CDs and include a 'name' column to the information
1137passed to object inflation
5ac6a044 1138
87c4e602 1139=head2 select
1140
27f01d1f 1141=over 4
1142
1143=item Arguments: (\@columns)
1144
1145=back
976f3686 1146
4a28c340 1147Indicates which columns should be selected from the storage. You can use
1148column names, or in the case of RDBMS back ends, function or stored procedure
1149names:
1150
24d67825 1151 $rs = $schema->resultset('Employee')->search(undef, {
1152 select => [
1153 'name',
1154 { count => 'employeeid' },
1155 { sum => 'salary' }
1156 ]
1157 });
4a28c340 1158
1159When you use function/stored procedure names and do not supply an C<as>
1160attribute, the column names returned are storage-dependent. E.g. MySQL would
24d67825 1161return a column named C<count(employeeid)> in the above example.
976f3686 1162
87c4e602 1163=head2 as
1164
27f01d1f 1165=over 4
1166
1167=item Arguments: (\@names)
1168
1169=back
076652e8 1170
4a28c340 1171Indicates column names for object inflation. This is used in conjunction with
1172C<select>, usually when C<select> contains one or more function or stored
1173procedure names:
1174
24d67825 1175 $rs = $schema->resultset('Employee')->search(undef, {
1176 select => [
1177 'name',
1178 { count => 'employeeid' }
1179 ],
a0638a7b 1180 as => ['name', 'employee_count'],
24d67825 1181 });
4a28c340 1182
24d67825 1183 my $employee = $rs->first(); # get the first Employee
4a28c340 1184
1185If the object against which the search is performed already has an accessor
1186matching a column name specified in C<as>, the value can be retrieved using
1187the accessor as normal:
1188
24d67825 1189 my $name = $employee->name();
4a28c340 1190
1191If on the other hand an accessor does not exist in the object, you need to
1192use C<get_column> instead:
1193
24d67825 1194 my $employee_count = $employee->get_column('employee_count');
4a28c340 1195
1196You can create your own accessors if required - see
1197L<DBIx::Class::Manual::Cookbook> for details.
ee38fa40 1198
bfab575a 1199=head2 join
ee38fa40 1200
a33df5d4 1201Contains a list of relationships that should be joined for this query. For
1202example:
1203
1204 # Get CDs by Nine Inch Nails
1205 my $rs = $schema->resultset('CD')->search(
1206 { 'artist.name' => 'Nine Inch Nails' },
1207 { join => 'artist' }
1208 );
1209
1210Can also contain a hash reference to refer to the other relation's relations.
1211For example:
1212
1213 package MyApp::Schema::Track;
1214 use base qw/DBIx::Class/;
1215 __PACKAGE__->table('track');
1216 __PACKAGE__->add_columns(qw/trackid cd position title/);
1217 __PACKAGE__->set_primary_key('trackid');
1218 __PACKAGE__->belongs_to(cd => 'MyApp::Schema::CD');
1219 1;
1220
1221 # In your application
1222 my $rs = $schema->resultset('Artist')->search(
1223 { 'track.title' => 'Teardrop' },
1224 {
1225 join => { cd => 'track' },
1226 order_by => 'artist.name',
1227 }
1228 );
1229
2cb360cc 1230If the same join is supplied twice, it will be aliased to <rel>_2 (and
1231similarly for a third time). For e.g.
1232
24d67825 1233 my $rs = $schema->resultset('Artist')->search({
1234 'cds.title' => 'Down to Earth',
1235 'cds_2.title' => 'Popular',
1236 }, {
1237 join => [ qw/cds cds/ ],
1238 });
2cb360cc 1239
24d67825 1240will return a set of all artists that have both a cd with title 'Down
1241to Earth' and a cd with title 'Popular'.
2cb360cc 1242
1243If you want to fetch related objects from other tables as well, see C<prefetch>
ae1c90a1 1244below.
ee38fa40 1245
87c4e602 1246=head2 prefetch
1247
27f01d1f 1248=over 4
1249
1250=item Arguments: (\@relationships)
1251
1252=back
ee38fa40 1253
ae1c90a1 1254Contains one or more relationships that should be fetched along with the main
bfab575a 1255query (when they are accessed afterwards they will have already been
a33df5d4 1256"prefetched"). This is useful for when you know you will need the related
ae1c90a1 1257objects, because it saves at least one query:
1258
1259 my $rs = $schema->resultset('Tag')->search(
5e8b1b2a 1260 undef,
ae1c90a1 1261 {
1262 prefetch => {
1263 cd => 'artist'
1264 }
1265 }
1266 );
1267
1268The initial search results in SQL like the following:
1269
1270 SELECT tag.*, cd.*, artist.* FROM tag
1271 JOIN cd ON tag.cd = cd.cdid
1272 JOIN artist ON cd.artist = artist.artistid
1273
1274L<DBIx::Class> has no need to go back to the database when we access the
1275C<cd> or C<artist> relationships, which saves us two SQL statements in this
1276case.
1277
2cb360cc 1278Simple prefetches will be joined automatically, so there is no need
1279for a C<join> attribute in the above search. If you're prefetching to
1280depth (e.g. { cd => { artist => 'label' } or similar), you'll need to
1281specify the join as well.
ae1c90a1 1282
1283C<prefetch> can be used with the following relationship types: C<belongs_to>,
2cb360cc 1284C<has_one> (or if you're using C<add_relationship>, any relationship declared
1285with an accessor type of 'single' or 'filter').
ee38fa40 1286
87c4e602 1287=head2 from
1288
27f01d1f 1289=over 4
1290
1291=item Arguments: (\@array)
1292
1293=back
ee38fa40 1294
4a28c340 1295The C<from> attribute gives you manual control over the C<FROM> clause of SQL
1296statements generated by L<DBIx::Class>, allowing you to express custom C<JOIN>
1297clauses.
ee38fa40 1298
a33df5d4 1299NOTE: Use this on your own risk. This allows you to shoot off your foot!
4a28c340 1300C<join> will usually do what you need and it is strongly recommended that you
1301avoid using C<from> unless you cannot achieve the desired result using C<join>.
1302
1303In simple terms, C<from> works as follows:
1304
1305 [
1306 { <alias> => <table>, -join-type => 'inner|left|right' }
1307 [] # nested JOIN (optional)
1308 { <table.column> = <foreign_table.foreign_key> }
1309 ]
1310
1311 JOIN
1312 <alias> <table>
1313 [JOIN ...]
1314 ON <table.column> = <foreign_table.foreign_key>
1315
1316An easy way to follow the examples below is to remember the following:
1317
1318 Anything inside "[]" is a JOIN
1319 Anything inside "{}" is a condition for the enclosing JOIN
1320
1321The following examples utilize a "person" table in a family tree application.
1322In order to express parent->child relationships, this table is self-joined:
1323
1324 # Person->belongs_to('father' => 'Person');
1325 # Person->belongs_to('mother' => 'Person');
1326
1327C<from> can be used to nest joins. Here we return all children with a father,
1328then search against all mothers of those children:
1329
1330 $rs = $schema->resultset('Person')->search(
5e8b1b2a 1331 undef,
4a28c340 1332 {
1333 alias => 'mother', # alias columns in accordance with "from"
1334 from => [
1335 { mother => 'person' },
1336 [
1337 [
1338 { child => 'person' },
1339 [
1340 { father => 'person' },
1341 { 'father.person_id' => 'child.father_id' }
1342 ]
1343 ],
1344 { 'mother.person_id' => 'child.mother_id' }
fd9f5466 1345 ],
4a28c340 1346 ]
1347 },
1348 );
1349
1350 # Equivalent SQL:
1351 # SELECT mother.* FROM person mother
1352 # JOIN (
1353 # person child
1354 # JOIN person father
1355 # ON ( father.person_id = child.father_id )
1356 # )
1357 # ON ( mother.person_id = child.mother_id )
1358
1359The type of any join can be controlled manually. To search against only people
1360with a father in the person table, we could explicitly use C<INNER JOIN>:
1361
1362 $rs = $schema->resultset('Person')->search(
5e8b1b2a 1363 undef,
4a28c340 1364 {
1365 alias => 'child', # alias columns in accordance with "from"
1366 from => [
1367 { child => 'person' },
1368 [
1369 { father => 'person', -join-type => 'inner' },
1370 { 'father.id' => 'child.father_id' }
1371 ],
1372 ]
1373 },
1374 );
1375
1376 # Equivalent SQL:
1377 # SELECT child.* FROM person child
1378 # INNER JOIN person father ON child.father_id = father.id
ee38fa40 1379
bfab575a 1380=head2 page
076652e8 1381
27f01d1f 1382=over 4
1383
1384=item Arguments: ($page)
1385
1386=back
1387
a33df5d4 1388For a paged resultset, specifies which page to retrieve. Leave unset
bfab575a 1389for an unpaged resultset.
076652e8 1390
bfab575a 1391=head2 rows
076652e8 1392
27f01d1f 1393=over 4
1394
1395=item Arguments: ($rows)
1396
1397=back
1398
1399For a paged resultset, specifies how many rows are in each page:
4a28c340 1400
1401 rows => 10
1402
1403Can also be used to simulate an SQL C<LIMIT>.
076652e8 1404
87c4e602 1405=head2 group_by
1406
27f01d1f 1407=over 4
1408
1409=item Arguments: (\@columns)
1410
1411=back
54540863 1412
bda4c2b8 1413A arrayref of columns to group by. Can include columns of joined tables.
54540863 1414
675ce4a6 1415 group_by => [qw/ column1 column2 ... /]
1416
54540863 1417=head2 distinct
1418
a33df5d4 1419Set to 1 to group by all columns.
1420
534ca143 1421=head2 cache
1422
1423Set to 1 to cache search results. This prevents extra SQL queries if you
1424revisit rows in your ResultSet:
1425
1426 my $resultset = $schema->resultset('Artist')->search( undef, { cache => 1 } );
1427
1428 while( my $artist = $resultset->next ) {
1429 ... do stuff ...
1430 }
1431
1432 $rs->first; # without cache, this would issue a query
1433
1434By default, searches are not cached.
1435
a33df5d4 1436For more examples of using these attributes, see
1437L<DBIx::Class::Manual::Cookbook>.
54540863 1438
bfab575a 1439=cut
076652e8 1440
89c0a5a2 14411;