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