X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSet.pm;h=ab96fffcc0f7ec3104462f5567bfdcabcf27be0c;hb=f4409169fe98a88a7802b96e8a75838e8a4756c6;hp=32e4177e8fa155c39c63fcf42ed92e30b8c75b34;hpb=c5b7d79941cd6942aeec1e81e1d4f7f9ad7eb62f;p=dbsrgits%2FDBIx-Class-Historic.git diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index 32e4177..ab96fff 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -32,6 +32,7 @@ In the examples below, the following table classes are used: package MyApp::Schema::Artist; use base qw/DBIx::Class/; + __PACKAGE__->load_components(qw/Core/); __PACKAGE__->table('artist'); __PACKAGE__->add_columns(qw/artistid name/); __PACKAGE__->set_primary_key('artistid'); @@ -40,7 +41,8 @@ In the examples below, the following table classes are used: package MyApp::Schema::CD; use base qw/DBIx::Class/; - __PACKAGE__->table('artist'); + __PACKAGE__->load_components(qw/Core/); + __PACKAGE__->table('cd'); __PACKAGE__->add_columns(qw/cdid artist title year/); __PACKAGE__->set_primary_key('cdid'); __PACKAGE__->belongs_to(artist => 'MyApp::Schema::Artist'); @@ -48,7 +50,9 @@ In the examples below, the following table classes are used: =head1 METHODS -=head2 new($source, \%$attrs) +=head2 new + +=head3 Arguments: ($source, \%$attrs) The resultset constructor. Takes a source object (usually a L) and an attribute hash (see L @@ -84,6 +88,7 @@ sub new { } #use Data::Dumper; warn Dumper(@{$attrs}{qw/select as/}); $attrs->{from} ||= [ { $alias => $source->from } ]; + $attrs->{seen_join} ||= {}; if (my $join = delete $attrs->{join}) { foreach my $j (ref $join eq 'ARRAY' ? (@{$join}) : ($join)) { @@ -93,7 +98,7 @@ sub new { $seen{$j} = 1; } } - push(@{$attrs->{from}}, $source->resolve_join($join, $attrs->{alias})); + push(@{$attrs->{from}}, $source->resolve_join($join, $attrs->{alias}, $attrs->{seen_join})); } $attrs->{group_by} ||= $attrs->{select} if delete $attrs->{distinct}; @@ -110,11 +115,10 @@ sub new { push(@{$attrs->{from}}, $source->resolve_join($p, $attrs->{alias})) unless $seen{$p}; } - my @cols = (); - push @cols, $source->resolve_prefetch($p, $attrs->{alias}); + my @prefetch = $source->resolve_prefetch($p, $attrs->{alias}); #die Dumper \@cols; - push(@{$attrs->{select}}, @cols); - push(@{$attrs->{as}}, @cols); + push(@{$attrs->{select}}, map { $_->[0] } @prefetch); + push(@{$attrs->{as}}, map { $_->[1] } @prefetch); } } @@ -190,7 +194,9 @@ sub search_literal { return $self->search(\$cond, $attrs); } -=head2 find(@colvalues), find(\%cols, \%attrs?) +=head2 find + +=head3 Arguments: (@colvalues) | (\%cols, \%attrs?) Finds a row based on its primary key or unique constraint. For example: @@ -259,10 +265,13 @@ sub search_related { "No such relationship ${rel} in search_related") unless $rel_obj; my $rs = $self->search(undef, { join => $rel }); + my $alias = ($rs->{attrs}{seen_join}{$rel} > 1 + ? join('_', $rel, $rs->{attrs}{seen_join}{$rel}) + : $rel); return $self->result_source->schema->resultset($rel_obj->{class} )->search( undef, { %{$rs->{attrs}}, - alias => $rel, + alias => $alias, select => undef(), as => undef() } )->search(@rest); @@ -304,7 +313,9 @@ sub search_like { return $class->search($query, { %$attrs }); } -=head2 slice($first, $last) +=head2 slice + +=head3 Arguments: ($first, $last) Returns a subset of elements from the resultset. @@ -363,7 +374,7 @@ sub _construct_object { return $new; } -=head2 result_source +=head2 result_source Returns a reference to the result source for this recordset. @@ -391,14 +402,14 @@ sub count { my $group_by; my $select = { 'count' => '*' }; if( $group_by = delete $self->{attrs}{group_by} ) { - my @distinct = @$group_by; + my @distinct = (ref $group_by ? @$group_by : ($group_by)); # todo: try CONCAT for multi-column pk my @pk = $self->result_source->primary_columns; if( scalar(@pk) == 1 ) { my $pk = shift(@pk); my $alias = $self->{attrs}{alias}; my $re = qr/^($alias\.)?$pk$/; - foreach my $column ( @$group_by ) { + foreach my $column ( @distinct) { if( $column =~ $re ) { @distinct = ( $column ); last; @@ -470,7 +481,9 @@ sub first { return $_[0]->reset->next; } -=head2 update(\%values) +=head2 update + +=head3 Arguments: (\%values) Sets the specified columns in the resultset to the supplied values. @@ -483,7 +496,9 @@ sub update { $self->result_source->from, $values, $self->{cond}); } -=head2 update_all(\%values) +=head2 update_all + +=head3 Arguments: (\%values) Fetches all objects and updates them one at a time. Note that C will run cascade triggers while L will not. @@ -507,7 +522,28 @@ Deletes the contents of the resultset from its result source. sub delete { my ($self) = @_; - $self->result_source->storage->delete($self->result_source->from, $self->{cond}); + my $del = {}; + $self->throw_exception("Can't delete on resultset with condition unless hash or array") + unless (ref($self->{cond}) eq 'HASH' || ref($self->{cond}) eq 'ARRAY'); + if (ref $self->{cond} eq 'ARRAY') { + $del = [ map { my %hash; + foreach my $key (keys %{$_}) { + $key =~ /([^\.]+)$/; + $hash{$1} = $_->{$key}; + }; \%hash; } @{$self->{cond}} ]; + } elsif ((keys %{$self->{cond}})[0] eq '-and') { + $del->{-and} = [ map { my %hash; + foreach my $key (keys %{$_}) { + $key =~ /([^\.]+)$/; + $hash{$1} = $_->{$key}; + }; \%hash; } @{$self->{cond}{-and}} ]; + } else { + foreach my $key (keys %{$self->{cond}}) { + $key =~ /([^\.]+)$/; + $del->{$1} = $self->{cond}{$key}; + } + } + $self->result_source->storage->delete($self->result_source->from, $del); return 1; } @@ -541,7 +577,9 @@ sub pager { $self->{count}, $attrs->{rows}, $self->{page}); } -=head2 page($page_num) +=head2 page + +=head3 Arguments: ($page_num) Returns a new resultset for the specified page. @@ -554,7 +592,9 @@ sub page { return (ref $self)->new($self->result_source, $attrs); } -=head2 new_result(\%vals) +=head2 new_result + +=head3 Arguments: (\%vals) Creates a result in the resultset's result class. @@ -576,7 +616,9 @@ sub new_result { $obj; } -=head2 create(\%vals) +=head2 create + +=head3 Arguments: (\%vals) Inserts a record into the resultset and returns the object. @@ -590,7 +632,9 @@ sub create { return $self->new_result($attrs)->insert; } -=head2 find_or_create(\%vals, \%attrs?) +=head2 find_or_create + +=head3 Arguments: (\%vals, \%attrs?) $class->find_or_create({ key => $val, ... }); @@ -718,13 +762,17 @@ overview of them: Which column(s) to order the results by. This is currently passed through directly to SQL, so you can give e.g. C for a descending order. -=head2 cols (arrayref) +=head2 cols + +=head3 Arguments: (arrayref) Shortcut to request a particular set of columns to be retrieved. Adds C onto the start of any column without a C<.> in it and sets C as normal. -=head2 include_columns (arrayref) +=head2 include_columns + +=head3 Arguments: (arrayref) Shortcut to include additional columns in the returned results - for example @@ -732,7 +780,9 @@ Shortcut to include additional columns in the returned results - for example would add a 'name' column to the information passed to object inflation -=head2 select (arrayref) +=head2 select + +=head3 Arguments: (arrayref) Indicates which columns should be selected from the storage. You can use column names, or in the case of RDBMS back ends, function or stored procedure @@ -753,7 +803,9 @@ When you use function/stored procedure names and do not supply an C attribute, the column names returned are storage-dependent. E.g. MySQL would return a column named C in the above example. -=head2 as (arrayref) +=head2 as + +=head3 Arguments: (arrayref) Indicates column names for object inflation. This is used in conjunction with C contains one or more function or stored @@ -817,10 +869,23 @@ For example: } ); -If you want to fetch columns from related tables as well, see C +If the same join is supplied twice, it will be aliased to _2 (and +similarly for a third time). For e.g. + + my $rs = $schema->resultset('Artist')->search( + { 'cds.title' => 'Foo', + 'cds_2.title' => 'Bar' }, + { join => [ qw/cds cds/ ] }); + +will return a set of all artists that have both a cd with title Foo and a cd +with title Bar. + +If you want to fetch related objects from other tables as well, see C below. -=head2 prefetch arrayref/hashref +=head2 prefetch + +=head3 Arguments: arrayref/hashref Contains one or more relationships that should be fetched along with the main query (when they are accessed afterwards they will have already been @@ -846,13 +911,18 @@ L has no need to go back to the database when we access the C or C relationships, which saves us two SQL statements in this case. -Any prefetched relationship will be joined automatically, so there is no need -for a C attribute in the above search. +Simple prefetches will be joined automatically, so there is no need +for a C attribute in the above search. If you're prefetching to +depth (e.g. { cd => { artist => 'label' } or similar), you'll need to +specify the join as well. C can be used with the following relationship types: C, -C. +C (or if you're using C, any relationship declared +with an accessor type of 'single' or 'filter'). + +=head2 from -=head2 from (arrayref) +=head3 Arguments: (arrayref) The C attribute gives you manual control over the C clause of SQL statements generated by L, allowing you to express custom C @@ -952,7 +1022,9 @@ For a paged resultset, how many rows per page: Can also be used to simulate an SQL C. -=head2 group_by (arrayref) +=head2 group_by + +=head3 Arguments: (arrayref) A arrayref of columns to group by. Can include columns of joined tables.