X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSet.pm;h=8adff20c10a2b9f444dc13bc0c1d5317956bb9f9;hb=550adccc763b6887aa2ce43b1d1d9fb48b240763;hp=25d8b032bed81c85b66c72aca937f879f0fda8fc;hpb=32c26d019a0401493720710f3358988ee7318d32;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index 25d8b03..8adff20 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -3,14 +3,15 @@ package DBIx::Class::ResultSet; use strict; use warnings; use overload - '0+' => \&count, - 'bool' => sub { 1; }, + '0+' => "count", + 'bool' => "_bool", fallback => 1; use Carp::Clan qw/^DBIx::Class/; use Data::Page; use Storable; use DBIx::Class::ResultSetColumn; use DBIx::Class::ResultSourceHandle; +use List::Util (); use base qw/DBIx::Class/; __PACKAGE__->mk_group_accessors('simple' => qw/result_class _source_handle/); @@ -50,6 +51,10 @@ In the examples below, the following table classes are used: __PACKAGE__->belongs_to(artist => 'MyApp::Schema::Artist'); 1; +=head1 OVERLOADING + +If a resultset is used as a number it returns the C. However, if it is used as a boolean it is always true. So if you want to check if a result set has any results use C. C will always be true. + =head1 METHODS =head2 new @@ -168,18 +173,26 @@ always return a resultset, even in list context. sub search_rs { my $self = shift; - my $rows; - - unless (@_) { # no search, effectively just a clone - $rows = $self->get_cache; - } - my $attrs = {}; $attrs = pop(@_) if @_ > 1 and ref $_[$#_] eq 'HASH'; my $our_attrs = { %{$self->{attrs}} }; my $having = delete $our_attrs->{having}; my $where = delete $our_attrs->{where}; + my $rows; + + my %safe = (alias => 1, cache => 1); + + unless ( + (@_ && defined($_[0])) # @_ == () or (undef) + || + (keys %$attrs # empty attrs or only 'safe' attrs + && List::Util::first { !$safe{$_} } keys %$attrs) + ) { + # no search, effectively just a clone + $rows = $self->get_cache; + } + my $new_attrs = { %{$our_attrs}, %{$attrs} }; # merge new attrs into inherited @@ -319,11 +332,15 @@ Additionally, you can specify the columns explicitly by name: If the C is specified as C, it searches only on the primary key. If no C is specified, it searches on all unique constraints defined on the -source, including the primary key. +source for which column data is provided, including the primary key. If your table does not have a primary key, you B provide a value for the C attribute matching one of the unique constraints on the source. +Note: If your query does not return only one row, a warning is generated: + + Query returned more than one row + See also L and L. For information on how to declare unique constraints, see L. @@ -375,25 +392,46 @@ sub find { @{$input_query}{@keys} = values %related; } - my @unique_queries = $self->_unique_queries($input_query, $attrs); # Build the final query: Default to the disjunction of the unique queries, # but allow the input query in case the ResultSet defines the query or the # user is abusing find my $alias = exists $attrs->{alias} ? $attrs->{alias} : $self->{attrs}{alias}; - my $query = @unique_queries - ? [ map { $self->_add_alias($_, $alias) } @unique_queries ] - : $self->_add_alias($input_query, $alias); + my $query; + if (exists $attrs->{key}) { + my @unique_cols = $self->result_source->unique_constraint_columns($attrs->{key}); + my $unique_query = $self->_build_unique_query($input_query, \@unique_cols); + $query = $self->_add_alias($unique_query, $alias); + } + else { + my @unique_queries = $self->_unique_queries($input_query, $attrs); + $query = @unique_queries + ? [ map { $self->_add_alias($_, $alias) } @unique_queries ] + : $self->_add_alias($input_query, $alias); + } # Run the query if (keys %$attrs) { my $rs = $self->search($query, $attrs); - return keys %{$rs->_resolved_attrs->{collapse}} ? $rs->next : $rs->single; + if (keys %{$rs->_resolved_attrs->{collapse}}) { + my $row = $rs->next; + carp "Query returned more than one row" if $rs->next; + return $row; + } + else { + return $rs->single; + } } else { - return keys %{$self->_resolved_attrs->{collapse}} - ? $self->search($query)->next - : $self->single($query); + if (keys %{$self->_resolved_attrs->{collapse}}) { + my $rs = $self->search($query); + my $row = $rs->next; + carp "Query returned more than one row" if $rs->next; + return $row; + } + else { + return $self->single($query); + } } } @@ -483,6 +521,17 @@ sub search_related { return shift->related_resultset(shift)->search(@_); } +=head2 search_related_rs + +This method works exactly the same as search_related, except that +it guarantees a restultset, even in list context. + +=cut + +sub search_related_rs { + return shift->related_resultset(shift)->search_rs(@_); +} + =head2 cursor =over 4 @@ -987,6 +1036,10 @@ sub _count { # Separated out so pager can get the full count return $count; } +sub _bool { + return 1; +} + =head2 count_literal =over 4 @@ -2115,7 +2168,12 @@ See L for details. sub throw_exception { my $self=shift; - $self->_source_handle->schema->throw_exception(@_); + if (ref $self && $self->_source_handle->schema) { + $self->_source_handle->schema->throw_exception(@_) + } else { + croak(@_); + } + } # XXX: FIXME: Attributes docs need clearing up