adding dg classes to represent schema. these are currently dependent on
Allen Day [Fri, 5 Sep 2003 11:21:26 +0000 (11:21 +0000)]
the schema::* classes, but i'd like them to break away at some point as
an alternate way to represent a schema.

lib/SQL/Translator/Schema/Graph.pm [new file with mode: 0644]
lib/SQL/Translator/Schema/Graph/CompoundEdge.pm [new file with mode: 0644]
lib/SQL/Translator/Schema/Graph/Edge.pm [new file with mode: 0644]
lib/SQL/Translator/Schema/Graph/HyperEdge.pm [new file with mode: 0644]
lib/SQL/Translator/Schema/Graph/Node.pm [new file with mode: 0644]
lib/SQL/Translator/Schema/Graph/Port.pm [new file with mode: 0644]

diff --git a/lib/SQL/Translator/Schema/Graph.pm b/lib/SQL/Translator/Schema/Graph.pm
new file mode 100644 (file)
index 0000000..64ae6d2
--- /dev/null
@@ -0,0 +1,139 @@
+package SQL::Translator::Schema::Graph;
+
+use strict;
+
+use Data::Dumper;
+
+use SQL::Translator::Schema::Graph::Node;
+use SQL::Translator::Schema::Graph::Edge;
+use SQL::Translator::Schema::Graph::Port;
+use SQL::Translator::Schema::Graph::CompoundEdge;
+use SQL::Translator::Schema::Graph::HyperEdge;
+
+use constant Node => 'SQL::Translator::Schema::Graph::Node';
+use constant Edge => 'SQL::Translator::Schema::Graph::Edge';
+use constant Port => 'SQL::Translator::Schema::Graph::Port';
+use constant CompoundEdge => 'SQL::Translator::Schema::Graph::CompoundEdge';
+use constant HyperEdge => 'SQL::Translator::Schema::Graph::HyperEdge';
+
+use Class::MakeMethods::Template::Hash (
+  'new --and_then_init' => 'new',
+  object => [
+                        'translator' => {class => 'SQL::Translator'},
+                       ],
+  'hash' => [ qw( node ) ],
+  'scalar' => [ qw( baseclass ) ],
+  'number --counter' => [ qw( order ) ],
+);
+
+sub init {
+  my $self = shift;
+  #
+  # build package objects
+  #
+  foreach my $table ($self->translator->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];
+
+       my $node = Node->new();
+
+       $self->node_push($table->name => $node);
+
+       $node->order($self->order_incr());
+       $node->name( $self->translator->format_package_name($table->name) );
+       $node->base( $self->baseclass );
+       $node->table( $table );
+       $node->primary_key( ($table->primary_key->fields)[0] );
+
+       # Primary key may have a differenct accessor method name
+       $node->primary_key_accessor(
+                                                               defined($self->translator->format_pk_name)
+                                                               ? $self->translator->format_pk_name->( $node->name, $node->primary_key )
+                                                               : undef
+                                                          );
+  }
+
+  foreach my $node ($self->node_values){
+       foreach my $field ($node->table->get_fields){
+         next unless $field->is_foreign_key;
+
+         my $that = $self->node($field->foreign_key_reference->reference_table);
+
+         #this means we have an incomplete schema
+         next unless $that;
+
+         my $edge = Edge->new(
+                                                  type => 'import',
+                                                  thisnode => $node,
+                                                  thisfield => $field,
+                                                  thatnode => $that,
+                                                  thatfield => ($field->foreign_key_reference->reference_fields)[0]
+                                                 );
+
+
+         $node->has($that->name, $node->has($that->name)+1);
+         $that->many($node->name, $that->many($node->name)+1);
+
+         $node->push_edges( $edge );
+         $that->push_edges( $edge->flip );
+       }
+  }
+
+  #
+  # type MM relationships
+  #
+  foreach my $lnode (sort $self->node_values){
+       next if $lnode->table->is_data;
+       foreach my $inode1 (sort $self->node_values){
+         next if $inode1 eq $lnode;
+
+         my @inode1_imports = grep { $_->type eq 'import' and $_->thatnode eq $inode1 } $lnode->edges;
+         next unless @inode1_imports;
+
+         foreach my $inode2 (sort $self->node_values){
+               my %i = map {$_->thatnode->name => 1} grep { $_->type eq 'import'} $lnode->edges;
+               if(scalar(keys %i) == 1) {
+               } else {
+                 last if $inode1 eq $inode2;
+               }
+
+               next if $inode2 eq $lnode;
+               my @inode2_imports =  grep { $_->type eq 'import' and $_->thatnode eq $inode2 } $lnode->edges;
+               next unless @inode2_imports;
+
+               my $cedge = CompoundEdge->new();
+               $cedge->via($lnode);
+
+               $cedge->push_edges( map {$_->flip} grep {$_->type eq 'import' and ($_->thatnode eq $inode1 or $_->thatnode eq $inode2)} $lnode->edges);
+
+               if(scalar(@inode1_imports) == 1 and scalar(@inode2_imports) == 1){
+                 $cedge->type('one2one');
+
+                 $inode1->via($inode2->name,$inode1->via($inode2->name)+1);
+                 $inode2->via($inode1->name,$inode2->via($inode1->name)+1);
+               }
+               elsif(scalar(@inode1_imports)  > 1 and scalar(@inode2_imports) == 1){
+                 $cedge->type('many2one');
+
+                 $inode1->via($inode2->name,$inode1->via($inode2->name)+1);
+                 $inode2->via($inode1->name,$inode2->via($inode1->name)+1);
+               }
+               elsif(scalar(@inode1_imports) == 1 and scalar(@inode2_imports)  > 1){
+                 #handled above
+               }
+               elsif(scalar(@inode1_imports)  > 1 and scalar(@inode2_imports)  > 1){
+                 $cedge->type('many2many');
+
+                 $inode1->via($inode2->name,$inode1->via($inode2->name)+1);
+                 $inode2->via($inode1->name,$inode2->via($inode1->name)+1);
+               }
+
+               $inode1->push_compoundedges($cedge);
+               $inode2->push_compoundedges($cedge) unless $inode1 eq $inode2;
+
+         }
+       }
+  }
+}
+
+1;
diff --git a/lib/SQL/Translator/Schema/Graph/CompoundEdge.pm b/lib/SQL/Translator/Schema/Graph/CompoundEdge.pm
new file mode 100644 (file)
index 0000000..ab115b2
--- /dev/null
@@ -0,0 +1,13 @@
+package SQL::Translator::Schema::Graph::CompoundEdge;
+
+use strict;
+use base qw(SQL::Translator::Schema::Graph::Edge);
+use Class::MakeMethods::Template::Hash (
+  new => ['new'],
+  object => [
+                        'via'  => {class => 'SQL::Translator::Schema::Graph::Node'},
+                       ],
+  'array_of_objects -class SQL::Translator::Schema::Graph::Edge' => [ qw( edges ) ],
+);
+
+1;
diff --git a/lib/SQL/Translator/Schema/Graph/Edge.pm b/lib/SQL/Translator/Schema/Graph/Edge.pm
new file mode 100644 (file)
index 0000000..6915e71
--- /dev/null
@@ -0,0 +1,28 @@
+package SQL::Translator::Schema::Graph::Edge;
+
+use strict;
+
+use Class::MakeMethods::Template::Hash (
+  new => ['new'],
+  scalar => [ qw( type ) ],
+  array => [ qw( traversals ) ],
+  object => [
+                        'thisfield'    => {class => 'SQL::Translator::Schema::Field'}, #FIXME
+                        'thatfield'    => {class => 'SQL::Translator::Schema::Field'}, #FIXME
+                        'thisnode'     => {class => 'SQL::Translator::Schema::Graph::Node'},
+                        'thatnode'     => {class => 'SQL::Translator::Schema::Graph::Node'},
+
+                       ],
+);
+
+sub flip {
+  my $self = shift;
+  return SQL::Translator::Schema::Graph::Edge->new( thisfield => $self->thatfield,
+                                                                                                       thatfield => $self->thisfield,
+                                                                                                       thisnode  => $self->thatnode,
+                                                                                                       thatnode  => $self->thisnode,
+                                                                                                       type => $self->type eq 'import' ? 'export' : 'import'
+                                                                                                 );
+}
+
+1;
diff --git a/lib/SQL/Translator/Schema/Graph/HyperEdge.pm b/lib/SQL/Translator/Schema/Graph/HyperEdge.pm
new file mode 100644 (file)
index 0000000..c5ebec1
--- /dev/null
@@ -0,0 +1,12 @@
+package SQL::Translator::Schema::Graph::HyperEdge;
+
+use strict;
+use base qw(SQL::Translator::Schema::Graph::Edge);
+
+use Class::MakeMethods::Template::Hash (
+  'array_of_objects -class SQL::Translator::Schema::Field' => [ qw( thisviafield thatviafield thisfield thatfield) ], #FIXME
+  'array_of_objects -class SQL::Translator::Schema::Graph::Node'                  => [ qw( thisnode thatnode ) ],
+  object => [ 'vianode' => {class => 'SQL::Translator::Schema::Graph::Node'} ],
+);
+
+1;
diff --git a/lib/SQL/Translator/Schema/Graph/Node.pm b/lib/SQL/Translator/Schema/Graph/Node.pm
new file mode 100644 (file)
index 0000000..156370a
--- /dev/null
@@ -0,0 +1,15 @@
+package SQL::Translator::Schema::Graph::Node;
+
+use strict;
+
+use Class::MakeMethods::Template::Hash (
+  new => [ 'new' ],
+  'array_of_objects -class SQL::Translator::Schema::Graph::Edge' => [ qw( edges ) ],
+  'array_of_objects -class SQL::Translator::Schema::Graph::CompoundEdge' => [ qw( compoundedges ) ],
+  'array_of_objects -class SQL::Translator::Schema::Graph::HyperEdge' => [ qw( hyperedges ) ],
+  'hash' => [ qw( many via has ) ],
+  scalar => [ qw( base name order primary_key primary_key_accessor table ) ],
+  number => [ qw( order ) ],
+);
+
+1;
diff --git a/lib/SQL/Translator/Schema/Graph/Port.pm b/lib/SQL/Translator/Schema/Graph/Port.pm
new file mode 100644 (file)
index 0000000..f0aeab4
--- /dev/null
@@ -0,0 +1,5 @@
+package SQL::Translator::Schema::Graph::Port;
+
+use strict;
+
+1;