- Added some stuff to MANIFEST.SKIP
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Producer / GraphViz.pm
index 74a52bd..5be1a64 100644 (file)
@@ -1,7 +1,7 @@
 package SQL::Translator::Producer::GraphViz;
 
 # -------------------------------------------------------------------
-# $Id: GraphViz.pm,v 1.14 2007-09-26 13:20:09 schiffbruechige Exp $
+# $Id$
 # -------------------------------------------------------------------
 # Copyright (C) 2002-4 SQLFairy Authors
 #
@@ -38,7 +38,7 @@ SQL::Translator::Producer::GraphViz - GraphViz producer for SQL::Translator
           add_color => 1,
           show_constraints => 1,
           show_datatypes => 1,
-          show_col_sizes => 1
+          show_sizes => 1
       }
   ) or die SQL::Translator->error;
 
@@ -93,22 +93,22 @@ height (in inches) of the output grahic
 custom font size for node and edge labels (note that arbitrarily large
 sizes may be ignored due to page size or graph size constraints)
 
-==item * fontname
+=item * fontname
 
 custom font name (or full path to font file) for node, edge, and graph
 labels
 
-==item * nodeattrs
+=item * nodeattrs
 
 reference to a hash of node attribute names and their values; these
 may override general fontname or fontsize parameter
 
-==item * edgeattrs
+=item * edgeattrs
 
 reference to a hash of edge attribute names and their values; these
 may override general fontname or fontsize parameter
 
-==item * graphattrs
+=item * graphattrs
 
 reference to a hash of graph attribute names and their values; these
 may override the general fontname parameter
@@ -129,7 +129,7 @@ if set to a true value, the datatype of each column will be
 displayed next to each column's name; this option will have no
 effect if the value of show_fields is set to false
 
-=item * show_col_sizes
+=item * show_sizes
 
 if set to a true value, the size (in bytes) of each CHAR and
 VARCHAR column will be displayed in parentheses next to the
@@ -171,6 +171,35 @@ like-named argument in the make_natural_join method (see
 natural_join above) of SQL::Translator::Schema, if either
 the natural_join or join_pk_only options has a true value
 
+=item * show_indexes
+
+if set to a true value, each record will also show the indexes
+set on each table. it describes the index types along with
+which columns are included in the index. this option requires
+that show_fields is a true value as well
+
+=item * show_index_name
+
+if show_indexes is set to a true value, then the value of this
+parameter determines whether or not to print names of indexes.
+if show_index_name is false, then a list of indexed columns
+will appear below the field list. otherwise, it will be a list
+prefixed with the name of each index. it defaults to true.
+
+=item * friendly_ints
+
+if set to a true value, each integer type field will be displayed
+as a smallint, integer or bigint depending on the field's
+associated size parameter. this only applies for the 'integer'
+type (and not the lowercase 'int' type, which is assumed to be a
+32-bit integer).
+
+=item * friendly_ints_extended
+
+if set to a true value, the friendly ints displayed will take into
+account the non-standard types, 'tinyint' and 'mediumint' (which,
+as far as I am aware, is only implemented in MySQL)
+
 =back
 
 =cut
@@ -182,7 +211,7 @@ use SQL::Translator::Schema::Constants;
 use SQL::Translator::Utils qw(debug);
 
 use vars qw[ $VERSION $DEBUG ];
-$VERSION = sprintf "%d.%02d", q$Revision: 1.14 $ =~ /(\d+)\.(\d+)/;
+$VERSION = sprintf "%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/;
 $DEBUG   = 0 unless defined $DEBUG;
 
 use constant VALID_LAYOUT => {
@@ -258,10 +287,14 @@ sub produce {
     my $show_fk_only     = $args->{'show_fk_only'};
     my $show_datatypes   = $args->{'show_datatypes'};
     my $show_sizes       = $args->{'show_sizes'};
+    my $show_indexes     = $args->{'show_indexes'};
+    my $show_index_name  = $args->{'show_index_name'} || 1;
+    my $friendly_ints    = $args->{'friendly_ints'};
+    my $friendly_ints_ex = $args->{'friendly_ints_extended'};
     my $show_constraints = $args->{'show_constraints'};
     my $join_pk_only     = $args->{'join_pk_only'};
-    my $skip_fields      = $args->{'skip_fields'};
-    my %skip             = map { s/^\s+|\s+$//g; $_, 1 }
+    my $skip_fields      = $args->{'skip_fields'} || '';
+    my %skip             = map { s/^\s+|\s+$//g; length $_ ? ($_, 1) : () }
                            split ( /,/, $skip_fields );
     $natural_join      ||= $join_pk_only;
 
@@ -339,29 +372,94 @@ sub produce {
             @fields = grep { $_->is_foreign_key } @fields;
         }
 
-        my $field_str = join(
-            '\l',
-            map {
-                '-\ '
-                . $_->name
-                . ( $show_datatypes ? '\ ' . $_->data_type : '')
-                . ( $show_sizes && ! $show_datatypes ? '\ ' : '')
-                . ( $show_sizes && $_->data_type =~ /^(VAR)?CHAR2?$/i ? '(' . $_->size . ')' : '')
-                . ( $show_constraints ?
-                    ( $_->is_primary_key || $_->is_foreign_key || $_->is_unique ? '\ [' : '' )
-                    . ( $_->is_primary_key ? 'PK' : '' )
-                    . ( $_->is_primary_key && ($_->is_foreign_key || $_->is_unique) ? ',' : '' )
-                    . ( $_->is_foreign_key ? 'FK' : '' )
-                    . ( $_->is_unique && ($_->is_primary_key || $_->is_foreign_key) ? ',' : '' )
-                    . ( $_->is_unique ? 'U' : '' )
-                    . ( $_->is_primary_key || $_->is_foreign_key || $_->is_unique ? ']' : '' )
-                : '' )
-                . '\ '
-            } @fields
-        ) . '\l';
-        my $label = $show_fields ? "{$table_name|$field_str}" : $table_name;
+        my $label = '{' . $table_name;
+        if ($show_fields) {
+          my $field_str = '';
+          foreach my $field (@fields) {
+            $field_str .= '-\ ' . $field->name;
+            if ($show_datatypes) {
+              my $dt = lc($field->data_type);
+
+              # For the integer type, transform into different types based on
+              # requested size, if a size is given.
+              if ($friendly_ints && $dt eq 'integer' && $field->size) {
+                # Automatically translate to int2, int4, int8
+                # Type (Bits)     Max. Signed/Unsigned    Length
+                # tinyint* (8)    128                     3
+                #                 255                     3
+                # smallint (16)   32767                   5
+                #                 65535                   5
+                # mediumint* (24) 8388607                 7
+                #                 16777215                8
+                # int (32)        2147483647              10
+                #                 4294967295              10
+                # bigint (64)     9223372036854775807     19
+                #                 18446744073709551615    20
+                #
+                # * tinyint and mediumint are nonstandard extensions which are
+                #   only available under MySQL (to my knowledge)
+                my $size = $field->size;
+                if ($size > 10) {
+                  $dt = 'bigint';
+                }
+                elsif ($size > 5) {
+                  $dt = 'integer';
+                  if ($friendly_ints_ex && $size <= 8) {
+                    $dt = 'mediumint';
+                  }
+                }
+                else {
+                  $dt = 'smallint';
+                  if ($friendly_ints_ex && $size <= 3) {
+                    $dt = 'tinyint';
+                  }
+                }
+              }
+
+              $field_str .= '\ ' . $dt;
+              if ($show_sizes && $field->size && ($dt =~ /^(var)?char2?$/ || $dt eq 'numeric' || $dt eq 'decimal')) {
+                $field_str .= '(' . $field->size . ')';
+              }
+            }
+
+            if ($show_constraints) {
+              my @constraints;
+              push(@constraints, 'PK') if $field->is_primary_key;
+              push(@constraints, 'FK') if $field->is_foreign_key;
+              push(@constraints, 'U')  if $field->is_unique;
+              if (scalar(@constraints)) {
+                $field_str .= '\ [' . join(',\ ', @constraints) . ']';
+              }
+            }
+            $field_str .= '\l';
+          }
+          $label .= '|' . $field_str;
+        }
+
+        if ($show_indexes) {
+          my $index_str = '';
+          foreach my $index ($table->get_indices) {
+            next unless $index->is_valid;
+
+            $index_str .= '*\ ';
+            if ($show_index_name) {
+              $index_str .= $index->name . ': ';
+            }
+            $index_str .= join(', ', $index->fields);
+            if ($index->type eq 'UNIQUE') {
+              $index_str .= '\ [U]';
+            }
+            $index_str .= '\l';
+          }
+          # Only add the last box if index_str is non-null
+          if (length $index_str) {
+            $label .= '|' . $index_str;
+          }
+        }
+        $label .= '}';
 #        $gv->add_node( $table_name, label => $label );
-        $gv->add_node( $table_name, label => $label, ($node_shape eq 'record' ? ( shape => $node_shape ) : ()) );
+#        $gv->add_node( $table_name, label => $label, ($node_shape eq 'record' ? ( shape => $node_shape ) : ()) );
+        $gv->add_node( $table_name, label => $label, shape => $node_shape );
         debug("Processing table '$table_name'");
 
         debug("Fields = ", join(', ', map { $_->name } @fields));
@@ -422,8 +520,8 @@ sub produce {
         for my $i ( 0 .. $#tables ) {
             my $table1 = $tables[ $i ];
             for my $j ( 0 .. $#tables ) {
+                next if $i == $j;
                 my $table2 = $tables[ $j ];
-                next if $table1 eq $table2;
                 next if $done{ $table1 }{ $table2 };
                 $gv->add_edge( $table2, $table1 );
                 $done{ $table1 }{ $table2 } = 1;
@@ -457,6 +555,10 @@ sub produce {
 
 Ken Y. Clark E<lt>kclark@cpan.orgE<gt>
 
+=head2 CONTRIBUTORS
+
+Jonathan Yu E<lt>frequency@cpan.orgE<gt>
+
 =head1 SEE ALSO
 
 SQL::Translator, GraphViz