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