more functionality in Table.pm, Turnkey.pm is broken (working on it...)
Allen Day [Fri, 29 Aug 2003 08:00:51 +0000 (08:00 +0000)]
lib/SQL/Translator/Producer/Turnkey.pm
lib/SQL/Translator/Schema/Table.pm

index 8e07f75..1754d71 100644 (file)
@@ -3,8 +3,8 @@ package Turnkey::Package;
 use strict;
 use Class::MakeMethods::Template::Hash (
   new => [ 'new' ],
-  hash => [ qw( many ) ],
-  hash_of_arrays => [ qw( many_via) ],
+  'array' => [ qw( many ) ],
+  hash_of_arrays => [ qw( one2one one2many many2one many2many) ],
   scalar => [ qw( base name order primary_key primary_key_accessor table) ],
 );
 
@@ -21,7 +21,7 @@ sub init {
 package SQL::Translator::Producer::Turnkey;
 
 # -------------------------------------------------------------------
-# $Id: Turnkey.pm,v 1.2 2003-08-29 05:38:56 allenday Exp $
+# $Id: Turnkey.pm,v 1.3 2003-08-29 08:00:51 allenday Exp $
 # -------------------------------------------------------------------
 # Copyright (C) 2003 Allen Day <allenday@ucla.edu>,
 #                    Brian O'Connor <boconnor@ucla.edu>,
@@ -44,7 +44,7 @@ package SQL::Translator::Producer::Turnkey;
 
 use strict;
 use vars qw[ $VERSION $DEBUG ];
-$VERSION = sprintf "%d.%02d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/;
+$VERSION = sprintf "%d.%02d", q$Revision: 1.3 $ =~ /(\d+)\.(\d+)/;
 $DEBUG   = 1 unless defined $DEBUG;
 
 use SQL::Translator::Schema::Constants;
@@ -87,7 +87,9 @@ sub produce {
        my %packages;
        my $order;
 
-
+       #
+       # build package objects
+       #
        foreach my $table ($schema->get_tables){
          die __PACKAGE__." table ".$table->name." doesn't have a primary key!" unless $table->primary_key;
          die __PACKAGE__." table ".$table->name." can't have a composite primary key!" if ($table->primary_key->fields)[1];
@@ -106,171 +108,214 @@ sub produce {
                                                                         defined($t->format_pk_name) ? $t->format_pk_name->( $package->name, $package->primary_key )
                                                                                                     : undef
                                                                        );
+
+         foreach my $field ($table->get_fields){
+               next unless $field->is_foreign_key;
+
+               $package->push_many( $field->foreign_key_reference->reference_table );
+         }
        }
 
+       #
+       # identify FK relationships
+       #
        foreach my $maylink ( $schema->get_tables ){
          foreach my $left ($schema->get_tables){
                foreach my $right ($schema->get_tables){
 
                  next if $left->name eq $right->name;
 
-                 if( $maylink->can_link($left,$right) ){
-
-                       $lpackage = $packages{$left->name};
-                       $rpackage = $packages{$right->name};
-
-                       $lpackage->many_via($rpackage => $maylink);
-                       $rpackage->many_via($lpackage => $maylink);
-#                      $linktable{ $maylink->name } = $maylink;
+                 my $lpackage = $packages{$left->name};
+                 my $rpackage = $packages{$right->name};
+
+warn $left->name, "\t", $right->name;
+                 my($link,$lconstraints,$rconstraints) = @{ $maylink->can_link($left,$right) };
+
+                 #one FK to one FK
+                 if( $link eq 'one2one'){
+warn "\tone2one";
+                       $lpackage->one2one_push($rpackage->name, [$rpackage, $maylink]);
+                       $rpackage->one2one_push($lpackage->name, [$lpackage, $maylink]);
+
+                 #one FK to many FK
+                 } elsif( $link eq 'one2many'){
+warn "\tone2many";
+                       $lpackage->one2many_push($rpackage->name, [$rpackage, $maylink]);
+                       $rpackage->many2one_push($lpackage->name, [$lpackage, $maylink]);
+
+                 #many FK to one FK
+                 } elsif( $link eq 'many2one'){
+warn "\tmany2one";
+                       $lpackage->many2one_push($rpackage->name, [$rpackage, $maylink]);
+                       $rpackage->one2many_push($lpackage->name, [$lpackage, $maylink]);
+
+                 #many FK to many FK
+                 } elsif( $link eq 'many2many'){
+warn "\tmany2many";
+                       $lpackage->many2many_push($rpackage->name, [$rpackage, $maylink]);
+                       $rpackage->many2many_push($lpackage->name, [$lpackage, $maylink]);
+
+                 } else {
+                       #not linkable
                  }
-
                }
          }
        }
 
     #
-    # Iterate over all tables
+    # create methods
     #
-    for my $table_from ( $schema->get_tables ) {
+       foreach my $package_from (values %packages){
+         next unless $package_from->table->is_data;
+
          my %linked;
 
+         my %o2o = $package_from->one2one;
+warn Dumper(%o2o);
+         my %o2m = $package_from->one2many;
+warn Dumper(%o2m);
+         my %m2o = $package_from->many2one;
+warn Dumper(%m2o);
+         my %m2m = $package_from->many2many;
+warn Dumper(%m2m);
+
+         foreach my $package_to (keys %{ $package_from->one2one }){
+               $package_to = $packages{$package_to};
+               foreach my $bridge ( $package_from->one2one($package_to->name) ){
+                 $bridge->[3] = $t->format_fk_name ? $t->format_fk_name->(
+                                                                                                                                $package_from->one2one($package_to->name)->[1]->name,
+                                                                                                                                $package_to->primary_key
+                                                                                                                               ).'s'
+                                                                             : $package_from->one2one($package_to->name)->[1]->name .'_'.
+                                                                               $package_to->primary_key .'s';
+               }
+         }
 
-         next unless $table_from->is_data;
-
-         if($table_from->is_data){
-               foreach my $link ( keys %{ $linkable{ $table_from->name } } ) {
-                 my $linkmethodname;
-
-                       if ( my $fk_xform = $t->format_fk_name ) {
-                         # ADD CALLBACK FOR PLURALIZATION MANGLING HERE
-                         $linkmethodname = $fk_xform->($linkable{$table->name}{$link}->name,
-                                                                                       ($schema->get_table($link)->primary_key->fields)[0]).'s';
-                       } else {
-                         # ADD CALLBACK FOR PLURALIZATION MANGLING HERE
-                         $linkmethodname = $linkable{$table->name}{$link}->name.'_'.
-                               ($schema->get_table($link)->primary_key->fields)[0].'s';
-                       }
-
-                       my @rk_fields = ();
-                       my @lk_fields = ();
-                       foreach my $field ($linkable{$table->name}{$link}->get_fields) {
-                         next unless $field->is_foreign_key;
-
-                         next unless(
-                                                 $field->foreign_key_reference->reference_table eq $table->name
-                                                 ||
-                                                 $field->foreign_key_reference->reference_table eq $link
-                                                );
-                         push @lk_fields, ($field->foreign_key_reference->reference_fields)[0]
-                               if $field->foreign_key_reference->reference_table eq $link;
-                         push @rk_fields, $field->name
-                               if $field->foreign_key_reference->reference_table eq $table->name;
-                       }
-
-                       #if one possible traversal via link table
-                       if (scalar(@rk_fields) == 1 and scalar(@lk_fields) == 1) {
-                         foreach my $rk_field (@rk_fields) {
-                               #push @{ $packages{ $table_pkg_name }{'has_many'}{ $link } },
-                               push @{ $packages{ $package->name }{'has_many'}{$link}{'link_one_one'} },
-                                 "sub ".$linkmethodname." { my \$self = shift; ".
-                                       "return map \$_->".
-                                         ($schema->get_table($link)->primary_key->fields)[0].
-                                               ", \$self->".$linkable{$table->name}{$link}->name.
-                                                 "_".$rk_field." }\n\n";
-                               #push @{ $packages{ $table_pkg_name }{'has_many'}{ $link }{'one_one'} },
-                               #  {link_method_name => $linkmethodname, primary_key_field => ($schema->get_table($link)->primary_key->fields)[0],
-                               #   table_name => $linkable{$table_name}{$link}->name, rk_field => $rk_field};
-                         }
-                         #else there is more than one way to traverse it.  ack!
-                         #let's treat these types of link tables as a many-to-one (easier)
-                         #
-                         #NOTE: we need to rethink the link method name, as the cardinality
-                         #has shifted on us.
-                       } elsif (scalar(@rk_fields) == 1) {
-                         foreach my $rk_field (@rk_fields) {
-                               # ADD CALLBACK FOR PLURALIZATION MANGLING HERE
-                               #push @{ $packages{ $table_pkg_name }{'has_many'}{ $link } },
-                               push @{ $packages{ $package->name }{'has_many'}{ $link }{'link_many_one'} },
-                                 "sub " . $linkable{$table->name}{$link}->name .
-                                       "s { my \$self = shift; return \$self->" .
-                                         $linkable{$table->name}{$link}->name . "_" .
-                                               $rk_field . "(\@_) }\n\n";
-                               #push @{ $packages{ $table_pkg_name }{'has_many'}{ $link }{'many_one'} },
-                               #  {
-                               #    table_name => $linkable{$table_name}{$link}->name, rk_field => $rk_field
-                               #  };
-                         }
-                       } elsif (scalar(@lk_fields) == 1) {
-                         #these will be taken care of on the other end...
-                       } else {
-                         #many many many.  need multiple iterations here, data structure revision
-                         #to handle N FK sources.  This code has not been tested and likely doesn't
-                         #work here
-                         foreach my $rk_field (@rk_fields) {
-                               # ADD CALLBACK FOR PLURALIZATION MANGLING HERE
-                               #push @{ $packages{ $table_pkg_name }{'has_many'}{ $link } },
-                               push @{ $packages{ $package->name }{'has_many'}{ $link }{'link_many_many'} },
-                                 "sub " . $linkable{$table->name}{$link}->name . "_" . $rk_field .
-                                       "s { my \$self = shift; return \$self->" .
-                                         $linkable{$table->name}{$link}->name . "_" .
-                                               $rk_field . "(\@_) }\n\n";
-                               #push @{ $packages{ $table_pkg_name }{'has_many'}{ $link }{'many_many'} },
-                               #  {
-                               #   table_name => $linkable{$table_name}{$link}->name, rk_field => $rk_field
-                               #  };
-                         }
-                       }
-                 }
-        }
-
-
-        #
-        # Use foreign keys to set up "has_a/has_many" relationships.
-        #
-        foreach my $field ( $table->get_fields ) {
-            if ( $field->is_foreign_key ) {
-                my $table_name = $table->name;
-                my $field_name = $field->name;
-                my $fk_method  = $t->format_fk_name($table_name, $field_name);
-                my $fk         = $field->foreign_key_reference;
-                my $ref_table  = $fk->reference_table;
-                my $ref_pkg    = $t->format_package_name($ref_table);
-                my $ref_field  = ($fk->reference_fields)[0];
-
-                push @{ $packages{ $package->name }{'has_a'} },
-                    $package->name."->has_a( $field_name => '$ref_pkg');\n".
-                    "sub $fk_method { return shift->$field_name }\n\n"
-                ;
+         foreach my $package_to (keys %{ $package_from->one2many }){
+               $package_to = $packages{$package_to};
+               foreach my $bridge ( $package_from->one2many($package_to->name) ){
+                 $bridge->[3] = $t->format_fk_name ? $t->format_fk_name->(
+                                                                                                                                $package_from->one2many($package_to->name)->[1]->name,
+                                                                                                                                $package_to->primary_key
+                                                                                                                               ).'s'
+                                                                             : $package_from->one2many($package_to->name)->[1]->name .'_'.
+                                                                               $package_to->primary_key .'s';
+               }
+         }
+
+         foreach my $package_to (keys %{ $package_from->many2one }){
+               $package_to = $packages{$package_to};
+               foreach my $bridge ( $package_from->many2one($package_to->name) ){
+                 $bridge->[3] = $t->format_fk_name ? $t->format_fk_name->(
+                                                                                                                                $package_from->many2one($package_to->name)->[1]->name,
+                                                                                                                                $package_to->primary_key
+                                                                                                                               ).'s'
+                                                                             : $package_from->many2one($package_to->name)->[1]->name .'_'.
+                                                                               $package_to->primary_key .'s';
+               }
+         }
+
+         foreach my $package_to (keys %{ $package_from->many2many }){
+               $package_to = $packages{$package_to};
+               foreach my $bridge ( $package_from->many2many($package_to->name) ){
+                 $bridge->[3] = $t->format_fk_name ? $t->format_fk_name->(
+                                                                                                                                $package_from->many2many($package_to->name)->[1]->name,
+                                                                                                                                $package_to->primary_key
+                                                                                                                               ).'s'
+                                                                             : $package_from->many2many($package_to->name)->[1]->name .'_'.
+                                                                               $package_to->primary_key .'s';
+               }
+         }
+
+
+
+
+#              #if one possible traversal via link table
+#              if (scalar(@rk_fields) == 1 and scalar(@lk_fields) == 1) {
+#                foreach my $rk_field (@rk_fields) {
+#                      push @{ $packages{ $package->name }{'has_many'}{$link}{'link_one_one'} },
+#                        "sub ".$linkmethodname." { my \$self = shift; ".
+#                              "return map \$_->".
+#                                ($schema->get_table($link)->primary_key->fields)[0].
+#                                      ", \$self->".$linkable{$table_from->name}{$link}->name.
+#                                        "_".$rk_field." }\n\n";
+#                }
+#                #NOTE: we need to rethink the link method name, as the cardinality
+#                #has shifted on us.
+#              } elsif (scalar(@rk_fields) == 1) {
+#                foreach my $rk_field (@rk_fields) {
+#                      # ADD CALLBACK FOR PLURALIZATION MANGLING HERE
+#                      push @{ $packages{ $package->name }{'has_many'}{ $link }{'link_many_one'} },
+#                        "sub " . $linkable{$table_from->name}{$link}->name .
+#                              "s { my \$self = shift; return \$self->" .
+#                                $linkable{$table_from->name}{$link}->name . "_" .
+#                                      $rk_field . "(\@_) }\n\n";
+#                }
+#              } elsif (scalar(@lk_fields) == 1) {
+#                #these will be taken care of on the other end...
+#              } else {
+#                #many many many.  need multiple iterations here, data structure revision
+#                #to handle N FK sources.  This code has not been tested and likely doesn't
+#                #work here
+#                foreach my $rk_field (@rk_fields) {
+#                      # ADD CALLBACK FOR PLURALIZATION MANGLING HERE
+#                      push @{ $packages{ $package->name }{'has_many'}{ $link }{'link_many_many'} },
+#                        "sub " . $linkable{$table_from->name}{$link}->name . "_" . $rk_field .
+#                              "s { my \$self = shift; return \$self->" .
+#                                $linkable{$table_from->name}{$link}->name . "_" .
+#                                      $rk_field . "(\@_) }\n\n";
+#                }
+#              }
+#        }
+
+
+#        #
+#        # Use foreign keys to set up "has_a/has_many" relationships.
+#        #
+#         foreach my $field ( $table_from->get_fields ) {
+#             if ( $field->is_foreign_key ) {
+#                 my $table_name = $table_from->name;
+#                 my $field_name = $field->name;
+#                 my $fk_method  = $t->format_fk_name($table_name, $field_name);
+#                 my $fk         = $field->foreign_key_reference;
+#                 my $ref_table  = $fk->reference_table;
+#                 my $ref_pkg    = $t->format_package_name($ref_table);
+#                 my $ref_field  = ($fk->reference_fields)[0];
+
+#                 push @{ $packages{ $package->name }{'has_a'} },
+#                     $package->name."->has_a( $field_name => '$ref_pkg');\n".
+#                     "sub $fk_method { return shift->$field_name }\n\n"
+#                 ;
                                
                                
-                #
-                # If this table "has a" to the other, then it follows 
-                # that the other table "has many" of this one, right?
-                #
-                               # No... there is the possibility of 1-1 cardinality
-
-                               #if there weren't M-M relationships via the has_many
-                               #being set up here, create nice pluralized method alias
-                               #rather for user as alt. to ugly tablename_fieldname name
-                               if(! $packages{ $ref_pkg }{ 'has_many' }{ $table->name } ){
-                                 # ADD CALLBACK FOR PLURALIZATION MANGLING HERE
-                                 #push @{ $packages{ $ref_pkg }{'has_many'}{ $table_name } },
-                               #       "sub $table_name\s {\n    return shift->$table_name\_$field_name\n}\n\n";
-                                 push @{ $packages{ $ref_pkg }{'has_many'}{ $table->name }{'fk_pluralized'} },
-                                       { table_name => $table->name, field_name => $field_name };
-
-                               #else ugly
-                               } else {
-                               }
-
-                               #push @{ $packages{ $ref_pkg }{'has_many'}{ $table_name } },
-                               #  "$ref_pkg->has_many(\n    '${table_name}_${field_name}', ".
-                               #  "'$table_pkg_name' => '$field_name'\n);\n\n";
-                               push @{ $packages{ $ref_pkg }{'has_many'}{ $table_name }{pluralized} },
-                                 { ref_pkg => $ref_pkg, table_pkg_name => $package->name, table_name => $table->name, field_name => $field_name };
-            }
-               }
-       }
+#                 #
+#                 # If this table "has a" to the other, then it follows 
+#                 # that the other table "has many" of this one, right?
+#                 #
+#                              # No... there is the possibility of 1-1 cardinality
+
+#                              #if there weren't M-M relationships via the has_many
+#                              #being set up here, create nice pluralized method alias
+#                              #rather for user as alt. to ugly tablename_fieldname name
+#                              if(! $packages{ $ref_pkg }{ 'has_many' }{ $table_from->name } ){
+#                                # ADD CALLBACK FOR PLURALIZATION MANGLING HERE
+#                                #push @{ $packages{ $ref_pkg }{'has_many'}{ $table_name } },
+#                              #       "sub $table_name\s {\n    return shift->$table_name\_$field_name\n}\n\n";
+#                                push @{ $packages{ $ref_pkg }{'has_many'}{ $table_from->name }{'fk_pluralized'} },
+#                                      { table_name => $table_from->name, field_name => $field_name };
+
+#                              #else ugly
+#                              } else {
+#                              }
+
+#                              #push @{ $packages{ $ref_pkg }{'has_many'}{ $table_name } },
+#                              #  "$ref_pkg->has_many(\n    '${table_name}_${field_name}', ".
+#                              #  "'$table_pkg_name' => '$field_name'\n);\n\n";
+#                              push @{ $packages{ $ref_pkg }{'has_many'}{ $table_name }{pluralized} },
+#                                { ref_pkg => $ref_pkg, table_pkg_name => $package->name, table_name => $table_from->name, field_name => $field_name };
+#                        }
+#              }
+       }
 
        my %metadata;
        $metadata{"packages"} = \%packages;
index 0476992..fc29754 100644 (file)
@@ -1,7 +1,7 @@
 package SQL::Translator::Schema::Table;
 
 # ----------------------------------------------------------------------
-# $Id: Table.pm,v 1.15 2003-08-29 05:38:56 allenday Exp $
+# $Id: Table.pm,v 1.16 2003-08-29 08:00:51 allenday Exp $
 # ----------------------------------------------------------------------
 # Copyright (C) 2003 Ken Y. Clark <kclark@cpan.org>
 #
@@ -46,11 +46,12 @@ use SQL::Translator::Schema::Constants;
 use SQL::Translator::Schema::Constraint;
 use SQL::Translator::Schema::Field;
 use SQL::Translator::Schema::Index;
+use Data::Dumper;
 
 use base 'Class::Base';
 use vars qw( $VERSION $FIELD_ORDER );
 
-$VERSION = sprintf "%d.%02d", q$Revision: 1.15 $ =~ /(\d+)\.(\d+)/;
+$VERSION = sprintf "%d.%02d", q$Revision: 1.16 $ =~ /(\d+)\.(\d+)/;
 
 # ----------------------------------------------------------------------
 sub init {
@@ -425,7 +426,7 @@ sub is_data {
   $self->{'is_data'} = 0;
 
   foreach my $field ($self->get_fields){
-       if(!$field->is_primary_key or !$field->is_foreign_key){
+       if(!$field->is_primary_key and !$field->is_foreign_key){
          $self->{'is_data'} = 1;
          return $self->{'is_data'}
        }
@@ -448,13 +449,11 @@ Determine whether the table can link two arg tables via many-to-many.
 
   my($self,$table1,$table2) = @_;
 
-  #get tables in abc order
-  ($table1,$table2) = sort {$a->name cmp $b->name} ($table1,$table2);
-
   return $self->{'can_link'}{$table1->name}{$table2->name} if defined $self->{'can_link'}{$table1->name}{$table2->name};
 
   if($self->is_data == 1){
-       $self->{'can_link'}{$table1->name}{$table2->name} = 0;
+       $self->{'can_link'}{$table1->name}{$table2->name} = [0];
+       $self->{'can_link'}{$table2->name}{$table1->name} = [0];
        return $self->{'can_link'}{$table1->name}{$table2->name};
   }
 
@@ -462,23 +461,53 @@ Determine whether the table can link two arg tables via many-to-many.
 
   foreach my $field ($self->get_fields){
        #if the table has non-key fields, it can't be a link
-       if(!$field->is_primary_key or !$field->is_foreign_key){
-         $self->{'can_link'}{$table1->name}{$table2->name} = 0;
+       if(!$field->is_primary_key and !$field->is_foreign_key){
+         $self->{'can_link'}{$table1->name}{$table2->name} = [0];
+         $self->{'can_link'}{$table2->name}{$table1->name} = [0];
          return $self->{'can_link'}{$table1->name}{$table2->name};
 
        #otherwise, count up how many fields refer to each FK table.field
        } elsif($field->is_foreign_key){
-         $fk{$field->foreign_key_reference->reference_table->name}++;
+         push @{ $fk{$field->foreign_key_reference->reference_table->name} }, $field->foreign_key_reference;
        }
   }
 
-  if($fk{ $table1->name } == 1
+  #trivial traversal, only one way to link the two tables
+  if(scalar($fk{ $table1->name } == 1)
         and
-        $fk{ $table2->name } == 1
+        scalar($fk{ $table2->name } == 1)
        ){
-       $self->{'can_link'}{$table1->name}{$table2->name} = 1;
+       $self->{'can_link'}{$table1->name}{$table2->name} = ['one2one', $fk{$table1->name}, $fk{$table2->name}];
+       $self->{'can_link'}{$table1->name}{$table2->name} = ['one2one', $fk{$table2->name}, $fk{$table1->name}];
+
+  #non-trivial traversal.  one way to link table2, many ways to link table1
+  } elsif(scalar($fk{ $table1->name }  > 1)
+                 and
+                 scalar($fk{ $table2->name } == 1)
+                ){
+       $self->{'can_link'}{$table1->name}{$table2->name} = ['many2one', $fk{$table1->name}, $fk{$table2->name}];
+       $self->{'can_link'}{$table2->name}{$table1->name} = ['one2many', $fk{$table2->name}, $fk{$table1->name}];
+
+  #non-trivial traversal.  one way to link table1, many ways to link table2
+  } elsif(scalar($fk{ $table1->name } == 1)
+                 and
+                 scalar($fk{ $table2->name }  > 1)
+                ){
+       $self->{'can_link'}{$table1->name}{$table2->name} = ['one2many', $fk{$table1->name}, $fk{$table2->name}];
+       $self->{'can_link'}{$table2->name}{$table1->name} = ['many2one', $fk{$table2->name}, $fk{$table1->name}];
+
+  #non-trivial traversal.  many ways to link table1 and table2
+  } elsif(scalar($fk{ $table1->name }  > 1)
+                 and
+                 scalar($fk{ $table2->name }  > 1)
+                ){
+       $self->{'can_link'}{$table1->name}{$table2->name} = ['many2many', $fk{$table1->name}, $fk{$table2->name}];
+       $self->{'can_link'}{$table2->name}{$table1->name} = ['many2many', $fk{$table2->name}, $fk{$table1->name}];
+
+  #one of the tables didn't export a key to this table, no linking possible
   } else {
-       $self->{'can_link'}{$table1->name}{$table2->name} = 0;
+       $self->{'can_link'}{$table1->name}{$table2->name} = [0];
+       $self->{'can_link'}{$table2->name}{$table1->name} = [0];
   }
 
   return $self->{'can_link'}{$table1->name}{$table2->name};