From: Ken Youens-Clark Date: Wed, 25 Jun 2003 18:47:45 +0000 (+0000) Subject: Allow translation from parsers other than MySQL, Pg, and Oracle and just X-Git-Tag: v0.04~392 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=bf4629e70da9dec161c4aeb65a19e5423aba7bc4;p=dbsrgits%2FSQL-Translator.git Allow translation from parsers other than MySQL, Pg, and Oracle and just set up table more manually than using the "set_up_table" method; no reason to accept "$data" at beginning as it's not being sent anymore; no longer using "$USER" or "$PASS" as they were only used once; removed Class::DBI::Join as Michael Schwern (the module maintainer and Author Emeritus of Class::DBI) says that Class::DBI handles this fine now that this extra module will be leaving CPAN soon; only create PK accessor method if a callback was installed for it; use "$table->primary_key" to get PK rather than running through the constraints to find it; delay creation of output for each table until after we've gone through everything so we can better set up the "has_a" and "has_many" relationships; intuit "has_many" as the reverse of "has_a"; cleaned up "link tables" section, but commented out as I'm not sure if my addition of "has_many" code might not do the same thing. --- diff --git a/lib/SQL/Translator/Producer/ClassDBI.pm b/lib/SQL/Translator/Producer/ClassDBI.pm index 2232c55..4763772 100755 --- a/lib/SQL/Translator/Producer/ClassDBI.pm +++ b/lib/SQL/Translator/Producer/ClassDBI.pm @@ -1,7 +1,7 @@ package SQL::Translator::Producer::ClassDBI; # ------------------------------------------------------------------- -# $Id: ClassDBI.pm,v 1.19 2003-06-25 02:04:33 allenday Exp $ +# $Id: ClassDBI.pm,v 1.20 2003-06-25 18:47:45 kycl4rk Exp $ # ------------------------------------------------------------------- # Copyright (C) 2003 Allen Day , # Ying Zhang @@ -23,197 +23,258 @@ package SQL::Translator::Producer::ClassDBI; use strict; use vars qw[ $VERSION $DEBUG ]; -$VERSION = sprintf "%d.%02d", q$Revision: 1.19 $ =~ /(\d+)\.(\d+)/; +$VERSION = sprintf "%d.%02d", q$Revision: 1.20 $ =~ /(\d+)\.(\d+)/; $DEBUG = 1 unless defined $DEBUG; use SQL::Translator::Schema::Constants; use SQL::Translator::Utils qw(header_comment); use Data::Dumper; +my %CDBI_auto_pkgs = ( + MySQL => 'mysql', + PostgreSQL => 'Pg', + Oracle => 'Oracle', +); + +# ------------------------------------------------------------------- sub produce { - my ($translator, $data) = @_; - local $DEBUG = $translator->debug; - my $no_comments = $translator->no_comments; - my $schema = $translator->schema; - - my $create; - $create .= header_comment(__PACKAGE__, "# ") unless ($no_comments); - - $create .= "package " . $translator->format_package_name('DBI'). ";\n\n"; - - $create .= "use strict;\n\n"; - $create .= "my \$USER = '';\n"; - $create .= "my \$PASS = '';\n\n"; - - my $from = _from($translator->parser_type()); - - $create .= "use base 'Class::DBI::$from';\n\n" . - $translator->format_package_name('DBI') . - "->set_db('Main', 'dbi:$from:_', \$USER, \$PASS);\n\n"; - + my $translator = shift; + local $DEBUG = $translator->debug; + my $no_comments = $translator->no_comments; + my $schema = $translator->schema; + my $args = $translator->producer_args; + my $db_user = $args->{'db_user'} || ''; + my $db_pass = $args->{'db_pass'} || ''; + my $dsn = $args->{'dsn'} || 'dbi:$from:_'; + my $main_pkg_name = $translator->format_package_name('DBI'); + my $header = header_comment(__PACKAGE__, "# "); + my $sep = '# ' . '-' x 67; + + my $parser_type = ( split /::/, $translator->parser_type )[-1]; + my $from = $CDBI_auto_pkgs{ $parser_type } || ''; + # # Iterate over all tables # + my ( %packages, $order ); for my $table ( $schema->get_tables ) { my $table_name = $table->name or next; - my %pk; - unless ( $no_comments ) { - $create .= - "#\n# Package: " . - $translator->format_package_name($table_name). - "\n#\n" - } + my $table_pkg_name = $translator->format_package_name($table_name); + $packages{ $table_pkg_name } = { + order => ++$order, + pkg_name => $table_pkg_name, + base => $main_pkg_name, + table => $table_name, + }; - $create .= "package ".$translator->format_package_name($table_name).";\n\n"; - $create .= "use strict;\n"; - $create .= "use base qw(".$translator->format_package_name('DBI').");\n"; - $create .= "use mixin 'Class::DBI::Join';\n"; - $create .= "use Class::DBI::Pager;\n\n"; - - $create .= $translator->format_package_name($table_name)."->set_up_table('$table_name');\n\n"; - # - # Primary key? + # Primary key may have a differenct accessor method name # - foreach my $constraint ( $table->get_constraints ) { - next unless $constraint->type eq PRIMARY_KEY; - my $field = ($constraint->fields)[0]; - - $pk{ $table_name } = $field; - $create .= "sub " .$translator->format_pk_name( - $translator->format_package_name( $table_name ), - $field - ) . " { shift->".$field." }\n\n"; + if ( my $pk_xform = $translator->format_pk_name ) { + if ( my $constraint = $table->primary_key ) { + my $field = ($constraint->fields)[0]; + my $pk_name = $pk_xform->($table_pkg_name, $field); + + $packages{ $table_pkg_name }{'pk_accessor'} = + "#\n# Primary key accessor\n#\n". + "sub $pk_name {\n shift->$field\n}\n" + ; + } } - + # - # Find foreign keys + # 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 = $field->foreign_key_reference; my $ref_table = $fk->reference_table; - my @ref_fields = $fk->reference_fields; - my @fields = $fk->fields; + my $ref_pkg = $translator->format_package_name($ref_table); + my $ref_fld = + $translator->format_fk_name($ref_table, $field_name); - $create .= $translator->format_package_name($table_name). - "->hasa(\n '" . - $translator->format_package_name($ref_table). - "' => '$field_name'\n);\n\n"; - $create .= "sub " . - $translator->format_fk_name($ref_table, $field_name). - " {\n return shift->$field_name\n}\n\n"; + push @{ $packages{ $table_pkg_name }{'has_a'} }, + "$table_pkg_name->has_a(\n". + " $field_name => '$ref_pkg'\n);\n\n". + "sub $ref_fld {\n". + " return shift->$field_name\n}\n\n" + ; + # + # If this table "has a" to the other, then it follows + # that the other table "has many" of this one, right? + # + push @{ $packages{ $ref_pkg }{'has_many'} }, + "$ref_pkg->has_many(\n '$table_name', ". + "'$table_pkg_name' => '$field_name'\n);\n\n" + ; } } - # - # Identify link tables, defined as tables that have only PK and FK - # fields - # - my %linkable; - my %linktable; - foreach my $table ($schema->get_tables) { - my $is_link = 1; - foreach my $field ($table->get_fields){ - $is_link = 0 and last unless $field->is_primary_key or $field->is_foreign_key; - } - - if($is_link){ - foreach my $left ($table->get_fields){ - next unless $left->is_foreign_key and $schema->get_table($left->foreign_key_reference->reference_table); - - - next unless $left->is_foreign_key and - $schema->get_table( - $left->foreign_key_reference->reference_table - )->get_field( - ($left->foreign_key_reference->reference_fields)[0] - )->is_primary_key; - - foreach my $right ($table->get_fields){ - #skip the diagonal - next if $left->name eq $right->name; - - next unless $right->is_foreign_key and $schema->get_table($right->foreign_key_reference->reference_table); - - next unless $right->is_foreign_key and - $schema->get_table( - $right->foreign_key_reference->reference_table - )->get_field( - ($right->foreign_key_reference->reference_fields)[0] - )->is_primary_key; - - - $linkable{$left->foreign_key_reference->reference_table}{$right->foreign_key_reference->reference_table} = $table; - $linkable{$right->foreign_key_reference->reference_table}{$left->foreign_key_reference->reference_table} = $table; - $linktable{$table->name} = $table; - - } - } - } - - } - - - # - # Generate many-to-many linking methods for data tables - # - my $is_data = 0; - map {(!$_->is_foreign_key and !$_->is_primary_key) ? $is_data++ : 0} $table->get_fields; - my %linked; - if($is_data){ - foreach my $link (keys %{$linkable{$table->name}}){ - my $linkmethodname = "_".$translator->format_fk_name($table->name,$link)."_refs"; - - - $create .= $translator->format_package_name($table->name). - "->has_many('$linkmethodname','". - $translator->format_package_name($linkable{$table->name}{$link}->name)."','". - ($schema->get_table($link)->primary_key->fields)[0]."');\n"; -# $link."');\n"; - $create .= "sub ". $translator->format_fk_name($table,$link). - ### HARDCODED 's' HERE. ADD CALLBACK FOR PLURALIZATION MANGLING - "s {\n my \$self = shift; return map \$_->".$link. - ", \$self->".$linkmethodname.";\n}\n\n"; - } - } - } - - $create .= '1;'; + # + # Identify link tables, defined as tables that have + # only PK and FK fields. + # +# 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; +# } +# } +# +# if ( $is_link ) { +# foreach my $left ( $table->get_fields ) { +# next unless $left->is_foreign_key and $schema->get_table( +# $left->foreign_key_reference->reference_table +# ); +# +# next unless $left->is_foreign_key and $schema->get_table( +# $left->foreign_key_reference->reference_table +# )->get_field( +# ($left->foreign_key_reference->reference_fields)[0] +# )->is_primary_key; +# +# foreach my $right ( $table->get_fields ) { +# #skip the diagonal +# next if $left->name eq $right->name; +# +# next unless $right->is_foreign_key and +# $schema->get_table( +# $right->foreign_key_reference->reference_table +# ) +# ; +# +# next unless $right->is_foreign_key and +# $schema->get_table( +# $right->foreign_key_reference->reference_table +# )->get_field( +# ($right->foreign_key_reference->reference_fields)[0] +# )->is_primary_key +# ; +# +# +# $linkable{ +# $left->foreign_key_reference->reference_table +# }{ +# $right->foreign_key_reference->reference_table +# } = $table; +# +# $linkable{ +# $right->foreign_key_reference->reference_table +# }{ +# $left->foreign_key_reference->reference_table +# } = $table; +# +# $linktable{ $table->name } = $table; +# } +# } +# } +# } +# +# # +# # Generate many-to-many linking methods for data tables +# # +# my $is_data = 0; +# for ( $table->get_fields ) { +# $is_data++ if !$_->is_foreign_key and !$_->is_primary_key; +# } +# +# my %linked; +# if ( $is_data ) { +# foreach my $link ( keys %{ $linkable{ $table->name } } ) { +# my $linkmethodname = +# "_".$translator->format_fk_name($table->name,$link)."_refs" +# ; +# +# $create .= $translator->format_package_name($table->name). +# "->has_many('$linkmethodname','". +# $translator->format_package_name( +# $linkable{$table->name}{$link}->name +# )."','". +# ($schema->get_table($link)->primary_key->fields)[0]."');\n" +# ; +# +# $create .= "sub ". $translator->format_fk_name($table,$link). +# # HARDCODED 's' HERE. +# # ADD CALLBACK FOR PLURALIZATION MANGLING +# "s {\n my \$self = shift; return map \$_->".$link. +# ", \$self->".$linkmethodname.";\n}\n\n" +# ; +# } +# } + } - return $create; -} + my $base_pkg = sprintf( 'Class::DBI%s', $from ? "::$from" : '' ); + my $create = join("\n", + "package $main_pkg_name;\n", + $header, + "use strict;", + "use base '$base_pkg';\n", + "$main_pkg_name->set_db('Main', '$dsn', '$db_user', '$db_pass');\n\n", + ); + + for my $pkg_name ( + sort { $packages{ $a }{'order'} <=> $packages{ $b }{'order'} } + keys %packages + ) { + my $pkg = $packages{ $pkg_name }; + + $create .= join("\n", + $sep, + "package ".$pkg->{'pkg_name'}.";", + "use base '".$pkg->{'base'}."';", + "use Class::DBI::Pager;\n\n", + ); + if ( $from ) { + $create .= + $pkg->{'pkg_name'}."->set_up_table('".$pkg->{'table'}."');\n\n"; + } + else { + my $table = $schema->get_table( $pkg->{'table'} ); + my @field_names = map { $_->name } $table->get_fields; + + $create .= join("\n", + $pkg_name."->table('".$pkg->{'table'}."');\n", + $pkg_name."->columns(All => qw/". + join(' ', @field_names)."/);\n\n", + ); + } -sub _from { - my $from = shift; - my @temp = split(/::/, $from); - $from = $temp[$#temp]; + if ( my $pk = $pkg->{'pk_accessor'} ) { + $create .= $pk; + } - if ( $from eq 'MySQL') { - $from = lc($from); - } elsif ( $from eq 'PostgreSQL') { - $from = 'Pg'; - } elsif ( $from eq 'Oracle') { - $from = 'Oracle'; - } else { - die "__PACKAGE__ can't handle vendor $from"; + if ( my @has_a = @{ $pkg->{'has_a'} || [] } ) { + $create .= $_ for @has_a; + } + + if ( my @has_many = @{ $pkg->{'has_many'} || [] } ) { + $create .= $_ for @has_many; + } } - return $from; + $create .= "1;\n"; + + return $create; } 1; -__END__ +# ------------------------------------------------------------------- + +=pod =head1 NAME -SQL::Translator::Producer::ClassDBI - - Translate SQL schemata into Class::DBI classes +SQL::Translator::Producer::ClassDBI - create Class::DBI classes from schema =head1 SYNOPSIS