- Added some stuff to MANIFEST.SKIP
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Parser / XML / XMI / Rational.pm
CommitLineData
b2a00f50 1package SQL::Translator::Parser::XML::XMI::Rational;
2
3# -------------------------------------------------------------------
821a0fde 4# $Id$
b2a00f50 5# -------------------------------------------------------------------
6# Copyright (C) 2003 Mark Addison <mark.addison@itn.co.uk>,
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public License as
10# published by the Free Software Foundation; version 2.
11#
12# This program is distributed in the hope that it will be useful, but
13# WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15# General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20# 02111-1307 USA
21# -------------------------------------------------------------------
22
23=head1 NAME
24
25SQL::Translator::Parser::XML::XMI::Rational - Create Schema using Rational's UML
26Data Modeling Profile.
27
28=cut
29
30use strict;
96f38d80 31
32use vars qw[ $DEBUG $VERSION @EXPORT_OK ];
821a0fde 33$VERSION = sprintf "%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/;
96f38d80 34$DEBUG = 0 unless defined $DEBUG;
35use Exporter;
36use base qw(Exporter);
37@EXPORT_OK = qw(parse);
38
b2a00f50 39use SQL::Translator::Parser::XML::XMI;
40use SQL::Translator::Utils 'debug';
41
42# Set the parg for the conversion sub then use the XMI parser
43sub parse {
44 my ( $translator ) = @_;
96f38d80 45 local $DEBUG = $translator->debug;
b2a00f50 46 my $pargs = $translator->parser_args;
47 $pargs->{classes2schema} = \&classes2schema;
48 return SQL::Translator::Parser::XML::XMI::parse(@_);
49}
50
a8ae1e5c 51sub _parameters_in {
52 my $params = shift;
53 return grep {$_->{kind} ne "return"} @$params;
54}
55
b2a00f50 56sub classes2schema {
57 my ($schema, $classes) = @_;
58
59 foreach my $class (@$classes) {
60 next unless $class->{stereotype} eq "Table";
61
62 # Add the table
63 debug "Adding class: $class->{name}";
64 my $table = $schema->add_table( name => $class->{name} )
65 or die "Schema Error: ".$schema->error;
66
67 #
68 # Fields from Class attributes
69 #
70 foreach my $attr ( @{$class->{attributes}} ) {
71 next unless $attr->{stereotype} eq "Column"
72 or $attr->{stereotype} eq "PK"
73 or $attr->{stereotype} eq "FK"
74 or $attr->{stereotype} eq "PFK";
75
76 my $ispk =
77 $attr->{stereotype} eq "PK" or $attr->{stereotype} eq "PFK"
78 ? 1 : 0;
79 my %data = (
80 name => $attr->{name},
81 data_type => $attr->{datatype},
82 is_primary_key => $ispk,
83 );
84 $data{default_value} = $attr->{initialValue}
85 if exists $attr->{initialValue};
86 $data{data_type} = $attr->{_map_taggedValues}{dataType}{dataValue}
87 || $attr->{datatype};
88 $data{size} = $attr->{_map_taggedValues}{size}{dataValue};
89 $data{is_nullable}=$attr->{_map_taggedValues}{nullable}{dataValue};
90
91 my $field = $table->add_field( %data ) or die $schema->error;
92 $table->primary_key( $field->name ) if $data{'is_primary_key'};
93 }
94
95 #
96 # Constraints and indexes from Operations
97 #
98 foreach my $op ( @{$class->{operations}} ) {
99 next unless my $stereo = $op->{stereotype};
100 my @fields = map {$_->{name}} grep {$_->{kind} ne "return"} @{$op->{parameters}};
101 my %data = (
102 name => $op->{name},
103 type => "",
104 fields => [@fields],
105 );
106
107 # Work out type and any other data
108 if ( $stereo eq "Unique" ) {
109 $data{type} = "UNIQUE";
110 }
111 elsif ( $stereo eq "PK" ) {
112 $data{type} = "PRIMARY_KEY";
113 }
56c4b15c 114 # Work out the ref table
a8ae1e5c 115 elsif ( $stereo eq "FK" ) {
116 $data{type} = "FOREIGN_KEY";
117 _add_fkey_refs($class,$op,\%data);
118 }
b2a00f50 119
120 # Add the constraint or index
121 if ( $data{type} ) {
122 $table->add_constraint( %data ) or die $schema->error;
123 }
124 elsif ( $stereo eq "Index" ) {
125 $data{type} = "NORMAL";
126 $table->add_index( %data ) or die $schema->error;
127 }
128
b2a00f50 129 } # Ops loop
130
131 } # Classes loop
132}
133
a8ae1e5c 134use Data::Dumper;
135sub _add_fkey_refs {
136 my ($class,$op,$data) = @_;
137
138 # Find the association ends
139 my ($end) = grep { $_->{name} eq $op->{name} } @{$class->{associationEnds}};
a8ae1e5c 140 return unless $end;
141 # Find the fkey op
142 my ($refop) = grep { $_->{name} eq $end->{otherEnd}{name} }
143 @{$end->{otherEnd}{participant}{operations}};
144 return unless $refop;
145
146 $data->{reference_table} = $end->{otherEnd}{participant}{name};
147 $data->{reference_fields} = [ map("$_->{name}", _parameters_in($refop->{parameters})) ];
148 return $data;
149}
150
b2a00f50 1511; #---------------------------------------------------------------------------
152
153__END__
154
155=pod
156
157=head1 SYNOPSIS
158
159 use SQL::Translator;
160 use SQL::Translator::Parser::XML::XMI;
161
162 my $translator = SQL::Translator->new(
163 from => 'XML-XMI-Rational',
164 to => 'MySQL',
165 filename => 'schema.xmi',
166 show_warnings => 1,
167 add_drop_table => 1,
168 );
169
170 print $obj->translate;
171
172=head1 DESCRIPTION
173
174Translates Schema described using Rational Software's UML Data Modeling Profile.
175Finding good information on this profile seems to be very difficult so this
176is based on a vague white paper and notes in vendors docs!
177
178Below is a summary of what this parser thinks the profile looks like.
179
180B<Tables> Are classes marked with <<Table>> stereotype.
181
182B<Fields> Attributes stereotyped with <<Column>> or one of the key stereotypes.
183Additional info is added using tagged values of C<dataType>, C<size> and
184C<nullable>. Default value is given using normal UML default value for the
185attribute.
186
187B<Keys> Key fields are marked with <<PK>>, <<FK>> or <<PFK>>. Note that this is
188really to make it obvious on the diagram, you must still add the constraints.
189(This parser will also automatically add the constraint for single field pkeys
190for attributes marked with PK but I think this is out of spec.)
191
192B<Constraints> Stereotyped operations, with the names of the parameters
193indicating which fields it applies to. Can use <<PK>>, <<FK>>, <<Unique>> or
194<<Index>>.
195
a8ae1e5c 196B<Relationships> You can model the relationships in the diagram and have the
197translator add the foreign key constraints for you. The forign keys are defined
198as <<FK>> operations as show above. To show which table they point to join the
199class to the taget classwith an association where the role names are the names
200of the constraints to join.
201
b2a00f50 202e.g.
203
204 +------------------------------------------------------+
205 | <<Table>> |
206 | Foo |
207 +------------------------------------------------------+
208 | <<PK>> fooID { dataType=INT size=10 nullable=0 } |
209 | <<Column>> name { dataType=VARCHAR size=255 } |
210 | <<Column>> description { dataType=TEXT } |
211 +------------------------------------------------------+
a8ae1e5c 212 | <<PK>> pkcon( fooID ) |
b2a00f50 213 | <<Unique>> con2( name ) |
214 +------------------------------------------------------+
a8ae1e5c 215 |
216 | pkcon
217 |
218 |
219 |
220 |
221 | fkcon
222 |
223 +------------------------------------------------------+
224 | <<Table>> |
225 | Bar |
226 +------------------------------------------------------+
227 | <<PK>> barID { dataType=INT size=10 nullable=0 } |
228 | <<FK>> fooID { dataType=INT size=10 nullable=0 } |
229 | <<Column>> name { dataType=VARCHAR size=255 } |
230 +------------------------------------------------------+
231 | <<PK>> pkcon( barID ) |
232 | <<FK>> fkcon( fooID ) |
233 +------------------------------------------------------+
b2a00f50 234
235 CREATE TABLE Foo (
236 fooID INT(10) NOT NULL,
237 name VARCHAR(255),
238 description TEXT,
239 PRIMARY KEY (fooID),
a8ae1e5c 240 UNIQUE con2 (name)
241 );
242
243 CREATE TABLE Bar (
244 barID INT(10) NOT NULL,
245 fooID INT(10) NOT NULL,
246 name VARCHAR(255),
247 PRIMARY KEY (fooID),
248 FOREIGN KEY fkcon (fooID) REFERENCES Foo (fooID)
b2a00f50 249 );
250
251=head1 ARGS
252
253=head1 BUGS
254
255=head1 TODO
256
a8ae1e5c 257The Rational profile also defines ways to model stuff above tables such as the
258actuall db.
b2a00f50 259
260=head1 AUTHOR
261
262Mark D. Addison E<lt>mark.addison@itn.co.ukE<gt>.
263
264=head1 SEE ALSO
265
266perl(1), SQL::Translator::Parser::XML::XMI
267
268=cut