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