From c90ea4fb4fafa840a680c2638c3ebcadbc164ac9 Mon Sep 17 00:00:00 2001 From: Lukas Cardot Date: Mon, 2 Sep 2024 17:54:24 -0400 Subject: [PATCH 1/2] make TableModel and RowModel immutable --- .../oss/jcv/db/assertj/DbComparatorAssertJ.kt | 22 +++---- .../jcv/db/cassandra/util/QueryConverter.kt | 18 +++--- .../ekino/oss/jcv/db/DbComparatorAssert.kt | 2 +- .../ekino/oss/jcv/db/config/DatabaseType.kt | 2 +- .../com/ekino/oss/jcv/db/model/TableModel.kt | 9 ++- .../oss/jcv/db/DbComparatorAssertTest.kt | 62 ++++++++++--------- .../oss/jcv/db/util/JsonConverterTest.kt | 25 ++++---- .../oss/jcv/db/jdbc/util/QueryConverter.kt | 9 ++- .../oss/jcv/db/mongo/util/MongoConverter.kt | 5 +- 9 files changed, 78 insertions(+), 76 deletions(-) diff --git a/jcv-db-assertj-db/src/main/kotlin/com/ekino/oss/jcv/db/assertj/DbComparatorAssertJ.kt b/jcv-db-assertj-db/src/main/kotlin/com/ekino/oss/jcv/db/assertj/DbComparatorAssertJ.kt index dd20330..9ab6065 100644 --- a/jcv-db-assertj-db/src/main/kotlin/com/ekino/oss/jcv/db/assertj/DbComparatorAssertJ.kt +++ b/jcv-db-assertj-db/src/main/kotlin/com/ekino/oss/jcv/db/assertj/DbComparatorAssertJ.kt @@ -26,8 +26,7 @@ import org.json.JSONException import org.skyscreamer.jsonassert.JSONCompareMode import java.io.InputStream import java.sql.DriverManager -import java.util.HashMap -import java.util.Objects +import java.util.* import javax.sql.DataSource class DbComparatorAssertJ( @@ -86,16 +85,15 @@ class DbComparatorAssertJ( } private fun Table.convertTableToTableModel(): TableModel { - val tableModel = TableModel() - this.rowsList.forEach { - val rowModel = RowModel() - val cells = HashMap() - - it.columnsNameList.forEach { columnName -> cells[columnName] = it.getColumnValue(columnName) } - rowModel.cells = cells - tableModel.addRow(rowModel) - } - return tableModel + return rowsList + .map { row -> + row.columnsNameList.associateWith { + row.getColumnValue(it) + } + } + .map(::RowModel) + .toSet() + .let(::TableModel) } private fun getMapperByDbType(source: Source?, dataSource: DataSource?): TypeMapper { diff --git a/jcv-db-cassandra/src/main/kotlin/com/ekino/oss/jcv/db/cassandra/util/QueryConverter.kt b/jcv-db-cassandra/src/main/kotlin/com/ekino/oss/jcv/db/cassandra/util/QueryConverter.kt index 80fd850..f15159b 100644 --- a/jcv-db-cassandra/src/main/kotlin/com/ekino/oss/jcv/db/cassandra/util/QueryConverter.kt +++ b/jcv-db-cassandra/src/main/kotlin/com/ekino/oss/jcv/db/cassandra/util/QueryConverter.kt @@ -31,14 +31,16 @@ class QueryConverter(private val dataSource: CassandraDataSource? = null) { } private fun fromResultSetToTableModel(resultSet: ResultSet): TableModel { - val rows = mutableSetOf() - resultSet.forEach { - val cells = mutableMapOf() - for (i in 0 until it.columnDefinitions.size()) { - cells[it.columnDefinitions[i].name.asCql(true)] = it.getObject(i) + return resultSet + .map { element -> + element.columnDefinitions + .mapIndexed { index, columnDefinition -> + columnDefinition.name.asCql(true) to element.getObject(index) + } + .toMap() + .let(::RowModel) } - rows.add(RowModel(cells)) - } - return TableModel(rows) + .toSet() + .let(::TableModel) } } diff --git a/jcv-db-core/src/main/kotlin/com/ekino/oss/jcv/db/DbComparatorAssert.kt b/jcv-db-core/src/main/kotlin/com/ekino/oss/jcv/db/DbComparatorAssert.kt index 9919f5b..8b91c69 100644 --- a/jcv-db-core/src/main/kotlin/com/ekino/oss/jcv/db/DbComparatorAssert.kt +++ b/jcv-db-core/src/main/kotlin/com/ekino/oss/jcv/db/DbComparatorAssert.kt @@ -25,7 +25,7 @@ class DbComparatorAssert(private val actualJson: JSONArray, private val jsonComp @JvmStatic fun assertThatRowModel(rowModel: RowModel): DbComparatorAssert { - val actualJson = TableModel(mutableSetOf(rowModel)).getTableModelAsJson() + val actualJson = TableModel(setOf(rowModel)).getTableModelAsJson() return DbComparatorAssert( actualJson, JsonComparator(JSONCompareMode.NON_EXTENSIBLE, Validators.defaultValidators()) diff --git a/jcv-db-core/src/main/kotlin/com/ekino/oss/jcv/db/config/DatabaseType.kt b/jcv-db-core/src/main/kotlin/com/ekino/oss/jcv/db/config/DatabaseType.kt index 85d2ba9..2ae2cc6 100644 --- a/jcv-db-core/src/main/kotlin/com/ekino/oss/jcv/db/config/DatabaseType.kt +++ b/jcv-db-core/src/main/kotlin/com/ekino/oss/jcv/db/config/DatabaseType.kt @@ -6,6 +6,6 @@ enum class DatabaseType(private val productName: String) { MSSQL("Microsoft SQL Server"); companion object { - fun getDatabaseTypeByProductName(name: String) = values().find { it.productName == name } + fun getDatabaseTypeByProductName(name: String) = entries.find { it.productName == name } } } diff --git a/jcv-db-core/src/main/kotlin/com/ekino/oss/jcv/db/model/TableModel.kt b/jcv-db-core/src/main/kotlin/com/ekino/oss/jcv/db/model/TableModel.kt index 4e60833..f5dc7ba 100644 --- a/jcv-db-core/src/main/kotlin/com/ekino/oss/jcv/db/model/TableModel.kt +++ b/jcv-db-core/src/main/kotlin/com/ekino/oss/jcv/db/model/TableModel.kt @@ -5,9 +5,7 @@ import com.ekino.oss.jcv.db.mapper.TypeMapper import org.json.JSONArray import org.json.JSONObject -data class TableModel(val rows: MutableSet = mutableSetOf()) { - fun addRow(row: RowModel) = rows.add(row) - +data class TableModel(val rows: Set) { fun getTableModelAsJson(typeMapper: TypeMapper? = null): JSONArray { val mapper = typeMapper ?: DefaultMapper() return JSONArray( @@ -24,7 +22,8 @@ data class TableModel(val rows: MutableSet = mutableSetOf()) { .map { entry -> entry.key.lowercase() to getValueFromMapper(entry.value, mapper) }.toMap() .let { map -> JSONObject(map) } - private fun getValueFromMapper(value: Any?, mapper: TypeMapper) = value?.let { mapper.getValueFromColumn(it) } ?: JSONObject.NULL + private fun getValueFromMapper(value: Any?, mapper: TypeMapper) = + value?.let { mapper.getValueFromColumn(it) } ?: JSONObject.NULL } -data class RowModel(var cells: MutableMap = mutableMapOf()) +data class RowModel(val cells: Map) diff --git a/jcv-db-core/src/test/kotlin/com/ekino/oss/jcv/db/DbComparatorAssertTest.kt b/jcv-db-core/src/test/kotlin/com/ekino/oss/jcv/db/DbComparatorAssertTest.kt index 68c92ca..a4750a4 100644 --- a/jcv-db-core/src/test/kotlin/com/ekino/oss/jcv/db/DbComparatorAssertTest.kt +++ b/jcv-db-core/src/test/kotlin/com/ekino/oss/jcv/db/DbComparatorAssertTest.kt @@ -49,31 +49,32 @@ class DbComparatorAssertTest { ] """.trimIndent() - val tableModel = TableModel() - tableModel.addRow( - RowModel( - mutableMapOf( - "id" to "0840ad8f-db82-472d-9dff-bb6d64992222", - "column_boolean" to true, - "column_char_varying" to "char varying", - "column_varchar" to "varchar", - "column_character" to "character", - "column_char" to "char", - "column_text" to "text", - "column_unlimited_varchar" to "unlimited varcharZOEFOEZUFHHZELF", - "column_smallint" to 123, - "column_int" to 12355, - "column_serial" to 3282, - "column_float" to 123.2235, - "column_real" to 125125.13, - "column_numeric" to 312, - "column_date" to "2019-06-07", - "column_time" to "17:12:28", - "column_timestamp" to "2019-06-07 00:00:00.0", - "column_timestamptz" to "2019-06-07 00:00:00.0", - "column_interval" to "0 years 0 mons 100 days 0 hours 0 mins 0.00 secs", - "column_json" to JSONArray("[{\"key\": \"Hello World !\"}]"), - "column_jsonb" to JSONObject("{\"key\": \"Hello World !\"}") + val tableModel = TableModel( + setOf( + RowModel( + mapOf( + "id" to "0840ad8f-db82-472d-9dff-bb6d64992222", + "column_boolean" to true, + "column_char_varying" to "char varying", + "column_varchar" to "varchar", + "column_character" to "character", + "column_char" to "char", + "column_text" to "text", + "column_unlimited_varchar" to "unlimited varcharZOEFOEZUFHHZELF", + "column_smallint" to 123, + "column_int" to 12355, + "column_serial" to 3282, + "column_float" to 123.2235, + "column_real" to 125125.13, + "column_numeric" to 312, + "column_date" to "2019-06-07", + "column_time" to "17:12:28", + "column_timestamp" to "2019-06-07 00:00:00.0", + "column_timestamptz" to "2019-06-07 00:00:00.0", + "column_interval" to "0 years 0 mons 100 days 0 hours 0 mins 0.00 secs", + "column_json" to JSONArray("[{\"key\": \"Hello World !\"}]"), + "column_jsonb" to JSONObject("{\"key\": \"Hello World !\"}") + ) ) ) ) @@ -92,11 +93,12 @@ class DbComparatorAssertTest { ] """.trimIndent() - val tableModel = TableModel() - tableModel.addRow( - RowModel( - mutableMapOf( - "content_test" to "abcde" + val tableModel = TableModel( + setOf( + RowModel( + mapOf( + "content_test" to "abcde" + ) ) ) ) diff --git a/jcv-db-core/src/test/kotlin/com/ekino/oss/jcv/db/util/JsonConverterTest.kt b/jcv-db-core/src/test/kotlin/com/ekino/oss/jcv/db/util/JsonConverterTest.kt index c8d46cb..ba13721 100644 --- a/jcv-db-core/src/test/kotlin/com/ekino/oss/jcv/db/util/JsonConverterTest.kt +++ b/jcv-db-core/src/test/kotlin/com/ekino/oss/jcv/db/util/JsonConverterTest.kt @@ -32,31 +32,32 @@ class JsonConverterTest { @Test fun `Should load file and return a json array`() { val expectedResult = JSONArray("""[{"id":1}]""") - val inputString = this::class.java.classLoader.getResourceAsStream("test-file.json")!!.bufferedReader().use(BufferedReader::readText) + val inputString = this::class.java.classLoader.getResourceAsStream("test-file.json")!!.bufferedReader() + .use(BufferedReader::readText) assertThat(formatInput(inputString).toString()).isEqualTo(expectedResult.toString()) } @Test fun `Should get an error when trying to load a json object`() { val expectedResult = JSONArray("""[{"id":1}]""") - val inputString = this::class.java.classLoader.getResourceAsStream("test-file-object.json")!!.bufferedReader().use(BufferedReader::readText) + val inputString = this::class.java.classLoader.getResourceAsStream("test-file-object.json")!!.bufferedReader() + .use(BufferedReader::readText) assertThat(formatInput(inputString).toString()).isEqualTo(expectedResult.toString()) } @Test fun `Should get an error when trying to load an invalid json`() { - val inputString = this::class.java.classLoader.getResourceAsStream("test-file-invalid.json")!!.bufferedReader().use(BufferedReader::readText) + val inputString = this::class.java.classLoader.getResourceAsStream("test-file-invalid.json")!!.bufferedReader() + .use(BufferedReader::readText) assertThat(formatInput(inputString)).isNull() } @Test fun `Should convert table model to Json Array with default mapper`() { val table = TableModel( - mutableSetOf( + setOf( RowModel( - mutableMapOf( - "id" to 1 - ) + mutableMapOf("id" to 1) ) ) ) @@ -66,11 +67,9 @@ class JsonConverterTest { @Test fun `Should convert table model to Json Array with custom mapper`() { val table = TableModel( - mutableSetOf( + setOf( RowModel( - mutableMapOf( - "id" to 1 - ) + mapOf("id" to 1) ) ) ) @@ -79,6 +78,8 @@ class JsonConverterTest { override fun getValueFromColumn(value: Any) = "$value CUSTOM" } - assertThat(table.getTableModelAsJson(CustomMapper()).toString()).isEqualTo(JSONArray("""[{ "id" : "1 CUSTOM" }]""").toString()) + assertThat( + table.getTableModelAsJson(CustomMapper()).toString() + ).isEqualTo(JSONArray("""[{ "id" : "1 CUSTOM" }]""").toString()) } } diff --git a/jcv-db-jdbc/src/main/kotlin/com/ekino/oss/jcv/db/jdbc/util/QueryConverter.kt b/jcv-db-jdbc/src/main/kotlin/com/ekino/oss/jcv/db/jdbc/util/QueryConverter.kt index b9d1205..b0675ed 100644 --- a/jcv-db-jdbc/src/main/kotlin/com/ekino/oss/jcv/db/jdbc/util/QueryConverter.kt +++ b/jcv-db-jdbc/src/main/kotlin/com/ekino/oss/jcv/db/jdbc/util/QueryConverter.kt @@ -35,12 +35,11 @@ class QueryConverter(private val connection: Connection) { private fun buildTableModel(resultSet: ResultSet): TableModel { val rows = mutableSetOf() while (resultSet.next()) { - val numberColumn = resultSet.metaData.columnCount - val cells = mutableMapOf() - for (index in 1..numberColumn) { - cells[resultSet.metaData.getColumnName(index)] = resultSet.getObject(index) + (1..resultSet.metaData.columnCount).associate { + resultSet.metaData.getColumnName(it) to resultSet.getObject(it) } - rows.add(RowModel(cells)) + .let(::RowModel) + .let(rows::add) } return TableModel(rows) } diff --git a/jcv-db-mongo/src/main/kotlin/com/ekino/oss/jcv/db/mongo/util/MongoConverter.kt b/jcv-db-mongo/src/main/kotlin/com/ekino/oss/jcv/db/mongo/util/MongoConverter.kt index c960461..77b408b 100644 --- a/jcv-db-mongo/src/main/kotlin/com/ekino/oss/jcv/db/mongo/util/MongoConverter.kt +++ b/jcv-db-mongo/src/main/kotlin/com/ekino/oss/jcv/db/mongo/util/MongoConverter.kt @@ -7,8 +7,9 @@ import org.bson.Document class MongoConverter { fun convertContentToTableModel(collection: List): TableModel { - return TableModel(collection.map { convertDocumentToRowModel(it) }.toMutableSet()) + return TableModel(collection.map(::convertDocumentToRowModel).toSet()) } - private fun convertDocumentToRowModel(document: Document) = RowModel(document.keys.map { it to document[it]!! }.toMap().toMutableMap()) + private fun convertDocumentToRowModel(document: Document) = + RowModel(document.keys.associateWith { document[it]!! }.toMap()) } From fb80f9b2b892ae865ac15765fa6ce25a38afce6d Mon Sep 17 00:00:00 2001 From: Lukas Cardot Date: Mon, 2 Sep 2024 18:04:12 -0400 Subject: [PATCH 2/2] close cassandra session upon query execution --- .../db/cassandra/util/DBComparatorBuilder.kt | 19 ++++++------------- .../jcv/db/cassandra/util/QueryConverter.kt | 14 +++++++------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/jcv-db-cassandra/src/main/kotlin/com/ekino/oss/jcv/db/cassandra/util/DBComparatorBuilder.kt b/jcv-db-cassandra/src/main/kotlin/com/ekino/oss/jcv/db/cassandra/util/DBComparatorBuilder.kt index eb235bf..9f1e469 100644 --- a/jcv-db-cassandra/src/main/kotlin/com/ekino/oss/jcv/db/cassandra/util/DBComparatorBuilder.kt +++ b/jcv-db-cassandra/src/main/kotlin/com/ekino/oss/jcv/db/cassandra/util/DBComparatorBuilder.kt @@ -7,20 +7,13 @@ import com.ekino.oss.jcv.db.cassandra.DbComparatorCassandra import com.ekino.oss.jcv.db.config.DBValidators import org.skyscreamer.jsonassert.JSONCompareMode -class DBComparatorBuilder { +class DBComparatorBuilder( + private var mode: JSONCompareMode, + private var validators: List> +) { - constructor() - - constructor( - mode: JSONCompareMode, - validators: List> - ) { - this.mode = mode - this.validators = validators - } - - private lateinit var mode: JSONCompareMode - private lateinit var validators: List> + // todo(any): this datasource should not be nullable. + // It is however required because a builder can be built without one. private var datasource: CassandraDataSource? = null private var customMapper: CassandraMapper? = null diff --git a/jcv-db-cassandra/src/main/kotlin/com/ekino/oss/jcv/db/cassandra/util/QueryConverter.kt b/jcv-db-cassandra/src/main/kotlin/com/ekino/oss/jcv/db/cassandra/util/QueryConverter.kt index f15159b..c2feccf 100644 --- a/jcv-db-cassandra/src/main/kotlin/com/ekino/oss/jcv/db/cassandra/util/QueryConverter.kt +++ b/jcv-db-cassandra/src/main/kotlin/com/ekino/oss/jcv/db/cassandra/util/QueryConverter.kt @@ -7,16 +7,16 @@ import com.ekino.oss.jcv.db.model.RowModel import com.ekino.oss.jcv.db.model.TableModel import java.net.InetSocketAddress -class QueryConverter(private val dataSource: CassandraDataSource? = null) { +class QueryConverter(private val dataSource: CassandraDataSource?) { fun fromQueryToTableModel(query: String): TableModel { - val session = buildCqlSession(dataSource) - - val resultSet = session.execute(query) - return fromResultSetToTableModel(resultSet) + return buildCqlSession().use { session -> + val resultSet = session.execute(query) + fromResultSetToTableModel(resultSet) + } } - private fun buildCqlSession(dataSource: CassandraDataSource? = null): CqlSession { - dataSource ?: throw DbAssertException("You have to defined a valida datource") + private fun buildCqlSession(): CqlSession { + dataSource ?: throw DbAssertException("You have to defined a valida datasource") val builder = CqlSession .builder()