X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSet.pm;fp=lib%2FDBIx%2FClass%2FResultSet.pm;h=74940ebca3b7eacdbd6ca23d47f9beebc7531f85;hb=bc185c328c2881bbafb597ffba48a516f3f8bfeb;hp=cfb736b43a032e531a6d708f0c4d6faceb0813c3;hpb=b1e1d07360d6a1921358cf3952894c19faf14cea;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index cfb736b..74940eb 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -698,10 +698,14 @@ a warning: Query returned more than one row -In this case, you should be using L or L instead, or if you really +In this case, you should be using L or L instead, or if you really know what you are doing, use the L attribute to explicitly limit the size of the resultset. +This method will also throw an exception if it is called on a resultset prefetching +has_many, as such a prefetch implies fetching multiple rows from the database in +order to assemble the resulting object. + =back =cut @@ -714,6 +718,12 @@ sub single { my $attrs = $self->_resolved_attrs_copy; + if (keys %{$attrs->{collapse}}) { + $self->throw_exception( + 'single() can not be used on resultsets prefetching has_many. Use find( \%cond ) or next() instead' + ); + } + if ($where) { if (defined $attrs->{where}) { $attrs->{where} = { @@ -1144,7 +1154,7 @@ sub count { return $self->search(@_)->count if @_ and defined $_[0]; return scalar @{ $self->get_cache } if $self->get_cache; - my $meth = $self->_has_attr (qw/prefetch collapse distinct group_by/) + my $meth = $self->_has_resolved_attr (qw/collapse group_by/) ? 'count_grouped' : 'count' ; @@ -1276,15 +1286,15 @@ sub _rs_update_delete { my $rsrc = $self->result_source; - my $needs_group_by_subq = $self->_has_attr (qw/prefetch distinct join seen_join group_by/); - my $needs_subq = $self->_has_attr (qw/row offset page/); + my $needs_group_by_subq = $self->_has_resolved_attr (qw/collapse group_by -join/); + my $needs_subq = $self->_has_resolved_attr (qw/row offset/); if ($needs_group_by_subq or $needs_subq) { # make a new $rs selecting only the PKs (that's all we really need) my $attrs = $self->_resolved_attrs_copy; - delete $attrs->{$_} for qw/prefetch collapse select +select as +as columns +columns/; + delete $attrs->{$_} for qw/collapse select as/; $attrs->{columns} = [ map { "$attrs->{alias}.$_" } ($self->result_source->primary_columns) ]; if ($needs_group_by_subq) { @@ -1808,14 +1818,14 @@ sub _is_deterministic_value { return 0; } -# _has_attr +# _has_resolved_attr # # determines if the resultset defines at least one # of the attributes supplied # # used to determine if a subquery is neccessary -sub _has_attr { +sub _has_resolved_attr { my ($self, @attr_names) = @_; my $attrs = $self->_resolved_attrs; @@ -1823,7 +1833,7 @@ sub _has_attr { my $join_check_req; for my $n (@attr_names) { - ++$join_check_req if $n =~ /join/; + ++$join_check_req if $n eq '-join'; my $attr = $attrs->{$n}; @@ -1840,7 +1850,7 @@ sub _has_attr { } } - # a join can be expressed as a multi-level from + # a resolved join is expressed as a multi-level from return 1 if ( $join_check_req and @@ -2600,30 +2610,35 @@ sub _resolved_attrs { map { $prefix . $_ } ($source->primary_columns) ]; - my $collapse = $attrs->{collapse} || {}; + $attrs->{collapse} ||= {}; if ( my $prefetch = delete $attrs->{prefetch} ) { $prefetch = $self->_merge_attr( {}, $prefetch ); - my @pre_order; - foreach my $p ( ref $prefetch eq 'ARRAY' ? @$prefetch : ($prefetch) ) { - - # bring joins back to level of current class - my $join_map = $self->_joinpath_aliases ($attrs->{from}, $attrs->{seen_join}); - my @prefetch = - $source->_resolve_prefetch( $p, $alias, $join_map, \@pre_order, $collapse ); - push( @{ $attrs->{select} }, map { $_->[0] } @prefetch ); - push( @{ $attrs->{as} }, map { $_->[1] } @prefetch ); - } - push( @{ $attrs->{order_by} }, @pre_order ); + + my $prefetch_ordering = []; + + my $join_map = $self->_joinpath_aliases ($attrs->{from}, $attrs->{seen_join}); + + my @prefetch = + $source->_resolve_prefetch( $prefetch, $alias, $join_map, $prefetch_ordering, $attrs->{collapse} ); + + push( @{ $attrs->{select} }, map { $_->[0] } @prefetch ); + push( @{ $attrs->{as} }, map { $_->[1] } @prefetch ); + + push( @{ $attrs->{order_by} }, @$prefetch_ordering ); + $attrs->{_collapse_order_by} = \@$prefetch_ordering; } + if (delete $attrs->{distinct}) { $attrs->{group_by} ||= [ grep { !ref($_) || (ref($_) ne 'HASH') } @{$attrs->{select}} ]; } - $attrs->{collapse} = $collapse; - - if ( $attrs->{page} and not defined $attrs->{offset} ) { - $attrs->{offset} = ( $attrs->{rows} * ( $attrs->{page} - 1 ) ); + # if both page and offset are specified, produce a combined offset + # even though it doesn't make much sense, this is what pre 081xx has + # been doing + if (my $page = delete $attrs->{page}) { + $attrs->{offset} = ($attrs->{rows} * ($page - 1)) + + ($attrs->{offset} || 0); } return $self->{_attrs} = $attrs;