pre { | |
"Running ETL".println(); | |
var db : new DB!Database; | |
} | |
post { | |
// Store traceability links in custom model | |
var trace : new Trace!Trace; | |
for (t in transTrace.transformations) { | |
var link : new Trace!TraceLink; | |
link.sources.add(t.source); | |
link.targets = t.targets; | |
link.description = "Transformed by " + t.getRule().name; | |
trace.links.add(link); | |
} | |
} | |
// Transforms a class into a table and | |
// a primary key column | |
rule Class2Table | |
transform c : OO!Class | |
to t : DB!Table, pk : DB!Column { | |
t.name = c.name; | |
t.database = db; | |
// Fill the details of the primary key | |
// of the table | |
pk.name = t.primaryKeyName(); | |
pk.type = "INT"; | |
t.columns.add(pk); | |
t.primaryKeys.add(pk); | |
// If the class extends some other class | |
// create a foreign key pointing towards | |
// the primary key of the parent class | |
if (c.`extends`.isDefined()){ | |
var fk : new DB!ForeignKey; | |
var childFkCol : new DB!Column; | |
var parentFkCol : DB!Column; | |
var parentTable : DB!Table; | |
parentTable ::= c.`extends`; | |
parentFkCol = parentTable.primaryKeys.first(); | |
childFkCol.name = parentFkCol.name; | |
childFkCol.type = "INT"; | |
childFkCol.table = t; | |
fk.database = db; | |
fk.parent = parentFkCol; | |
fk.child = childFkCol; | |
fk.name = c.name + "Extends" + c.`extends`.name; | |
} | |
} | |
// Transforms a single-valued attribute | |
// to a column | |
rule SingleValuedAttribute2Column | |
transform a : OO!Attribute | |
to c : DB!Column { | |
guard : not a.isMany | |
c.name = a.name; | |
c.table ::= a.owner; | |
c.type = a.type.name.toDbType(); | |
} | |
// Transforms a multi-valued attribute | |
// to a table where its values are stored | |
// and a foreign key | |
rule MultiValuedAttribute2Table | |
transform a : OO!Attribute | |
to t : DB!Table, pkCol : DB!Column, valueCol : DB!Column, | |
fkCol : DB!Column, fk : DB!ForeignKey { | |
guard : a.isMany | |
// The table that stores the values | |
// has an "id" column and a "value" column | |
t.name = a.valuesTableName(); | |
t.database = db; | |
pkCol.name = "id"; | |
pkCol.table = t; | |
pkCol.type = "INT"; | |
valueCol.name = "value"; | |
valueCol.table = t; | |
valueCol.type = a.type.name.toDbType(); | |
// Another column is added into the table | |
// to link with the "id" column of the | |
// values table | |
fkCol.name = a.name + "Id"; | |
fkCol.table ::= a.owner; | |
fkCol.type = "INT"; | |
// The foreign key that connects | |
// the two columns is defined | |
fk.parent = pkCol; | |
fk.child = fkCol; | |
fk.database = db; | |
} | |
// Transforms a referecne into a foreign key | |
rule Reference2ForeignKey | |
transform r : OO!Reference | |
to fk : DB!ForeignKey, fkCol : DB!Column { | |
fkCol.table ::= r.type; | |
fkCol.name = r.name + "Id"; | |
fkCol.type = "INT"; | |
fk.database = db; | |
fk.parent = r.owner.equivalent().primaryKeys.first(); | |
fk.child = fkCol; | |
fk.name = r.name; | |
} | |
operation DB!Table primaryKeyName() : String { | |
return self.name.firstToLowerCase() + "Id"; | |
} | |
operation OO!Attribute valuesTableName() : String { | |
return self.owner.name + "_" + self.name.firstToUpperCase() + "Values"; | |
} | |
operation Any toDbType() : String { | |
var mapping : OO2DB!TypeMapping; | |
mapping = OO2DB!TypeMapping.allInstances(). | |
select(tm|tm.source = self).first; | |
if (not mapping.isDefined()){ | |
("Cannot find DB type for OO type " + self + | |
". Setting the default.").println(); | |
return OO2DB!TypeMap.allInstances().first().`default`.target; | |
} | |
else { | |
return mapping.target; | |
} | |
} |