diff --git a/src/main/kotlin/unibz.cs.semint.kprime/adapter/service/XMLSerializerJacksonAdapter.kt b/src/main/kotlin/unibz.cs.semint.kprime/adapter/service/XMLSerializerJacksonAdapter.kt index 0d83aad5798e7675def85abecdcab06740816fee..53030129f42ba24bdce88234f9cab65c1e117229 100644 --- a/src/main/kotlin/unibz.cs.semint.kprime/adapter/service/XMLSerializerJacksonAdapter.kt +++ b/src/main/kotlin/unibz.cs.semint.kprime/adapter/service/XMLSerializerJacksonAdapter.kt @@ -1,5 +1,6 @@ package unibz.cs.semint.kprime.adapter.service +import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.dataformat.xml.XmlMapper import com.fasterxml.jackson.module.kotlin.KotlinModule import unibz.cs.semint.kprime.domain.* @@ -56,4 +57,24 @@ class XMLSerializerJacksonAdapter : IXMLSerializerService { val mapper = XmlMapper() return mapper.readValue(s,Constraint::class.java) } + + // changeset + + override fun serializeChangeSet(changeset: ChangeSet): String { + val mapper = XmlMapper().registerModule(KotlinModule()) + return mapper.writeValueAsString(changeset) + } + + override fun deserializeChangeSet(changeset: String): ChangeSet { + val mapper = XmlMapper() + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + return mapper.readValue(changeset,ChangeSet::class.java) + } + + override fun prettyChangeSet(table: ChangeSet): String { + val mapper = XmlMapper().registerModule(KotlinModule()) + val writer = mapper.writerWithDefaultPrettyPrinter() + return writer.writeValueAsString(table) + } + } \ No newline at end of file diff --git a/src/main/kotlin/unibz.cs.semint.kprime/domain/ChangeSet.kt b/src/main/kotlin/unibz.cs.semint.kprime/domain/ChangeSet.kt new file mode 100644 index 0000000000000000000000000000000000000000..efb86f52b3d630b3529bbc1b3a8b5ef37e3938c3 --- /dev/null +++ b/src/main/kotlin/unibz.cs.semint.kprime/domain/ChangeSet.kt @@ -0,0 +1,14 @@ +package unibz.cs.semint.kprime.domain + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty + +class ChangeSet() { + + @JacksonXmlProperty(isAttribute = true) + var id: String = "" + + @JacksonXmlElementWrapper(useWrapping=false) + var createView= ArrayList<CreateView>() + +} \ No newline at end of file diff --git a/src/main/kotlin/unibz.cs.semint.kprime/domain/CreateView.kt b/src/main/kotlin/unibz.cs.semint.kprime/domain/CreateView.kt new file mode 100644 index 0000000000000000000000000000000000000000..16a0f0cf55f69689403ff16708e0c3f31246d543 --- /dev/null +++ b/src/main/kotlin/unibz.cs.semint.kprime/domain/CreateView.kt @@ -0,0 +1,16 @@ +package unibz.cs.semint.kprime.domain + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText + +class CreateView() { + + @JacksonXmlProperty(isAttribute = true) + var path: String = "" + @JacksonXmlProperty(isAttribute = true) + var schemaName: String = "" + @JacksonXmlProperty(isAttribute = true) + var viewName: String = "" + @JacksonXmlText + var value:String = "" +} \ No newline at end of file diff --git a/src/main/kotlin/unibz.cs.semint.kprime/scenario/PersonHSplitScenario.kt b/src/main/kotlin/unibz.cs.semint.kprime/scenario/PersonHSplitScenario.kt new file mode 100644 index 0000000000000000000000000000000000000000..0592068f133641b5031da3ba947ee5e6a6ab33f7 --- /dev/null +++ b/src/main/kotlin/unibz.cs.semint.kprime/scenario/PersonHSplitScenario.kt @@ -0,0 +1,141 @@ +package unibz.cs.semint.kprime.scenario + +import unibz.cs.semint.kprime.adapter.service.XMLSerializerJacksonAdapter +import unibz.cs.semint.kprime.domain.* +import unibz.cs.semint.kprime.usecase.SQLizeUseCase +import unibz.cs.semint.kprime.usecase.XMLSerializeUseCase + +class PersonHSplitScenario { + + fun run() { + val personMetadata = buildPersonMetadata() + hsplitPersonMetadata(personMetadata) + + } + + private fun buildPersonMetadata(): Database { + val db = Database() + val personTable = Table() + personTable.name= "person" + val colSSN = Column("SSN", "id.SSN", "dbname.SSN") + personTable.columns.add(colSSN) + colSSN.nullable=false + val colT = Column("T", "id.T", "dbname.T") + personTable.columns.add(colT) + colT.nullable=false + val colS = Column("S", "id.S", "dbname.S") + colS.nullable=true + personTable.columns.add(colS) + db.schema.tables.add(personTable) + val primaryConstraint = Constraint() + primaryConstraint.name="primaryKey.person" + primaryConstraint.source.table="person" + primaryConstraint.source.columns.add(colSSN) + primaryConstraint.source.columns.add(colT) + primaryConstraint.type=Constraint.TYPE.PRIMARY_KEY.name + db.schema.constraints.add(primaryConstraint) + return db + } + + private fun hsplitPersonMetadata(personMetadata: Database) { + printDb(personMetadata) + val detected = detect(personMetadata) + if (detected.ok!=null) { + val applied = apply(personMetadata, detected) + if (applied.ok!=null) { + printDb(applied.ok) + printSql(SQLizeUseCase().sqlize(applied.ok)) + } + + } + } + + private fun printSql(sqlines: List<String>) { + println() + println("--------------------------------------------------------------------------") + for (sql in sqlines) println(sql) + } + + private fun printDb(db:Database) { + println() + println("--------------------------------------------------------------------------") + println(XMLSerializeUseCase(XMLSerializerJacksonAdapter()).prettyDatabase(db)) + } + + private fun detect(personMetadata: Database): UseCaseResult<Database> { + val dbDetected = Database() + // Check if it has nullable column. + for (table in personMetadata.schema.tables) { + if (table.hasNullable()) { + // then this table has to be partitioned to remove nullable. + // adds this table to db to apply vertical partitioning. + dbDetected.schema.tables.add(table) + } + } + return UseCaseResult("done detect",dbDetected) + } + + private fun apply(personMetadata: Database, detected: UseCaseResult<Database>): UseCaseResult<Database>{ + // pure person + val table = Table() + table.name= "pure_person" + table.view="person" + table.condition="person.T=null AND person.S=null" + personMetadata.schema.tables.add(table) + val colSSN = Column("SSN", "id.SSN", "dbname.SSN") + colSSN.nullable=false + table.columns.add(colSSN) + + // person with only telephone + val tableWithT = Table() + tableWithT.view="person" + tableWithT.name= "person_with_T" + tableWithT.condition="person.T NOT null AND person.S=null" + personMetadata.schema.tables.add(tableWithT) + val colT = Column("T", "id.T", "dbname.T") + colT.nullable=false + tableWithT.columns.add(colSSN) + tableWithT.columns.add(colT) + + // person with only TS + val tableWithS = Table() + tableWithS.view="person" + tableWithS.name= "person_with_TS" + tableWithS.condition="person.T = null AND person.S NOT null" + personMetadata.schema.tables.add(tableWithS) + val colS = Column("S", "id.S", "dbname.S") + colS.nullable=false + tableWithS.columns.add(colSSN) + tableWithS.columns.add(colS) + + + // person with only S + val tableWithTS = Table() + tableWithTS.view="person" + tableWithTS.name= "person_with_S" + tableWithTS.condition="person.T NOT null AND person.S NOT null" + personMetadata.schema.tables.add(tableWithTS) + tableWithTS.columns.add(colSSN) + tableWithTS.columns.add(colT) + tableWithTS.columns.add(colS) + + // removes table person + val personTable = personMetadata.schema.table("person") + personMetadata.schema.tables.remove(personTable) + + // removes constraints from/to person + var contraintsToRemove = mutableSetOf<Constraint>() + for (contraint in personMetadata.schema.constraints) { + if (contraint.source.table=="person") { + contraintsToRemove.add(contraint) + } + if (contraint.target.table=="person") { + contraintsToRemove.add(contraint) + } + } + personMetadata.schema.constraints.removeAll(contraintsToRemove) + + // add constraint partition + return UseCaseResult("done apply", personMetadata) + } +} \ No newline at end of file diff --git a/src/main/kotlin/unibz.cs.semint.kprime/scenario/PersonVSplitScenario.kt b/src/main/kotlin/unibz.cs.semint.kprime/scenario/PersonVSplitScenario.kt index 3cb0b9e7e81d93a6b5aaeff947965c87bb3fa0da..217d9bd121c0c7b09019959a6202262238d3d606 100644 --- a/src/main/kotlin/unibz.cs.semint.kprime/scenario/PersonVSplitScenario.kt +++ b/src/main/kotlin/unibz.cs.semint.kprime/scenario/PersonVSplitScenario.kt @@ -1,141 +1,4 @@ package unibz.cs.semint.kprime.scenario -import unibz.cs.semint.kprime.adapter.service.XMLSerializerJacksonAdapter -import unibz.cs.semint.kprime.domain.* -import unibz.cs.semint.kprime.usecase.SQLizeUseCase -import unibz.cs.semint.kprime.usecase.XMLSerializeUseCase - class PersonVSplitScenario { - - fun run() { - val personMetadata = buildPersonMetadata() - vsplitPersonMetadata(personMetadata) - - } - - private fun buildPersonMetadata(): Database { - val db = Database() - val personTable = Table() - personTable.name= "person" - val colSSN = Column("SSN", "id.SSN", "dbname.SSN") - personTable.columns.add(colSSN) - colSSN.nullable=false - val colT = Column("T", "id.T", "dbname.T") - personTable.columns.add(colT) - colT.nullable=false - val colS = Column("S", "id.S", "dbname.S") - colS.nullable=true - personTable.columns.add(colS) - db.schema.tables.add(personTable) - val primaryConstraint = Constraint() - primaryConstraint.name="primaryKey.person" - primaryConstraint.source.table="person" - primaryConstraint.source.columns.add(colSSN) - primaryConstraint.source.columns.add(colT) - primaryConstraint.type=Constraint.TYPE.PRIMARY_KEY.name - db.schema.constraints.add(primaryConstraint) - return db - } - - private fun vsplitPersonMetadata(personMetadata: Database) { - printDb(personMetadata) - val detected = detect(personMetadata) - if (detected.ok!=null) { - val applied = apply(personMetadata, detected) - if (applied.ok!=null) { - printDb(applied.ok) - printSql(SQLizeUseCase().sqlize(applied.ok)) - } - - } - } - - private fun printSql(sqlines: List<String>) { - println() - println("--------------------------------------------------------------------------") - for (sql in sqlines) println(sql) - } - - private fun printDb(db:Database) { - println() - println("--------------------------------------------------------------------------") - println(XMLSerializeUseCase(XMLSerializerJacksonAdapter()).prettyDatabase(db)) - } - - private fun detect(personMetadata: Database): UseCaseResult<Database> { - val dbDetected = Database() - // Check if it has nullable column. - for (table in personMetadata.schema.tables) { - if (table.hasNullable()) { - // then this table has to be partitioned to remove nullable. - // adds this table to db to apply vertical partitioning. - dbDetected.schema.tables.add(table) - } - } - return UseCaseResult("done detect",dbDetected) - } - - private fun apply(personMetadata: Database, detected: UseCaseResult<Database>): UseCaseResult<Database>{ - // pure person - val table = Table() - table.name= "pure_person" - table.view="person" - table.condition="person.T=null AND person.S=null" - personMetadata.schema.tables.add(table) - val colSSN = Column("SSN", "id.SSN", "dbname.SSN") - colSSN.nullable=false - table.columns.add(colSSN) - - // person with only telephone - val tableWithT = Table() - tableWithT.view="person" - tableWithT.name= "person_with_T" - tableWithT.condition="person.T NOT null AND person.S=null" - personMetadata.schema.tables.add(tableWithT) - val colT = Column("T", "id.T", "dbname.T") - colT.nullable=false - tableWithT.columns.add(colSSN) - tableWithT.columns.add(colT) - - // person with only TS - val tableWithS = Table() - tableWithS.view="person" - tableWithS.name= "person_with_TS" - tableWithS.condition="person.T = null AND person.S NOT null" - personMetadata.schema.tables.add(tableWithS) - val colS = Column("S", "id.S", "dbname.S") - colS.nullable=false - tableWithS.columns.add(colSSN) - tableWithS.columns.add(colS) - - - // person with only S - val tableWithTS = Table() - tableWithTS.view="person" - tableWithTS.name= "person_with_S" - tableWithTS.condition="person.T NOT null AND person.S NOT null" - personMetadata.schema.tables.add(tableWithTS) - tableWithTS.columns.add(colSSN) - tableWithTS.columns.add(colT) - tableWithTS.columns.add(colS) - - // removes table person - val personTable = personMetadata.schema.table("person") - personMetadata.schema.tables.remove(personTable) - - // removes constraints from/to person - var contraintsToRemove = mutableSetOf<Constraint>() - for (contraint in personMetadata.schema.constraints) { - if (contraint.source.table=="person") { - contraintsToRemove.add(contraint) - } - if (contraint.target.table=="person") { - contraintsToRemove.add(contraint) - } - } - personMetadata.schema.constraints.removeAll(contraintsToRemove) - - // add constraint partition - return UseCaseResult("done apply", personMetadata) - } } \ No newline at end of file diff --git a/src/main/kotlin/unibz.cs.semint.kprime/usecase/XMLSerializeUseCase.kt b/src/main/kotlin/unibz.cs.semint.kprime/usecase/XMLSerializeUseCase.kt index 3ca07fa487774a6e44e1d2b5c1b11fd8e234ca7e..36475d22163ea08ea9ccf3dd05b00253fe0b1f26 100644 --- a/src/main/kotlin/unibz.cs.semint.kprime/usecase/XMLSerializeUseCase.kt +++ b/src/main/kotlin/unibz.cs.semint.kprime/usecase/XMLSerializeUseCase.kt @@ -43,4 +43,19 @@ class XMLSerializeUseCase(val xmlSerializerService: IXMLSerializerService) { fun deserializeConstraint(constraint: String): UseCaseResult<Constraint> { return UseCaseResult("done",xmlSerializerService.deserializeConstraint(constraint)) } + + // changeset + + fun serializeChangeSet(changeset: ChangeSet): UseCaseResult<String> { + return UseCaseResult("done",xmlSerializerService.serializeChangeSet(changeset)) + } + + fun deserializeChangeSet(changeset: String): UseCaseResult<ChangeSet> { + return UseCaseResult("done",xmlSerializerService.deserializeChangeSet(changeset)) + } + + fun prettyChangeSet(changeset: ChangeSet): UseCaseResult<String> { + return UseCaseResult("done",xmlSerializerService.prettyChangeSet(changeset)) + } + } \ No newline at end of file diff --git a/src/main/kotlin/unibz.cs.semint.kprime/usecase/service/IXMLSerializerService.kt b/src/main/kotlin/unibz.cs.semint.kprime/usecase/service/IXMLSerializerService.kt index 9c872ed37ce4464fe83d12445a9026f9fcd0e3a3..f8dd2d7bac1a81297ed6114d2a198e222617b050 100644 --- a/src/main/kotlin/unibz.cs.semint.kprime/usecase/service/IXMLSerializerService.kt +++ b/src/main/kotlin/unibz.cs.semint.kprime/usecase/service/IXMLSerializerService.kt @@ -1,5 +1,6 @@ package unibz.cs.semint.kprime.usecase.service +import unibz.cs.semint.kprime.domain.ChangeSet import unibz.cs.semint.kprime.domain.Constraint import unibz.cs.semint.kprime.domain.Database import unibz.cs.semint.kprime.domain.Table @@ -13,4 +14,7 @@ interface IXMLSerializerService { fun prettyDatabase(db: Database): String fun serializeConstraint(constraint: Constraint): String fun deserializeConstraint(s: String): Constraint + fun serializeChangeSet(changeset: ChangeSet): String + fun deserializeChangeSet(changeset: String): ChangeSet + fun prettyChangeSet(table: ChangeSet): String } \ No newline at end of file diff --git a/src/test/kotlin/unibz.cs.semint.kprime/domain/ChangeSetTest.kt b/src/test/kotlin/unibz.cs.semint.kprime/domain/ChangeSetTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..4b2206a0c70c1080103190c36548630e5baa8c50 --- /dev/null +++ b/src/test/kotlin/unibz.cs.semint.kprime/domain/ChangeSetTest.kt @@ -0,0 +1,46 @@ +package unibz.cs.semint.kprime.domain + +import org.junit.Test +import unibz.cs.semint.kprime.adapter.service.XMLSerializerJacksonAdapter +import unibz.cs.semint.kprime.usecase.XMLSerializeUseCase + +class ChangeSetTest { + + + @Test + fun test_serialize_changeset_xml() { + // given + val changeSet = ChangeSet() + val view = CreateView() + view.value="select * from table" + changeSet.createView.add(view) + changeSet.createView.add(view) + // when + val serializedChangeSet = XMLSerializeUseCase(XMLSerializerJacksonAdapter()).serializeChangeSet(changeSet) + // then + println(serializedChangeSet) + } + + @Test + fun test_parse_changeset_xml() { + // given + val changesetXml = """ + <changeSet author="liquibase-docs" id="createView-example"> + <createView catalogName="cat" + encoding="UTF-8" + fullDefinition="true" + path="A String" + relativeToChangelogFile="true" + remarks="A String" + replaceIfExists="false" + schemaName="public" + viewName="v_person">select id, name from person where id > 10</createView> + </changeSet> + """.trimIndent() + // when + val xmlSerializeUseCase = XMLSerializeUseCase(XMLSerializerJacksonAdapter()) + val changeSet = xmlSerializeUseCase.deserializeChangeSet(changesetXml) + // then + println(xmlSerializeUseCase.prettyChangeSet(changeSet.ok!!)) + } +} \ No newline at end of file diff --git a/src/test/kotlin/unibz.cs.semint.kprime/scenario/PersonVSplitScenarioTI.kt b/src/test/kotlin/unibz.cs.semint.kprime/scenario/PersonHSplitScenarioTI.kt similarity index 50% rename from src/test/kotlin/unibz.cs.semint.kprime/scenario/PersonVSplitScenarioTI.kt rename to src/test/kotlin/unibz.cs.semint.kprime/scenario/PersonHSplitScenarioTI.kt index a78e9d93648e231498fd7cf30a128cde8e6cd920..ae8a38132acb5dcb45b6dcc0a3fb6222852f0edc 100644 --- a/src/test/kotlin/unibz.cs.semint.kprime/scenario/PersonVSplitScenarioTI.kt +++ b/src/test/kotlin/unibz.cs.semint.kprime/scenario/PersonHSplitScenarioTI.kt @@ -2,14 +2,14 @@ package unibz.cs.semint.kprime.scenario import org.junit.Test -class PersonVSplitScenarioTI { +class PersonHSplitScenarioTI { @Test - fun test_person_vsplit_scenario() { + fun test_person_hsplit_scenario() { // given - val personVSplitScenario = PersonVSplitScenario() + val personHSplitScenario = PersonHSplitScenario() // when - personVSplitScenario.run() + personHSplitScenario.run() // then // prints splitted database } diff --git a/src/test/kotlin/unibz.cs.semint.kprime/usecase/serialize/XMLSerializerTableTest.kt b/src/test/kotlin/unibz.cs.semint.kprime/usecase/serialize/XMLSerializerTableTest.kt index b7fc961234baa3f3be9c201f32a5792ac60277fe..5349f457103ce4f026fccd55d1ae2629ddea6dad 100644 --- a/src/test/kotlin/unibz.cs.semint.kprime/usecase/serialize/XMLSerializerTableTest.kt +++ b/src/test/kotlin/unibz.cs.semint.kprime/usecase/serialize/XMLSerializerTableTest.kt @@ -24,7 +24,7 @@ class XMLSerializerTableTest { table.id="22" val result = serializer.serializeTable(table).ok // then - assertEquals("<table name=\"Gigi\" id=\"22\"><columns/></table>",result) + assertEquals("<table name=\"Gigi\" id=\"22\" view=\"\" condition=\"\"><columns/></table>",result) } @Test @@ -40,7 +40,7 @@ class XMLSerializerTableTest { val result = serializer.serializeTable(table).ok // then - assertEquals("<table name=\"Gigi\" id=\"22\"><columns><columns name=\"col1\" id=\"id1\" dbname=\"dbname1\" nullable=\"false\" dbtype=\"\"/><columns name=\"col2\" id=\"id2\" dbname=\"dbname2\" nullable=\"false\" dbtype=\"\"/></columns></table>",result) + assertEquals("<table name=\"Gigi\" id=\"22\" view=\"\" condition=\"\"><columns><columns name=\"col1\" id=\"id1\" dbname=\"dbname1\" nullable=\"false\" dbtype=\"\"/><columns name=\"col2\" id=\"id2\" dbname=\"dbname2\" nullable=\"false\" dbtype=\"\"/></columns></table>",result) } @Test diff --git a/src/test/resources/database_with_two_empty_tables.xml b/src/test/resources/database_with_two_empty_tables.xml index e79581a82c77f1407e11cfba2b257967a2947e04..73da3dc769ed92be8992067c5fd49b89566bd4c0 100644 --- a/src/test/resources/database_with_two_empty_tables.xml +++ b/src/test/resources/database_with_two_empty_tables.xml @@ -1,10 +1,10 @@ <database name="dbname" id="iddb"> <schema name="" id="idschema"> <tables> - <tables name="" id=""> + <tables name="" id="" condition="" view=""> <columns/> </tables> - <tables name="" id=""> + <tables name="" id="" condition="" view=""> <columns/> </tables> </tables> diff --git a/src/test/resources/table_two_columns.xml b/src/test/resources/table_two_columns.xml index 16c27530d00b643ad4cbad2bf779d7ea09ce8109..c705aa1343e518ca9aeb23e57d13d039e1f46233 100644 --- a/src/test/resources/table_two_columns.xml +++ b/src/test/resources/table_two_columns.xml @@ -1,4 +1,4 @@ -<table name="Gigi" id="23"> +<table name="Gigi" id="23" view="" condition=""> <columns> <columns name="col1" id="id1" dbname="dbname1" dbtype="" nullable="false"/> <columns name="col2" id="id2" dbname="dbname2" dbtype="" nullable="false"/>