Skip to content
Snippets Groups Projects
Commit dbdfc142 authored by npedot's avatar npedot
Browse files

adds TransformerXUseCase and TransformerXUseCaseTI

parent 577ba766
No related branches found
No related tags found
No related merge requests found
Showing
with 247 additions and 49 deletions
......@@ -2,53 +2,69 @@ package unibz.cs.semint.kprime.usecase.common
import freemarker.cache.ClassTemplateLoader
import freemarker.template.Configuration
import freemarker.template.Template
import org.w3c.dom.NodeList
import unibz.cs.semint.kprime.adapter.service.XMLSerializerJacksonAdapter
import unibz.cs.semint.kprime.domain.ddl.Database
import unibz.cs.semint.kprime.domain.dml.ChangeSet
import unibz.cs.semint.kprime.usecase.service.FileIOService
import java.io.File
import java.io.InputStream
import java.io.StringWriter
import java.io.Writer
import java.util.*
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.xpath.XPathConstants
import javax.xml.xpath.XPathFactory
class XPathTransformUseCase {
class XPathTransformUseCase {
fun transform(dbFilePath: String, trasformerName: String, trasformerDirection: String, trasformerVersion: String, tranformerParmeters: MutableMap<String, Any>,outWriter: Writer) :Database {
fun transform(
dbFilePath: String,
trasformerName: String,
trasformerDirection: String,
trasformerVersion: String,
tranformerParmeters: MutableMap<String, Any>)
:Database {
val vdecomposeFilePath = "/transformer/${trasformerName}/${trasformerDirection}/${trasformerName}_${trasformerDirection}_${trasformerVersion}.paths"
val vdecomposeTemplatePath = "transformer/${trasformerName}/${trasformerDirection}/${trasformerName}_${trasformerDirection}_${trasformerVersion}.template"
val personProperties = XPathTransformUseCase::class.java.getResourceAsStream(vdecomposeFilePath)
val xPaths = Properties()
xPaths.load(personProperties)
return transform(dbFilePath,vdecomposeTemplatePath,xPaths, tranformerParmeters,outWriter)
return transform(dbFilePath,vdecomposeTemplatePath,xPaths, tranformerParmeters)
}
/*
It uses 'changeset' template
*/
fun compute(dbFilePath: String, trasformerName: String, trasformerDirection: String, trasformerVersion: String, tranformerParmeters: MutableMap<String, Any>,outWriter: Writer) :ChangeSet {
fun compute(
dbFilePath: String,
trasformerName: String,
trasformerDirection: String,
trasformerVersion: String,
tranformerParmeters: MutableMap<String, Any>)
:ChangeSet {
val vdecomposeFilePath = "/transformer/${trasformerName}/${trasformerDirection}/${trasformerName}_${trasformerDirection}_${trasformerVersion}.paths"
val vdecomposeTemplatePath = "transformer/${trasformerName}/${trasformerDirection}/${trasformerName}_changeset_${trasformerVersion}.template"
val personProperties = XPathTransformUseCase::class.java.getResourceAsStream(vdecomposeFilePath)
val xPaths = Properties()
xPaths.load(personProperties)
return compute(dbFilePath, vdecomposeTemplatePath, xPaths, tranformerParmeters,outWriter)
return compute(dbFilePath, vdecomposeTemplatePath, xPaths, tranformerParmeters)
}
fun transform(dbFilePath: String, templateFilePath: String, xPaths: Properties, tranformerParmeters: MutableMap<String, Any>,outWriter:Writer): Database {
val changeSet = compute(dbFilePath, templateFilePath, xPaths, tranformerParmeters, outWriter)
if (changeSet == null) {
println("changeset null"); return Database()
}
fun transform(
dbFilePath: String,
templateFilePath: String,
xPaths: Properties,
tranformerParmeters:
MutableMap<String, Any>)
: Database {
val changeSet = compute(dbFilePath, templateFilePath, xPaths, tranformerParmeters)
//val dbXml = XPathTransformUseCase::class.java.getResource("/${dbFilePath}").readText()
val dbXml = FileIOService.readString(FileIOService.inputStreamFromPath(dbFilePath))
val serializer = XMLSerializerJacksonAdapter()
val db = serializer.deserializeDatabase(dbXml)
val newdb = ApplyChangeSetUseCase(serializer).apply(db, changeSet);
val newdb = ApplyChangeSetUseCase(serializer).apply(db, changeSet)
println("-----------------------NEW-DB---------------")
//println(serializer.prettyDatabase(newdb))
......@@ -101,8 +117,13 @@ class XPathTransformUseCase {
return listNodeValues
}
fun compute(dbFilePath: String, templateFilePath: String, xPaths: Properties, tranformerParmeters: MutableMap<String, Any>,outWriter:Writer): ChangeSet {
var dbInputStream: InputStream = FileIOService.inputStreamFromPath(dbFilePath)
fun compute(
dbFilePath: String,
templateFilePath: String,
xPaths: Properties,
tranformerParmeters: MutableMap<String, Any>)
: ChangeSet {
val dbInputStream : InputStream = FileIOService.inputStreamFromPath(dbFilePath)
val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
val doc = docBuilder.parse(dbInputStream)
......@@ -160,12 +181,27 @@ class XPathTransformUseCase {
// = = 0 xpath
println("22++++++++++++++++++++++++++++++++++++++++++-------------------------------")
val templ = //Template.getPlainTextTemplate("templ1",personTemplate,templConfig)
templConfig.getTemplate(templateFilePath)
lateinit var templ : Template
if (templateFilePath.startsWith("/")||
templateFilePath.startsWith("./")) {
templ = Template.getPlainTextTemplate("template1",
File(templateFilePath).readText(Charsets.UTF_8), templConfig)
val lastSlash = templateFilePath.lastIndexOf("/")
val templateDir = templateFilePath.substring(0,lastSlash)
val templateFileName = templateFilePath.substring(lastSlash)
//templConfig.setDirectoryForTemplateLoading(File("/home/nipe/Temp/kprime/transformers/vertical/decompose/"))
//templ = templConfig.getTemplate("vertical_decompose_1_changeset.xml")
println("${templateDir}:${templateFileName}")
templConfig.setDirectoryForTemplateLoading(File(templateDir))
templ = templConfig.getTemplate(templateFileName)
} else {
templ = templConfig.getTemplate(templateFilePath)
}
val outWriter = StringWriter()
templ.process(templModel, outWriter)
println("33++++++++++++++++++++++++++++++++++++++++++-------------------------------")
val changeSetXml = (outWriter as StringWriter).buffer.toString()
val changeSetXml = outWriter.buffer.toString()
println(changeSetXml)
val serializer = XMLSerializerJacksonAdapter()
println("44++++++++++++++++++++++++++++++++++++++++++-------------------------------")
......
......@@ -9,14 +9,11 @@ import unibz.cs.semint.kprime.usecase.TransformerUseCase
import unibz.cs.semint.kprime.usecase.common.XPathTransformUseCase
import unibz.cs.semint.kprime.usecase.service.FileIOService
import unibz.cs.semint.kprime.usecase.service.IXMLSerializerService
import java.io.File
import java.io.StringWriter
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
class TransformerVUseCase(serializer: IXMLSerializerService, fileIOAdapter: FileIOService) : TransformerUseCase {
val serializer = serializer
val fileIOAdapter = fileIOAdapter
class TransformerVUseCase(val serializer: IXMLSerializerService, val fileIOAdapter: FileIOService) : TransformerUseCase {
override fun decompose(db: Database, params:Map<String,Any>): Transformation {
val tranformerParmeters = mutableMapOf<String,Any>()
......@@ -41,8 +38,7 @@ class TransformerVUseCase(serializer: IXMLSerializerService, fileIOAdapter: File
"vertical",
"decompose",
"1",
tranformerParmeters,
StringWriter())
tranformerParmeters)
if (changeSet.size()!=0) {
val csFileName = workingDir + "${timestamp.format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss_nnnnnnnnnn"))}_cs.xml"
println("Written cs file $tableToSplit : $csFileName ")
......
package unibz.cs.semint.kprime.usecase.current
import unibz.cs.semint.kprime.domain.Applicability
import unibz.cs.semint.kprime.domain.Transformation
import unibz.cs.semint.kprime.domain.TransformationStrategy
import unibz.cs.semint.kprime.domain.ddl.Database
import unibz.cs.semint.kprime.usecase.TransformerUseCase
import unibz.cs.semint.kprime.usecase.common.ApplyChangeSetUseCase
import unibz.cs.semint.kprime.usecase.common.XPathTransformUseCase
import unibz.cs.semint.kprime.usecase.service.FileIOService
import unibz.cs.semint.kprime.usecase.service.IXMLSerializerService
import java.io.FileReader
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.*
/**
* Usage e.g.:
* TransformerXUseCase(
* XMLSerializerJacksonAdapter(),
* FileIOAdapter(),
* settingService.getWorkingDir() + TRACES_DIR +"/"
* settingService.getWorkingDir() + TRANSFORMERS_DIR +"/"+ transformerName +"/"+ transformerDocoTemplateFile
* settingService.getWorkingDir() + TRANSFORMERS_DIR +"/"+ transformerName +"/"+ transformerDocoXPathFile
* settingService.getWorkingDir() + TRANSFORMERS_DIR +"/"+ transformerName +"/"+ transformerCoTemplateFile
* settingService.getWorkingDir() + TRANSFORMERS_DIR +"/"+ transformerName +"/"+ transformerCoXPathFile
* transformerName)
*
*/
class TransformerXUseCase(
val serializer: IXMLSerializerService,
val fileIOAdapter: FileIOService,
val workingDir:String,
val docoTemplateFilePath:String,
val decoXPathsFilePath:String,
val coTemplateFilePath:String,
val coXPathsFilePath:String,
val name:String)
: TransformerUseCase {
private val xpathTransform = XPathTransformUseCase()
override fun decompose(db: Database, params: Map<String, Any>): Transformation {
val functionals = db.schema.functionals()
if (functionals.isEmpty()) return errorTransformation(db,"ERROR: TransformerXUseCase no functionals")
val dbFilePath = fileIOAdapter.writeOnWorkingFilePath(serializer.prettyDatabase(db), workingDir + "db_worked.xml")
println("Updated db file db_worked.xml")
val xPaths = Properties()
xPaths.load(FileReader(decoXPathsFilePath))
//val changeSetFileName = workingDir + "${LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss_nnnnnnnnnn"))}_cs.xml"
val tranformerParmeters = mutableMapOf<String,Any>()
tranformerParmeters.putAll(params)
val changeSet = xpathTransform.compute(dbFilePath, docoTemplateFilePath, xPaths, tranformerParmeters)
println("Computed changeSet : $changeSet")
val newdb = ApplyChangeSetUseCase(serializer).apply(db, changeSet)
val newDbFileName = workingDir + "${LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss_nnnnnnnnnn"))}_db.xml"
fileIOAdapter.writeOnWorkingFilePath(serializer.prettyDatabase(newdb), newDbFileName)
println("Written new db file : $newDbFileName")
return Transformation(changeSet, newdb, "TransformerXUseCase.decomposed ")
}
override fun compose(db: Database, params: Map<String, Any>): Transformation {
TODO("Not yet implemented")
}
override fun decomposeApplicable(db: Database, transformationStrategy: TransformationStrategy): Applicability {
return Applicability(true,"decomposeApplicable", mutableMapOf())
}
override fun composeApplicable(db: Database, transformationStrategy: TransformationStrategy): Applicability {
return Applicability(false,"decomposeApplicable", mutableMapOf())
}
}
\ No newline at end of file
......@@ -5,7 +5,6 @@ import unibz.cs.semint.kprime.adapter.service.XMLSerializerJacksonAdapter
import unibz.cs.semint.kprime.domain.Xrule
import unibz.cs.semint.kprime.usecase.common.XMLSerializeUseCase
import unibz.cs.semint.kprime.usecase.common.XPathTransformUseCase
import java.io.StringWriter
import java.util.*
import kotlin.test.assertEquals
......@@ -23,10 +22,10 @@ class PersonTransfomerScenarioTI {
val transfomerXml = PersonTransfomerScenarioTI::class.java.getResource("/transformer/verticalTransfomer.xml").readText()
val vTransfomer = XMLSerializeUseCase(XMLSerializerJacksonAdapter()).deserializeTransformer(transfomerXml).ok
val templateFilePath = vTransfomer!!.splitter.template.filename
val xrules = toProperties(vTransfomer!!.splitter.xman.xrules)
val xrules = toProperties(vTransfomer.splitter.xman.xrules)
println(templateFilePath)
// when
val newDb = XPathTransformUseCase().transform(dbFilePath, templateFilePath, xrules, tranformerParmeters, StringWriter())
val newDb = XPathTransformUseCase().transform(dbFilePath, templateFilePath, xrules, tranformerParmeters)
// then
val lineage = newDb.lineage("person1")
assertEquals(lineage.size,2)
......@@ -37,7 +36,7 @@ class PersonTransfomerScenarioTI {
}
private fun toProperties(xrules: ArrayList<Xrule>): Properties {
var pros = Properties()
val pros = Properties()
for (xrule in xrules) {
pros[xrule.name]=xrule.rule
}
......@@ -58,10 +57,10 @@ class PersonTransfomerScenarioTI {
val transfomerXml = PersonTransfomerScenarioTI::class.java.getResource("/transformer/verticalTransfomer.xml").readText()
val vTransfomer = XMLSerializeUseCase(XMLSerializerJacksonAdapter()).deserializeTransformer(transfomerXml).ok
val templateFilePath = vTransfomer!!.composer.template.filename
val xrules = toProperties(vTransfomer!!.composer.xman.xrules)
val xrules = toProperties(vTransfomer.composer.xman.xrules)
println(templateFilePath)
// when
val newDb = XPathTransformUseCase().transform(dbFilePath, templateFilePath, xrules, tranformerParmeters, StringWriter())
val newDb = XPathTransformUseCase().transform(dbFilePath, templateFilePath, xrules, tranformerParmeters)
// then
println(newDb)
}
......
......@@ -3,6 +3,7 @@ package unibz.cs.semint.kprime.scenario.person
import org.junit.Test
import unibz.cs.semint.kprime.usecase.common.XPathTransformUseCase
import java.io.OutputStreamWriter
import java.io.StringWriter
class PersonXPathScenarioTI {
......@@ -18,7 +19,7 @@ class PersonXPathScenarioTI {
tranformerParmeters["targetTable1"]="person1"
tranformerParmeters["targetTable2"]="person2"
// when
XPathTransformUseCase().transform(dbFilePath, trasformerName, trasformerDirection, trasformerVersion,tranformerParmeters, OutputStreamWriter(System.out))
XPathTransformUseCase().transform(dbFilePath, trasformerName, trasformerDirection, trasformerVersion,tranformerParmeters)
// then
// print to console output
}
......@@ -33,7 +34,7 @@ class PersonXPathScenarioTI {
val tranformerParmeters = mutableMapOf<String,Any>()
tranformerParmeters["table"]="person"
// when
XPathTransformUseCase().transform(dbFilePath, trasformerName, trasformerDirection, trasformerVersion,tranformerParmeters,OutputStreamWriter(System.out))
XPathTransformUseCase().transform(dbFilePath, trasformerName, trasformerDirection, trasformerVersion,tranformerParmeters)
// then
// print to console output
}
......
......@@ -3,8 +3,6 @@ package unibz.cs.semint.kprime.scenario.sakila
import org.junit.Test
import unibz.cs.semint.kprime.adapter.file.FileIOAdapter
import unibz.cs.semint.kprime.adapter.service.XMLSerializerJacksonAdapter
import unibz.cs.semint.kprime.scenario.sakila.readMeta
import unibz.cs.semint.kprime.scenario.sakila.sakilaDataSource
import unibz.cs.semint.kprime.usecase.current.TransformerVUseCase
/*
......@@ -39,7 +37,7 @@ class SakilaRefactTI {
@Test
// TODO work in progress...
fun test_api() {
var db = readMeta(sakilaDataSource())
val db = readMeta(sakilaDataSource())
if (db==null) {
println("sakila meta db not open")
return
......@@ -58,7 +56,8 @@ class SakilaRefactTI {
"targetTable2" to "film_rental",
"workingDir" to workingDir
)
db = TransformerVUseCase(XMLSerializerJacksonAdapter(), FileIOAdapter()).decompose(db,params).newdb // detect lossy
//val newdb =
TransformerVUseCase(XMLSerializerJacksonAdapter(), FileIOAdapter()).decompose(db,params).newdb // detect lossy
// .hdecompose("film_core","film_ita","film_not_ita","select * where language='IT'") // detect lossy
// .genarm()
// .alias("film_ita","film_italiani")
......
......@@ -9,7 +9,6 @@ import unibz.cs.semint.kprime.domain.dql.Query
import unibz.cs.semint.kprime.usecase.common.SQLizeUseCase
import unibz.cs.semint.kprime.usecase.common.XMLSerializeUseCase
import unibz.cs.semint.kprime.usecase.common.XPathTransformUseCase
import java.io.StringWriter
class SakilaTransfomerScenarioTI {
......@@ -24,16 +23,15 @@ class SakilaTransfomerScenarioTI {
val transfomerXml = SakilaTransfomerScenarioTI::class.java.getResource("/transformer/verticalTransfomer.xml").readText()
val vTransfomer = XMLSerializeUseCase(XMLSerializerJacksonAdapter()).deserializeTransformer(transfomerXml).ok
val templateFilePath = vTransfomer!!.splitter.template.filename
val xrules = Xrule.toProperties(vTransfomer!!.splitter.xman.xrules)
val xrules = Xrule.toProperties(vTransfomer.splitter.xman.xrules)
val tranformerParmeters = mutableMapOf<String,Any>()
tranformerParmeters["originTable"]="film"
tranformerParmeters["targetTable1"]="film1"
tranformerParmeters["targetTable2"]="film2"
println(templateFilePath)
// when
val newdb = XPathTransformUseCase().transform(dbFilePath, templateFilePath, xrules, tranformerParmeters, StringWriter())
val newdb = XPathTransformUseCase().transform(dbFilePath, templateFilePath, xrules, tranformerParmeters)
// then
val simpleQueryTab = Query.buildFromTable(newdb, "film2")
val simpleQueryMap1 = Query.buildFromMapping(newdb, "film1")!!
val simpleQueryMap2 = Query.buildFromMapping(newdb, "film2")!!
......@@ -49,8 +47,8 @@ class SakilaTransfomerScenarioTI {
val sqlize = SQLizeUseCase().sqlize(simpleQueryMap1)
println(sqlize)
val result1 = QueryJdbcAdapter().query(sakilaSource, simpleQueryMap1)
val result2 = QueryJdbcAdapter().query(sakilaSource, simpleQueryMap2)
QueryJdbcAdapter().query(sakilaSource, simpleQueryMap1)
QueryJdbcAdapter().query(sakilaSource, simpleQueryMap2)
// print to console output
}
......@@ -63,15 +61,15 @@ class SakilaTransfomerScenarioTI {
// given
val dbFilePath = "db/sakila_film_functional.xml"
val transfomerXml = SakilaTransfomerScenarioTI::class.java.getResource("/transformer/verticalTransfomer.xml").readText()
val vTransfomer = XMLSerializeUseCase(XMLSerializerJacksonAdapter()).deserializeTransformer(transfomerXml).ok
val templateFilePath = vTransfomer!!.splitter.template.filename
val xrules = Xrule.toProperties(vTransfomer!!.splitter.xman.xrules)
val vTransfomer = XMLSerializeUseCase(XMLSerializerJacksonAdapter()).deserializeTransformer(transfomerXml).ok!!
val templateFilePath = vTransfomer.splitter.template.filename
val xrules = Xrule.toProperties(vTransfomer.splitter.xman.xrules)
val tranformerParmeters = mutableMapOf<String,Any>()
tranformerParmeters["originTable"]="film"
tranformerParmeters["targetTable1"]="film_core"
tranformerParmeters["targetTable2"]="film_nullable"
println(templateFilePath)
val newDb = XPathTransformUseCase().transform(dbFilePath, templateFilePath, xrules, tranformerParmeters, StringWriter())
val newDb = XPathTransformUseCase().transform(dbFilePath, templateFilePath, xrules, tranformerParmeters)
// create the db views
val type = "psql"
val name = "sakila-source"
......@@ -100,9 +98,9 @@ class SakilaTransfomerScenarioTI {
// given
val dbFilePath = "db/sakila_film_functional.xml"
val transfomerXml = SakilaTransfomerScenarioTI::class.java.getResource("/transformer/horizontalTransfomer.xml").readText()
val vTransfomer = XMLSerializeUseCase(XMLSerializerJacksonAdapter()).deserializeTransformer(transfomerXml).ok
val templateFilePath = vTransfomer!!.splitter.template.filename
val xrules = Xrule.toProperties(vTransfomer!!.splitter.xman.xrules)
val vTransfomer = XMLSerializeUseCase(XMLSerializerJacksonAdapter()).deserializeTransformer(transfomerXml).ok!!
val templateFilePath = vTransfomer.splitter.template.filename
val xrules = Xrule.toProperties(vTransfomer.splitter.xman.xrules)
val tranformerParmeters = mutableMapOf<String,Any>()
tranformerParmeters["originTable"]="film"
tranformerParmeters["targetTable1"]="film_italiano"
......@@ -110,7 +108,8 @@ class SakilaTransfomerScenarioTI {
tranformerParmeters["condition"]="select * from film where language_id=2"
println(templateFilePath)
// when
val newDb = XPathTransformUseCase().transform(dbFilePath, templateFilePath, xrules, tranformerParmeters, StringWriter())
//val newDb =
XPathTransformUseCase().transform(dbFilePath, templateFilePath, xrules, tranformerParmeters)
// then
// print to console output
......
package unibz.cs.semint.kprime.support
import freemarker.template.Configuration
import freemarker.template.Template
import org.junit.Ignore
import org.junit.Test
import java.io.File
import java.io.StringWriter
class FreemarkerTI {
@Test
@Ignore
fun test_freemarker_templating_file() {
// given
val templateFilePath = "/home/nipe/Temp/kprime/transformers/vertical/decompose/vertical_decompose_1_changeset.xml"
val templConfig = Configuration(Configuration.VERSION_2_3_29)
lateinit var templ : Template
if (templateFilePath.startsWith("/")||
templateFilePath.startsWith("./")) {
val readText = File(templateFilePath).readText(Charsets.UTF_8)
// val readText = """
// <#list keys as key>
// <columns name="//$//{key}" id="id.//$//{key}" dbname="" nullable="false" dbtype=""/>
// </#list>
// """.trimIndent()
templ = Template.getPlainTextTemplate("template1",
readText, templConfig)
} else {
templ = templConfig.getTemplate(templateFilePath)
}
val templModel = mutableMapOf<String, List<String>>(
"keys" to listOf("Uno","Due")
)
val outWriter = StringWriter()
// when
templ.process(templModel, outWriter)
// then
val changeSetXml = outWriter.buffer.toString()
println(changeSetXml)
}
}
\ No newline at end of file
package unibz.cs.semint.kprime.usecase
import org.junit.Test
import unibz.cs.semint.kprime.adapter.file.FileIOAdapter
import unibz.cs.semint.kprime.adapter.service.XMLSerializerJacksonAdapter
import unibz.cs.semint.kprime.scenario.sakila.readMeta
import unibz.cs.semint.kprime.scenario.sakila.sakilaDataSource
import unibz.cs.semint.kprime.usecase.current.TransformerXUseCase
class TransformerXUseCaseTI {
@Test
fun test_transformerx_decompose(){
// given
val db = readMeta(sakilaDataSource())
if (db==null) {
println("sakila meta db not open")
return
}
db.schema
//.checkBcnf()
.addFunctionals("film","film_id --> replacement_cost, rental_duration, rental_rate")
// val workingDir = "/home/nicola/Tmp/"
val workingDir = "/home/nipe/Temp/kprime/"
val transformerName="vertical"
val params = mutableMapOf<String,Any>(
"originTable" to "film",
"targetTable1" to "film_catalog",
"targetTable2" to "film_rental"
)
// when
TransformerXUseCase(
XMLSerializerJacksonAdapter(),
FileIOAdapter(),
workingDir + "traces/",
workingDir + "transformers/"+transformerName+"/decompose/vertical_decompose_1_changeset.xml",
workingDir + "transformers/"+transformerName+"/decompose/vertical_decompose_1_paths.properties",
"",
"",
transformerName)
.decompose(
db,params
)
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment