| 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; |
| } |
| } |
| } |