From: Allen Day Date: Fri, 29 Aug 2003 08:00:51 +0000 (+0000) Subject: more functionality in Table.pm, Turnkey.pm is broken (working on it...) X-Git-Tag: v0.04~202 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=c8515c9f7364cf9b8537970fce730b80a65da9f7;p=dbsrgits%2FSQL-Translator.git more functionality in Table.pm, Turnkey.pm is broken (working on it...) --- diff --git a/lib/SQL/Translator/Producer/Turnkey.pm b/lib/SQL/Translator/Producer/Turnkey.pm index 8e07f75..1754d71 100644 --- a/lib/SQL/Translator/Producer/Turnkey.pm +++ b/lib/SQL/Translator/Producer/Turnkey.pm @@ -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 , # Brian O'Connor , @@ -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; diff --git a/lib/SQL/Translator/Schema/Table.pm b/lib/SQL/Translator/Schema/Table.pm index 0476992..fc29754 100644 --- a/lib/SQL/Translator/Schema/Table.pm +++ b/lib/SQL/Translator/Schema/Table.pm @@ -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 # @@ -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};