blob: 20ac270befdd2ae748ee639f66d7905f5143283a [file] [log] [blame]
import UML: 'ManualUML.ecore'::uml;
import RDBMS: 'ManualRDBMS.ecore'::rdbms;
import UML2RDBMS: 'ManualUML2RDBMS.ecore'::uml2rdbms;
transformation ManualUML2RDBMS {
check uml imports UML;
enforce rdbms imports RDBMS;
middle imports UML2RDBMS;
}
map __root__ in ManualUML2RDBMS {
for p1 : UML::Package in UML::Package.allInstances() {
call packageToSchemaLM {
p iterates p1;
}
}
}
map packageToSchemaLM in ManualUML2RDBMS {
guard:uml p:Package;
new:middle p2s:PackageToSchema;
set p2s.umlPackage := p;
set p2s.name := p.name;
/* L to M */
-- A package has elements, elements can be Classifiers or Associations. A
-- classifier can be a Class or a PrimitiveDataType
-- PrimitiveDataType
for child in p.elements {
call integerToNumberLM {
p uses p;
check prim iterates child;
p2s uses p2s;
}
call booleanToBooleanLM {
p uses p;
check prim iterates child;
p2s uses p2s;
}
call stringToVarcharLM {
p uses p;
check prim iterates child;
p2s uses p2s;
}
}
for child in p.elements {
-- Class
call classToTableLM {
p uses p;
check c iterates child;
p2s uses p2s;
}
-- Associations
call associationToForeignKeyLM {
p uses p;
check a iterates child;
p2s uses p2s;
}
}
/* M to M */
/* M to R */
call packageToSchemaMR {
p2s uses p2s;
}
}
map packageToSchemaMR in ManualUML2RDBMS {
in:middle p2s:PackageToSchema;
new:rdbms s:Schema;
set p2s.schema := s;
call packageToSchemaMR_1 {
s_1 uses s;
p2s_1 uses p2s;
}
for child in p2s.primitivesToNames {
call integerToNumberMR {
p2s uses p2s;
p2n iterates child;
}
call booleanToBooleanMR {
p2s uses p2s;
p2n iterates child;
}
call stringToVarcharMR {
p2s uses p2s;
p2n iterates child;
}
}
for child in p2s.classesToTables {
call classToTableMR {
p2s uses p2s;
c2t iterates child;
s uses s;
}
}
}
map packageToSchemaMR_1 in ManualUML2RDBMS {
in:middle p2s_1:PackageToSchema;
in:rdbms s_1:Schema;
set s_1.name := p2s_1.name;
}
map integerToNumberLM in ManualUML2RDBMS {
in:uml p:Package;
guard:uml prim:PrimitiveDataType;
in:middle p2s:PackageToSchema;
check prim.namespace = p;
check prim.name = 'Integer';
check p2s.umlPackage=p;
new:middle p2n:PrimitiveToName;
set p2n.owner := p2s;
set p2n._'primitive' := prim;
set p2n.name := prim.name + '2' + 'NUMBER';
set p2n.typeName := 'NUMBER';
}
map integerToNumberMR in ManualUML2RDBMS {
in:middle p2s:PackageToSchema;
guard:middle p2n:PrimitiveToName;
check p2n.owner = p2s;
check p2n.name = 'Integer' + '2' + 'NUMBER';
}
map booleanToBooleanLM in ManualUML2RDBMS {
in:uml p:Package;
guard:uml prim:PrimitiveDataType;
in:middle p2s:PackageToSchema;
check prim.namespace = p;
check prim.name = 'Boolean';
check p2s.umlPackage=p;
new:middle p2n:PrimitiveToName;
set p2n.owner := p2s;
set p2n._'primitive' := prim;
set p2n.name := prim.name + '2' + 'BOOLEAN';
set p2n.typeName := 'BOOLEAN';
}
map booleanToBooleanMR in ManualUML2RDBMS {
in:middle p2s:PackageToSchema;
guard:middle p2n:PrimitiveToName;
check p2n.owner = p2s;
check p2n.name = 'Boolean' + '2' + 'BOOLEAN';
}
map stringToVarcharLM in ManualUML2RDBMS {
in:uml p:Package;
guard:uml prim:PrimitiveDataType;
in:middle p2s:PackageToSchema;
check prim.namespace = p;
check prim.name = 'String';
check p2s.umlPackage=p;
new:middle p2n:PrimitiveToName;
set p2n.owner := p2s;
set p2n._'primitive' := prim;
set p2n.name := prim.name + '2' + 'VARCHAR';
set p2n.typeName := 'VARCHAR';
}
map stringToVarcharMR in ManualUML2RDBMS {
in:middle p2s:PackageToSchema;
guard:middle p2n:PrimitiveToName;
check p2n.owner = p2s;
check p2n.name = 'String' + '2' + 'VARCHAR';
}
query ManualUML2RDBMS::getAllSupers(cls : UML::Class[1]) : Set(UML::Class) {
cls.general->collect(gen | getAllSupers(gen))->including(cls)->asSet()
}
query ManualUML2RDBMS::getAllAttributes(cls : UML::Class[1]) : Set(UML::Attribute) {
getAllSupers(cls).attributes->asSet() -- ->collect(c | c._'attribute')
}
query ManualUML2RDBMS::getAllForwards(cls : UML::Class[1]) : Set(UML::Association) {
getAllSupers(cls).forward->asSet()
}
map classToTableLM in ManualUML2RDBMS {
in:uml p:Package;
guard:uml c:Class;
in:middle p2s:PackageToSchema;
check c.kind = 'persistent';
check c.namespace = p;
check p2s.umlPackage=p;
new:middle c2t:ClassToTable;
set c2t.owner := p2s;
set c2t.umlClass := c;
set c2t.name := c.name;
-- A Class has attributes
for anAttribute in c.attributes {
call classPrimitiveAttributesLM {
c uses c;
a iterates anAttribute;
fao uses c2t;
}
call classComplexAttributesLM {
c uses c;
a iterates anAttribute;
fao uses c2t;
}
call complexAttributePrimitiveAttributesLM {
ca iterates anAttribute;
check c uses anAttribute.type;
}
call complexAttributeComplexAttributesLM {
ca iterates anAttribute;
check c uses anAttribute.type;
}
}
}
map classToTableMR in ManualUML2RDBMS {
in:middle p2s:PackageToSchema;
guard:middle c2t:ClassToTable;
in:rdbms s:Schema;
check c2t.owner = p2s;
new:rdbms t:Table;
set t.kind := 'base';
set t.schema := s;
call classToTableMR_1 {
c2t_1 uses c2t;
t_1 uses t;
}
call classToTableMR_2 {
t_2 uses t;
c2t_2 uses c2t;
}
for child in c2t.associationsToForeignKeys {
call associationToForeignKeyMR {
p2s uses p2s;
dt uses t;
-- sc2t iterates c2t;
-- dc2t <= c2t.associationsToForeignKeys.referenced;
sc2t uses t.ClassToTable;
dc2t uses t.ClassToTable;
a2f iterates child;
s uses s;
st uses t;
rk uses c2t.primaryKey;
}
}
-- A Class has attributes
for child in c2t.fromAttributes->union(c2t.fromAttributes->selectByKind(UML2RDBMS::NonLeafAttribute).fromAttributes) {
call attributeColumnsMR {
c2t uses c2t;
check a2c iterates child;
t uses t;
}
}
}
map classToTableMR_1 in ManualUML2RDBMS {
in:middle c2t_1:ClassToTable;
in:rdbms t_1:Table;
set c2t_1.table := t_1;
set t_1.name := c2t_1.name;
}
map classToTableMR_2 in ManualUML2RDBMS {
in:middle c2t_2:ClassToTable;
in:rdbms t_2:Table;
new:rdbms pk:Key;
new:rdbms pc:Column;
set pk.owner := t_2;
set pk.kind := 'primary';
set pc.owner := t_2;
set pc._'key' := OrderedSet(Key){pk};
set pc.type := 'NUMBER';
call classToTableMR_2_1 {
c2t_2_1 uses c2t_2;
pk_2_1 uses pk;
pc_2_1 uses pc; -- TODO Check this
}
call classToTableMR_2_2 {
pk_2_2 uses pk;
pc_2_2 uses pc;
t_2_2 uses t_2;
}
}
map classToTableMR_2_1 in ManualUML2RDBMS {
in:middle c2t_2_1:ClassToTable;
in:rdbms pk_2_1:Key;
in:rdbms pc_2_1:Column;
set c2t_2_1.primaryKey := pk_2_1;
set c2t_2_1.column := pc_2_1;
}
map classToTableMR_2_2 in ManualUML2RDBMS {
in:rdbms pk_2_2:Key;
in:rdbms pc_2_2:Column;
in:rdbms t_2_2:Table;
set pc_2_2.name := t_2_2.name+'_tid';
set pk_2_2.name := t_2_2.name+'_pk';
}
map associationToForeignKeyLM in ManualUML2RDBMS {
in:uml p:Package;
guard:uml a:Association;
in:middle p2s:PackageToSchema;
check var sc:Class := a.source;
check var dc:Class := a.destination;
check var sc2t:ClassToTable := sc.ClassToTable;
check var dc2t:ClassToTable := dc.ClassToTable;
check a.namespace = p;
check sc.namespace = p;
-- getAllForwards(sc)->includes(a);
-- getAllSupers(dc)->includes(a.destination);
check p2s.umlPackage = p;
new:middle a2f:AssociationToForeignKey;
set sc2t.owner := p2s;
set a2f.owner := sc2t;
set a2f.referenced := dc2t;
set a2f.association := a;
-- FIXME Bug 461994 working around Bug 459397; dc2 is gratuitous
set a2f.name := let dc2 = dc in if a.destination=dc and a.source=sc
then a.name
else if a.destination<>dc and a.source=sc
then dc2.name +'_'+a.name
else if a.destination=dc and a.source<>sc
then a.name+'_'+sc.name
else dc2.name+'_'+a.name+'_'+sc.name
endif endif endif;
}
map associationToForeignKeyMR in ManualUML2RDBMS {
in:middle p2s:PackageToSchema;
in:middle sc2t:ClassToTable;
in:middle dc2t:ClassToTable;
guard:middle a2f:AssociationToForeignKey;
in:rdbms s:Schema;
in:rdbms st:Table;
in:rdbms dt:Table;
in:rdbms rk:Key;
check a2f.owner = sc2t;
check a2f.referenced = dc2t;
check p2s.schema = s;
--sc2t.table = st;
--dc2t.table = dt;
-- sc2t := st.ClassToTable;
-- dc2t := dt.ClassToTable;
check st.schema = s;
-- rk.owner = dt;
-- rk.kind = 'primary';
new:rdbms fk:ForeignKey;
new:rdbms fc:Column;
set sc2t.owner := p2s;
set fk.name := a2f.name;
set fc.name := a2f.name +'_tid';
set fk.owner := st;
set fc.owner := st;
call associationToForeignKeyMR_1 {
fk uses fk;
fc uses fc;
dt uses a2f.referenced.table;
rk uses rk;
}
call associationToForeignKeyMR_2 {
a2f_1 uses a2f;
fk_1 uses fk;
fc_1 uses fc;
}
}
map associationToForeignKeyMR_1 in ManualUML2RDBMS {
in:rdbms fk:ForeignKey;
in:rdbms fc:Column;
in:rdbms dt:Table;
in:rdbms rk:Key;
set fk.refersTo := rk;
set fc.foreignKeys := OrderedSet(ForeignKey){fk};
set fc.type := rk.column->first().type;
}
map associationToForeignKeyMR_2 in ManualUML2RDBMS {
in:middle a2f_1:AssociationToForeignKey;
in:rdbms fk_1:ForeignKey;
in:rdbms fc_1:Column;
set a2f_1.foreignKey := fk_1;
set a2f_1.column := fc_1;
}
map classPrimitiveAttributesLM in ManualUML2RDBMS {
in:uml c:Class;
guard:uml a:Attribute;
in:middle fao:ClassToTable;
check var t:PrimitiveDataType := a.type;
check var p2n:PrimitiveToName := t.PrimitiveToName;
check a.owner = c;
--getAllAttributes(c)->includes(a);
check fao.umlClass = c;
new:middle atc:AttributeToColumn;
set atc._'attribute' := a;
set atc.owner := fao;
set atc.type := p2n;
set atc.kind := a.kind;
set atc.name := a.name;
set atc.leafs := Set(AttributeToColumn) {atc};
}
map classComplexAttributesLM in ManualUML2RDBMS {
in:uml c:Class;
guard:uml a:Attribute;
in:middle fao:ClassToTable;
check var t:Class := a.type;
check a.owner = c;
--getAllAttributes(c)->includes(a);
check fao.umlClass=c;
new:middle fa:NonLeafAttribute;
set fa._'attribute' := a;
set fa.owner := fao;
set fa.kind := a.kind;
set fa.name := a.name;
set fa.leafs := fao.fromAttributes.leafs->asSet();
}
map complexAttributePrimitiveAttributesLM in ManualUML2RDBMS {
in:uml c:Class;
guard:uml ca:Attribute;
check var fao:NonLeafAttribute := ca.FromAttribute;
check ca.type = c;
-- getAllAttributes(c)->includes(a);
for anAttribute in c.attributes {
call complexAttributePrimitiveAttributesLM_1 {
c_1 uses c;
ca_1 uses ca;
fao_1 uses fao;
a_1 iterates anAttribute;
}
}
}
map complexAttributePrimitiveAttributesLM_1 in ManualUML2RDBMS {
in:uml c_1:Class;
guard:uml a_1:Attribute;
in:uml ca_1:Attribute;
in:middle fao_1:NonLeafAttribute;
check var t_1:PrimitiveDataType := a_1.type;
check var p2n_1:PrimitiveToName := t_1.PrimitiveToName;
new:middle fa:AttributeToColumn;
set fa.owner := fao_1;
set fa.leafs := Set(AttributeToColumn) {fa};
set fa._'attribute' := a_1;
set fa.type := p2n_1;
set fa.kind := a_1.kind;
set fa.name := ca_1.name + '_' + a_1.name;
}
map complexAttributeComplexAttributesLM in ManualUML2RDBMS {
in:uml c:Class;
guard:uml ca:Attribute;
check var fao:NonLeafAttribute := ca.FromAttribute;
check ca.type = c;
--getAllAttributes(c)->includes(a);
for anAttribute in c.attributes {
call complexAttributeComplexAttributesLM_1 {
ca_1 uses ca;
a_1 iterates anAttribute;
c_1 uses c;
fao_1 uses fao;
}
}
}
map complexAttributeComplexAttributesLM_1 in ManualUML2RDBMS {
in:uml c_1:Class;
in:uml ca_1:Attribute;
guard:uml a_1:Attribute;
in:middle fao_1:NonLeafAttribute;
check var t_1:Class := a_1.type;
check a_1.owner = c_1;
--getAllAttributes(c)->includes(a);
new:middle fa:NonLeafAttribute;
set fa.owner := fao_1;
set fa.leafs := fao_1.fromAttributes.leafs->asSet();
set fa._'attribute' := a_1;
set fa.kind := a_1.kind;
set fa.name := ca_1.name + '_' + a_1.name;
-- set fa._'attribute' := t_1;
}
map attributeColumnsMR in ManualUML2RDBMS {
in:middle c2t:ClassToTable;
guard:middle a2c:AttributeToColumn;
in:rdbms t:Table;
check var p2n:PrimitiveToName := a2c.type;
check var ct:String := p2n.typeName;
-- c2t.fromAttributes.leafs->includes(a2c); -- need to go deeper in the recursion
-- a2c.owner = c2t; NOT ALL a2c are owned by c2t (complex attributes)
check c2t.table = t;
new:rdbms c:Column;
set c.owner := t;
call attributeColumnsMR_1 {
a2c_1 uses a2c;
c_1 uses c;
}
call attributeColumnsMR_2 {
a2c_2 uses a2c;
c_2 uses c;
p2n_2 uses p2n;
ct_2 uses ct;
}
call attributeColumnsMR_3 {
c_3 uses c;
a2c_3 uses a2c;
}
}
map attributeColumnsMR_1 in ManualUML2RDBMS {
in:middle a2c_1:AttributeToColumn;
in:rdbms c_1:Column;
set a2c_1.column := c_1;
}
map attributeColumnsMR_2 in ManualUML2RDBMS {
in:middle p2n_2:PrimitiveToName;
in:middle a2c_2:AttributeToColumn;
in:rdbms c_2:Column;
in:rdbms ct_2:String;
check a2c_2.type = p2n_2;
set c_2.type := ct_2;
call attributeColumnsMR_2_1 {
p2n_2_1 uses p2n_2;
ct_2_1 uses ct_2;
}
}
map attributeColumnsMR_2_1 in ManualUML2RDBMS {
in:middle p2n_2_1:PrimitiveToName;
in:rdbms ct_2_1:String;
set p2n_2_1.typeName := ct_2_1;
}
map attributeColumnsMR_3 in ManualUML2RDBMS {
in:middle a2c_3:AttributeToColumn;
in:rdbms c_3:Column;
set c_3.name := a2c_3.name;
set c_3.kind := a2c_3.kind;
}