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