package unibz.cs.semint.kprime.domain.ddl import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement @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 key(tableName: String): Set<Column> { var resultCols = mutableSetOf<Column>() val first = constraints().filter { c -> c.type == Constraint.TYPE.PRIMARY_KEY.name && c.name == "primaryKey.${tableName}" }.toList() if (first.isEmpty()) return mutableSetOf() return first[0].source.columns.toSet() } fun key(tableName:String,k:Set<Column>) { val primaryConstraint = Constraint() primaryConstraint.name="primaryKey.$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) } 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.table.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() } fun functional(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 = key {} 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 = 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 = 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(SchemaAlgo.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(SchemaAlgo.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(SchemaAlgo.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(SchemaAlgo.checkBCNF(table.columns.toSet(), fds.toSet())) } return allViolations } }