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