Skip to content

Commit

Permalink
refactor: refactor unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
driessamyn committed Feb 25, 2025
1 parent 9094ece commit 3edd02f
Show file tree
Hide file tree
Showing 31 changed files with 850 additions and 904 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ tasks.named<Test>("test") {
systemProperties(
// Configuration parameters to execute classes in parallel but methods in same thread
"junit.jupiter.execution.parallel.enabled" to "true",
"junit.jupiter.execution.parallel.mode.default" to "concurrent",
"junit.jupiter.execution.parallel.mode.default" to "same_thread",
"junit.jupiter.execution.parallel.mode.classes.default" to "concurrent",
)
}
Expand Down Expand Up @@ -146,4 +146,4 @@ val dokkaHtmlJar by tasks.registering(Jar::class) {
description = "A HTML Documentation JAR containing Dokka HTML"
from(tasks.dokkaGeneratePublicationHtml.flatMap { it.outputDirectory })
archiveClassifier.set("html-doc")
}
}
4 changes: 4 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ dependencies {

testImplementation(libs.mockito)
testImplementation(libs.bundles.test)
testRuntimeOnly(libs.slf4j.simple)
testRuntimeOnly("org.junit.platform:junit-platform-launcher")

integrationTestImplementation(libs.bundles.test)
integrationTestImplementation(libs.bundles.test.containers)
integrationTestImplementation(libs.bundles.test.dbs)
integrationTestRuntimeOnly(libs.slf4j.simple)
integrationTestRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
3 changes: 3 additions & 0 deletions core/src/main/kotlin/net/samyn/kapper/Exceptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ class KapperParseException(message: String, cause: Throwable? = null) :

class KapperResultException(message: String, cause: Throwable? = null) :
RuntimeException(message, cause)

class KapperQueryException(message: String, cause: Throwable? = null) :
RuntimeException(message, cause)
98 changes: 15 additions & 83 deletions core/src/main/kotlin/net/samyn/kapper/Kapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package net.samyn.kapper

import net.samyn.kapper.internal.KapperImpl
import net.samyn.kapper.internal.Mapper
import net.samyn.kapper.internal.logger
import java.sql.Connection
import java.sql.ResultSet

Expand All @@ -13,8 +14,21 @@ typealias Args = Map<String, Any?>
*/
interface Kapper {
companion object {
/**
* Create a new instance of the Kapper.
*
* @return A new instance of [Kapper].
*/
@JvmStatic
fun getInstance(): Kapper = KapperImpl()
fun createInstance(): Kapper = KapperImpl()

/**
* Singleton instance of the Kapper.
*/
@JvmStatic
val instance: Kapper by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
createInstance()
}.also { logger.info("Kapper instance created") }
}

/**
Expand Down Expand Up @@ -51,74 +65,6 @@ interface Kapper {
args: Args,
): List<T>

/**
* Execute a SQL query and map the results to a list of instances of the specified class.
*
* @param clazz The class to map the results to.
* @param connection The SQL connection to use.
* @param sql The SQL query to execute.
* @param args Optional parameters to be substituted in the SQL query during execution. Parameter substitution is based on the HashMap keys.
* @return The query result as a list of [T] instances.
*/
fun <T : Any> query(
clazz: Class<T>,
connection: Connection,
sql: String,
args: HashMap<String, Any?>,
): List<T> = query(clazz, connection, sql, args.toMap())

/**
* Execute a SQL query and map the results to a list of instances of the specified class.
*
* @param clazz The class to map the results to.
* @param connection The SQL connection to use.
* @param sql The SQL query to execute.
* @param mapper Optional mapping function to map the [ResultSet] to the target class.
* @param args Optional parameters to be substituted in the SQL query during execution. Parameter substitution is based on the HashMap keys.
* @return The query result as a list of [T] instances.
*/
fun <T : Any> query(
clazz: Class<T>,
connection: Connection,
sql: String,
mapper: (ResultSet, Map<String, Field>) -> T,
args: HashMap<String, Any?>,
): List<T> = query(clazz, connection, sql, mapper, args.toMap())

/**
* Execute a SQL query and map the result to a single instance of the specified class, or null if no results are found.
*
* @param clazz The class to map the result to.
* @param connection The SQL connection to use.
* @param sql The SQL query to execute.
* @param args Optional parameters to be substituted in the SQL query during execution. Parameter substitution is based on the HashMap keys.
* @return Returns a single result or `null` if no results are found. Throws an exception if more than one result is present.
*/
fun <T : Any> querySingle(
clazz: Class<T>,
connection: Connection,
sql: String,
args: HashMap<String, Any?>,
): T? = querySingle(clazz, connection, sql, args.toMap())

/**
* Execute a SQL query and map the result to a single instance of the specified class, or null of no results found.
*
* @param clazz The class to map the result to.
* @param connection The SQL connection to use.
* @param sql The SQL query to execute.
* @param mapper Optional mapping function to map the [ResultSet] to the target class.
* @param args Optional parameters to be substituted in the SQL query during execution. Parameter substitution is based on the HashMap keys.
* @return Returns a single result or `null` if no results are found. Throws an exception if more than one result is present.
*/
fun <T : Any> querySingle(
clazz: Class<T>,
connection: Connection,
sql: String,
mapper: (ResultSet, Map<String, Field>) -> T,
args: HashMap<String, Any?>,
): T? = querySingle(clazz, connection, sql, mapper, args.toMap())

/**
* Execute a SQL query and map the result to a single instance of the specified class, or null of no results found.
*
Expand Down Expand Up @@ -153,20 +99,6 @@ interface Kapper {
args: Args,
): T?

/**
* Execute a SQL statement that does not return a result set.
*
* @param connection The SQL connection to use.
* @param sql The SQL statement to execute.
* @param args Optional parameters to be substituted in the SQL statement. Parameter substitution is based on the HashMap keys.
* @return The number of rows affected by the statement.
*/
fun execute(
connection: Connection,
sql: String,
args: HashMap<String, Any?>,
): Int

/**
* Execute a SQL statement that does not return a result set.
*
Expand Down
10 changes: 0 additions & 10 deletions core/src/main/kotlin/net/samyn/kapper/KapperInstance.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ fun Connection.execute(
sql: String,
vararg args: Pair<String, Any?>,
): Int {
return KapperInstance.get().execute(this, sql, args.toMap())
return Kapper.instance.execute(this, sql, args.toMap())
}
4 changes: 2 additions & 2 deletions core/src/main/kotlin/net/samyn/kapper/KapperKotlinQueryFun.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ fun <T : Any> Connection.query(
clazz: KClass<T>,
sql: String,
vararg args: Pair<String, Any?>,
): List<T> = KapperInstance.get().query(clazz.java, this, sql, args.toMap())
): List<T> = Kapper.instance.query(clazz.java, this, sql, args.toMap())

/**
* Execute a SQL query and map the results to a list of instances of the specified class with a custom mapper.
Expand All @@ -97,4 +97,4 @@ fun <T : Any> Connection.query(
sql: String,
mapper: (ResultSet, Map<String, Field>) -> T,
args: Map<String, Any?>,
): List<T> = KapperInstance.get().query(clazz.java, this, sql, mapper, args)
): List<T> = Kapper.instance.query(clazz.java, this, sql, mapper, args)
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ fun <T : Any> Connection.querySingle(
clazz: KClass<T>,
sql: String,
vararg args: Pair<String, Any?>,
): T? = KapperInstance.get().querySingle(clazz.java, this, sql, args.toMap())
): T? = Kapper.instance.querySingle(clazz.java, this, sql, args.toMap())

/**
* Execute a SQL query and map the result to a single instance of the specified class, or null of no results found.
Expand All @@ -105,4 +105,4 @@ fun <T : Any> Connection.querySingle(
sql: String,
mapper: (ResultSet, Map<String, Field>) -> T,
vararg args: Pair<String, Any?>,
): T? = KapperInstance.get().querySingle(clazz.java, this, sql, mapper, args.toMap())
): T? = Kapper.instance.querySingle(clazz.java, this, sql, mapper, args.toMap())
2 changes: 1 addition & 1 deletion core/src/main/kotlin/net/samyn/kapper/internal/ArgsFun.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import java.sql.PreparedStatement
internal fun Args.setParameters(
query: Query,
stmt: PreparedStatement,
dbFlavour: DbConnectionUtils.DbFlavour,
dbFlavour: DbFlavour,
) {
this.forEach { a ->
val indexes =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ internal class AutoConverter(
value: Any,
target: KClass<*>,
): Any =
// Kover considers this not covered, which I think is a bug. Will reproduce in separate project and raise issue.
// Kover considers this not covered, which I think is a bug.
// https://github.com/Kotlin/kotlinx-kover/issues/729
converters[target]?.invoke(value) ?: throw KapperUnsupportedOperationException(
"Cannot auto-convert from ${value.javaClass} to ${target.qualifiedName}",
)
Expand Down

This file was deleted.

22 changes: 22 additions & 0 deletions core/src/main/kotlin/net/samyn/kapper/internal/DbFlavour.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@file:JvmSynthetic

package net.samyn.kapper.internal

import java.sql.Connection

fun Connection.getDbFlavour(): DbFlavour {
val productName = this.metaData.databaseProductName.lowercase()
return if (productName.contains("postgres") || productName.contains("enterprisedb")) {
DbFlavour.POSTGRESQL
} else if (productName.contains("mysql")) {
DbFlavour.MYSQL
} else {
DbFlavour.UNKNOWN
}
}

enum class DbFlavour {
POSTGRESQL,
MYSQL,
UNKNOWN,
}
23 changes: 8 additions & 15 deletions core/src/main/kotlin/net/samyn/kapper/internal/KapperImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ import net.samyn.kapper.Args
import net.samyn.kapper.Field
import net.samyn.kapper.Kapper
import net.samyn.kapper.KapperResultException
import net.samyn.kapper.internal.DbConnectionUtils.getDbFlavour
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.sql.Connection
import java.sql.ResultSet

internal class KapperImpl(
private val queryBuilder: (String) -> Query = { Query(it) },
private val queryFactory: (String) -> Query = { Query(it) },
) : Kapper {
companion object {
private val logger: Logger = LoggerFactory.getLogger(this::class.java)
Expand All @@ -26,14 +25,14 @@ internal class KapperImpl(
mapper: (ResultSet, Map<String, Field>) -> T,
args: Args,
): List<T> {
val results = mutableListOf<T>()
connection.executeQuery(sql, args).use { rs ->
val fields = rs.extractFields()
while (rs.next()) {
results.add(mapper(rs, fields))
return buildList {
connection.executeQuery(queryFactory(sql), args).use { rs ->
val fields = rs.extractFields()
while (rs.next()) {
add(mapper(rs, fields))
}
}
}
return results
}

override fun <T : Any> querySingle(
Expand All @@ -59,19 +58,13 @@ internal class KapperImpl(
return results.firstOrNull()
}

override fun execute(
connection: Connection,
sql: String,
args: HashMap<String, Any?>,
): Int = execute(connection, sql, args.toMap())

override fun execute(
connection: Connection,
sql: String,
args: Args,
): Int {
// TODO: cache query
val query = queryBuilder(sql)
val query = queryFactory(sql)
connection.prepareStatement(query.sql).use { stmt ->
args.setParameters(query, stmt, connection.getDbFlavour())
logger.debug("Executing prepared statement: {}", stmt)
Expand Down
Loading

0 comments on commit 3edd02f

Please sign in to comment.