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