Schema.kt 10.12 KiB
package unibz.cs.semint.kprime.domain.ddl
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement
import unibz.cs.semint.kprime.domain.ddl.schemalgo.check3NF
import unibz.cs.semint.kprime.domain.ddl.schemalgo.checkBCNF
import unibz.cs.semint.kprime.domain.ddl.schemalgo.decomposeTo3NF
import unibz.cs.semint.kprime.domain.ddl.schemalgo.decomposeToBCNF
@JacksonXmlRootElement(localName = "schema")
class Schema () {
@JacksonXmlProperty(isAttribute = true)
var name: String =""
@JacksonXmlProperty(isAttribute = true)
var id: String=""
var tables: ArrayList<Table>? = ArrayList<Table>()
var constraints: MutableList<Constraint>? = ArrayList<Constraint>()
fun table(name: String): Table? {
if (tables().isEmpty()) return null
return tables().filter { t -> t.name==name }.firstOrNull()
}
fun constraints(): MutableList<Constraint> {
if (constraints!=null) return constraints as MutableList<Constraint>
return ArrayList()
}
fun tables():ArrayList<Table> {
if (tables!=null) return tables as ArrayList<Table>
return ArrayList()
}
fun constraint(name: String): Constraint? {
if (constraints().isEmpty()) return null
return constraints().filter { c -> c.name==name}.firstOrNull()
}
fun keys(tableName: String): List<Constraint> {
val first = constraints().filter { c ->
c.type == Constraint.TYPE.PRIMARY_KEY.name &&
c.source.table == "${tableName}"
}.toList()
return first
}
fun key(tableName: String): Set<Column> {
var resultCols = mutableSetOf<Column>()
val keys = keys(tableName)
if (keys.isEmpty()) return mutableSetOf()
return keys[0].source.columns.toSet()
}
fun addKey(tableName:String, k:Set<Column>): Constraint {
val primaryConstraint = Constraint()
primaryConstraint.name="pkey_$tableName"
primaryConstraint.source.table="$tableName"
primaryConstraint.source.columns.addAll(k)
primaryConstraint.target.columns.addAll(k)
primaryConstraint.type= Constraint.TYPE.PRIMARY_KEY.name
constraints().add(primaryConstraint)
return primaryConstraint
}
fun keys(): List<Constraint> {
return constraints().filter { c -> c.type.equals(Constraint.TYPE.PRIMARY_KEY.name) }
}
fun foreignKeys(): List<Constraint> {
return constraints().filter { c -> c.type.equals(Constraint.TYPE.FOREIGN_KEY.name) }
}
fun foreignsTable(tableName: String): List<Constraint> {
return foreignKeys().filter { f -> f.source.name.equals(tableName) }
}
fun foreignsTargets(tableName: String): List<Constraint> {
return foreignKeys().filter { f -> f.target.name.equals(tableName) }
}
fun doubleIncs(): List<Constraint> {
return constraints().filter { c -> c.type.equals(Constraint.TYPE.DOUBLE_INCLUSION.name) }
}
fun functionalLHS(tableName: String): Set<Column> {
var resultCols = mutableSetOf<Column>()
val first = constraints().filter { c ->
c.type == Constraint.TYPE.FUNCTIONAL.name &&
c.name == "functional.${tableName}"
}.toList()
if (first.isEmpty()) return mutableSetOf()
return first[0].source.columns.toSet()
}
fun functionals(): Set<Constraint> {
var resultCols = mutableSetOf<Column>()
return constraints().filter { c ->
c.type == Constraint.TYPE.FUNCTIONAL.name }.toSet()
}
fun functionalsTable(tableName:String): List<Constraint> {
return functionals().filter { f -> f.source.table.equals(tableName) }
}
fun functionalRHS(tableName: String): Set<Column> {
var resultCols = mutableSetOf<Column>()
val first = constraints().filter { c ->
c.type == Constraint.TYPE.FUNCTIONAL.name &&
c.name == "functional.${tableName}"
}.toList()
if (first.isEmpty()) return mutableSetOf()
return first[0].target.columns.toSet()
}
internal fun addFunctional(tableName:String, lhs:Set<Column>, rhs:Set<Column>){
val functionalConstraint = Constraint()
functionalConstraint.name="functional.$tableName"
functionalConstraint.source.table="$tableName"
functionalConstraint.source.columns.addAll(lhs)
functionalConstraint.target.table="$tableName"
functionalConstraint.target.columns.addAll(rhs)
functionalConstraint.type= Constraint.TYPE.FUNCTIONAL.name
constraints().add(functionalConstraint)
}
fun addFunctional(commandArgs:String): Schema {
val tableName:String = commandArgs.split(":")[0]
val setExpression: String= commandArgs.split(":")[1]
return addFunctional(tableName,setExpression)
}
fun addTable(commandArgs:String) : Schema {
val table = SchemaCmdParser.parseTable(commandArgs)
tables().add(table)
return this
}
fun dropTable(commandArgs:String) : Schema {
var tableNames = commandArgs.split(" ")
for (tableName in tableNames) {
val t= table(tableName)
if (t!=null){ tables().remove(t)}
val toRemove = mutableListOf<Constraint>()
for (constr in constraints()) {
if (constr.source.table.equals(tableName))
toRemove.add(constr)
if (constr.target.table.equals(tableName))
toRemove.add(constr)
}
constraints().removeAll(toRemove)
}
return this
}
fun dropConstraint(commnadArgs:String) : Schema {
var constraintNames = commnadArgs.split(" ")
for (constraintName in constraintNames) {
var constraint = constraint(constraintName)
constraints().remove(constraint)
}
return this
}
fun addFunctional(tableName:String, setExpression: String): Schema {
val constraintsToAdd = Constraint.set(setExpression)
for (constraint in constraintsToAdd) {
constraint.name=tableName+".functional"
constraint.type=Constraint.TYPE.FUNCTIONAL.name
constraint.source.table=tableName
constraint.target.table=tableName
}
constraints().addAll(constraintsToAdd)
return this
}
fun addKey(commandArgs:String):Schema {
val tableName:String = commandArgs.split(":")[0]
val attributeNames = commandArgs.split(":")[1]
val constraint = Constraint.addKey {}
constraint.name = tableName+".primaryKey"
constraint.source.table=tableName
constraint.target.table=tableName
constraint.source.columns.addAll(Column.set(attributeNames))
constraint.target.columns.addAll(Column.set(attributeNames))
constraints().add(constraint)
return this
}
fun addForeignKey(commandArgs:String):Schema {
val source:String = commandArgs.split("-->")[0]
val target:String = commandArgs.split("-->")[1]
val sourceTableName:String = source.split(":")[0]
val sourceAttributeNames = source.split(":")[1]
val targetTableName:String = target.split(":")[0]
val targetAttributeNames = target.split(":")[1]
val constraint = Constraint.foreignkey {}
constraint.name = "${sourceTableName}_${targetTableName}.foreignKey"
constraint.source.table=sourceTableName
constraint.target.table=targetTableName
constraint.source.columns.addAll(Column.set(sourceAttributeNames))
constraint.target.columns.addAll(Column.set(targetAttributeNames))
constraints().add(constraint)
return this
}
fun addDoubleInc(commandArgs:String):Schema {
val source:String = commandArgs.split("-->")[0]
val target:String = commandArgs.split("-->")[1]
val sourceTableName:String = source.split(":")[0]
val sourceAttributeNames = source.split(":")[1]
val targetTableName:String = target.split(":")[0]
val targetAttributeNames = target.split(":")[1]
val constraint = Constraint.doubleInclusion {}
constraint.name = "${sourceTableName}_${targetTableName}.doubleInc"
constraint.source.table=sourceTableName
constraint.target.table=targetTableName
constraint.source.columns.addAll(Column.set(sourceAttributeNames))
constraint.target.columns.addAll(Column.set(targetAttributeNames))
constraints().add(constraint)
return this
}
fun decomposeBCNF(): Set<Relation> {
var allDecomposed = mutableSetOf<Relation>()
var tables = tables()
for ( table in tables) {
var fds = functionalsTable(table.name)
allDecomposed.addAll(decomposeToBCNF(table.columns.toSet(), fds.toSet()))
}
return allDecomposed
}
fun decompose3NF(): Set<Relation> {
var allDecomposed = mutableSetOf<Relation>()
var tables = tables()
for ( table in tables) {
var fds = functionalsTable(table.name)
allDecomposed.addAll(decomposeTo3NF(table.columns.toSet(), fds.toSet()))
}
return allDecomposed
}
fun violations3NF(): Set<Constraint> {
var allViolations = mutableSetOf<Constraint>()
var tables = tables()
for ( table in tables) {
var fds = functionalsTable(table.name)
allViolations.addAll(check3NF(table.columns.toSet(), fds.toSet()))
}
return allViolations
}
fun violationsBCNF(): Set<Constraint> {
var allViolations = mutableSetOf<Constraint>()
var tables = tables()
for ( table in tables) {
var fds = functionalsTable(table.name)
allViolations.addAll(checkBCNF(table.columns.toSet(), fds.toSet()))
}
return allViolations
}
/**
* TODO weak if has primarykey with-a column used as foreignkey.
fun isTableWeak(tableName:String):Boolean {
val key = key(tableName)
for (keycol in key) {
foreignKeys().forEach{fkey -> fkey.target.columns. }
}
return false
}
*/
}