Hopefully made in-place compose_connection work
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / ResultSet.pm
CommitLineData
89c0a5a2 1package DBIx::Class::ResultSet;
2
3use strict;
4use warnings;
aa562407 5use Carp qw/croak/;
89c0a5a2 6use overload
7 '0+' => 'count',
a910dc57 8 'bool' => sub { 1; },
89c0a5a2 9 fallback => 1;
3c5b25c5 10use Data::Page;
ea20d0fd 11use Storable;
89c0a5a2 12
ee38fa40 13=head1 NAME
14
bfab575a 15DBIx::Class::ResultSet - Responsible for fetching and creating resultset.
ee38fa40 16
bfab575a 17=head1 SYNOPSIS
ee38fa40 18
a33df5d4 19 my $rs = $schema->resultset('User')->search(registered => 1);
20 my @rows = $schema->resultset('Foo')->search(bar => 'baz');
ee38fa40 21
22=head1 DESCRIPTION
23
bfab575a 24The resultset is also known as an iterator. It is responsible for handling
a33df5d4 25queries that may return an arbitrary number of rows, e.g. via L</search>
bfab575a 26or a C<has_many> relationship.
ee38fa40 27
a33df5d4 28In the examples below, the following table classes are used:
29
30 package MyApp::Schema::Artist;
31 use base qw/DBIx::Class/;
32 __PACKAGE__->table('artist');
33 __PACKAGE__->add_columns(qw/artistid name/);
34 __PACKAGE__->set_primary_key('artistid');
35 __PACKAGE__->has_many(cds => 'MyApp::Schema::CD');
36 1;
37
38 package MyApp::Schema::CD;
39 use base qw/DBIx::Class/;
40 __PACKAGE__->table('artist');
41 __PACKAGE__->add_columns(qw/cdid artist title year/);
42 __PACKAGE__->set_primary_key('cdid');
43 __PACKAGE__->belongs_to(artist => 'MyApp::Schema::Artist');
44 1;
45
ee38fa40 46=head1 METHODS
47
976f3686 48=head2 new($source, \%$attrs)
ee38fa40 49
a33df5d4 50The resultset constructor. Takes a source object (usually a
80c90f5d 51L<DBIx::Class::ResultSourceProxy::Table>) and an attribute hash (see L</ATRRIBUTES>
a33df5d4 52below). Does not perform any queries -- these are executed as needed by the
53other methods.
54
55Generally you won't need to construct a resultset manually. You'll
56automatically get one from e.g. a L</search> called in scalar context:
57
58 my $rs = $schema->resultset('CD')->search({ title => '100th Window' });
ee38fa40 59
60=cut
61
89c0a5a2 62sub new {
fea3d045 63 my $class = shift;
f9db5527 64 return $class->new_result(@_) if ref $class;
fea3d045 65 my ($source, $attrs) = @_;
b98e75f6 66 #use Data::Dumper; warn Dumper($attrs);
ea20d0fd 67 $attrs = Storable::dclone($attrs || {}); # { %{ $attrs || {} } };
c7ce65e6 68 my %seen;
6aeb9185 69 my $alias = ($attrs->{alias} ||= 'me');
a9433341 70 if ($attrs->{cols} || !$attrs->{select}) {
71 delete $attrs->{as} if $attrs->{cols};
976f3686 72 my @cols = ($attrs->{cols}
73 ? @{delete $attrs->{cols}}
a9433341 74 : $source->columns);
6aeb9185 75 $attrs->{select} = [ map { m/\./ ? $_ : "${alias}.$_" } @cols ];
976f3686 76 }
6aeb9185 77 $attrs->{as} ||= [ map { m/^$alias\.(.*)$/ ? $1 : $_ } @{$attrs->{select}} ];
976f3686 78 #use Data::Dumper; warn Dumper(@{$attrs}{qw/select as/});
fea3d045 79 $attrs->{from} ||= [ { $alias => $source->from } ];
b52e9bf8 80 if (my $join = delete $attrs->{join}) {
81 foreach my $j (ref $join eq 'ARRAY'
82 ? (@{$join}) : ($join)) {
c7ce65e6 83 if (ref $j eq 'HASH') {
84 $seen{$_} = 1 foreach keys %$j;
85 } else {
86 $seen{$j} = 1;
87 }
88 }
8452e496 89 push(@{$attrs->{from}}, $source->resolve_join($join, $attrs->{alias}));
c7ce65e6 90 }
54540863 91 $attrs->{group_by} ||= $attrs->{select} if delete $attrs->{distinct};
b3e8ac9b 92
93 if (my $prefetch = delete $attrs->{prefetch}) {
94 foreach my $p (ref $prefetch eq 'ARRAY'
95 ? (@{$prefetch}) : ($prefetch)) {
96 if( ref $p eq 'HASH' ) {
97 foreach my $key (keys %$p) {
98 push(@{$attrs->{from}}, $source->resolve_join($p, $attrs->{alias}))
99 unless $seen{$key};
100 }
101 }
102 else {
103 push(@{$attrs->{from}}, $source->resolve_join($p, $attrs->{alias}))
104 unless $seen{$p};
105 }
106 my @cols = ();
107 push @cols, $source->resolve_prefetch($p, $attrs->{alias});
108 #die Dumper \@cols;
109 push(@{$attrs->{select}}, @cols);
110 push(@{$attrs->{as}}, @cols);
111 }
fef5d100 112 }
b3e8ac9b 113
6aeb9185 114 if ($attrs->{page}) {
115 $attrs->{rows} ||= 10;
116 $attrs->{offset} ||= 0;
117 $attrs->{offset} += ($attrs->{rows} * ($attrs->{page} - 1));
118 }
89c0a5a2 119 my $new = {
cda04c3a 120 source => $source,
89c0a5a2 121 cond => $attrs->{where},
0a3c5b43 122 from => $attrs->{from},
3c5b25c5 123 count => undef,
93b004d3 124 page => delete $attrs->{page},
3c5b25c5 125 pager => undef,
89c0a5a2 126 attrs => $attrs };
2f5911b2 127 bless ($new, $class);
9229f20a 128 return $new;
89c0a5a2 129}
130
bfab575a 131=head2 search
0a3c5b43 132
87f0da6a 133 my @obj = $rs->search({ foo => 3 }); # "... WHERE foo = 3"
134 my $new_rs = $rs->search({ foo => 3 });
135
6009260a 136If you need to pass in additional attributes but no additional condition,
a33df5d4 137call it as C<search({}, \%attrs);>.
87f0da6a 138
a33df5d4 139 # "SELECT foo, bar FROM $class_table"
140 my @all = $class->search({}, { cols => [qw/foo bar/] });
0a3c5b43 141
142=cut
143
144sub search {
145 my $self = shift;
146
6009260a 147 #use Data::Dumper;warn Dumper(@_);
148
0a3c5b43 149 my $attrs = { %{$self->{attrs}} };
150 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
6aeb9185 151 $attrs = { %$attrs, %{ pop(@_) } };
0a3c5b43 152 }
153
6aeb9185 154 my $where = (@_ ? ((@_ == 1 || ref $_[0] eq "HASH") ? shift : {@_}) : undef());
0a3c5b43 155 if (defined $where) {
156 $where = (defined $attrs->{where}
ad3d2d7c 157 ? { '-and' =>
158 [ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
159 $where, $attrs->{where} ] }
0a3c5b43 160 : $where);
161 $attrs->{where} = $where;
162 }
163
fea3d045 164 my $rs = (ref $self)->new($self->{source}, $attrs);
0a3c5b43 165
166 return (wantarray ? $rs->all : $rs);
167}
168
87f0da6a 169=head2 search_literal
170
6009260a 171 my @obj = $rs->search_literal($literal_where_cond, @bind);
172 my $new_rs = $rs->search_literal($literal_where_cond, @bind);
173
174Pass a literal chunk of SQL to be added to the conditional part of the
87f0da6a 175resultset.
6009260a 176
bfab575a 177=cut
178
6009260a 179sub search_literal {
180 my ($self, $cond, @vals) = @_;
181 my $attrs = (ref $vals[$#vals] eq 'HASH' ? { %{ pop(@vals) } } : {});
182 $attrs->{bind} = [ @{$self->{attrs}{bind}||[]}, @vals ];
183 return $self->search(\$cond, $attrs);
184}
0a3c5b43 185
87f0da6a 186=head2 find(@colvalues), find(\%cols, \%attrs?)
187
188Finds a row based on its primary key or unique constraint. For example:
189
87f0da6a 190 my $cd = $schema->resultset('CD')->find(5);
191
192Also takes an optional C<key> attribute, to search by a specific key or unique
193constraint. For example:
194
195 my $cd = $schema->resultset('CD')->find_or_create(
196 {
197 artist => 'Massive Attack',
198 title => 'Mezzanine',
199 },
200 { key => 'artist_title' }
201 );
202
a33df5d4 203See also L</find_or_create> and L</update_or_create>.
204
87f0da6a 205=cut
716b3d29 206
207sub find {
208 my ($self, @vals) = @_;
209 my $attrs = (@vals > 1 && ref $vals[$#vals] eq 'HASH' ? pop(@vals) : {});
87f0da6a 210
211 my @cols = $self->{source}->primary_columns;
212 if (exists $attrs->{key}) {
213 my %uniq = $self->{source}->unique_constraints;
214 $self->( "Unknown key " . $attrs->{key} . " on " . $self->name )
215 unless exists $uniq{$attrs->{key}};
216 @cols = @{ $uniq{$attrs->{key}} };
217 }
218 #use Data::Dumper; warn Dumper($attrs, @vals, @cols);
219 $self->{source}->result_class->throw( "Can't find unless a primary key or unique constraint is defined" )
220 unless @cols;
221
716b3d29 222 my $query;
223 if (ref $vals[0] eq 'HASH') {
224 $query = $vals[0];
87f0da6a 225 } elsif (@cols == @vals) {
716b3d29 226 $query = {};
87f0da6a 227 @{$query}{@cols} = @vals;
716b3d29 228 } else {
229 $query = {@vals};
230 }
231 #warn Dumper($query);
232 # Useless -> disabled
233 #$self->{source}->result_class->throw( "Can't find unless all primary keys are specified" )
234 # unless (keys %$query >= @pk); # If we check 'em we run afoul of uc/lc
235 # column names etc. Not sure what to do yet
236 return $self->search($query)->next;
237}
238
b52e9bf8 239=head2 search_related
240
241 $rs->search_related('relname', $cond?, $attrs?);
242
a33df5d4 243Search the specified relationship. Optionally specify a condition for matching
244records.
245
b52e9bf8 246=cut
247
6aeb9185 248sub search_related {
249 my ($self, $rel, @rest) = @_;
f9db5527 250 my $rel_obj = $self->{source}->relationship_info($rel);
6aeb9185 251 $self->{source}->result_class->throw(
252 "No such relationship ${rel} in search_related")
253 unless $rel_obj;
6aeb9185 254 my $rs = $self->search(undef, { join => $rel });
ea20d0fd 255 return $self->{source}->schema->resultset($rel_obj->{class}
256 )->search( undef,
257 { %{$rs->{attrs}},
258 alias => $rel,
259 select => undef(),
260 as => undef() }
6aeb9185 261 )->search(@rest);
262}
b52e9bf8 263
bfab575a 264=head2 cursor
ee38fa40 265
bfab575a 266Returns a storage-driven cursor to the given resultset.
ee38fa40 267
268=cut
269
73f58123 270sub cursor {
271 my ($self) = @_;
2f5911b2 272 my ($source, $attrs) = @{$self}{qw/source attrs/};
6aeb9185 273 $attrs = { %$attrs };
73f58123 274 return $self->{cursor}
976f3686 275 ||= $source->storage->select($self->{from}, $attrs->{select},
73f58123 276 $attrs->{where},$attrs);
277}
278
87f0da6a 279=head2 search_like
280
a33df5d4 281Perform a search, but use C<LIKE> instead of equality as the condition. Note
282that this is simply a convenience method; you most likely want to use
283L</search> with specific operators.
284
285For more information, see L<DBIx::Class::Manual::Cookbook>.
87f0da6a 286
287=cut
58a4bd18 288
289sub search_like {
290 my $class = shift;
291 my $attrs = { };
292 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
293 $attrs = pop(@_);
294 }
295 my $query = ref $_[0] eq "HASH" ? { %{shift()} }: {@_};
296 $query->{$_} = { 'like' => $query->{$_} } for keys %$query;
297 return $class->search($query, { %$attrs });
298}
299
bfab575a 300=head2 slice($first, $last)
ee38fa40 301
bfab575a 302Returns a subset of elements from the resultset.
ee38fa40 303
304=cut
305
89c0a5a2 306sub slice {
307 my ($self, $min, $max) = @_;
308 my $attrs = { %{ $self->{attrs} || {} } };
6aeb9185 309 $attrs->{offset} ||= 0;
310 $attrs->{offset} += $min;
89c0a5a2 311 $attrs->{rows} = ($max ? ($max - $min + 1) : 1);
fea3d045 312 my $slice = (ref $self)->new($self->{source}, $attrs);
89c0a5a2 313 return (wantarray ? $slice->all : $slice);
314}
315
87f0da6a 316=head2 next
ee38fa40 317
a33df5d4 318Returns the next element in the resultset (C<undef> is there is none).
319
320Can be used to efficiently iterate over records in the resultset:
321
322 my $rs = $schema->resultset('CD')->search({});
323 while (my $cd = $rs->next) {
324 print $cd->title;
325 }
ee38fa40 326
327=cut
328
89c0a5a2 329sub next {
330 my ($self) = @_;
73f58123 331 my @row = $self->cursor->next;
a953d8d9 332# warn Dumper(\@row); use Data::Dumper;
89c0a5a2 333 return unless (@row);
c7ce65e6 334 return $self->_construct_object(@row);
335}
336
337sub _construct_object {
338 my ($self, @row) = @_;
b3e8ac9b 339 my @as = @{ $self->{attrs}{as} };
976f3686 340 #warn "@cols -> @row";
b3e8ac9b 341 my $info = [ {}, {} ];
342 foreach my $as (@as) {
343 my $target = $info;
344 my @parts = split(/\./, $as);
345 my $col = pop(@parts);
346 foreach my $p (@parts) {
347 $target = $target->[1]->{$p} ||= [];
c7ce65e6 348 }
b3e8ac9b 349 $target->[0]->{$col} = shift @row;
c7ce65e6 350 }
b3e8ac9b 351 #use Data::Dumper; warn Dumper(\@as, $info);
c01ab172 352 my $new = $self->{source}->result_class->inflate_result(
b3e8ac9b 353 $self->{source}, @$info);
33ce49d6 354 $new = $self->{attrs}{record_filter}->($new)
355 if exists $self->{attrs}{record_filter};
356 return $new;
89c0a5a2 357}
358
bfab575a 359=head2 count
ee38fa40 360
bfab575a 361Performs an SQL C<COUNT> with the same query as the resultset was built
6009260a 362with to find the number of elements. If passed arguments, does a search
363on the resultset and counts the results of that.
ee38fa40 364
365=cut
366
89c0a5a2 367sub count {
6009260a 368 my $self = shift;
369 return $self->search(@_)->count if @_ && defined $_[0];
aa562407 370 croak "Unable to ->count with a GROUP BY" if defined $self->{attrs}{group_by};
6aeb9185 371 unless (defined $self->{count}) {
976f3686 372 my $attrs = { %{ $self->{attrs} },
54540863 373 select => { 'count' => '*' },
374 as => [ 'count' ] };
ea20d0fd 375 # offset, order by and page are not needed to count. record_filter is cdbi
376 delete $attrs->{$_} for qw/rows offset order_by page pager record_filter/;
3c5b25c5 377
fea3d045 378 ($self->{count}) = (ref $self)->new($self->{source}, $attrs)->cursor->next;
3c5b25c5 379 }
380 return 0 unless $self->{count};
6aeb9185 381 my $count = $self->{count};
382 $count -= $self->{attrs}{offset} if $self->{attrs}{offset};
383 $count = $self->{attrs}{rows} if
384 ($self->{attrs}{rows} && $self->{attrs}{rows} < $count);
385 return $count;
89c0a5a2 386}
387
bfab575a 388=head2 count_literal
6009260a 389
a33df5d4 390Calls L</search_literal> with the passed arguments, then L</count>.
6009260a 391
392=cut
393
394sub count_literal { shift->search_literal(@_)->count; }
395
bfab575a 396=head2 all
ee38fa40 397
bfab575a 398Returns all elements in the resultset. Called implictly if the resultset
399is returned in list context.
ee38fa40 400
401=cut
402
89c0a5a2 403sub all {
404 my ($self) = @_;
c7ce65e6 405 return map { $self->_construct_object(@$_); }
73f58123 406 $self->cursor->all;
89c0a5a2 407}
408
bfab575a 409=head2 reset
ee38fa40 410
bfab575a 411Resets the resultset's cursor, so you can iterate through the elements again.
ee38fa40 412
413=cut
414
89c0a5a2 415sub reset {
416 my ($self) = @_;
73f58123 417 $self->cursor->reset;
89c0a5a2 418 return $self;
419}
420
bfab575a 421=head2 first
ee38fa40 422
bfab575a 423Resets the resultset and returns the first element.
ee38fa40 424
425=cut
426
89c0a5a2 427sub first {
428 return $_[0]->reset->next;
429}
430
c01ab172 431=head2 update(\%values)
432
a33df5d4 433Sets the specified columns in the resultset to the supplied values.
c01ab172 434
435=cut
436
437sub update {
438 my ($self, $values) = @_;
aa562407 439 croak "Values for update must be a hash" unless ref $values eq 'HASH';
c01ab172 440 return $self->{source}->storage->update(
441 $self->{source}->from, $values, $self->{cond});
442}
443
444=head2 update_all(\%values)
445
a33df5d4 446Fetches all objects and updates them one at a time. Note that C<update_all>
447will run cascade triggers while L</update> will not.
c01ab172 448
449=cut
450
451sub update_all {
452 my ($self, $values) = @_;
aa562407 453 croak "Values for update must be a hash" unless ref $values eq 'HASH';
c01ab172 454 foreach my $obj ($self->all) {
455 $obj->set_columns($values)->update;
456 }
457 return 1;
458}
459
bfab575a 460=head2 delete
ee38fa40 461
c01ab172 462Deletes the contents of the resultset from its result source.
ee38fa40 463
464=cut
465
28927b50 466sub delete {
89c0a5a2 467 my ($self) = @_;
c01ab172 468 $self->{source}->storage->delete($self->{source}->from, $self->{cond});
89c0a5a2 469 return 1;
470}
471
c01ab172 472=head2 delete_all
473
a33df5d4 474Fetches all objects and deletes them one at a time. Note that C<delete_all>
475will run cascade triggers while L</delete> will not.
c01ab172 476
477=cut
478
479sub delete_all {
480 my ($self) = @_;
481 $_->delete for $self->all;
482 return 1;
483}
28927b50 484
bfab575a 485=head2 pager
ee38fa40 486
487Returns a L<Data::Page> object for the current resultset. Only makes
a33df5d4 488sense for queries with a C<page> attribute.
ee38fa40 489
490=cut
491
3c5b25c5 492sub pager {
493 my ($self) = @_;
494 my $attrs = $self->{attrs};
aa562407 495 croak "Can't create pager for non-paged rs" unless $self->{page};
6aeb9185 496 $attrs->{rows} ||= 10;
497 $self->count;
498 return $self->{pager} ||= Data::Page->new(
93b004d3 499 $self->{count}, $attrs->{rows}, $self->{page});
3c5b25c5 500}
501
bfab575a 502=head2 page($page_num)
ee38fa40 503
bfab575a 504Returns a new resultset for the specified page.
ee38fa40 505
506=cut
507
3c5b25c5 508sub page {
509 my ($self, $page) = @_;
6aeb9185 510 my $attrs = { %{$self->{attrs}} };
3c5b25c5 511 $attrs->{page} = $page;
fea3d045 512 return (ref $self)->new($self->{source}, $attrs);
513}
514
515=head2 new_result(\%vals)
516
87f0da6a 517Creates a result in the resultset's result class.
fea3d045 518
519=cut
520
521sub new_result {
522 my ($self, $values) = @_;
523 $self->{source}->result_class->throw( "new_result needs a hash" )
524 unless (ref $values eq 'HASH');
525 $self->{source}->result_class->throw( "Can't abstract implicit construct, condition not a hash" )
526 if ($self->{cond} && !(ref $self->{cond} eq 'HASH'));
527 my %new = %$values;
528 my $alias = $self->{attrs}{alias};
529 foreach my $key (keys %{$self->{cond}||{}}) {
530 $new{$1} = $self->{cond}{$key} if ($key =~ m/^(?:$alias\.)?([^\.]+)$/);
531 }
097d3227 532 my $obj = $self->{source}->result_class->new(\%new);
533 $obj->result_source($self->{source}) if $obj->can('result_source');
534 $obj;
fea3d045 535}
536
537=head2 create(\%vals)
538
87f0da6a 539Inserts a record into the resultset and returns the object.
fea3d045 540
a33df5d4 541Effectively a shortcut for C<< ->new_result(\%vals)->insert >>.
fea3d045 542
543=cut
544
545sub create {
546 my ($self, $attrs) = @_;
547 $self->{source}->result_class->throw( "create needs a hashref" ) unless ref $attrs eq 'HASH';
548 return $self->new_result($attrs)->insert;
3c5b25c5 549}
550
87f0da6a 551=head2 find_or_create(\%vals, \%attrs?)
552
553 $class->find_or_create({ key => $val, ... });
c2b15ecc 554
c2b15ecc 555Searches for a record matching the search condition; if it doesn't find one,
cf7b40ed 556creates one and returns that instead.
87f0da6a 557
87f0da6a 558 my $cd = $schema->resultset('CD')->find_or_create({
559 cdid => 5,
560 artist => 'Massive Attack',
561 title => 'Mezzanine',
562 year => 2005,
563 });
564
565Also takes an optional C<key> attribute, to search by a specific key or unique
566constraint. For example:
567
568 my $cd = $schema->resultset('CD')->find_or_create(
569 {
570 artist => 'Massive Attack',
571 title => 'Mezzanine',
572 },
573 { key => 'artist_title' }
574 );
575
576See also L</find> and L</update_or_create>.
577
c2b15ecc 578=cut
579
580sub find_or_create {
581 my $self = shift;
87f0da6a 582 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
583 my $hash = ref $_[0] eq "HASH" ? shift : {@_};
584 my $exists = $self->find($hash, $attrs);
c2b15ecc 585 return defined($exists) ? $exists : $self->create($hash);
586}
587
87f0da6a 588=head2 update_or_create
589
590 $class->update_or_create({ key => $val, ... });
591
592First, search for an existing row matching one of the unique constraints
593(including the primary key) on the source of this resultset. If a row is
594found, update it with the other given column values. Otherwise, create a new
595row.
596
597Takes an optional C<key> attribute to search on a specific unique constraint.
598For example:
599
600 # In your application
601 my $cd = $schema->resultset('CD')->update_or_create(
602 {
603 artist => 'Massive Attack',
604 title => 'Mezzanine',
605 year => 1998,
606 },
607 { key => 'artist_title' }
608 );
609
610If no C<key> is specified, it searches on all unique constraints defined on the
611source, including the primary key.
612
613If the C<key> is specified as C<primary>, search only on the primary key.
614
a33df5d4 615See also L</find> and L</find_or_create>.
616
87f0da6a 617=cut
618
619sub update_or_create {
620 my $self = shift;
621
622 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
623 my $hash = ref $_[0] eq "HASH" ? shift : {@_};
624
625 my %unique_constraints = $self->{source}->unique_constraints;
626 my @constraint_names = (exists $attrs->{key}
627 ? ($attrs->{key})
628 : keys %unique_constraints);
629
630 my @unique_hashes;
631 foreach my $name (@constraint_names) {
632 my @unique_cols = @{ $unique_constraints{$name} };
633 my %unique_hash =
634 map { $_ => $hash->{$_} }
635 grep { exists $hash->{$_} }
636 @unique_cols;
637
638 push @unique_hashes, \%unique_hash
639 if (scalar keys %unique_hash == scalar @unique_cols);
640 }
641
642 my $row;
643 if (@unique_hashes) {
644 $row = $self->search(\@unique_hashes, { rows => 1 })->first;
645 if ($row) {
646 $row->set_columns($hash);
647 $row->update;
648 }
649 }
650
651 unless ($row) {
652 $row = $self->create($hash);
653 }
654
655 return $row;
656}
657
40dbc108 658=head1 ATTRIBUTES
076652e8 659
a33df5d4 660The resultset takes various attributes that modify its behavior. Here's an
661overview of them:
bfab575a 662
663=head2 order_by
076652e8 664
a33df5d4 665Which column(s) to order the results by. This is currently passed through
666directly to SQL, so you can give e.g. C<foo DESC> for a descending order.
076652e8 667
976f3686 668=head2 cols (arrayref)
669
a33df5d4 670Shortcut to request a particular set of columns to be retrieved. Adds
671C<me.> onto the start of any column without a C<.> in it and sets C<select>
672from that, then auto-populates C<as> from C<select> as normal.
976f3686 673
674=head2 select (arrayref)
675
4a28c340 676Indicates which columns should be selected from the storage. You can use
677column names, or in the case of RDBMS back ends, function or stored procedure
678names:
679
680 $rs = $schema->resultset('Foo')->search(
681 {},
682 {
cf7b40ed 683 select => [
4a28c340 684 'column_name',
685 { count => 'column_to_count' },
686 { sum => 'column_to_sum' }
cf7b40ed 687 ]
4a28c340 688 }
689 );
690
691When you use function/stored procedure names and do not supply an C<as>
692attribute, the column names returned are storage-dependent. E.g. MySQL would
693return a column named C<count(column_to_count)> in the above example.
976f3686 694
695=head2 as (arrayref)
076652e8 696
4a28c340 697Indicates column names for object inflation. This is used in conjunction with
698C<select>, usually when C<select> contains one or more function or stored
699procedure names:
700
701 $rs = $schema->resultset('Foo')->search(
702 {},
703 {
cf7b40ed 704 select => [
4a28c340 705 'column1',
706 { count => 'column2' }
cf7b40ed 707 ],
4a28c340 708 as => [qw/ column1 column2_count /]
709 }
710 );
711
712 my $foo = $rs->first(); # get the first Foo
713
714If the object against which the search is performed already has an accessor
715matching a column name specified in C<as>, the value can be retrieved using
716the accessor as normal:
717
718 my $column1 = $foo->column1();
719
720If on the other hand an accessor does not exist in the object, you need to
721use C<get_column> instead:
722
723 my $column2_count = $foo->get_column('column2_count');
724
725You can create your own accessors if required - see
726L<DBIx::Class::Manual::Cookbook> for details.
ee38fa40 727
bfab575a 728=head2 join
ee38fa40 729
a33df5d4 730Contains a list of relationships that should be joined for this query. For
731example:
732
733 # Get CDs by Nine Inch Nails
734 my $rs = $schema->resultset('CD')->search(
735 { 'artist.name' => 'Nine Inch Nails' },
736 { join => 'artist' }
737 );
738
739Can also contain a hash reference to refer to the other relation's relations.
740For example:
741
742 package MyApp::Schema::Track;
743 use base qw/DBIx::Class/;
744 __PACKAGE__->table('track');
745 __PACKAGE__->add_columns(qw/trackid cd position title/);
746 __PACKAGE__->set_primary_key('trackid');
747 __PACKAGE__->belongs_to(cd => 'MyApp::Schema::CD');
748 1;
749
750 # In your application
751 my $rs = $schema->resultset('Artist')->search(
752 { 'track.title' => 'Teardrop' },
753 {
754 join => { cd => 'track' },
755 order_by => 'artist.name',
756 }
757 );
758
759If you want to fetch the columns from the related table as well, see
760C<prefetch> below.
ee38fa40 761
bfab575a 762=head2 prefetch
ee38fa40 763
bfab575a 764Contains a list of relationships that should be fetched along with the main
765query (when they are accessed afterwards they will have already been
a33df5d4 766"prefetched"). This is useful for when you know you will need the related
767objects, because it saves a query. Currently limited to prefetching
bfab575a 768one relationship deep, so unlike C<join>, prefetch must be an arrayref.
ee38fa40 769
4a28c340 770=head2 from (arrayref)
ee38fa40 771
4a28c340 772The C<from> attribute gives you manual control over the C<FROM> clause of SQL
773statements generated by L<DBIx::Class>, allowing you to express custom C<JOIN>
774clauses.
ee38fa40 775
a33df5d4 776NOTE: Use this on your own risk. This allows you to shoot off your foot!
4a28c340 777C<join> will usually do what you need and it is strongly recommended that you
778avoid using C<from> unless you cannot achieve the desired result using C<join>.
779
780In simple terms, C<from> works as follows:
781
782 [
783 { <alias> => <table>, -join-type => 'inner|left|right' }
784 [] # nested JOIN (optional)
785 { <table.column> = <foreign_table.foreign_key> }
786 ]
787
788 JOIN
789 <alias> <table>
790 [JOIN ...]
791 ON <table.column> = <foreign_table.foreign_key>
792
793An easy way to follow the examples below is to remember the following:
794
795 Anything inside "[]" is a JOIN
796 Anything inside "{}" is a condition for the enclosing JOIN
797
798The following examples utilize a "person" table in a family tree application.
799In order to express parent->child relationships, this table is self-joined:
800
801 # Person->belongs_to('father' => 'Person');
802 # Person->belongs_to('mother' => 'Person');
803
804C<from> can be used to nest joins. Here we return all children with a father,
805then search against all mothers of those children:
806
807 $rs = $schema->resultset('Person')->search(
808 {},
809 {
810 alias => 'mother', # alias columns in accordance with "from"
811 from => [
812 { mother => 'person' },
813 [
814 [
815 { child => 'person' },
816 [
817 { father => 'person' },
818 { 'father.person_id' => 'child.father_id' }
819 ]
820 ],
821 { 'mother.person_id' => 'child.mother_id' }
822 ],
823 ]
824 },
825 );
826
827 # Equivalent SQL:
828 # SELECT mother.* FROM person mother
829 # JOIN (
830 # person child
831 # JOIN person father
832 # ON ( father.person_id = child.father_id )
833 # )
834 # ON ( mother.person_id = child.mother_id )
835
836The type of any join can be controlled manually. To search against only people
837with a father in the person table, we could explicitly use C<INNER JOIN>:
838
839 $rs = $schema->resultset('Person')->search(
840 {},
841 {
842 alias => 'child', # alias columns in accordance with "from"
843 from => [
844 { child => 'person' },
845 [
846 { father => 'person', -join-type => 'inner' },
847 { 'father.id' => 'child.father_id' }
848 ],
849 ]
850 },
851 );
852
853 # Equivalent SQL:
854 # SELECT child.* FROM person child
855 # INNER JOIN person father ON child.father_id = father.id
ee38fa40 856
bfab575a 857=head2 page
076652e8 858
a33df5d4 859For a paged resultset, specifies which page to retrieve. Leave unset
bfab575a 860for an unpaged resultset.
076652e8 861
bfab575a 862=head2 rows
076652e8 863
4a28c340 864For a paged resultset, how many rows per page:
865
866 rows => 10
867
868Can also be used to simulate an SQL C<LIMIT>.
076652e8 869
a33df5d4 870=head2 group_by (arrayref)
54540863 871
4a28c340 872A arrayref of columns to group by. Can include columns of joined tables. Note
873note that L</count> doesn't work on grouped resultsets.
54540863 874
675ce4a6 875 group_by => [qw/ column1 column2 ... /]
876
54540863 877=head2 distinct
878
a33df5d4 879Set to 1 to group by all columns.
880
881For more examples of using these attributes, see
882L<DBIx::Class::Manual::Cookbook>.
54540863 883
bfab575a 884=cut
076652e8 885
89c0a5a2 8861;