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