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