checks if the complex conditions are overriden in set_from_related
Daniel Ruoso [Mon, 22 Nov 2010 13:56:57 +0000 (10:56 -0300)]
lib/DBIx/Class/ResultSet.pm
lib/DBIx/Class/ResultSource.pm
t/lib/DBICTest/Schema/Artist.pm
t/relationship/custom.t

index d826e03..124600b 100644 (file)
@@ -2343,8 +2343,16 @@ sub _merge_with_rscond {
 
     while ( my($col, $value) = each %implied ) {
       my $vref = ref $value;
-      if ($vref eq 'HASH' && keys(%$value) && (keys %$value)[0] eq '=') {
-        $new_data{$col} = $value->{'='};
+      if ($vref eq 'HASH') {
+        if (keys(%$value) && (keys %$value)[0] eq '=') {
+          $new_data{$col} = $value->{'='};
+        }
+        # in a complex condition, set_from_related needs to override
+        # the columns that are involved.
+        elsif (!exists $data->{$col} &&
+               !exists $data->{"$alias.$col"}) {
+          $self->throw_exception("unable to set_from_related via complex condition on column(s): '$col'");
+        }
       }
       elsif( !$vref or $vref eq 'SCALAR' or blessed($value) ) {
         $new_data{$col} = $value;
index e5fb395..4f41baa 100644 (file)
@@ -1677,6 +1677,7 @@ sub _resolve_prefetch {
         "Can't prefetch has_many ${pre} (join cond too complex)")
         unless ref($rel_info->{cond}) eq 'HASH';
       my $dots = @{[$as_prefix =~ m/\./g]} + 1; # +1 to match the ".${as_prefix}"
+
       if (my ($fail) = grep { @{[$_ =~ m/\./g]} == $dots }
                          keys %{$collapse}) {
         my ($last) = ($fail =~ /([^\.]+)$/);
@@ -1690,6 +1691,7 @@ sub _resolve_prefetch {
           . 'Use at your own risk.'
         );
       }
+
       #my @col = map { (/^self\.(.+)$/ ? ("${as_prefix}.$1") : ()); }
       #              values %{$rel_info->{cond}};
       $collapse->{".${as_prefix}${pre}"} = [ $rel_source->_pri_cols ];
index b8b7911..48538bc 100644 (file)
@@ -64,24 +64,29 @@ __PACKAGE__->has_many(
 );
 
 __PACKAGE__->has_many(
-  cds_80s_noopt => 'DBICTest::Schema::CD',
+  cds_90s => 'DBICTest::Schema::CD',
   sub {
     my $args = shift;
     return (
       { "$args->{foreign_alias}.artist" => { -ident => "$args->{self_alias}.artistid" },
-        "$args->{foreign_alias}.year"   => { '>' => 1979, '<' => 1990 },
+        "$args->{foreign_alias}.year"   => { '>' => 1989, '<' => 2000 },
       }
     );
-  },
+  }
 );
 
+
 __PACKAGE__->has_many(
-  cds_90s => 'DBICTest::Schema::CD',
+  cds_84 => 'DBICTest::Schema::CD',
   sub {
     my $args = shift;
     return (
       { "$args->{foreign_alias}.artist" => { -ident => "$args->{self_alias}.artistid" },
-        "$args->{foreign_alias}.year"   => { '>' => 1989, '<' => 2000 },
+        "$args->{foreign_alias}.year"   => 1984,
+      },
+      $args->{self_rowobj} && {
+        "$args->{foreign_alias}.artist" => $args->{self_rowobj}->artistid,
+        "$args->{foreign_alias}.year"   => 1984,
       }
     );
   }
index c94758c..3b58926 100644 (file)
@@ -20,19 +20,63 @@ foreach my $year (1975..1995) {
 }
 
 my @cds_80s = $artist->cds_80s;
-is(@cds_80s, 6, '6 80s cds found');
+is(@cds_80s, 6, '6 80s cds found (1980 - 1985)');
+map { ok($_->year < 1990 && $_->year > 1979) } @cds_80s;
 
 my @cds_90s = $artist2->cds_90s;
-is(@cds_90s, 6, '6 90s cds found even with non-optimized search');
+is(@cds_90s, 6, '6 90s cds found (1990 - 1995) even with non-optimized search');
+map { ok($_->year < 2000 && $_->year > 1989) } @cds_90s;
 
-map { ok($_->year < 1990 && $_->year > 1979) } @cds_80s;
+# search for all artists prefetching published cds in the 80s...
+#####
+# the join must be a prefetch, but it can't work until the collapse rewrite is finished
+# (right-side vs left-side order)
+#####
+TODO: {
+  local $TODO = "Replace the join below with this when we fix the collapser";
+  lives_ok {
+    my @all_artists_with_80_cds = $schema->resultset("Artist")->search
+      ({ 'cds_80s.cdid' => { '!=' => undef } }, { prefetch => 'cds_80s' })->all;
+  } 'prefetchy-fetchy-fetch?';
+}
 
+my @all_artists_with_80_cds = $schema->resultset("Artist")->search
+  ({ 'cds_80s.cdid' => { '!=' => undef } }, { join => 'cds_80s', distinct => 1 });
+
+is_deeply(
+  [ sort ( map { $_->year } map { $_->cds_80s->all } @all_artists_with_80_cds ) ],
+  [ sort (1980..1989, 1980..1985) ],
+  '16 correct cds found'
+);
+
+# try to create_related a 80s cd
+throws_ok {
+  $artist->create_related('cds_80s', { title => 'related creation 1' });
+} qr/\Qunable to set_from_related via complex 'cds_80s' condition on column(s): 'year'/, 'Create failed - complex cond';
+
+# now supply an explicit arg overwriting the ambiguous cond
+my $id_2020 = $artist->create_related('cds_80s', { title => 'related creation 2', year => '2020' })->id;
+is(
+  $schema->resultset('CD')->find($id_2020)->title,
+  'related creation 2',
+  '2020 CD created correctly'
+);
+
+# try a default year from a specific rel
+my $id_1984 = $artist->create_related('cds_84', { title => 'related creation 3' })->id;
+is(
+  $schema->resultset('CD')->find($id_1984)->title,
+  'related creation 3',
+  '1984 CD created correctly'
+);
+
+# try a specific everything via a non-simplified rel
+throws_ok {
+  $artist->create_related('cds_90s', { title => 'related_creation 4', year => '2038' });
+} qr/\Qunable to set_from_related - no simplified condition available for 'cds_90s'/, 'Create failed - non-simplified rel';
 
-# search for all artists prefetching published cds in the 80s...
-my @all_cds_80s = $schema->resultset("Artist")->search
-  ({ 'cds_80s_noopt.cdid' => { '!=' => undef } }, { join => 'cds_80s_noopt' });
-is(@all_cds_80s, 16, '16 cds found even with the non-optimized search');
 
+# Do a self-join last-entry search
 my @last_track_ids;
 for my $cd ($schema->resultset('CD')->search ({}, { order_by => 'cdid'})->all) {
   push @last_track_ids, $cd->tracks