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