Fix func_rs() and as_subselect_rs() to start behaving as advertised
Peter Rabbitson [Tue, 27 Sep 2016 17:35:15 +0000 (19:35 +0200)]
No idea how it never got noticed, but both have been broken since the very
first commits that introduced the methods ( 4fa7bc22 / e4bb6727 ). While
changing them 7 years later is a rather serious modification of behavior,
the old way never worked without users having to force-scalar each call site.

If someone has been relying on e.g. [ func_rs(...) ] to return actual result
objects instead of the resultset instance - things will blow up rather quickly
and loudly (aside from the carp()-ed warning encouraging users to switch to
scalar ctx explicitly)

[ func( ... ) ] of course continues to behave like before (directly returning
raw values off the cursor... sigh)

Changes
lib/DBIx/Class/ResultSet.pm
lib/DBIx/Class/ResultSetColumn.pm
t/88result_set_column.t

diff --git a/Changes b/Changes
index 6a63e5b..fabe41d 100644 (file)
--- a/Changes
+++ b/Changes
@@ -27,6 +27,8 @@ Revision history for DBIx::Class
           an underlying search_rs(), as by design these arguments would be
           used only on the first call to ->related_resultset(), and ignored
           afterwards. Instead an exception (detailing the fix) is thrown.
+        - Change func_rs() and as_subselect_rs() to properly ignore list
+          context (i.e. wantarray). Both were implemented broken from day 1 :/
         - Increased checking for the correctness of the is_nullable attribute
           within the prefetch result parser may highlight previously unknown
           mismatches between your codebase and data source
index 2d6ea30..a274ee7 100644 (file)
@@ -3504,6 +3504,21 @@ but because we isolated the group by into a subselect the above works.
 =cut
 
 sub as_subselect_rs {
+
+  # FIXME - remove at some point in the future (2018-ish)
+  wantarray
+    and
+  carp_unique(
+    'Starting with DBIC@0.082900 as_subselect_rs() always returns a ResultSet '
+  . 'instance regardless of calling context. Please force scalar() context to '
+  . 'silence this warning'
+  )
+    and
+  DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_WANTARRAY
+    and
+  my $sog = fail_on_internal_wantarray
+  ;
+
   my $self = shift;
 
   my $alias = $self->current_source_alias;
@@ -3516,7 +3531,7 @@ sub as_subselect_rs {
   delete $fresh_rs->{cond};
   delete @{$fresh_rs->{attrs}}{qw/where bind/};
 
-  return $fresh_rs->search( {}, {
+  $fresh_rs->search_rs( {}, {
     from => [{
       $alias => $self->as_query,
       -alias  => $alias,
index a514139..5b510de 100644 (file)
@@ -448,7 +448,21 @@ sub func_rs {
     $rs = $rs->as_subselect_rs;
   }
 
-  $rs->search( undef, {
+  # FIXME - remove at some point in the future (2018-ish)
+  wantarray
+    and
+  carp_unique(
+    'Starting with DBIC@0.082900 func_rs() always returns a ResultSet '
+  . 'instance regardless of calling context. Please force scalar() context to '
+  . 'silence this warning'
+  )
+    and
+  DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_WANTARRAY
+    and
+  my $sog = fail_on_internal_wantarray
+  ;
+
+  $rs->search_rs( undef, {
     columns => { $self->{_as} => { $function => $select } }
   } );
 }
index f27c5dd..7abf670 100644 (file)
@@ -40,6 +40,13 @@ while (my $r = $rs_title->next) {
 
 is_deeply (\@all_titles, \@nexted_titles, 'next works');
 
+my @list_ctx;
+warnings_exist {
+  @list_ctx = $rs_year->func_rs('DISTINCT');
+} [qr/\Qfunc_rs() always returns a ResultSet instance regardless of calling context/];
+is( scalar @list_ctx, 1, 'wantarray context does not affect func_rs');
+isa_ok( $list_ctx[0], 'DBIx::Class::ResultSet' );
+isa_ok( scalar( $rs_year->func_rs('DISTINCT') ), 'DBIx::Class::ResultSet' );
 is_deeply( [ sort $rs_year->func('DISTINCT') ], [ 1997, 1998, 1999, 2001 ],  "wantarray context okay");
 ok ($max_year->next == $rs_year->max, q/get_column (\'FUNC') ok/);