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