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