The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
################################################################
# AutoDIA - Automatic Dia XML.   (C)Copyright 2001 A Trevena   #
#                                                              #
# AutoDIA comes with ABSOLUTELY NO WARRANTY; see COPYING file  #
# This is free software, and you are welcome to redistribute   #
# it under certain conditions; see COPYING file for details    #
################################################################
package Autodia::Handler::DBI_SQLT;

require Exporter;

use strict;

use warnings;
use warnings::register;

use vars qw($VERSION @ISA @EXPORT);
use Autodia::Handler;

@ISA = qw(Autodia::Handler Exporter);

use Autodia::Diagram;
use Data::Dumper;
use DBI;

use SQL::Translator;
use SQL::Translator::Schema::Constants;


#---------------------------------------------------------------

#####################
# Constructor Methods

# new inherited from Autodia::Handler

#------------------------------------------------------------------------
# Access Methods

# parse_file inherited from Autodia::Handler

#-----------------------------------------------------------------------------
# Internal Methods

# _initialise inherited from Autodia::Handler

sub _parse_file { # parses dbi-connection string
  my $self     = shift();
  my $filename = shift();
  my %config   = %{$self->{Config}};
  $self->{Diagram}->directed(0);

  # new dbi connection
  my $dbh = DBI->connect("DBI:$filename", $config{username}, $config{password},
			 {
			     RaiseError       => 1,
			     FetchHashKeyName => 'NAME_lc',
			 }
			);

  warn "got dbh : $dbh\n";

  my $translator  =  SQL::Translator->new(
					  parser      => 'DBI',
					  dbh         => $dbh,
					  parser_args     => {
							      dsn         => "dbi:$filename",
							      db_user     => $config{username},
							      db_password => $config{password},
							     }

					 );


  my $parser      = $translator->parser;
  my $parser_type = $translator->parser_type;
  my $data;
  my $parser_output;
  eval { $parser_output = $parser->($translator, $$data) };
  if ($@ || ! $parser_output) {
      my $msg = sprintf "translate: Error with parser '%s': %s",
	$parser_type, ($@) ? $@ : " no results";
      die $translator->error($msg);
  }

  warn "parser : $parser, parser_type : $parser_type, parser_output : $parser_output\n";

  my $schema = $translator->schema;

  warn "got schema : $schema\n";

  # got to about here applying dbi datatypes patch
  foreach my $table ($schema->get_tables) {
      warn "got table : $table name\n";
      my $table_name = $table->name;
      # create new 'class' representing table
      my $Class = Autodia::Diagram::Class->new($table);
      # add 'class' to diagram
      $self->{Diagram}->add_class($Class);

      # get primary key fields.
      my %pkey_fields = map { $_ => 1 } $schema->pkey_fields;

      # get foreign key fields.
      my %fkey_fields = map { $_ => 1 } $schema->fkey_fields;

      for my $field ($table->get_fields) {
	  my $field_name = $field->name;
	  $Class->add_attribute({
				 name => $field_name,
				 visibility => 0,
				 type => $field->data_type,
				});

	  if ($fkey_fields{$field_name}) {
	      $Class->add_operation( { name=>'Key', type=>'Foreign', Params=>[ { Name => $field_name, Type => $field->data_type, }], visibility=>0, } );
	  }
	  if ($pkey_fields{$field_name}) {
	      $Class->add_operation( { name=>'Key', type=>'Primary', Params=>[ { Name => $field_name, Type => $field->data_type, }], visibility=>0, } );
	  }
      }
      
      for my $c ( $table->get_constraints ) {
	  next unless $c->type eq FOREIGN_KEY;
	  my $fk_table = $c->reference_table or next;
	  next unless defined $schema->get_table( $fk_table );
	  for my $fk_field ( $c->reference_fields ) {
	      $self->{foreign_tables}{$fk_table} = {
						    table => $table,
						    field => $fk_field,
						    class => $Class,
						   };
	  }
      }
  }

  # fix - need to handle multiple relations per table
  foreach my $fk_table (keys %{$self->{foreign_tables}} ) {
      foreach my $relation ( @{$self->{foreign_tables}{$fk_table}}) {
	  $self->_add_foreign_keytable($relation->{table},
				 $relation->{field},
				 $relation->{class},
				 $fk_table);
      }
  }

  $dbh->disconnect;
  return 1;
}


sub _add_foreign_keytable {
  my ($self,$table,$field,$Class,$dep) = @_;

  my $Superclass = Autodia::Diagram::Superclass->new($dep);
  my $exists_already = $self->{Diagram}->add_superclass($Superclass);
  $Superclass = $exists_already if (ref $exists_already);

  # create new relationship
  my $Relationship = Autodia::Diagram::Relation->new($Class, $Superclass);
  # add Relationship to superclass
  $Superclass->add_relation($Relationship);
  # add Relationship to class
  $Class->add_relation($Relationship);
  # add Relationship to diagram
  $self->{Diagram}->add_relation($Relationship);

  return;
}

sub _discard_line
{
  warn "not implemented\n";
  return 0;
}

1;

###############################################################################

=head1 NAME

Autodia::Handler::DBI.pm - AutoDia handler for DBI connections

=head1 INTRODUCTION

This module parses the contents of a database through a dbi connection and builds a diagram

%language_handlers = { .. , dbi => "Autodia::Handler::DBI", .. };

=head1 CONSTRUCTION METHOD

use Autodia::Handler::DBI;

my $handler = Autodia::Handler::DBI->New(\%Config);
This creates a new handler using the Configuration hash to provide rules selected at the command line.

=head1 ACCESS METHODS

$handler->Parse($connection); # where connection includes full or dbi connection string

$handler->output(); # any arguments are ignored.

=cut