blob: e5bedb315101803ad130b9307e0283e7f204f973 [file] [log] [blame]
// Transforms an object-oriented model
// to a relational database schema
pre {
var db : new Target!Database;
}
// Transforms a class into a table and
// a primary key column
rule Class2Table
transform c : Source!Class
to t : Target!Table, pk : Target!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 Target!ForeignKey;
var childFkCol : new Target!Column;
var parentFkCol : Target!Column;
var parentTable : Target!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 : Source!Attribute
to c : Target!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 : Source!Attribute
to t : Target!Table, pkCol : Target!Column, valueCol : Target!Column,
fkCol : Target!Column, fk : Target!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 : Source!Reference
to fk : Target!ForeignKey, fkCol : Target!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 Target!Table primaryKeyName() : String {
return self.name.firstToLowerCase() + "Id";
}
operation Source!Attribute valuesTableName() : String {
return self.owner.name + "_" + self.name.firstToUpperCase() + "Values";
}
operation Any toDbType() : String {
switch (self) {
case "String": return "NVARCHAR";
case "Boolean": return "BIT";
case "Integer": return "INT";
case "Real": return "NUMBER";
default: return "NVARCHAR";
}
}