blob: 99b433eb0851725ae8ffed7788230bfec602ce20 [file] [log] [blame]
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;
}
}