Tighten even more inflate_result() invocations, for crazy overloads
Peter Rabbitson [Sun, 27 Jul 2014 21:50:25 +0000 (23:50 +0200)]
Changes
lib/DBIx/Class/ResultSet.pm
t/resultset/inflate_result_api.t

diff --git a/Changes b/Changes
index 2aebd6d..7f174c4 100644 (file)
--- a/Changes
+++ b/Changes
@@ -22,6 +22,8 @@ Revision history for DBIx::Class
           existed between storage accessor setters and the determine_driver
           routines, triggering a connection before the set-cycle is finished
         - Fix collapse being ignored on single-origin selection (RT#95658)
+        - Fix incorrect behavior on custom result_class inflators altering
+          the amount of returned results
         - Fix failure to detect stable order criteria when in iterator
           mode of a has_many prefetch off a search_related chain
         - Prevent erroneous database hit when accessing prefetched related
index 44adfe8..8745c5f 100644 (file)
@@ -1429,15 +1429,19 @@ sub _construct_results {
     #
     # crude unscientific benchmarking indicated the shortcut eval is not worth it for
     # this particular resultset size
-    elsif (@$rows < 60) {
+    elsif ( $self->{_result_inflator}{is_core_row} and @$rows < 60 ) {
       for my $r (@$rows) {
         $r = $inflator_cref->($res_class, $rsrc, { map { $infmap->[$_] => $r->[$_] } (0..$#$infmap) } );
       }
     }
     else {
       eval sprintf (
-        '$_ = $inflator_cref->($res_class, $rsrc, { %s }) for @$rows',
-        join (', ', map { "\$infmap->[$_] => \$_->[$_]" } 0..$#$infmap )
+        ( $self->{_result_inflator}{is_core_row}
+          ? '$_ = $inflator_cref->($res_class, $rsrc, { %s }) for @$rows'
+          # a custom inflator may be a multiplier/reductor - put it in direct list ctx
+          : '@$rows = map { $inflator_cref->($res_class, $rsrc, { %s } ) } @$rows'
+        ),
+        ( join (', ', map { "\$infmap->[$_] => \$_->[$_]" } 0..$#$infmap ) )
       );
     }
   }
@@ -1510,10 +1514,15 @@ EOS
       $next_cref ? ( $next_cref, $self->{_stashed_rows} = [] ) : (),
     );
 
-    # Special-case multi-object HRI - there is no $inflator_cref pass
-    unless ($self->{_result_inflator}{is_hri}) {
+    # simple in-place substitution, does not regrow $rows
+    if ($self->{_result_inflator}{is_core_row}) {
       $_ = $inflator_cref->($res_class, $rsrc, @$_) for @$rows
     }
+    # Special-case multi-object HRI - there is no $inflator_cref pass at all
+    elsif ( ! $self->{_result_inflator}{is_hri} ) {
+      # the inflator may be a multiplier/reductor - put it in list ctx
+      @$rows = map { $inflator_cref->($res_class, $rsrc, @$_) } @$rows;
+    }
   }
 
   # The @$rows check seems odd at first - why wouldn't we want to warn
index 1fa917a..e6bedc2 100644 (file)
@@ -502,4 +502,31 @@ sub cmp_structures {
   cmp_deeply($left, $right, $msg||()) or next INFTYPE;
 }
 
+{
+  package DBICTest::_DoubleResult;
+
+  sub inflate_result {
+    my $class = shift;
+    return map { DBIx::Class::ResultClass::HashRefInflator->inflate_result(@_) } (1,2);
+  }
+}
+
+my $oxygene_rs = $schema->resultset('CD')->search({ 'me.title' => 'Oxygene' });
+
+is_deeply(
+  [ $oxygene_rs->search({}, { result_class => 'DBICTest::_DoubleResult' })->all ],
+  [ ({ $oxygene_rs->single->get_columns }) x 2 ],
+);
+
+is_deeply(
+  [ $oxygene_rs->search({}, {
+    result_class => 'DBICTest::_DoubleResult', prefetch => [qw(artist tracks)],
+    order_by => [qw(me.cdid tracks.title)],
+  })->all ],
+  [ (@{$oxygene_rs->search({}, {
+    prefetch=> [qw(artist tracks)],
+    order_by => [qw(me.cdid tracks.title)],
+  })->all_hri}) x 2 ],
+);
+
 done_testing;