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