LEFT join problem fixed
Matt S Trout [Thu, 31 May 2007 23:18:23 +0000 (23:18 +0000)]
Changes
lib/DBIx/Class/ResultSource.pm
t/76joins.t
t/90join_torture.t

diff --git a/Changes b/Changes
index 680d597..c6bbaad 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,6 @@
 Revision history for DBIx::Class
 
+        - fixup to ensure join always LEFT after first LEFT join depthwise
         - converted the vendor tests to use schema objects intead of schema
           classes, made cleaned more reliable with END blocks
         - versioning support via DBIx::Class::Schema::Versioned
index 9a2e061..a97560f 100644 (file)
@@ -713,16 +713,22 @@ Returns the join structure required for the related result source.
 =cut
 
 sub resolve_join {
-  my ($self, $join, $alias, $seen) = @_;
+  my ($self, $join, $alias, $seen, $force_left) = @_;
   $seen ||= {};
+  $force_left ||= { force => 0 };
   if (ref $join eq 'ARRAY') {
     return map { $self->resolve_join($_, $alias, $seen) } @$join;
   } elsif (ref $join eq 'HASH') {
     return
       map {
         my $as = ($seen->{$_} ? $_.'_'.($seen->{$_}+1) : $_);
-        ($self->resolve_join($_, $alias, $seen),
-          $self->related_source($_)->resolve_join($join->{$_}, $as, $seen));
+        local $force_left->{force};
+        (
+          $self->resolve_join($_, $alias, $seen, $force_left),
+          $self->related_source($_)->resolve_join(
+            $join->{$_}, $as, $seen, $force_left
+          )
+        );
       } keys %$join;
   } elsif (ref $join) {
     $self->throw_exception("No idea how to resolve join reftype ".ref $join);
@@ -732,7 +738,13 @@ sub resolve_join {
     my $as = ($count > 1 ? "${join}_${count}" : $join);
     my $rel_info = $self->relationship_info($join);
     $self->throw_exception("No such relationship ${join}") unless $rel_info;
-    my $type = $rel_info->{attrs}{join_type} || '';
+    my $type;
+    if ($force_left->{force}) {
+      $type = 'left';
+    } else {
+      $type = $rel_info->{attrs}{join_type} || '';
+      $force_left->{force} = 1 if lc($type) eq 'left';
+    }
     return [ { $as => $self->related_source($join)->from,
                -join_type => $type },
              $self->resolve_condition($rel_info->{cond}, $as, $alias) ];
index f384d4d..89c619d 100644 (file)
@@ -336,21 +336,18 @@ SKIP: {
 
 is($rs->next->name, 'Caterwauler McCrae', "Correct artist returned");
 
-TODO:  {
-    local $TODO = 'left join on prefetch to return valid rows';
-    my $cd = $schema->resultset('Artist')->first->create_related('cds',
-        {
-        title   => 'Unproduced Single',
-        year    => 2007
-    });
-
-    my $left_join = $schema->resultset('CD')->search(
-        { 'me.cdid' => $cd->cdid },
-        { prefetch => { cd_to_producer => 'producer' } }
-    );
-
-    cmp_ok($left_join, '==', 1, 'prefetch with no join record present');
-}
+my $cd = $schema->resultset('Artist')->first->create_related('cds',
+    {
+    title   => 'Unproduced Single',
+    year    => 2007
+});
+
+my $left_join = $schema->resultset('CD')->search(
+    { 'me.cdid' => $cd->cdid },
+    { prefetch => { cd_to_producer => 'producer' } }
+);
+
+cmp_ok($left_join, '==', 1, 'prefetch with no join record present');
 
 $queries = 0;
 $schema->storage->debugcb(sub { $queries++ });
index 7c66799..3e15664 100644 (file)
@@ -23,8 +23,8 @@ cmp_ok(scalar @cds, '==', 1, "condition based on inherited join okay");
 
 #this is wrong, should accept me.title really
 my $rs3 = $rs2->search_related('cds');
-cmp_ok(scalar($rs3->all), '==', 27, "All cds for artist returned");
-cmp_ok($rs3->count, '==', 27, "All cds for artist returned via count");
+cmp_ok(scalar($rs3->all), '==', 45, "All cds for artist returned");
+cmp_ok($rs3->count, '==', 45, "All cds for artist returned via count");
 
 my $rs4 = $schema->resultset("CD")->search({ 'artist.artistid' => '1' }, { join => ['tracks', 'artist'], prefetch => 'artist' });
 my @rs4_results = $rs4->all;