From: Allen Day Date: Fri, 29 Aug 2003 05:38:56 +0000 (+0000) Subject: moving reusable (useful?) code into schema classes X-Git-Tag: v0.04~203 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=69c7a62f38fa4519a8cdb14bed4af37f2c6206ff;p=dbsrgits%2FSQL-Translator.git moving reusable (useful?) code into schema classes --- diff --git a/lib/SQL/Translator/Producer/Turnkey.pm b/lib/SQL/Translator/Producer/Turnkey.pm index db3d697..8e07f75 100644 --- a/lib/SQL/Translator/Producer/Turnkey.pm +++ b/lib/SQL/Translator/Producer/Turnkey.pm @@ -1,9 +1,30 @@ +package Turnkey::Package; + +use strict; +use Class::MakeMethods::Template::Hash ( + new => [ 'new' ], + hash => [ qw( many ) ], + hash_of_arrays => [ qw( many_via) ], + scalar => [ qw( base name order primary_key primary_key_accessor table) ], +); + + +# get_set => [ qw(order base name table primary_key primary_key_accessor) ], +# new_with_init => 'new', +#; + +sub init { +} + +1; + package SQL::Translator::Producer::Turnkey; # ------------------------------------------------------------------- -# $Id: Turnkey.pm,v 1.1 2003-08-28 08:51:09 boconnor Exp $ +# $Id: Turnkey.pm,v 1.2 2003-08-29 05:38:56 allenday Exp $ # ------------------------------------------------------------------- # Copyright (C) 2003 Allen Day , +# Brian O'Connor , # Ying Zhang # # This program is free software; you can redistribute it and/or @@ -23,7 +44,7 @@ package SQL::Translator::Producer::Turnkey; use strict; use vars qw[ $VERSION $DEBUG ]; -$VERSION = sprintf "%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/; +$VERSION = sprintf "%d.%02d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/; $DEBUG = 1 unless defined $DEBUG; use SQL::Translator::Schema::Constants; @@ -63,125 +84,98 @@ sub produce { # my %linkable; my %linktable; - foreach my $table ( $schema->get_tables ) { - my $is_link = 1; - foreach my $field ( $table->get_fields ) { - unless ( $field->is_primary_key or $field->is_foreign_key ) { - $is_link = 0; - last; - } - } + my %packages; + my $order; - next unless $is_link; - - foreach my $left ( $table->get_fields ) { - next unless $left->is_foreign_key; - my $lfk = $left->foreign_key_reference or next; - my $lr_table = $schema->get_table( $lfk->reference_table ) - or next; - my $lr_field_name = ($lfk->reference_fields)[0]; - my $lr_field = $lr_table->get_field($lr_field_name); - next unless $lr_field->is_primary_key; - - foreach my $right ( $table->get_fields ) { - next if $left->name eq $right->name; - - my $rfk = $right->foreign_key_reference or next; - my $rr_table = $schema->get_table( $rfk->reference_table ) - or next; - my $rr_field_name = ($rfk->reference_fields)[0]; - my $rr_field = $rr_table->get_field($rr_field_name); - next unless $rr_field->is_primary_key; - - $linkable{ $lr_table->name }{ $rr_table->name } = $table; - $linkable{ $rr_table->name }{ $lr_table->name } = $table; - $linktable{ $table->name } = $table; - } - } - } - # - # Iterate over all tables - # - my ( %packages, $order ); - for my $table ( $schema->get_tables ) { - my $table_name = $table->name or next; - - my $table_pkg_name = $t->format_package_name($table_name); - $packages{ $table_pkg_name } = { - order => ++$order, - pkg_name => $table_pkg_name, - base => $main_pkg_name, - table => $table_name, - }; + 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]; - # - # Primary key may have a differenct accessor method name - # - if ( my $constraint = $table->primary_key ) { - my $field = ($constraint->fields)[0]; - $packages{ $table_pkg_name }{'columns_primary'} = $field; - if ( my $pk_xform = $t->format_pk_name ) { - my $pk_name = $pk_xform->( $table_pkg_name, $field ); + my $package = Turnkey::Package->new(); + $packages{ $package->name } = $package; - $packages{ $table_pkg_name }{'pk_accessor'} = - "#\n# Primary key accessor\n#\n". - "sub $pk_name {\n shift->$field\n}\n\n"; - - } - } + $package->order( ++$order ); + $package->name( $t->format_package_name($table->name) ); + $package->base( $main_pkg_name ); + $package->table( $table ); + $package->primary_key( ($table->primary_key->fields)[0] ); + # Primary key may have a differenct accessor method name + $package->primary_key_accessor( + defined($t->format_pk_name) ? $t->format_pk_name->( $package->name, $package->primary_key ) + : undef + ); + } - my $is_data = 0; - foreach my $field ( $table->get_fields ) { - if ( !$field->is_foreign_key and !$field->is_primary_key ) { - push @{ $packages{ $table_pkg_name }{'columns_essential'} }, $field->name; - $is_data++; - } elsif ( !$field->is_primary_key ) { - push @{ $packages{ $table_pkg_name }{'columns_others'} }, $field->name; + 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; } + } + } + } + + # + # Iterate over all tables + # + for my $table_from ( $schema->get_tables ) { + my %linked; - my %linked; - if ( $is_data ) { - foreach my $link ( keys %{ $linkable{ $table_name } } ) { - my $linkmethodname; + + 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, + $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.'_'. + $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) { + 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 $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 $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{ $table_pkg_name }{'has_many'}{$link}{'link_one_one'} }, + 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. + ", \$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], @@ -196,10 +190,10 @@ sub produce { foreach my $rk_field (@rk_fields) { # ADD CALLBACK FOR PLURALIZATION MANGLING HERE #push @{ $packages{ $table_pkg_name }{'has_many'}{ $link } }, - push @{ $packages{ $table_pkg_name }{'has_many'}{ $link }{'link_many_one'} }, - "sub " . $linkable{$table_name}{$link}->name . + 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 . "_" . + $linkable{$table->name}{$link}->name . "_" . $rk_field . "(\@_) }\n\n"; #push @{ $packages{ $table_pkg_name }{'has_many'}{ $link }{'many_one'} }, # { @@ -215,10 +209,10 @@ sub produce { foreach my $rk_field (@rk_fields) { # ADD CALLBACK FOR PLURALIZATION MANGLING HERE #push @{ $packages{ $table_pkg_name }{'has_many'}{ $link } }, - push @{ $packages{ $table_pkg_name }{'has_many'}{ $link }{'link_many_many'} }, - "sub " . $linkable{$table_name}{$link}->name . "_" . $rk_field . + 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 . "_" . + $linkable{$table->name}{$link}->name . "_" . $rk_field . "(\@_) }\n\n"; #push @{ $packages{ $table_pkg_name }{'has_many'}{ $link }{'many_many'} }, # { @@ -243,11 +237,9 @@ sub produce { my $ref_pkg = $t->format_package_name($ref_table); my $ref_field = ($fk->reference_fields)[0]; - push @{ $packages{ $table_pkg_name }{'has_a'} }, - "$table_pkg_name->has_a(\n". - " $field_name => '$ref_pkg'\n);\n\n". - "sub $fk_method {\n". - " return shift->$field_name\n}\n\n" + push @{ $packages{ $package->name }{'has_a'} }, + $package->name."->has_a( $field_name => '$ref_pkg');\n". + "sub $fk_method { return shift->$field_name }\n\n" ; @@ -260,12 +252,12 @@ sub produce { #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 } ){ + 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 }; + push @{ $packages{ $ref_pkg }{'has_many'}{ $table->name }{'fk_pluralized'} }, + { table_name => $table->name, field_name => $field_name }; #else ugly } else { @@ -275,7 +267,7 @@ sub produce { # "$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 => $table_pkg_name, table_name => $table_name, field_name => $field_name }; + { ref_pkg => $ref_pkg, table_pkg_name => $package->name, table_name => $table->name, field_name => $field_name }; } } } @@ -464,37 +456,38 @@ my $turnkey_xml_tt2 = < [% FOREACH package = linkable %] -[% END %] +[%- END -%] [% FOREACH focus_atom = linkable %] [% FOREACH link_atom = focus_atom.value %] - [% END %] -[% END %] + [%- END -%] +[%- END -%] - [% FOREACH focus_atom = linkable %] - - [% FOREACH link_atom = focus_atom.value %] - - [% END %] - - - [% END %] - - - - - +[% FOREACH focus_atom = linkable %] + + [% FOREACH link_atom = focus_atom.value %] + + [%- END -%] + + + [%- END -%] + + + + + + + +[% FOREACH focus_atom = linkable %] + +[%- END -%] - - [% FOREACH focus_atom = linkable %] - - [% END %] - + EOF @@ -571,10 +564,12 @@ sub translateForm my $args = $t->producer_args; my $tt2 = $args->{'template'}; my $tt2Ref; - if ($tt2 eq 'atom') { $tt2Ref = \$turnkey_atom_tt2; } - if ($tt2 eq 'dbi') { $tt2Ref = \$turnkey_dbi_tt2; } - if ($tt2 eq 'xml') { $tt2Ref = \$turnkey_xml_tt2; } - if ($tt2 eq 'template') { $tt2Ref = \$turnkey_template_tt2; } + + if ($tt2 eq 'atom') { $tt2Ref = \$turnkey_atom_tt2; } + elsif ($tt2 eq 'classdbi') { $tt2Ref = \$turnkey_dbi_tt2; } + elsif ($tt2 eq 'xml') { $tt2Ref = \$turnkey_xml_tt2; } + elsif ($tt2 eq 'template') { $tt2Ref = \$turnkey_template_tt2; } + else { die __PACKAGE__." didn't recognize your template option: $tt2" } my $vars = { packages => $output->{packages}, @@ -613,7 +608,7 @@ SQL::Translator::Producer::ClassDBI - create Class::DBI classes from schema Use this producer as you would any other from SQL::Translator. See L for details. -This package utilizes SQL::Translator's formatting methods +This package utilizes SQL::Translator\'s formatting methods format_package_name(), format_pk_name(), format_fk_name(), and format_table_name() as it creates classes, one per table in the schema provided. An additional base class is also created for database connectivity @@ -624,4 +619,4 @@ configuration. See L for details on how this works. Allen Day Eallenday@ucla.eduE Ying Zhang Ezyolive@yahoo.comE, Ken Y. Clark Ekclark@cpan.orgE, -Brian O'Connor Ebrian.oconnor@excite.comE. +Brian O\'Connor Ebrian.oconnor@excite.comE. diff --git a/lib/SQL/Translator/Schema/Table.pm b/lib/SQL/Translator/Schema/Table.pm index 878debe..0476992 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.14 2003-08-21 20:27:04 kycl4rk Exp $ +# $Id: Table.pm,v 1.15 2003-08-29 05:38:56 allenday Exp $ # ---------------------------------------------------------------------- # Copyright (C) 2003 Ken Y. Clark # @@ -50,7 +50,7 @@ use SQL::Translator::Schema::Index; use base 'Class::Base'; use vars qw( $VERSION $FIELD_ORDER ); -$VERSION = sprintf "%d.%02d", q$Revision: 1.14 $ =~ /(\d+)\.(\d+)/; +$VERSION = sprintf "%d.%02d", q$Revision: 1.15 $ =~ /(\d+)\.(\d+)/; # ---------------------------------------------------------------------- sub init { @@ -246,7 +246,7 @@ existing field, you will get an error and the field will not be created. my $field_name = $field->name or return $self->error('No name'); if ( exists $self->{'fields'}{ $field_name } ) { - return $self->error(qq[Can't create field: "$field_name" exists]); + return $self->error(qq[Can\'t create field: "$field_name" exists]); } else { $self->{'fields'}{ $field_name } = $field; @@ -418,6 +418,72 @@ Determine whether the view is valid or not. return 1; } +sub is_data { + my $self = shift; + return $self->{'is_data'} if defined $self->{'is_data'}; + + $self->{'is_data'} = 0; + + foreach my $field ($self->get_fields){ + if(!$field->is_primary_key or !$field->is_foreign_key){ + $self->{'is_data'} = 1; + return $self->{'is_data'} + } + } + + return $self->{'is_data'}; +} + +sub can_link { + +=pod + +=head2 can_link + +Determine whether the table can link two arg tables via many-to-many. + + my $ok = $table->can_link($table1,$table2); + +=cut + + 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; + return $self->{'can_link'}{$table1->name}{$table2->name}; + } + + my %fk = (); + + 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; + 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}++; + } + } + + if($fk{ $table1->name } == 1 + and + $fk{ $table2->name } == 1 + ){ + $self->{'can_link'}{$table1->name}{$table2->name} = 1; + } else { + $self->{'can_link'}{$table1->name}{$table2->name} = 0; + } + + return $self->{'can_link'}{$table1->name}{$table2->name}; +} + # ---------------------------------------------------------------------- sub name { @@ -425,7 +491,7 @@ sub name { =head2 name -Get or set the table's name. +Get or set the table\'s name. If provided an argument, checks the schema object for a table of that name and disallows the change if one exists. @@ -438,7 +504,7 @@ that name and disallows the change if one exists. if ( my $arg = shift ) { if ( my $schema = $self->schema ) { - return $self->error( qq[Can't use table name "$arg": table exists] ) + return $self->error( qq[Can\'t use table name "$arg": table exists] ) if $schema->get_table( $arg ); } $self->{'name'} = $arg; @@ -454,7 +520,7 @@ sub schema { =head2 schema -Get or set the table's schema object. +Get or set the table\'s schema object. my $schema = $table->schema; @@ -477,7 +543,7 @@ sub primary_key { =head2 options -Gets or sets the table's primary key(s). Takes one or more field +Gets or sets the table\'s primary key(s). Takes one or more field names (as a string, list or array[ref]) as an argument. If the field names are present, it will create a new PK if none exists, or it will add to the fields of an existing PK (and will unique the field names). @@ -543,7 +609,7 @@ sub options { =head2 options -Get or set the table's options (e.g., table types for MySQL). Returns +Get or set the table\'s options (e.g., table types for MySQL). Returns an array or array reference. my @options = $table->options; @@ -570,7 +636,7 @@ sub order { =head2 order -Get or set the table's order. +Get or set the table\'s order. my $order = $table->order(3);