From 8c7a4a73ed2f9a2cbcca9f0a923e751753ae7954 Mon Sep 17 00:00:00 2001 From: npedot <nicola.pedot@gmail.com> Date: Thu, 23 Jan 2020 08:33:25 +0100 Subject: [PATCH] adds person xpath scenario --- README.md | 9 +++- pom.xml | 6 +++ .../domain/Constraint.kt | 1 + .../usecase/HJoinUseCase.kt | 3 ++ .../usecase/VSplitUseCase.kt | 39 +++++++++------ .../scenario/PersonVSplitScenarioTI.kt | 6 +++ .../scenario/PersonXPathScenarioTI.kt | 39 +++++++++++++++ src/test/resources/db/person.xml | 38 ++++++++++++++ src/test/resources/db/person_out.template | 49 +++++++++++++++++++ 9 files changed, 174 insertions(+), 16 deletions(-) create mode 100644 src/test/kotlin/unibz.cs.semint.kprime/scenario/PersonXPathScenarioTI.kt create mode 100644 src/test/resources/db/person.xml create mode 100644 src/test/resources/db/person_out.template diff --git a/README.md b/README.md index 5f18680..b5ea283 100644 --- a/README.md +++ b/README.md @@ -73,4 +73,11 @@ technology depenent packages * schema clone, builder, immutable * schema pattern matcher * schema variable extrator -* sql view generator \ No newline at end of file +* sql view generator + +## references + +https://www.baeldung.com/java-xpath +https://freemarker.apache.org/ +https://github.com/ostap/relations-java +https://github.com/JSQLParser/JSqlParser/wiki/Examples-of-SQL-parsing \ No newline at end of file diff --git a/pom.xml b/pom.xml index 0221a52..f4ea53e 100644 --- a/pom.xml +++ b/pom.xml @@ -67,6 +67,12 @@ <artifactId>postgresql</artifactId> <version>42.2.8</version> </dependency> + <dependency> + <groupId>org.freemarker</groupId> + <artifactId>freemarker</artifactId> + <version>2.3.29</version> + </dependency> + <!-- test --> diff --git a/src/main/kotlin/unibz.cs.semint.kprime/domain/Constraint.kt b/src/main/kotlin/unibz.cs.semint.kprime/domain/Constraint.kt index 02efb4e..c136be4 100644 --- a/src/main/kotlin/unibz.cs.semint.kprime/domain/Constraint.kt +++ b/src/main/kotlin/unibz.cs.semint.kprime/domain/Constraint.kt @@ -5,6 +5,7 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement @JacksonXmlRootElement(localName = "constraint") class Constraint () { + enum class TYPE { FOREIGN_KEY,PRIMARY_KEY,FUNCTIONAL,DOUBLE_INCLUSION,INCLUSION,DISJUNCTION,COVER } diff --git a/src/main/kotlin/unibz.cs.semint.kprime/usecase/HJoinUseCase.kt b/src/main/kotlin/unibz.cs.semint.kprime/usecase/HJoinUseCase.kt index 0cbb420..a17d9d3 100644 --- a/src/main/kotlin/unibz.cs.semint.kprime/usecase/HJoinUseCase.kt +++ b/src/main/kotlin/unibz.cs.semint.kprime/usecase/HJoinUseCase.kt @@ -1,2 +1,5 @@ package unibz.cs.semint.kprime.usecase +class HJoinUseCase { + +} \ No newline at end of file diff --git a/src/main/kotlin/unibz.cs.semint.kprime/usecase/VSplitUseCase.kt b/src/main/kotlin/unibz.cs.semint.kprime/usecase/VSplitUseCase.kt index 9bdd18e..cacf67c 100644 --- a/src/main/kotlin/unibz.cs.semint.kprime/usecase/VSplitUseCase.kt +++ b/src/main/kotlin/unibz.cs.semint.kprime/usecase/VSplitUseCase.kt @@ -5,25 +5,33 @@ import unibz.cs.semint.kprime.domain.* class VSplitUseCase { fun compute(metadataDatabase: Database): ChangeSet { - // check for functional dep // create changeset var changeSet = ChangeSet() + // precondition: check for first table with functional dep, get the name + var tableWithFunctionalName= metadataDatabase.schema.constraints + .filter { c -> c.type==Constraint.TYPE.FUNCTIONAL.name } + .map { c -> c.source.table }.first() + if (tableWithFunctionalName.isEmpty()) return changeSet + // compute K - val keyCols = metadataDatabase.schema.key("person") + val keyCols = metadataDatabase.schema.key(tableWithFunctionalName) var key = keyCols.map { x -> x.name }.toSet() println("key $key") + // compute LHS - var lhsCols = metadataDatabase.schema.functionalLHS("person") + var lhsCols = metadataDatabase.schema.functionalLHS(tableWithFunctionalName) var lhs= lhsCols.map { x -> x.name }.toSet() println("lhs $lhs") if (lhs.isEmpty()) return changeSet + // compute RHS - val rhsCols = metadataDatabase.schema.functionalRHS("person") + val rhsCols = metadataDatabase.schema.functionalRHS(tableWithFunctionalName) var rhs = rhsCols.map { x -> x.name }.toSet() println("rhs $rhs") + // compute Rest - val allCols = metadataDatabase.schema.table("person").columns.toSet() + val allCols = metadataDatabase.schema.table(tableWithFunctionalName).columns.toSet() val all = allCols.map { x -> x.name }.toSet() var rest = all.minus(key).minus(lhs).minus(rhs) val allNotKey = all.minus(key) @@ -32,25 +40,26 @@ class VSplitUseCase { println("rest $rest") // create view1 = select K,LHS,Rest - var view1cols = "select "+key.plus(lhs).plus(rest).joinToString()+" from person" + var view1cols = "select "+key.plus(lhs).plus(rest).joinToString()+" from $tableWithFunctionalName" val view1 = CreateView() view1.viewName="tableName1" view1.text=view1cols changeSet.createView.add(view1) + // create view2 = select LHS,RHS - var view2cols = "select "+lhs.plus(rhs).joinToString()+" from person" + var view2cols = "select "+lhs.plus(rhs).joinToString()+" from $tableWithFunctionalName" val view2 = CreateView() view2.viewName="tableName2" view2.text=view2cols changeSet.createView.add(view2) - // create inclusion constraint tab1 tab2 - val inclusionTab1Tab2 = Constraint() - inclusionTab1Tab2.type=Constraint.TYPE.INCLUSION.name - inclusionTab1Tab2.source.table="tableName1" - inclusionTab1Tab2.source.columns.addAll(lhsCols) - inclusionTab1Tab2.target.table="tableName2" - inclusionTab1Tab2.target.columns.addAll(lhsCols) - changeSet.createConstraint.add(inclusionTab1Tab2) + + // create key constraint tab2 + val keyTab2 = Constraint() + keyTab2.type=Constraint.TYPE.PRIMARY_KEY.name + keyTab2.source.table="tableName2" + keyTab2.source.columns.addAll(lhsCols) + changeSet.createConstraint.add(keyTab2) + // create inclusion constraint tab2 tab1 val inclusionTab2Tab1 = Constraint() inclusionTab2Tab1.type=Constraint.TYPE.DOUBLE_INCLUSION.name diff --git a/src/test/kotlin/unibz.cs.semint.kprime/scenario/PersonVSplitScenarioTI.kt b/src/test/kotlin/unibz.cs.semint.kprime/scenario/PersonVSplitScenarioTI.kt index 86dd0e8..70911ea 100644 --- a/src/test/kotlin/unibz.cs.semint.kprime/scenario/PersonVSplitScenarioTI.kt +++ b/src/test/kotlin/unibz.cs.semint.kprime/scenario/PersonVSplitScenarioTI.kt @@ -51,4 +51,10 @@ class PersonVSplitScenarioTI { // prints changeset println(XMLSerializeUseCase(XMLSerializerJacksonAdapter()).prettyChangeSet(changeSet)) } + + @Test + fun test_print_input_db() { + val db = buildPersonMetadata() + println(XMLSerializeUseCase(XMLSerializerJacksonAdapter()).prettyDatabase(db).ok) + } } \ No newline at end of file diff --git a/src/test/kotlin/unibz.cs.semint.kprime/scenario/PersonXPathScenarioTI.kt b/src/test/kotlin/unibz.cs.semint.kprime/scenario/PersonXPathScenarioTI.kt new file mode 100644 index 0000000..ec92474 --- /dev/null +++ b/src/test/kotlin/unibz.cs.semint.kprime/scenario/PersonXPathScenarioTI.kt @@ -0,0 +1,39 @@ +package unibz.cs.semint.kprime.scenario + +import freemarker.cache.ClassTemplateLoader +import freemarker.template.Configuration +import freemarker.template.Template +import org.junit.Test +import java.io.OutputStreamWriter + +class PersonXPathScenarioTI { + + @Test + fun test_xpath_extraction_on_person_db() { + // given + // input person db + val personDbXml = PersonXPathScenarioTI::class.java.getResource("/db/person.xml").readText() + //println(personDbXml) + // input person out template + val personTemplate = PersonXPathScenarioTI::class.java.getResource("/db/person_out.template").readText() + //println(personTemplate) + // extract vars as value attributes via xpaths + val keys = listOf<String>("SSN") + val lhss = listOf<String>("T") + val rhss = listOf<String>("S") + val rests = listOf<String>("X") + // use vars in template + val templConfig = Configuration(Configuration.VERSION_2_3_29) + val classTemplLoader = ClassTemplateLoader(PersonXPathScenarioTI::javaClass.javaClass,"/") + templConfig.templateLoader= classTemplLoader + val templModel = mapOf<String,Any>( + "keys" to keys, + "lhss" to lhss, + "rhss" to rhss, + "rests" to rests) + val templ = //Template.getPlainTextTemplate("templ1",personTemplate,templConfig) + templConfig.getTemplate("db/person_out.template") + val out = OutputStreamWriter(System.out) + templ.process(templModel,out) + } +} \ No newline at end of file diff --git a/src/test/resources/db/person.xml b/src/test/resources/db/person.xml new file mode 100644 index 0000000..40ddf5e --- /dev/null +++ b/src/test/resources/db/person.xml @@ -0,0 +1,38 @@ +<database name="" id=""> + <schema name="" id=""> + <tables> + <tables name="person" id="" view="" condition=""> + <columns> + <columns name="SSN" id="id.SSN" dbname="dbname.SSN" nullable="false" dbtype=""/> + <columns name="T" id="id.T" dbname="dbname.T" nullable="false" dbtype=""/> + <columns name="S" id="id.S" dbname="dbname.S" nullable="true" dbtype=""/> + <columns name="X" id="id.X" dbname="dbname.X" nullable="true" dbtype=""/> + </columns> + </tables> + </tables> + <constraints> + <constraints name="primaryKey.person" id="" type="PRIMARY_KEY"> + <source name="" id="" table="person"> + <columns> + <columns name="SSN" id="id.SSN" dbname="dbname.SSN" nullable="false" dbtype=""/> + </columns> + </source> + <target name="" id="" table=""> + <columns/> + </target> + </constraints> + <constraints name="functional.person" id="" type="FUNCTIONAL"> + <source name="" id="" table="person"> + <columns> + <columns name="T" id="id.T" dbname="dbname.T" nullable="false" dbtype=""/> + </columns> + </source> + <target name="" id="" table="person"> + <columns> + <columns name="S" id="id.S" dbname="dbname.S" nullable="true" dbtype=""/> + </columns> + </target> + </constraints> + </constraints> + </schema> +</database> diff --git a/src/test/resources/db/person_out.template b/src/test/resources/db/person_out.template new file mode 100644 index 0000000..7468553 --- /dev/null +++ b/src/test/resources/db/person_out.template @@ -0,0 +1,49 @@ +<database name="" id=""> + <schema name="" id=""> + <tables> + <tables name="person1" id="" view="" condition=""> + <columns> + <#list keys as key> + <columns name=${key} id="id.${key}" nullable="false" dbtype=""/> + </#list> + <#list lhss as lhs> + <columns name="${lhs}" id="id.${lhs}" nullable="false" dbtype=""/> + </#list> + <#list rests as rest> + <columns name="${rest}" id="id.${rest}" nullable="true" dbtype=""/> + </#list> + </columns> + </tables> + <tables name="person2" id="" view="" condition=""> + <columns> + <columns name="T" id="id.T" dbname="dbname.T" nullable="false" dbtype=""/> + <columns name="S" id="id.S" dbname="dbname.S" nullable="true" dbtype=""/> + </columns> + </tables> + </tables> + <constraints> + <constraints name="primaryKey.person" id="" type="PRIMARY_KEY"> + <source name="" id="" table="person"> + <columns> + <columns name="SSN" id="id.SSN" dbname="dbname.SSN" nullable="false" dbtype=""/> + </columns> + </source> + <target name="" id="" table=""> + <columns/> + </target> + </constraints> + <constraints name="functional.person" id="" type="FUNCTIONAL"> + <source name="" id="" table="person"> + <columns> + <columns name="T" id="id.T" dbname="dbname.T" nullable="false" dbtype=""/> + </columns> + </source> + <target name="" id="" table="person"> + <columns> + <columns name="S" id="id.S" dbname="dbname.S" nullable="true" dbtype=""/> + </columns> + </target> + </constraints> + </constraints> + </schema> +</database> -- GitLab