blob: 4446595e816c4ca1d2fc06115d53cfa123af7243 [file] [log] [blame]
import SimpleUML: 'SimpleUML.ecore'::simpleuml;
import SimpleRDBMS: 'SimpleRDBMS.ecore'::simplerdbms;
import UMLtoRDBMS: 'UMLtoRDBMS.ecore'::umltordbms;
transformation umlRdbms {
uml imports SimpleUML;
rdbms imports SimpleRDBMS;
imports UMLtoRDBMS;
}
/* -- Package and Schema mapping
class PackageToSchema {
composite classesToTables : Set(ClassToTable) opposites owner;
composite primitivesToNames : Set(PrimitiveToName) opposites owner;
name : String;
-- uml
umlPackage : Package;
-- rdbms
schema : Schema;
}
*/
map packageToSchema in umlRdbms {
uml () {
p:Package |
}
check enforce rdbms () {
s:Schema |
}
where () {
realize p2s:PackageToSchema |
p2s.umlPackage = p;
p2s.schema = s;
}
map {
where () {
p2s.name := p.name;
p2s.name := s.name;
p.name := p2s.name;
s.name := p2s.name;
}
}
}
/* -- Primitive data type marshaling
class PrimitiveToName {
owner : PackageToSchema opposites primitivesToNames;
name : String;
-- uml
_'primitive' : PrimitiveDataType;
-- rdbms
typeName : String;
}
*/
map primitiveToName in umlRdbms {
uml (p:Package |) {
prim:PrimitiveDataType |
prim.namespace = p;
}
check enforce rdbms () {
sqlType:String |
}
where (p2s:PackageToSchema | p2s.umlPackage = p;) {
realize p2n:PrimitiveToName |
p2n.owner := p2s;
p2n._'primitive' := prim;
p2n.typeName := sqlType;
}
map {
where () {
p2n.name := prim.name + '2' + sqlType;
}
}
}
map integerToNumber in umlRdbms refines primitiveToName {
uml () {
prim.name = 'Integer';
}
check enforce rdbms () {
sqlType := 'NUMBER';
}
}
map booleanToBoolean in umlRdbms refines primitiveToName {
uml () {
prim.name = 'Boolean';
}
check enforce rdbms () {
sqlType := 'BOOLEAN';
}
}
map stringToVarchar in umlRdbms refines primitiveToName {
uml () {
prim.name = 'String';
}
check enforce rdbms () {
sqlType := 'VARCHAR';
}
}
-- utility functions for flattening
map flattening in umlRdbms {
}
query umlRdbms::getAllSupers(cls : SimpleUML::Class) : Set(SimpleUML::Class) {
cls.general->collect(gen | getAllSupers(gen))->including(cls)->asSet()
}
query umlRdbms::getAllAttributes(cls : SimpleUML::Class) : Set( SimpleUML::Attribute) {
getAllSupers(cls).attributes->asSet()
}
query umlRdbms::getAllForwards(cls : SimpleUML::Class) : Set( SimpleUML::Association) {
getAllSupers(cls).forward->asSet()
}
/* -- Class and Table mapping
class ClassToTable extends FromAttributeOwner, ToColumn {
owner : PackageToSchema opposites classesToTables;
composite associationToForeignKeys :
OrderedSet(AssociationToForeignKey) opposites owner;
name : String;
-- uml
umlClass : Class;
-- rdbms
table : Table;
primaryKey : Key;
}
*/
map classToTable in umlRdbms {
check enforce uml (p:Package |) {
realize c:Class |
c.kind := 'persistent';
c.namespace := p;
}
check enforce rdbms (s:Schema |) {
realize t:Table |
t.kind <> 'meta';
default t.kind := 'base';
t.schema := s;
}
where (p2s:PackageToSchema |
p2s.umlPackage = p; p2s.schema = s;) {
realize c2t:ClassToTable |
c2t.owner := p2s;
c2t.umlClass := c;
c2t.table := t;
}
map {
where () {
c2t.name := c.name;
c2t.name := t.name;
c.name := c2t.name;
t.name := c2t.name;
}
}
map {
check enforce rdbms () {
realize pk:Key,
realize pc:Column |
pk.owner := t;
pk.kind := 'primary';
pc.owner := t;
pc.key->includes(pk);
default pc.key := OrderedSet(Key){pk};
default pc.type := 'NUMBER';
}
where () {
c2t.primaryKey := pk;
c2t.column := pc;
}
map {
check enforce rdbms () {
pc.name := t.name+'_tid';
pk.name := t.name+'_pk';
}
}
}
}
/* -- Association and ForeignKey mapping
class AssociationToForeignKey extends ToColumn {
referenced : ClassToTable;
owner : ClassToTable opposites associationToForeignKeys;
name : String;
-- uml
association : Association;
-- rdbms
foreignKey : ForeignKey;
}
*/
map associationToForeignKey in umlRdbms refines flattening {
check enforce uml (p:Package, sc:Class, dc:Class |
sc.namespace = p;) {
realize a:Association |
getAllForwards(sc)->includes(a);
default a.source := sc;
getAllSupers(dc)->includes(a.destination);
default a.destination := dc;
default a.namespace := p;
}
check enforce rdbms (s:Schema, st:Table, dt:Table, rk:Key |
st.schema = s;
rk.owner = dt;
rk.kind = 'primary';
) {
realize fk:ForeignKey,
realize fc:Column |
fk.owner := st;
fc.owner := st;
fk.refersTo := rk;
fc.foreignKeys->includes(fk);
default fc.foreignKeys := OrderedSet(ForeignKey){fk};
}
where (p2s:PackageToSchema, sc2t:ClassToTable, dc2t:ClassToTable |
sc2t.owner = p2s;
p2s.umlPackage = p;
p2s.schema = s;
sc2t.table = st;
dc2t.table = dt;
sc2t.umlClass = sc;
dc2t.umlClass = dc;
) {
realize a2f:AssociationToForeignKey |
a2f.owner := sc2t;
a2f.referenced := dc2t;
a2f.association := a;
a2f.foreignKey := fk;
a2f.column := fc;
}
map {
where () {
a2f.name := if a.destination=dc and a.source=sc
then a.name
else if a.destination<>dc and a.source=sc
then dc.name+'_'+a.name
else if a.destination=dc and a.source<>sc
then a.name+'_'+sc.name
else dc.name+'_'+a.name+'_'+sc.name
endif endif endif;
a.name := if a.destination=dc and a.source=sc
then a2f.name
else a.name
endif;
fk.name := a2f.name;
a2f.name := fk.name;
fc.name := a2f.name +'_tid';
}
}
map {
where () {
fc.type := rk.column->first().type;
}
}
}
/* -- attribute mapping
abstract class FromAttributeOwner {
composite fromAttributes : Set(FromAttribute) opposites owner;
}
abstract class FromAttribute {
name : String;
kind : String;
owner : FromAttributeOwner opposites fromAttributes;
leafs : Set(AttributeToColumn);
-- uml
_'attribute' : Attribute;
}
abstract class ToColumn {
-- rdbms
column : Column;
}
class NonLeafAttribute extends FromAttributeOwner, FromAttribute {
leafs := fromAttributes.leafs;
}
class AttributeToColumn extends FromAttribute, ToColumn {
type : PrimitiveToName;
}
*/
map attributes in umlRdbms refines flattening {
check enforce uml (c:Class |) {
realize a:Attribute |
default a.owner := c;
getAllAttributes(c)->includes(a);
}
where (fao:FromAttributeOwner |) {
realize fa : FromAttribute |
fa._'attribute' := a;
fa.owner := fao;
}
map {
where () {
fa.kind := a.kind;
a.kind := fa.kind;
}
}
}
map classAttributes in umlRdbms refines attributes {
where (fao:ClassToTable | fao.umlClass = c;) {}
map {
where () {
fa.name := a.name;
a.name := fa.name;
}
}
}
map primitiveAttribute in umlRdbms refines attributes {
check enforce uml (t:PrimitiveDataType |) {
a.type := t;
}
where (p2n:PrimitiveToName | p2n._'primitive' = t;) {
realize fa:AttributeToColumn |
fa.type := p2n;
}
map {
where () {
fa.leafs := Set(AttributeToColumn) {fa};
}
}
}
map complexAttributeAttributes in umlRdbms refines attributes {
check uml (ca:Attribute |
ca.type = c; ) {}
where (fao:NonLeafAttribute |
fao._'attribute' = ca; ) {}
map {
where () {
fa.name := fao.name + '_' + a.name;
}
}
}
map complexAttribute in umlRdbms refines attributes {
check uml (t:Class |) {
a.type = t;
}
where () {
realize fa:NonLeafAttribute |
}
map {
where () {
fa.leafs := fao.fromAttributes.leafs;
}
}
}
map classPrimitiveAttributes in umlRdbms refines classAttributes, primitiveAttribute {}
map classComplexAttributes in umlRdbms refines classAttributes, complexAttribute {}
map complexAttributePrimitiveAttributes in umlRdbms refines complexAttributeAttributes, primitiveAttribute {}
map complexAttributeComplexAttributes in umlRdbms refines complexAttributeAttributes, complexAttribute {}
-- column mapping
map attributeColumns in umlRdbms {
check enforce rdbms (t:Table |) {
realize c:Column |
c.owner := t;
c.key->size()=0;
c.foreignKeys->size()=0;
}
where (c2t:ClassToTable | c2t.table = t;) {
realize a2c:AttributeToColumn |
a2c.column := c;
c2t.fromAttributes.leafs->includes(a2c);
default a2c.owner := c2t; -- Check, not always a2c are owned by c2t, it maybe a nla!
}
map {
check enforce rdbms (ct:String |) {
c.type := ct;
}
where (p2n:PrimitiveToName |) {
a2c.type := p2n;
p2n.typeName := ct;
}
}
map {
where () {
c.name := a2c.name;
a2c.name := c.name;
}
}
map {
where () {
c.kind := a2c.kind;
a2c.kind := c.kind;
}
}
}