package SQL::Translator::Parser::XML::XMI::SQLFairy;
# -------------------------------------------------------------------
-# $Id: SQLFairy.pm,v 1.2 2003-10-13 17:05:55 grommit Exp $
+# $Id: SQLFairy.pm,v 1.3 2003-10-14 23:19:43 grommit Exp $
# -------------------------------------------------------------------
# Copyright (C) 2003 Mark Addison <mark.addison@itn.co.uk>,
#
use strict;
use vars qw[ $DEBUG $VERSION @EXPORT_OK ];
-$VERSION = sprintf "%d.%02d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/;
+$VERSION = sprintf "%d.%02d", q$Revision: 1.3 $ =~ /(\d+)\.(\d+)/;
$DEBUG = 0 unless defined $DEBUG;
use Exporter;
use base qw(Exporter);
else
{
# m:n
- warn "Sorry, n:m associations not yet implimented for xmi.id=".$assoc->{"xmi.id"}."\n";
+ many2many($assoc);
+ #warn "Sorry, n:m associations not yet implimented for xmi.id=".$assoc->{"xmi.id"}."\n";
}
}
}
# Maps a 1:M association into the schema
-sub one2many {
+sub one2many
+{
my ($assoc) = @_;
my @ends = @{$assoc->{associationEnds}};
my ($end1) = grep $_->{multiplicity}{rangeUpper} == 1, @ends;
) or die $schema->error;
}
+# Maps m:n into schema by building a link table.
+sub many2many
+{
+ my ($assoc) = @_;
+ my @end = @{$assoc->{associationEnds}};
+
+ # Create the link table
+ my $name = $end[0]->{participant}{name}."_".$end[1]->{participant}{name};
+ my $link_table = $schema->add_table( name => $name )
+ or die "Schema Error: ".$schema->error;
+
+ # Export the pkey(s) from the ends into the link table
+ my @pkeys;
+ foreach (@end) {
+ my $table = $schema->get_table($_->{participant}{name});
+ my @fkeys = $table->primary_key->fields;
+ push @pkeys,@fkeys;
+ foreach ( @fkeys ) {
+ my $fld = $table->get_field($_);
+ my %data;
+ $data{$_} = $fld->$_()
+ foreach (
+ qw/name size data_type default_value is_nullable is_unique/);
+ $data{is_auto_increment} = 0;
+ $data{extra} = { $fld->extra }; # Copy
+ $link_table->add_field(%data) or die $table->error;
+ }
+ $link_table->add_constraint(
+ type => "FOREIGN_KEY",
+ fields => [@fkeys],
+ reference_table => $table->{name},
+ reference_fields => [@fkeys],
+ ) or die $schema->error;
+
+ }
+ # Add pkey constraint
+ $link_table->add_constraint( type => "PRIMARY KEY", fields => [@pkeys] )
+ or die $link_table->error;
+
+
+ # Add fkeys to our participants
+}
1; #---------------------------------------------------------------------------
__END__
# Testing 1,2,3,..
#=============================================================================
-plan tests => 94;
+plan tests => 151;
my $testschema = "$Bin/data/xmi/OrderDB.sqlfairy.poseidon2.xmi";
die "Can't find test schema $testschema" unless -e $testschema;
is( $scma->is_valid, 1, 'Schema is valid' );
my @tblnames = map {$_->name} $scma->get_tables;
is(scalar(@{$scma->get_tables}), scalar(@tblnames), "Right number of tables");
-is_deeply( \@tblnames, [qw/Order OrderLine Customer/]
- ,"tables");
+is_deeply( \@tblnames,
+ [qw/Order OrderLine Customer ContactDetails ContactDetails_Customer/]
+,"tables");
test_table( $scma->get_table("Customer"),
name => "Customer",
],
);
+test_table( $scma->get_table("ContactDetails_Customer"),
+ name => "ContactDetails_Customer",
+ fields => [
+ {
+ name => "ContactDetailsID",
+ data_type => "INT",
+ size => 10,
+ default_value => undef,
+ is_nullable => 0,
+ is_primary_key => 1,
+ is_auto_increment => 0,
+ },
+ {
+ name => "CustomerID",
+ data_type => "INT",
+ size => 10,
+ default_value => undef,
+ is_nullable => 0,
+ is_primary_key => 1,
+ is_auto_increment => 0,
+ },
+ ],
+ constraints => [
+ {
+ type => "FOREIGN KEY",
+ fields => "ContactDetailsID",
+ reference_table => "ContactDetails",
+ reference_fields => "ContactDetailsID",
+ },
+ {
+ type => "FOREIGN KEY",
+ fields => "CustomerID",
+ reference_table => "Customer",
+ reference_fields => "CustomerID",
+ },
+ {
+ type => "PRIMARY KEY",
+ fields => "ContactDetailsID,CustomerID",
+ },
+ ],
+);
+
+test_table( $scma->get_table("ContactDetails"),
+ name => "ContactDetails",
+ fields => [
+ {
+ name => "address",
+ data_type => "VARCHAR",
+ size => "255",
+ default_value => undef,
+ is_nullable => 1,
+ is_primary_key => 0,
+ },
+ {
+ name => "telephone",
+ data_type => "VARCHAR",
+ size => "255",
+ default_value => undef,
+ is_nullable => 1,
+ is_primary_key => 0,
+ },
+ {
+ name => "ContactDetailsID",
+ data_type => "INT",
+ size => 10,
+ default_value => undef,
+ is_nullable => 0,
+ is_primary_key => 1,
+ is_auto_increment => 1,
+ },
+ ],
+ constraints => [
+ {
+ type => "PRIMARY KEY",
+ fields => "ContactDetailsID",
+ },
+ ],
+);
+
test_table( $scma->get_table("Order"),
name => "Order",
fields => [
<?xml version = '1.0' encoding = 'UTF-8' ?>\r
-<XMI xmi.version = '1.2' xmlns:UML = 'org.omg.xmi.namespace.UML' timestamp = 'Mon Oct 13 17:05:12 BST 2003'>\r
+<XMI xmi.version = '1.2' xmlns:UML = 'org.omg.xmi.namespace.UML' timestamp = 'Wed Oct 15 00:05:38 BST 2003'>\r
<XMI.header>\r
<XMI.documentation>\r
<XMI.exporter>Netbeans XMI Writer</XMI.exporter>\r
<UML:MultiplicityRange xmi.id = '5539d8:f7b62bc3a2:-7feb' lower = '1' upper = '1'/>\r
</UML:Multiplicity.range>\r
</UML:Multiplicity>\r
+ <UML:Multiplicity xmi.id = '9f3e95:f83c9ca08d:-7ffb'>\r
+ <UML:Multiplicity.range>\r
+ <UML:MultiplicityRange xmi.id = '9f3e95:f83c9ca08d:-7ffa' lower = '1' upper = '1'/>\r
+ </UML:Multiplicity.range>\r
+ </UML:Multiplicity>\r
+ <UML:Multiplicity xmi.id = '9f3e95:f83c9ca08d:-7ff9'>\r
+ <UML:Multiplicity.range>\r
+ <UML:MultiplicityRange xmi.id = '9f3e95:f83c9ca08d:-7ff8' lower = '1' upper = '1'/>\r
+ </UML:Multiplicity.range>\r
+ </UML:Multiplicity>\r
+ <UML:Multiplicity xmi.id = '9f3e95:f83c9ca08d:-7ff7'>\r
+ <UML:Multiplicity.range>\r
+ <UML:MultiplicityRange xmi.id = '9f3e95:f83c9ca08d:-7ff6' lower = '0' upper = '-1'/>\r
+ </UML:Multiplicity.range>\r
+ </UML:Multiplicity>\r
<UML:Model xmi.id = '5539d8:f7b62bc3a2:-7ff5' name = 'OrderDB' isSpecification = 'false'\r
isRoot = 'false' isLeaf = 'false' isAbstract = 'false'>\r
<UML:Namespace.ownedElement>\r
<UML:Stereotype.baseClass>ModelElement</UML:Stereotype.baseClass>\r
</UML:Stereotype>\r
<UML:Comment xmi.id = '24d0fa:f8019a3e88:-7fa7' name = '' visibility = 'public'\r
- isSpecification = 'false' body = 'sqlfSize override on customerID Implied pkey - uses 1st field'>\r
+ isSpecification = 'false' body = 'sqlfSize override on customerID'>\r
<UML:Comment.annotatedElement>\r
<UML:Class xmi.idref = '5539d8:f7b62bc3a2:-7fe7'/>\r
</UML:Comment.annotatedElement>\r
</UML:TaggedValue>\r
</UML:ModelElement.taggedValue>\r
</UML:DataType>\r
+ <UML:Class xmi.id = '9f3e95:f83c9ca08d:-7ff5' name = 'ContactDetails' visibility = 'public'\r
+ isSpecification = 'false' isRoot = 'false' isLeaf = 'false' isAbstract = 'false'\r
+ isActive = 'false'>\r
+ <UML:Classifier.feature>\r
+ <UML:Attribute xmi.id = '9f3e95:f83c9ca08d:-7ff4' name = 'address' visibility = 'public'\r
+ isSpecification = 'false' ownerScope = 'instance'>\r
+ <UML:StructuralFeature.type>\r
+ <UML:DataType xmi.idref = '24d0fa:f8019a3e88:-7f93'/>\r
+ </UML:StructuralFeature.type>\r
+ </UML:Attribute>\r
+ <UML:Attribute xmi.id = '9f3e95:f83c9ca08d:-7ff3' name = 'telephone' visibility = 'public'\r
+ isSpecification = 'false' ownerScope = 'instance'>\r
+ <UML:StructuralFeature.type>\r
+ <UML:DataType xmi.idref = '24d0fa:f8019a3e88:-7f93'/>\r
+ </UML:StructuralFeature.type>\r
+ </UML:Attribute>\r
+ </UML:Classifier.feature>\r
+ </UML:Class>\r
+ <UML:Association xmi.id = '9f3e95:f83c9ca08d:-7ff2' isSpecification = 'false'\r
+ isRoot = 'false' isLeaf = 'false' isAbstract = 'false'>\r
+ <UML:Association.connection>\r
+ <UML:AssociationEnd xmi.id = '9f3e95:f83c9ca08d:-7ff1' visibility = 'public'\r
+ isSpecification = 'false' isNavigable = 'true' ordering = 'unordered' aggregation = 'none'\r
+ targetScope = 'instance' changeability = 'changeable'>\r
+ <UML:AssociationEnd.multiplicity>\r
+ <UML:Multiplicity xmi.id = '9f3e95:f83c9ca08d:-7ff0'>\r
+ <UML:Multiplicity.range>\r
+ <UML:MultiplicityRange xmi.id = '9f3e95:f83c9ca08d:-7fef' lower = '0' upper = '-1'/>\r
+ </UML:Multiplicity.range>\r
+ </UML:Multiplicity>\r
+ </UML:AssociationEnd.multiplicity>\r
+ <UML:AssociationEnd.participant>\r
+ <UML:Class xmi.idref = '9f3e95:f83c9ca08d:-7ff5'/>\r
+ </UML:AssociationEnd.participant>\r
+ </UML:AssociationEnd>\r
+ <UML:AssociationEnd xmi.id = '9f3e95:f83c9ca08d:-7fee' name = '' visibility = 'public'\r
+ isSpecification = 'false' isNavigable = 'true' ordering = 'unordered' aggregation = 'none'\r
+ targetScope = 'instance' changeability = 'changeable'>\r
+ <UML:AssociationEnd.multiplicity>\r
+ <UML:Multiplicity xmi.id = '9f3e95:f83c9ca08d:-7fed'>\r
+ <UML:Multiplicity.range>\r
+ <UML:MultiplicityRange xmi.id = '9f3e95:f83c9ca08d:-7fec' lower = '1' upper = '-1'/>\r
+ </UML:Multiplicity.range>\r
+ </UML:Multiplicity>\r
+ </UML:AssociationEnd.multiplicity>\r
+ <UML:AssociationEnd.participant>\r
+ <UML:Class xmi.idref = '5539d8:f7b62bc3a2:-7fe7'/>\r
+ </UML:AssociationEnd.participant>\r
+ </UML:AssociationEnd>\r
+ </UML:Association.connection>\r
+ </UML:Association>\r
</UML:Namespace.ownedElement>\r
</UML:Model>\r
<UML:TagDefinition xmi.id = '1f5eb7f:f7bb15dc4a:-7ffa' name = 'size' isSpecification = 'false'\r