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