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