Bring in line behavior of related_resultset() on both $rs and $result
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / ResultSet.pm
index 3ec0268..3d1a3a1 100644 (file)
@@ -5,6 +5,7 @@ use warnings;
 use base qw/DBIx::Class/;
 use DBIx::Class::Carp;
 use DBIx::Class::ResultSetColumn;
+use DBIx::Class::ResultClass::HashRefInflator;
 use Scalar::Util qw/blessed weaken reftype/;
 use DBIx::Class::_Util qw(
   fail_on_internal_wantarray fail_on_internal_call UNRESOLVABLE_CONDITION
@@ -1382,11 +1383,7 @@ sub _construct_results {
   $self->{_result_inflator}{is_hri} = ( (
     ! $self->{_result_inflator}{is_core_row}
       and
-    $inflator_cref == (
-      require DBIx::Class::ResultClass::HashRefInflator
-        &&
-      DBIx::Class::ResultClass::HashRefInflator->can('inflate_result')
-    )
+    $inflator_cref == \&DBIx::Class::ResultClass::HashRefInflator::inflate_result
   ) ? 1 : 0 ) unless defined $self->{_result_inflator}{is_hri};
 
 
@@ -1463,6 +1460,9 @@ sub _construct_results {
         if @violating_idx;
 
       $unrolled_non_null_cols_to_check = join (',', @$check_non_null_cols);
+
+      utf8::upgrade($unrolled_non_null_cols_to_check)
+        if DBIx::Class::_ENV_::STRESSTEST_UTF8_UPGRADE_GENERATED_COLLAPSER_SOURCE;
     }
 
     my $next_cref =
@@ -3220,10 +3220,16 @@ Returns a related resultset for the supplied relationship name.
 =cut
 
 sub related_resultset {
-  my ($self, $rel) = @_;
+  $_[0]->throw_exception(
+    'Extra arguments to $rs->related_resultset() were always quietly '
+  . 'discarded without consideration, you need to switch to '
+  . '...->related_resultset( $relname )->search_rs( $search, $args ) instead.'
+  ) if @_ > 2;
 
-  return $self->{related_resultsets}{$rel}
-    if defined $self->{related_resultsets}{$rel};
+  return $_[0]->{related_resultsets}{$_[1]}
+    if defined $_[0]->{related_resultsets}{$_[1]};
+
+  my ($self, $rel) = @_;
 
   return $self->{related_resultsets}{$rel} = do {
     my $rsrc = $self->result_source;
@@ -3236,22 +3242,25 @@ sub related_resultset {
 
     my $attrs = $self->_chain_relationship($rel);
 
-    my $join_count = $attrs->{seen_join}{$rel};
+    my $storage = $rsrc->schema->storage;
 
-    my $alias = $self->result_source->storage
-        ->relname_to_table_alias($rel, $join_count);
+    # Previously this atribute was deleted (instead of being set as it is now)
+    # Doing so seems to be harmless in all available test permutations
+    # See also 01d59a6a6 and mst's comment below
+    #
+    $attrs->{alias} = $storage->relname_to_table_alias(
+      $rel,
+      $attrs->{seen_join}{$rel}
+    );
 
     # since this is search_related, and we already slid the select window inwards
     # (the select/as attrs were deleted in the beginning), we need to flip all
     # left joins to inner, so we get the expected results
     # read the comment on top of the actual function to see what this does
-    $attrs->{from} = $rsrc->schema->storage->_inner_join_to_node ($attrs->{from}, $alias);
-
+    $attrs->{from} = $storage->_inner_join_to_node( $attrs->{from}, $attrs->{alias} );
 
     #XXX - temp fix for result_class bug. There likely is a more elegant fix -groditi
-    delete @{$attrs}{qw(result_class alias)};
-
-    my $rel_source = $rsrc->related_source($rel);
+    delete $attrs->{result_class};
 
     my $new = do {
 
@@ -3260,16 +3269,19 @@ sub related_resultset {
       # source you need to know what alias it's -going- to have for things
       # to work sanely (e.g. RestrictWithObject wants to be able to add
       # extra query restrictions, and these may need to be $alias.)
-
-      my $rel_attrs = $rel_source->resultset_attributes;
-      local $rel_attrs->{alias} = $alias;
-
-      $rel_source->resultset
-                 ->search_rs(
-                     undef, {
-                       %$attrs,
-                       where => $attrs->{where},
-                   });
+      #                                       -- mst ~ 2007 (01d59a6a6)
+      #
+      # FIXME - this seems to be no longer neccessary (perhaps due to the
+      # advances in relcond resolution. Testing DBIC::S::RWO and its only
+      # dependent (as of Jun 2015 ) does not yield any difference with or
+      # without this line. Nevertheless keep it as is for now, to minimize
+      # churn, there is enough potential for breakage in 0.0829xx as it is
+      #                                       -- ribasushi Jun 2015
+      #
+      my $rel_source = $rsrc->related_source($rel);
+      local $rel_source->resultset_attributes->{alias} = $attrs->{alias};
+
+      $rel_source->resultset->search_rs( undef, $attrs );
     };
 
     if (my $cache = $self->get_cache) {
@@ -3320,6 +3332,9 @@ source alias of the current result set:
     });
   }
 
+The alias of L<newly created resultsets|/search> can be altered by the
+L<alias attribute|/alias>.
+
 =cut
 
 sub current_source_alias {
@@ -3614,6 +3629,7 @@ sub _resolved_attrs {
       ];
   }
 
+
   for my $attr (qw(order_by group_by)) {
 
     if ( defined $attrs->{$attr} ) {
@@ -3627,49 +3643,21 @@ sub _resolved_attrs {
     }
   }
 
-  # generate selections based on the prefetch helper
-  my ($prefetch, @prefetch_select, @prefetch_as);
-  $prefetch = $self->_merge_joinpref_attr( {}, delete $attrs->{prefetch} )
-    if defined $attrs->{prefetch};
-
-  if ($prefetch) {
-
-    $self->throw_exception("Unable to prefetch, resultset contains an unnamed selector $attrs->{_dark_selector}{string}")
-      if $attrs->{_dark_selector};
 
+  # set collapse default based on presence of prefetch
+  my $prefetch;
+  if (
+    defined $attrs->{prefetch}
+      and
+    $prefetch = $self->_merge_joinpref_attr( {}, delete $attrs->{prefetch} )
+  ) {
     $self->throw_exception("Specifying prefetch in conjunction with an explicit collapse => 0 is unsupported")
       if defined $attrs->{collapse} and ! $attrs->{collapse};
 
     $attrs->{collapse} = 1;
-
-    # this is a separate structure (we don't look in {from} directly)
-    # as the resolver needs to shift things off the lists to work
-    # properly (identical-prefetches on different branches)
-    my $join_map = {};
-    if (ref $attrs->{from} eq 'ARRAY') {
-
-      my $start_depth = $attrs->{seen_join}{-relation_chain_depth} || 0;
-
-      for my $j ( @{$attrs->{from}}[1 .. $#{$attrs->{from}} ] ) {
-        next unless $j->[0]{-alias};
-        next unless $j->[0]{-join_path};
-        next if ($j->[0]{-relation_chain_depth} || 0) < $start_depth;
-
-        my @jpath = map { keys %$_ } @{$j->[0]{-join_path}};
-
-        my $p = $join_map;
-        $p = $p->{$_} ||= {} for @jpath[ ($start_depth/2) .. $#jpath]; #only even depths are actual jpath boundaries
-        push @{$p->{-join_aliases} }, $j->[0]{-alias};
-      }
-    }
-
-    my @prefetch = $source->_resolve_prefetch( $prefetch, $alias, $join_map );
-
-    # save these for after distinct resolution
-    @prefetch_select = map { $_->[0] } @prefetch;
-    @prefetch_as = map { $_->[1] } @prefetch;
   }
 
+
   # run through the resulting joinstructure (starting from our current slot)
   # and unset collapse if proven unnecessary
   #
@@ -3719,6 +3707,7 @@ sub _resolved_attrs {
     }
   }
 
+
   # generate the distinct induced group_by before injecting the prefetched select/as parts
   if (delete $attrs->{distinct}) {
     if ($attrs->{group_by}) {
@@ -3738,9 +3727,38 @@ sub _resolved_attrs {
     }
   }
 
-  # inject prefetch-bound selection (if any)
-  push @{$attrs->{select}}, @prefetch_select;
-  push @{$attrs->{as}}, @prefetch_as;
+
+  # generate selections based on the prefetch helper
+  if ($prefetch) {
+
+    $self->throw_exception("Unable to prefetch, resultset contains an unnamed selector $attrs->{_dark_selector}{string}")
+      if $attrs->{_dark_selector};
+
+    # this is a separate structure (we don't look in {from} directly)
+    # as the resolver needs to shift things off the lists to work
+    # properly (identical-prefetches on different branches)
+    my $joined_node_aliases_map = {};
+    if (ref $attrs->{from} eq 'ARRAY') {
+
+      my $start_depth = $attrs->{seen_join}{-relation_chain_depth} || 0;
+
+      for my $j ( @{$attrs->{from}}[1 .. $#{$attrs->{from}} ] ) {
+        next unless $j->[0]{-alias};
+        next unless $j->[0]{-join_path};
+        next if ($j->[0]{-relation_chain_depth} || 0) < $start_depth;
+
+        my @jpath = map { keys %$_ } @{$j->[0]{-join_path}};
+
+        my $p = $joined_node_aliases_map;
+        $p = $p->{$_} ||= {} for @jpath[ ($start_depth/2) .. $#jpath]; #only even depths are actual jpath boundaries
+        push @{$p->{-join_aliases} }, $j->[0]{-alias};
+      }
+    }
+
+    ( push @{$attrs->{select}}, $_->[0] ) and ( push @{$attrs->{as}}, $_->[1] )
+      for $source->_resolve_selection_from_prefetch( $prefetch, $joined_node_aliases_map );
+  }
+
 
   $attrs->{_simple_passthrough_construction} = !(
     $attrs->{collapse}
@@ -3748,6 +3766,7 @@ sub _resolved_attrs {
     grep { $_ =~ /\./ } @{$attrs->{as}}
   );
 
+
   # 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
@@ -3813,8 +3832,10 @@ sub _calculate_score {
 
   if (ref $b eq 'HASH') {
     my ($b_key) = keys %{$b};
+    $b_key = '' if ! defined $b_key;
     if (ref $a eq 'HASH') {
       my ($a_key) = keys %{$a};
+      $a_key = '' if ! defined $a_key;
       if ($a_key eq $b_key) {
         return (1 + $self->_calculate_score( $a->{$a_key}, $b->{$b_key} ));
       } else {
@@ -4081,13 +4102,13 @@ is the same as
     as     => [qw(some_column dbic_slot)]
 
 If you want to individually retrieve related columns (in essence perform
-manual prefetch) you have to make sure to specify the correct inflation slot
+manual L</prefetch>) you have to make sure to specify the correct inflation slot
 chain such that it matches existing relationships:
 
     my $rs = $schema->resultset('Artist')->search({}, {
         # required to tell DBIC to collapse has_many relationships
         collapse => 1,
-        join     => { cds => 'tracks'},
+        join     => { cds => 'tracks' },
         '+columns'  => {
           'cds.cdid'         => 'cds.cdid',
           'cds.tracks.title' => 'tracks.title',
@@ -4099,12 +4120,13 @@ scalar reference or a literal bind value, and these values will be available
 in the result with C<get_column> (see also
 L<SQL::Abstract/Literal SQL and value type operators>):
 
-    # equivalent SQL: SELECT 1, 'a string', IF(x,1,2) ...
+    # equivalent SQL: SELECT 1, 'a string', IF(my_column,?,?) ...
+    # bind values: $true_value, $false_value
     columns => [
         {
             foo => \1,
             bar => \q{'a string'},
-            baz => \[ '?', 'IF(x,1,2)' ],
+            baz => \[ 'IF(my_column,?,?)', $true_value, $false_value ],
         }
     ]
 
@@ -4590,19 +4612,14 @@ setting is ignored and an appropriate warning is issued.
 
 =head2 where
 
-=over 4
-
-Adds to the WHERE clause.
+Adds extra conditions to the resultset, combined with the preexisting C<WHERE>
+conditions, same as the B<first> argument to the L<search operator|/search>
 
   # only return rows WHERE deleted IS NULL for all searches
   __PACKAGE__->resultset_attributes({ where => { deleted => undef } });
 
-Can be overridden by passing C<< { where => undef } >> as an attribute
-to a resultset.
-
-For more complicated where clauses see L<SQL::Abstract/WHERE CLAUSES>.
-
-=back
+Note that the above example is
+L<strongly discouraged|DBIx::Class::ResultSource/resultset_attributes>.
 
 =head2 cache