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