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