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