Clarify what happens on distinct + get_column($aggregate_alias)
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / ResultSetColumn.pm
index f372e9d..3b1f875 100644 (file)
@@ -5,7 +5,8 @@ use warnings;
 
 use base 'DBIx::Class';
 use DBIx::Class::Carp;
-use DBIx::Class::Exception;
+use DBIx::Class::_Util 'fail_on_internal_wantarray';
+use namespace::clean;
 
 # not importing first() as it will clash with our own method
 use List::Util ();
@@ -58,7 +59,7 @@ sub new {
   my $as_index = List::Util::first { ($as_list->[$_] || "") eq $column } 0..$#$as_list;
   my $select = defined $as_index ? $select_list->[$as_index] : $column;
 
-  my ($new_parent_rs, $colmap);
+  my $colmap;
   for ($rsrc->columns, $column) {
     if ($_ =~ /^ \Q$alias\E \. ([^\.]+) $ /x) {
       $colmap->{$_} = $1;
@@ -69,6 +70,7 @@ sub new {
     }
   }
 
+  my $new_parent_rs;
   # analyze the order_by, and see if it is done over a function/nonexistentcolumn
   # if this is the case we will need to wrap a subquery since the result of RSC
   # *must* be a single column select
@@ -78,7 +80,7 @@ sub new {
       ( $rsrc->schema->storage->_extract_order_criteria ($orig_attrs->{order_by} ) )
   ) {
     # nuke the prefetch before collapsing to sql
-    my $subq_rs = $rs->search;
+    my $subq_rs = $rs->search_rs;
     $subq_rs->{attrs}{join} = $subq_rs->_merge_joinpref_attr( $subq_rs->{attrs}{join}, delete $subq_rs->{attrs}{prefetch} );
     $new_parent_rs = $subq_rs->as_subselect_rs;
   }
@@ -94,11 +96,11 @@ sub new {
 
   # {collapse} would mean a has_many join was injected, which in turn means
   # we need to group *IF WE CAN* (only if the column in question is unique)
-  if (!$orig_attrs->{group_by} && keys %{$orig_attrs->{collapse}}) {
+  if (!$orig_attrs->{group_by} && $orig_attrs->{collapse}) {
 
     if ($colmap->{$select} and $rsrc->_identifying_column_set([$colmap->{$select}])) {
       $new_attrs->{group_by} = [ $select ];
-      delete $new_attrs->{distinct}; # it is ignored when group_by is present
+      delete @{$new_attrs}{qw(distinct _grouped_by_distinct)}; # it is ignored when group_by is present
     }
     else {
       carp (
@@ -108,7 +110,13 @@ sub new {
     }
   }
 
-  my $new = bless { _select => $select, _as => $column, _parent_resultset => $new_parent_rs }, $class;
+  # collapse the selector to a literal so that it survives a possible distinct parse
+  # if it turns out to be an aggregate - at least the user will get a proper exception
+  # instead of silent drop of the group_by altogether
+  my $new = bless {
+    _select => \ $rsrc->storage->sql_maker->_recurse_fields($select),
+    _as => $column,
+    _parent_resultset => $new_parent_rs }, $class;
   return $new;
 }
 
@@ -401,6 +409,7 @@ sub func {
   my $cursor = $self->func_rs($function)->cursor;
 
   if( wantarray ) {
+    DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_WANTARRAY and my $sog = fail_on_internal_wantarray($self);
     return map { $_->[ 0 ] } $cursor->all;
   }
 
@@ -423,12 +432,19 @@ Creates the resultset that C<func()> uses to run its query.
 
 sub func_rs {
   my ($self,$function) = @_;
-  return $self->{_parent_resultset}->search(
-    undef, {
-      select => {$function => $self->{_select}},
-      as => [$self->{_as}],
-    },
-  );
+
+  my $rs = $self->{_parent_resultset};
+  my $select = $self->{_select};
+
+  # wrap a grouped rs
+  if ($rs->_resolved_attrs->{group_by}) {
+    $select = $self->{_as};
+    $rs = $rs->as_subselect_rs;
+  }
+
+  $rs->search( undef, {
+    columns => { $self->{_as} => { $function => $select } }
+  } );
 }
 
 =head2 throw_exception
@@ -438,7 +454,7 @@ See L<DBIx::Class::Schema/throw_exception> for details.
 =cut
 
 sub throw_exception {
-  my $self=shift;
+  my $self = shift;
 
   if (ref $self && $self->{_parent_resultset}) {
     $self->{_parent_resultset}->throw_exception(@_);