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