Fix search_related wrt grouped resultsets (distinct is currently passed to the new...
Peter Rabbitson [Fri, 27 Nov 2009 00:38:11 +0000 (00:38 +0000)]
lib/DBIx/Class/ResultSet.pm
t/count/prefetch.t
t/count/search_related.t

index 468816b..d8645ba 100644 (file)
@@ -2518,9 +2518,9 @@ sub related_resultset {
         "' has no such relationship $rel")
       unless $rel_info;
 
-    my ($from,$seen,$attrs) = $self->_chain_relationship($rel);
+    my $attrs = $self->_chain_relationship($rel);
 
-    my $join_count = $seen->{$rel};
+    my $join_count = $attrs->{seen_join}{$rel};
     my $alias = ($join_count > 1 ? join('_', $rel, $join_count) : $rel);
 
     #XXX - temp fix for result_class bug. There likely is a more elegant fix -groditi
@@ -2552,13 +2552,7 @@ sub related_resultset {
                  ->search_rs(
                      undef, {
                        %$attrs,
-                       join => undef,
-                       prefetch => undef,
-                       select => undef,
-                       as => undef,
-                       where => $self->{cond},
-                       seen_join => $seen,
-                       from => $from,
+                       where => $attrs->{where},
                    });
     };
     $new->set_cache($new_cache) if $new_cache;
@@ -2627,8 +2621,16 @@ sub _chain_relationship {
   my $source = $self->result_source;
   my $attrs = { %{$self->{attrs}||{}} };
 
+  # we need to take the prefetch the attrs into account before we
+  # ->_resolve_join as otherwise they get lost - captainL
+  my $join = $self->_merge_attr( $attrs->{join}, $attrs->{prefetch} );
+
+  delete @{$attrs}{qw/join prefetch collapse select as columns +select +as +columns/};
+
+  my $seen = { %{ (delete $attrs->{seen_join}) || {} } };
+
   my $from;
-  my @force_subq_attrs = qw/offset rows/;
+  my @force_subq_attrs = qw/offset rows group_by having/;
 
   if (
     ($attrs->{from} && ref $attrs->{from} ne 'ARRAY')
@@ -2640,7 +2642,8 @@ sub _chain_relationship {
       -alias => $attrs->{alias},
       $attrs->{alias} => $self->as_query,
     }];
-    delete @{$attrs}{@force_subq_attrs};
+    delete @{$attrs}{@force_subq_attrs, 'where'};
+    $seen->{-relation_chain_depth} = 0;
   }
   elsif ($attrs->{from}) {  #shallow copy suffices
     $from = [ @{$attrs->{from}} ];
@@ -2653,17 +2656,12 @@ sub _chain_relationship {
     }];
   }
 
-  my $seen = { %{$attrs->{seen_join} || {} } };
-  my $jpath = ($attrs->{seen_join} && keys %{$attrs->{seen_join}})
+  my $jpath = ($seen->{-relation_chain_depth})
     ? $from->[-1][0]{-join_path}
     : [];
 
-  # we need to take the prefetch the attrs into account before we
-  # ->_resolve_join as otherwise they get lost - captainL
-  my $merged = $self->_merge_attr( $attrs->{join}, $attrs->{prefetch} );
-
   my @requested_joins = $source->_resolve_join(
-    $merged,
+    $join,
     $attrs->{alias},
     $seen,
     $jpath,
@@ -2710,7 +2708,7 @@ sub _chain_relationship {
 
   $seen->{-relation_chain_depth}++;
 
-  return ($from,$seen,$attrs);
+  return {%$attrs, from => $from, seen_join => $seen};
 }
 
 # too many times we have to do $attrs = { %{$self->_resolved_attrs} }
index a0b6d75..6959400 100644 (file)
@@ -53,8 +53,15 @@ my $schema = DBICTest->init_schema();
       SELECT COUNT( * )
         FROM (
           SELECT genre.genreid
-            FROM artist me
-            JOIN cd cds ON cds.artist = me.artistid
+            FROM (
+              SELECT cds.cdid, cds.artist, cds.title, cds.year, cds.genreid, cds.single_track
+                FROM (
+                  SELECT me.artistid, me.name, me.rank, me.charfield
+                    FROM artist me GROUP BY me.artistid, me.name, me.rank, me.charfield
+                ) me
+                LEFT JOIN cd cds ON cds.artist = me.artistid
+              GROUP BY cds.cdid, cds.artist, cds.title, cds.year, cds.genreid, cds.single_track
+            ) cds
             JOIN genre genre ON genre.genreid = cds.genreid
             LEFT JOIN cd cds_2 ON cds_2.genreid = genre.genreid
           WHERE ( genre.name = ? )
index b9804ea..11f5796 100644 (file)
@@ -14,7 +14,28 @@ my $track_count = $cd_rs->first->tracks->count;
 
 cmp_ok ($track_count, '>', 1, 'First CD has several tracks');
 
-is ($cd_rs->search_related ('tracks')->count, $track_count, 'related->count returns correct number');
-is (scalar ($cd_rs->search_related ('tracks')->all), $track_count, 'related->all returns correct number of objects');
+is ($cd_rs->search_related ('tracks')->count, $track_count, 'related->count returns correct number chained off a limited rs');
+is (scalar ($cd_rs->search_related ('tracks')->all), $track_count, 'related->all returns correct number of objects chained off a limited rs');
+
+
+my $joined_cd_rs = $cd_rs->search ({}, {
+  join => 'tracks', rows => 2, distinct => 1, having => \ 'count(tracks.trackid) > 2',
+});
+
+my $multiple_track_count = $schema->resultset('Track')->search ({
+  cd => { -in => $joined_cd_rs->get_column ('cdid')->as_query }
+})->count;
+
+
+is (
+  $joined_cd_rs->search_related ('tracks')->count,
+  $multiple_track_count,
+  'related->count returns correct number chained off a grouped rs',
+);
+is (
+  scalar ($joined_cd_rs->search_related ('tracks')->all),
+  $multiple_track_count,
+  'related->all returns correct number of objects chained off a grouped rs',
+);
 
 done_testing;