prepared for release.
[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} ) {
dec2517f 397 my @distinct = (ref $group_by ? @$group_by : ($group_by));
15c382be 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) = @_;
ca4b5ab7 513 my $del = {};
514 $self->throw_exception("Can't delete on resultset with condition unless hash or array")
515 unless (ref($self->{cond}) eq 'HASH' || ref($self->{cond}) eq 'ARRAY');
516 if (ref $self->{cond} eq 'ARRAY') {
517 $del = [ map { my %hash;
518 foreach my $key (keys %{$_}) {
519 $key =~ /([^\.]+)$/;
520 $hash{$1} = $_->{$key};
521 }; \%hash; } @{$self->{cond}} ];
522 } elsif ((keys %{$self->{cond}})[0] eq '-and') {
523 $del->{-and} = [ map { my %hash;
524 foreach my $key (keys %{$_}) {
525 $key =~ /([^\.]+)$/;
526 $hash{$1} = $_->{$key};
527 }; \%hash; } @{$self->{cond}{-and}} ];
528 } else {
529 foreach my $key (keys %{$self->{cond}}) {
530 $key =~ /([^\.]+)$/;
531 $del->{$1} = $self->{cond}{$key};
532 }
533 }
534 $self->result_source->storage->delete($self->result_source->from, $del);
89c0a5a2 535 return 1;
536}
537
c01ab172 538=head2 delete_all
539
a33df5d4 540Fetches all objects and deletes them one at a time. Note that C<delete_all>
541will run cascade triggers while L</delete> will not.
c01ab172 542
543=cut
544
545sub delete_all {
546 my ($self) = @_;
547 $_->delete for $self->all;
548 return 1;
549}
28927b50 550
bfab575a 551=head2 pager
ee38fa40 552
553Returns a L<Data::Page> object for the current resultset. Only makes
a33df5d4 554sense for queries with a C<page> attribute.
ee38fa40 555
556=cut
557
3c5b25c5 558sub pager {
559 my ($self) = @_;
560 my $attrs = $self->{attrs};
701da8c4 561 $self->throw_exception("Can't create pager for non-paged rs") unless $self->{page};
6aeb9185 562 $attrs->{rows} ||= 10;
563 $self->count;
564 return $self->{pager} ||= Data::Page->new(
93b004d3 565 $self->{count}, $attrs->{rows}, $self->{page});
3c5b25c5 566}
567
bfab575a 568=head2 page($page_num)
ee38fa40 569
bfab575a 570Returns a new resultset for the specified page.
ee38fa40 571
572=cut
573
3c5b25c5 574sub page {
575 my ($self, $page) = @_;
6aeb9185 576 my $attrs = { %{$self->{attrs}} };
3c5b25c5 577 $attrs->{page} = $page;
701da8c4 578 return (ref $self)->new($self->result_source, $attrs);
fea3d045 579}
580
581=head2 new_result(\%vals)
582
87f0da6a 583Creates a result in the resultset's result class.
fea3d045 584
585=cut
586
587sub new_result {
588 my ($self, $values) = @_;
701da8c4 589 $self->throw_exception( "new_result needs a hash" )
fea3d045 590 unless (ref $values eq 'HASH');
701da8c4 591 $self->throw_exception( "Can't abstract implicit construct, condition not a hash" )
fea3d045 592 if ($self->{cond} && !(ref $self->{cond} eq 'HASH'));
593 my %new = %$values;
594 my $alias = $self->{attrs}{alias};
595 foreach my $key (keys %{$self->{cond}||{}}) {
596 $new{$1} = $self->{cond}{$key} if ($key =~ m/^(?:$alias\.)?([^\.]+)$/);
597 }
701da8c4 598 my $obj = $self->result_source->result_class->new(\%new);
599 $obj->result_source($self->result_source) if $obj->can('result_source');
097d3227 600 $obj;
fea3d045 601}
602
603=head2 create(\%vals)
604
87f0da6a 605Inserts a record into the resultset and returns the object.
fea3d045 606
a33df5d4 607Effectively a shortcut for C<< ->new_result(\%vals)->insert >>.
fea3d045 608
609=cut
610
611sub create {
612 my ($self, $attrs) = @_;
701da8c4 613 $self->throw_exception( "create needs a hashref" ) unless ref $attrs eq 'HASH';
fea3d045 614 return $self->new_result($attrs)->insert;
3c5b25c5 615}
616
87f0da6a 617=head2 find_or_create(\%vals, \%attrs?)
618
619 $class->find_or_create({ key => $val, ... });
c2b15ecc 620
c2b15ecc 621Searches for a record matching the search condition; if it doesn't find one,
cf7b40ed 622creates one and returns that instead.
87f0da6a 623
87f0da6a 624 my $cd = $schema->resultset('CD')->find_or_create({
625 cdid => 5,
626 artist => 'Massive Attack',
627 title => 'Mezzanine',
628 year => 2005,
629 });
630
631Also takes an optional C<key> attribute, to search by a specific key or unique
632constraint. For example:
633
634 my $cd = $schema->resultset('CD')->find_or_create(
635 {
636 artist => 'Massive Attack',
637 title => 'Mezzanine',
638 },
639 { key => 'artist_title' }
640 );
641
642See also L</find> and L</update_or_create>.
643
c2b15ecc 644=cut
645
646sub find_or_create {
647 my $self = shift;
87f0da6a 648 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
649 my $hash = ref $_[0] eq "HASH" ? shift : {@_};
650 my $exists = $self->find($hash, $attrs);
c2b15ecc 651 return defined($exists) ? $exists : $self->create($hash);
652}
653
87f0da6a 654=head2 update_or_create
655
656 $class->update_or_create({ key => $val, ... });
657
658First, search for an existing row matching one of the unique constraints
659(including the primary key) on the source of this resultset. If a row is
660found, update it with the other given column values. Otherwise, create a new
661row.
662
663Takes an optional C<key> attribute to search on a specific unique constraint.
664For example:
665
666 # In your application
667 my $cd = $schema->resultset('CD')->update_or_create(
668 {
669 artist => 'Massive Attack',
670 title => 'Mezzanine',
671 year => 1998,
672 },
673 { key => 'artist_title' }
674 );
675
676If no C<key> is specified, it searches on all unique constraints defined on the
677source, including the primary key.
678
679If the C<key> is specified as C<primary>, search only on the primary key.
680
a33df5d4 681See also L</find> and L</find_or_create>.
682
87f0da6a 683=cut
684
685sub update_or_create {
686 my $self = shift;
687
688 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
689 my $hash = ref $_[0] eq "HASH" ? shift : {@_};
690
701da8c4 691 my %unique_constraints = $self->result_source->unique_constraints;
87f0da6a 692 my @constraint_names = (exists $attrs->{key}
693 ? ($attrs->{key})
694 : keys %unique_constraints);
695
696 my @unique_hashes;
697 foreach my $name (@constraint_names) {
698 my @unique_cols = @{ $unique_constraints{$name} };
699 my %unique_hash =
700 map { $_ => $hash->{$_} }
701 grep { exists $hash->{$_} }
702 @unique_cols;
703
704 push @unique_hashes, \%unique_hash
705 if (scalar keys %unique_hash == scalar @unique_cols);
706 }
707
708 my $row;
709 if (@unique_hashes) {
710 $row = $self->search(\@unique_hashes, { rows => 1 })->first;
711 if ($row) {
712 $row->set_columns($hash);
713 $row->update;
714 }
715 }
716
717 unless ($row) {
718 $row = $self->create($hash);
719 }
720
721 return $row;
722}
723
701da8c4 724=head2 throw_exception
725
726See Schema's throw_exception
727
728=cut
729
730sub throw_exception {
731 my $self=shift;
732 $self->result_source->schema->throw_exception(@_);
733}
734
40dbc108 735=head1 ATTRIBUTES
076652e8 736
a33df5d4 737The resultset takes various attributes that modify its behavior. Here's an
738overview of them:
bfab575a 739
740=head2 order_by
076652e8 741
a33df5d4 742Which column(s) to order the results by. This is currently passed through
743directly to SQL, so you can give e.g. C<foo DESC> for a descending order.
076652e8 744
976f3686 745=head2 cols (arrayref)
746
a33df5d4 747Shortcut to request a particular set of columns to be retrieved. Adds
748C<me.> onto the start of any column without a C<.> in it and sets C<select>
749from that, then auto-populates C<as> from C<select> as normal.
976f3686 750
5ac6a044 751=head2 include_columns (arrayref)
752
753Shortcut to include additional columns in the returned results - for example
754
755 { include_columns => ['foo.name'], join => ['foo'] }
756
757would add a 'name' column to the information passed to object inflation
758
976f3686 759=head2 select (arrayref)
760
4a28c340 761Indicates which columns should be selected from the storage. You can use
762column names, or in the case of RDBMS back ends, function or stored procedure
763names:
764
765 $rs = $schema->resultset('Foo')->search(
766 {},
767 {
cf7b40ed 768 select => [
4a28c340 769 'column_name',
770 { count => 'column_to_count' },
771 { sum => 'column_to_sum' }
cf7b40ed 772 ]
4a28c340 773 }
774 );
775
776When you use function/stored procedure names and do not supply an C<as>
777attribute, the column names returned are storage-dependent. E.g. MySQL would
778return a column named C<count(column_to_count)> in the above example.
976f3686 779
780=head2 as (arrayref)
076652e8 781
4a28c340 782Indicates column names for object inflation. This is used in conjunction with
783C<select>, usually when C<select> contains one or more function or stored
784procedure names:
785
786 $rs = $schema->resultset('Foo')->search(
787 {},
788 {
cf7b40ed 789 select => [
4a28c340 790 'column1',
791 { count => 'column2' }
cf7b40ed 792 ],
4a28c340 793 as => [qw/ column1 column2_count /]
794 }
795 );
796
797 my $foo = $rs->first(); # get the first Foo
798
799If the object against which the search is performed already has an accessor
800matching a column name specified in C<as>, the value can be retrieved using
801the accessor as normal:
802
803 my $column1 = $foo->column1();
804
805If on the other hand an accessor does not exist in the object, you need to
806use C<get_column> instead:
807
808 my $column2_count = $foo->get_column('column2_count');
809
810You can create your own accessors if required - see
811L<DBIx::Class::Manual::Cookbook> for details.
ee38fa40 812
bfab575a 813=head2 join
ee38fa40 814
a33df5d4 815Contains a list of relationships that should be joined for this query. For
816example:
817
818 # Get CDs by Nine Inch Nails
819 my $rs = $schema->resultset('CD')->search(
820 { 'artist.name' => 'Nine Inch Nails' },
821 { join => 'artist' }
822 );
823
824Can also contain a hash reference to refer to the other relation's relations.
825For example:
826
827 package MyApp::Schema::Track;
828 use base qw/DBIx::Class/;
829 __PACKAGE__->table('track');
830 __PACKAGE__->add_columns(qw/trackid cd position title/);
831 __PACKAGE__->set_primary_key('trackid');
832 __PACKAGE__->belongs_to(cd => 'MyApp::Schema::CD');
833 1;
834
835 # In your application
836 my $rs = $schema->resultset('Artist')->search(
837 { 'track.title' => 'Teardrop' },
838 {
839 join => { cd => 'track' },
840 order_by => 'artist.name',
841 }
842 );
843
2cb360cc 844If the same join is supplied twice, it will be aliased to <rel>_2 (and
845similarly for a third time). For e.g.
846
847 my $rs = $schema->resultset('Artist')->search(
848 { 'cds.title' => 'Foo',
849 'cds_2.title' => 'Bar' },
850 { join => [ qw/cds cds/ ] });
851
852will return a set of all artists that have both a cd with title Foo and a cd
853with title Bar.
854
855If you want to fetch related objects from other tables as well, see C<prefetch>
ae1c90a1 856below.
ee38fa40 857
ae1c90a1 858=head2 prefetch arrayref/hashref
ee38fa40 859
ae1c90a1 860Contains one or more relationships that should be fetched along with the main
bfab575a 861query (when they are accessed afterwards they will have already been
a33df5d4 862"prefetched"). This is useful for when you know you will need the related
ae1c90a1 863objects, because it saves at least one query:
864
865 my $rs = $schema->resultset('Tag')->search(
866 {},
867 {
868 prefetch => {
869 cd => 'artist'
870 }
871 }
872 );
873
874The initial search results in SQL like the following:
875
876 SELECT tag.*, cd.*, artist.* FROM tag
877 JOIN cd ON tag.cd = cd.cdid
878 JOIN artist ON cd.artist = artist.artistid
879
880L<DBIx::Class> has no need to go back to the database when we access the
881C<cd> or C<artist> relationships, which saves us two SQL statements in this
882case.
883
2cb360cc 884Simple prefetches will be joined automatically, so there is no need
885for a C<join> attribute in the above search. If you're prefetching to
886depth (e.g. { cd => { artist => 'label' } or similar), you'll need to
887specify the join as well.
ae1c90a1 888
889C<prefetch> can be used with the following relationship types: C<belongs_to>,
2cb360cc 890C<has_one> (or if you're using C<add_relationship>, any relationship declared
891with an accessor type of 'single' or 'filter').
ee38fa40 892
4a28c340 893=head2 from (arrayref)
ee38fa40 894
4a28c340 895The C<from> attribute gives you manual control over the C<FROM> clause of SQL
896statements generated by L<DBIx::Class>, allowing you to express custom C<JOIN>
897clauses.
ee38fa40 898
a33df5d4 899NOTE: Use this on your own risk. This allows you to shoot off your foot!
4a28c340 900C<join> will usually do what you need and it is strongly recommended that you
901avoid using C<from> unless you cannot achieve the desired result using C<join>.
902
903In simple terms, C<from> works as follows:
904
905 [
906 { <alias> => <table>, -join-type => 'inner|left|right' }
907 [] # nested JOIN (optional)
908 { <table.column> = <foreign_table.foreign_key> }
909 ]
910
911 JOIN
912 <alias> <table>
913 [JOIN ...]
914 ON <table.column> = <foreign_table.foreign_key>
915
916An easy way to follow the examples below is to remember the following:
917
918 Anything inside "[]" is a JOIN
919 Anything inside "{}" is a condition for the enclosing JOIN
920
921The following examples utilize a "person" table in a family tree application.
922In order to express parent->child relationships, this table is self-joined:
923
924 # Person->belongs_to('father' => 'Person');
925 # Person->belongs_to('mother' => 'Person');
926
927C<from> can be used to nest joins. Here we return all children with a father,
928then search against all mothers of those children:
929
930 $rs = $schema->resultset('Person')->search(
931 {},
932 {
933 alias => 'mother', # alias columns in accordance with "from"
934 from => [
935 { mother => 'person' },
936 [
937 [
938 { child => 'person' },
939 [
940 { father => 'person' },
941 { 'father.person_id' => 'child.father_id' }
942 ]
943 ],
944 { 'mother.person_id' => 'child.mother_id' }
945 ],
946 ]
947 },
948 );
949
950 # Equivalent SQL:
951 # SELECT mother.* FROM person mother
952 # JOIN (
953 # person child
954 # JOIN person father
955 # ON ( father.person_id = child.father_id )
956 # )
957 # ON ( mother.person_id = child.mother_id )
958
959The type of any join can be controlled manually. To search against only people
960with a father in the person table, we could explicitly use C<INNER JOIN>:
961
962 $rs = $schema->resultset('Person')->search(
963 {},
964 {
965 alias => 'child', # alias columns in accordance with "from"
966 from => [
967 { child => 'person' },
968 [
969 { father => 'person', -join-type => 'inner' },
970 { 'father.id' => 'child.father_id' }
971 ],
972 ]
973 },
974 );
975
976 # Equivalent SQL:
977 # SELECT child.* FROM person child
978 # INNER JOIN person father ON child.father_id = father.id
ee38fa40 979
bfab575a 980=head2 page
076652e8 981
a33df5d4 982For a paged resultset, specifies which page to retrieve. Leave unset
bfab575a 983for an unpaged resultset.
076652e8 984
bfab575a 985=head2 rows
076652e8 986
4a28c340 987For a paged resultset, how many rows per page:
988
989 rows => 10
990
991Can also be used to simulate an SQL C<LIMIT>.
076652e8 992
a33df5d4 993=head2 group_by (arrayref)
54540863 994
bda4c2b8 995A arrayref of columns to group by. Can include columns of joined tables.
54540863 996
675ce4a6 997 group_by => [qw/ column1 column2 ... /]
998
54540863 999=head2 distinct
1000
a33df5d4 1001Set to 1 to group by all columns.
1002
1003For more examples of using these attributes, see
1004L<DBIx::Class::Manual::Cookbook>.
54540863 1005
bfab575a 1006=cut
076652e8 1007
89c0a5a2 10081;