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