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