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