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