X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSet.pm;h=e03a16d2a489fbcaf51e1bc6a6ee12b1e2f30a97;hb=a0638a7bb719844a0d5c264265a3a13b18d3318f;hp=626e1f71235ccd160d00f5402fe059cd681ace9f;hpb=bcd264195a5ab28e03232464f786c155524a12a9;p=dbsrgits%2FDBIx-Class-Historic.git diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index 626e1f7..e03a16d 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -21,7 +21,7 @@ DBIx::Class::ResultSet - Responsible for fetching and creating resultset. =head1 SYNOPSIS my $rs = $schema->resultset('User')->search(registered => 1); - my @rows = $schema->resultset('Foo')->search(bar => 'baz'); + my @rows = $schema->resultset('CD')->search(year => 2005); =head1 DESCRIPTION @@ -151,14 +151,16 @@ sub new { =head2 search - my @obj = $rs->search({ foo => 3 }); # "... WHERE foo = 3" - my $new_rs = $rs->search({ foo => 3 }); + my @cds = $rs->search({ year => 2001 }); # "... WHERE year = 2001" + my $new_rs = $rs->search({ year => 2005 }); If you need to pass in additional attributes but no additional condition, call it as C. - # "SELECT foo, bar FROM $class_table" - my @all = $class->search(undef, { columns => [qw/foo bar/] }); + # "SELECT name, artistid FROM $artist_table" + my @all_artists = $schema->resultset('Artist')->search(undef, { + columns => [qw/name artistid/], + }); =cut @@ -252,7 +254,7 @@ sub find { my @cols = $self->result_source->primary_columns; if (exists $attrs->{key}) { my %uniq = $self->result_source->unique_constraints; - $self->throw_exception( "Unknown key $attrs->{key} on $self->name" ) + $self->throw_exception( "Unknown key $attrs->{key} on '" . $self->result_source->name . "'" ) unless exists $uniq{$attrs->{key}}; @cols = @{ $uniq{$attrs->{key}} }; } @@ -505,43 +507,49 @@ clause. sub count { my $self = shift; return $self->search(@_)->count if @_ and defined $_[0]; - unless (defined $self->{count}) { - return scalar @{ $self->get_cache } if @{ $self->get_cache }; - my $select = { count => '*' }; - my $attrs = { %{ $self->{attrs} } }; - if (my $group_by = delete $attrs->{group_by}) { - delete $attrs->{having}; - my @distinct = (ref $group_by ? @$group_by : ($group_by)); - # todo: try CONCAT for multi-column pk - my @pk = $self->result_source->primary_columns; - if (@pk == 1) { - foreach my $column (@distinct) { - if ($column =~ qr/^(?:\Q$attrs->{alias}.\E)?$pk[0]$/) { - @distinct = ($column); - last; - } - } - } + return scalar @{ $self->get_cache } if @{ $self->get_cache }; - $select = { count => { distinct => \@distinct } }; - #use Data::Dumper; die Dumper $select; - } + my $count = $self->_count; + return 0 unless $count; - $attrs->{select} = $select; - $attrs->{as} = [qw/count/]; - # offset, order by and page are not needed to count. record_filter is cdbi - delete $attrs->{$_} for qw/rows offset order_by page pager record_filter/; - - ($self->{count}) = (ref $self)->new($self->result_source, $attrs)->cursor->next; - } - return 0 unless $self->{count}; - my $count = $self->{count}; $count -= $self->{attrs}{offset} if $self->{attrs}{offset}; $count = $self->{attrs}{rows} if $self->{attrs}{rows} and $self->{attrs}{rows} < $count; return $count; } +sub _count { # Separated out so pager can get the full count + my $self = shift; + my $select = { count => '*' }; + my $attrs = { %{ $self->{attrs} } }; + if (my $group_by = delete $attrs->{group_by}) { + delete $attrs->{having}; + my @distinct = (ref $group_by ? @$group_by : ($group_by)); + # todo: try CONCAT for multi-column pk + my @pk = $self->result_source->primary_columns; + if (@pk == 1) { + foreach my $column (@distinct) { + if ($column =~ qr/^(?:\Q$attrs->{alias}.\E)?$pk[0]$/) { + @distinct = ($column); + last; + } + } + } + + $select = { count => { distinct => \@distinct } }; + #use Data::Dumper; die Dumper $select; + } + + $attrs->{select} = $select; + $attrs->{as} = [qw/count/]; + + # offset, order by and page are not needed to count. record_filter is cdbi + delete $attrs->{$_} for qw/rows offset order_by page pager record_filter/; + + my ($count) = (ref $self)->new($self->result_source, $attrs)->cursor->next; + return $count; +} + =head2 count_literal Calls L with the passed arguments, then L. @@ -649,26 +657,41 @@ Deletes the contents of the resultset from its result source. sub delete { my ($self) = @_; 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') { + + if (!ref($self->{cond})) { + + # No-op. No condition, we're deleting everything + + } elsif (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 %{$_}) { + + } elsif (ref $self->{cond} eq 'HASH') { + + if ((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 =~ /([^.]+)$/; - $hash{$1} = $_->{$key}; - }; \%hash; } @{$self->{cond}{-and}} ]; - } else { - foreach my $key (keys %{$self->{cond}}) { - $key =~ /([^.]+)$/; - $del->{$1} = $self->{cond}{$key}; + $del->{$1} = $self->{cond}{$key}; + } } + } else { + $self->throw_exception( + "Can't delete on resultset with condition unless hash or array"); } + $self->result_source->storage->delete($self->result_source->from, $del); return 1; } @@ -698,9 +721,8 @@ sub pager { my $attrs = $self->{attrs}; $self->throw_exception("Can't create pager for non-paged rs") unless $self->{page}; $attrs->{rows} ||= 10; - $self->count; return $self->{pager} ||= Data::Page->new( - $self->{count}, $attrs->{rows}, $self->{page}); + $self->_count, $attrs->{rows}, $self->{page}); } =head2 page @@ -904,7 +926,7 @@ sub clear_cache { Returns a related resultset for the supplied relationship name. - $rs = $rs->related_resultset('foo'); + $artist_rs = $schema->resultset('CD')->related_resultset('Artist'); =cut @@ -953,8 +975,9 @@ overview of them: =head2 order_by -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. +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 on the column `year'. =head2 columns @@ -971,9 +994,13 @@ use the C attribute, as in earlier versions of DBIC.) Shortcut to include additional columns in the returned results - for example - { include_columns => ['foo.name'], join => ['foo'] } + $schema->resultset('CD')->search(undef, { + include_columns => ['artist.name'], + join => ['artist'] + }); -would add a 'name' column to the information passed to object inflation +would return all CDs and include a 'name' column to the information +passed to object inflation =head2 select @@ -983,20 +1010,17 @@ 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 names: - $rs = $schema->resultset('Foo')->search( - undef, - { - select => [ - 'column_name', - { count => 'column_to_count' }, - { sum => 'column_to_sum' } - ] - } - ); + $rs = $schema->resultset('Employee')->search(undef, { + select => [ + 'name', + { count => 'employeeid' }, + { sum => 'salary' } + ] + }); 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. +return a column named C in the above example. =head2 as @@ -1006,29 +1030,26 @@ Indicates column names for object inflation. This is used in conjunction with C contains one or more function or stored procedure names: - $rs = $schema->resultset('Foo')->search( - undef, - { - select => [ - 'column1', - { count => 'column2' } - ], - as => [qw/ column1 column2_count /] - } - ); + $rs = $schema->resultset('Employee')->search(undef, { + select => [ + 'name', + { count => 'employeeid' } + ], + as => ['name', 'employee_count'], + }); - my $foo = $rs->first(); # get the first Foo + my $employee = $rs->first(); # get the first Employee If the object against which the search is performed already has an accessor matching a column name specified in C, the value can be retrieved using the accessor as normal: - my $column1 = $foo->column1(); + my $name = $employee->name(); If on the other hand an accessor does not exist in the object, you need to use C instead: - my $column2_count = $foo->get_column('column2_count'); + my $employee_count = $employee->get_column('employee_count'); You can create your own accessors if required - see L for details. @@ -1067,13 +1088,15 @@ For example: 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/ ] }); + my $rs = $schema->resultset('Artist')->search({ + 'cds.title' => 'Down to Earth', + 'cds_2.title' => 'Popular', + }, { + 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. +will return a set of all artists that have both a cd with title 'Down +to Earth' and a cd with title 'Popular'. If you want to fetch related objects from other tables as well, see C below.