Fix RT52812
[dbsrgits/DBIx-Class.git] / lib / SQL / Translator / Parser / DBIx / Class.pm
index 2740760..e760580 100644 (file)
@@ -65,25 +65,28 @@ sub parse {
     }
 
 
-    my(@table_monikers, @view_monikers);
+    my(%table_monikers, %view_monikers);
     for my $moniker (@monikers){
       my $source = $dbicschema->source($moniker);
        if ( $source->isa('DBIx::Class::ResultSource::Table') ) {
-         push(@table_monikers, $moniker);
+         $table_monikers{$moniker}++;
       } elsif( $source->isa('DBIx::Class::ResultSource::View') ){
           next if $source->is_virtual;
-         push(@view_monikers, $moniker);
+         $view_monikers{$moniker}++;
       }
     }
 
     my %tables;
-    foreach my $moniker (sort @table_monikers)
+    foreach my $moniker (sort keys %table_monikers)
     {
         my $source = $dbicschema->source($moniker);
         my $table_name = $source->name;
-        $table_name = $$table_name if ref $table_name eq 'SCALAR';  #sqlt currently does not do quoting right anyway
 
-        # Its possible to have multiple DBIC sources using the same table
+        # FIXME - this isn't the right way to do it, but sqlt does not
+        # support quoting properly to be signaled about this
+        $table_name = $$table_name if ref $table_name eq 'SCALAR';
+
+        # It's possible to have multiple DBIC sources using the same table
         next if $tables{$table_name};
 
         $tables{$table_name}{source} = $source;
@@ -128,25 +131,33 @@ sub parse {
         my %created_FK_rels;
 
         # global add_fk_index set in parser_args
-        my $add_fk_index = (exists $args->{add_fk_index} && ($args->{add_fk_index} == 0)) ? 0 : 1;
+        my $add_fk_index = (exists $args->{add_fk_index} && ! $args->{add_fk_index}) ? 0 : 1;
 
         foreach my $rel (sort @rels)
         {
+
             my $rel_info = $source->relationship_info($rel);
 
             # Ignore any rel cond that isn't a straight hash
             next unless ref $rel_info->{cond} eq 'HASH';
 
-            my $othertable = $source->related_source($rel);
-            my $rel_table = $othertable->name;
-            $rel_table = $$rel_table if ref $rel_table eq 'SCALAR';  #sqlt currently does not do quoting right anyway
+            my $relsource = $source->related_source($rel);
+
+            # related sources might be excluded via a {sources} filter or might be views
+            next unless exists $table_monikers{$relsource->source_name};
+
+            my $rel_table = $relsource->name;
+
+            # FIXME - this isn't the right way to do it, but sqlt does not
+            # support quoting properly to be signaled about this
+            $rel_table = $$rel_table if ref $rel_table eq 'SCALAR';
 
             my $reverse_rels = $source->reverse_relationship_info($rel);
             my ($otherrelname, $otherrelationship) = each %{$reverse_rels};
 
             # Force the order of @cond to match the order of ->add_columns
             my $idx;
-            my %other_columns_idx = map {'foreign.'.$_ => ++$idx } $othertable->columns;            
+            my %other_columns_idx = map {'foreign.'.$_ => ++$idx } $relsource->columns;
             my @cond = sort { $other_columns_idx{$a} cmp $other_columns_idx{$b} } keys(%{$rel_info->{cond}}); 
 
             # Get the key information, mapping off the foreign/self markers
@@ -178,7 +189,7 @@ sub parse {
                     if ($fk_constraint) {
                         $cascade->{$c} = $rel_info->{attrs}{"on_$c"};
                     }
-                    else {
+                    elsif ( $rel_info->{attrs}{"on_$c"} ) {
                         carp "SQLT attribute 'on_$c' was supplied for relationship '$moniker/$rel', which does not appear to be a foreign constraint. "
                             . "If you are sure that SQLT must generate a constraint for this relationship, add 'is_foreign_key_constraint => 1' to the attributes.\n";
                     }
@@ -194,7 +205,7 @@ sub parse {
                 next unless $fk_constraint;
 
                 # Make sure we dont create the same foreign key constraint twice
-                my $key_test = join("\x00", @keys);
+                my $key_test = join("\x00", sort @keys);
                 next if $created_FK_rels{$rel_table}->{$key_test};
 
                 if (scalar(@keys)) {
@@ -203,8 +214,8 @@ sub parse {
 
                   my $is_deferrable = $rel_info->{attrs}{is_deferrable};
 
-                  # do not consider deferrable constraints and self-references
-                  # for dependency calculations
+                  # calculate dependencies: do not consider deferrable constraints and
+                  # self-references for dependency calculations
                   if (! $is_deferrable and $rel_table ne $table_name) {
                     $tables{$table_name}{foreign_table_deps}{$rel_table}++;
                   }
@@ -250,15 +261,32 @@ sub parse {
     ) {
       $schema->add_table ($tables{$table}{object});
       $tables{$table}{source} -> _invoke_sqlt_deploy_hook( $tables{$table}{object} );
-    }
 
+      # the hook might have already removed the table
+      if ($schema->get_table($table) && $table =~ /^ \s* \( \s* SELECT \s+/ix) {
+        warn <<'EOW';
+
+Custom SQL through ->name(\'( SELECT ...') is DEPRECATED, for more details see
+"Arbitrary SQL through a custom ResultSource" in DBIx::Class::Manual::Cookbook
+or http://search.cpan.org/dist/DBIx-Class/lib/DBIx/Class/Manual/Cookbook.pod
+
+EOW
+
+        # remove the table as there is no way someone might want to
+        # actually deploy this
+        $schema->drop_table ($table);
+      }
+    }
 
     my %views;
-    foreach my $moniker (sort @view_monikers)
+    foreach my $moniker (sort keys %view_monikers)
     {
         my $source = $dbicschema->source($moniker);
         my $view_name = $source->name;
-        $view_name = $$view_name if ref $view_name eq 'SCALAR';  #sqlt currently does not do quoting right anyway
+
+        # FIXME - this isn't the right way to do it, but sqlt does not
+        # support quoting properly to be signaled about this
+        $view_name = $$view_name if ref $view_name eq 'SCALAR';
 
         # Skip custom query sources
         next if ref $view_name;
@@ -266,6 +294,9 @@ sub parse {
         # Its possible to have multiple DBIC source using same table
         next if $views{$view_name}++;
 
+        $dbicschema->throw_exception ("view $view_name is missing a view_definition")
+            unless $source->view_definition;
+
         my $view = $schema->add_view (
           name => $view_name,
           fields => [ $source->columns ],