X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSet.pm;h=f56254e81fa6390bf01902afad109e7559c5753a;hb=7edf5f1cd3b097de79d262ed02d65128336f5893;hp=4a15e22945ebed1db9a5fc1269191b3d5d41b2a3;hpb=1c133e22c6e3f2701e057ee4f486f1fcaffe8428;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index 4a15e22..f56254e 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 @@ -95,6 +100,8 @@ sub new { $attrs->{alias} ||= 'me'; + # Creation of {} and bless separated to mitigate RH perl bug + # see https://bugzilla.redhat.com/show_bug.cgi?id=196836 my $self = { _source_handle => $source, result_class => $attrs->{result_class} || $source->resolve->result_class, @@ -138,6 +145,8 @@ L. For more examples of using this function, see L. For a complete documentation for the first argument, see L. +For more help on using joins with search, see L. + =cut sub search { @@ -164,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 @@ -268,7 +285,7 @@ CAVEAT: C is provided for Class::DBI compatibility and should only be used in that context. There are known problems using C in chained queries; it can result in bind values in the wrong order. See L and -L for seaching techniques that do not +L for searching techniques that do not require C. =cut @@ -315,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. @@ -371,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); + } } } @@ -479,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 @@ -518,9 +571,17 @@ sub cursor { Inflates the first result without creating a cursor if the resultset has any records in it; if not returns nothing. Used by L as an optimisation. -Can optionally take an additional condition *only* - this is a fast-code-path -method; if you need to add extra joins or similar call ->search and then -->single without a condition on the $rs returned from that. +Can optionally take an additional condition B - this is a fast-code-path +method; if you need to add extra joins or similar call L and then +L without a condition on the L returned from +that. + +B: As of 0.08100, this method assumes that the query returns only one +row. If more than one row is returned, you will receive a warning: + + Query returned more than one row + +In this case, you should be using L or L instead. =cut @@ -925,7 +986,7 @@ Performs an SQL C with the same query as the resultset was built with to find the number of elements. If passed arguments, does a search on the resultset and counts the results of that. -Note: When using C with C, L emulates C +Note: When using C with C, L emulates C using C. Some databases (notably SQLite) do not support C with multiple columns. If you are using such a database, you should only use columns from the main table in your C @@ -983,6 +1044,10 @@ sub _count { # Separated out so pager can get the full count return $count; } +sub _bool { + return 1; +} + =head2 count_literal =over 4 @@ -1559,7 +1624,7 @@ sub find_or_new { =item Arguments: \%vals -=item Return Value: $object +=item Return Value: a L $object =back @@ -2074,10 +2139,10 @@ sub _merge_attr { $position++; } my ($b_key) = ( ref $b_element eq 'HASH' ) ? keys %{$b_element} : ($b_element); + if ($best_candidate->{score} == 0 || exists $seen_keys->{$b_key}) { push( @{$a}, $b_element ); } else { - $seen_keys->{$b_key} = 1; # don't merge the same key twice my $a_best = $a->[$best_candidate->{position}]; # merge a_best and b_element together and replace original with merged if (ref $a_best ne 'HASH') { @@ -2087,6 +2152,7 @@ sub _merge_attr { $a->[$best_candidate->{position}] = { $key => $self->_merge_attr($a_best->{$key}, $b_element->{$key}) }; } } + $seen_keys->{$b_key} = 1; # don't merge the same key twice } return $a; @@ -2110,7 +2176,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 @@ -2199,7 +2270,7 @@ return a column named C in the above example. =over 4 Indicates additional columns to be selected from storage. Works the same as -L but adds columns to the selection. =back @@ -2207,7 +2278,7 @@ L