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