diff --git a/README.md b/README.md
index 8f644ac3..0eee53ab 100644
--- a/README.md
+++ b/README.md
@@ -39,14 +39,14 @@ For docs and info see the [wiki](https://github.com/jasync-sql/jasync-sql/wiki).
com.github.jasync-sql
jasync-mysql
- 2.2.0
+ 2.2.4
com.github.jasync-sql
jasync-postgresql
- 2.2.0
+ 2.2.4
```
@@ -56,9 +56,9 @@ For docs and info see the [wiki](https://github.com/jasync-sql/jasync-sql/wiki).
```gradle
dependencies {
// mysql
- compile 'com.github.jasync-sql:jasync-mysql:2.2.0'
+ compile 'com.github.jasync-sql:jasync-mysql:2.2.4'
// postgresql
- compile 'com.github.jasync-sql:jasync-postgresql:2.2.0'
+ compile 'com.github.jasync-sql:jasync-postgresql:2.2.4'
}
```
diff --git a/build.gradle.kts b/build.gradle.kts
index eba2e35a..19635393 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -24,7 +24,7 @@ apply(plugin = "io.github.gradle-nexus.publish-plugin")
allprojects {
group = "com.github.jasync-sql"
- version = "2.2.4"
+ version = "2.2.5"
apply(plugin = "kotlin")
apply(plugin = "maven-publish")
diff --git a/db-async-common/src/main/java/com/github/jasync/sql/db/exceptions/InsufficientParametersException.kt b/db-async-common/src/main/java/com/github/jasync/sql/db/exceptions/InsufficientParametersException.kt
index ea290f1e..5acb9370 100644
--- a/db-async-common/src/main/java/com/github/jasync/sql/db/exceptions/InsufficientParametersException.kt
+++ b/db-async-common/src/main/java/com/github/jasync/sql/db/exceptions/InsufficientParametersException.kt
@@ -10,10 +10,11 @@ package com.github.jasync.sql.db.exceptions
* @param given the collection given
*/
@Suppress("RedundantVisibilityModifier")
-public class InsufficientParametersException(expected: Int, given: List) : DatabaseException(
- "The query contains %s parameters but you gave it %s (%s)".format(
+public class InsufficientParametersException(query: String, expected: Int, given: List) : DatabaseException(
+ "The query contains %s parameters but you gave it %s (%s):${System.lineSeparator()}%s".format(
expected,
given.size,
- given.joinToString(",")
+ given.joinToString(","),
+ query
)
)
diff --git a/mysql-async/src/main/java/com/github/jasync/sql/db/mysql/MySQLConnection.kt b/mysql-async/src/main/java/com/github/jasync/sql/db/mysql/MySQLConnection.kt
index cae6ca6c..2591acf1 100644
--- a/mysql-async/src/main/java/com/github/jasync/sql/db/mysql/MySQLConnection.kt
+++ b/mysql-async/src/main/java/com/github/jasync/sql/db/mysql/MySQLConnection.kt
@@ -468,7 +468,7 @@ class MySQLConnection @JvmOverloads constructor(
this.validateIsReadyForQuery()
val totalParameters = params.query.count { it == '?' }
if (params.values.length != totalParameters) {
- throw InsufficientParametersException(totalParameters, params.values)
+ throw InsufficientParametersException(params.query, totalParameters, params.values)
}
val promise = CompletableFuture()
this.setQueryPromise(promise)
diff --git a/mysql-async/src/test/java/com/github/jasync/sql/db/mysql/QuerySpec.kt b/mysql-async/src/test/java/com/github/jasync/sql/db/mysql/QuerySpec.kt
index fe88a836..34c40f47 100644
--- a/mysql-async/src/test/java/com/github/jasync/sql/db/mysql/QuerySpec.kt
+++ b/mysql-async/src/test/java/com/github/jasync/sql/db/mysql/QuerySpec.kt
@@ -239,10 +239,11 @@ class QuerySpec : ConnectionHelper() {
@Test
fun `connection should fail if number of args required is different than the number of provided parameters`() {
withConnection { connection ->
- verifyException(InsufficientParametersException::class.java) {
+ val query = "select * from some_table where c = ? and b = ?"
+ verifyException(InsufficientParametersException::class.java, containedInMessage = query) {
executePreparedStatement(
connection,
- "select * from some_table where c = ? and b = ?",
+ query,
listOf("one", "two", "three")
)
}
diff --git a/mysql-async/src/test/java/com/github/jasync/sql/db/mysql/Utils.kt b/mysql-async/src/test/java/com/github/jasync/sql/db/mysql/Utils.kt
index a24a4ed5..2e991788 100644
--- a/mysql-async/src/test/java/com/github/jasync/sql/db/mysql/Utils.kt
+++ b/mysql-async/src/test/java/com/github/jasync/sql/db/mysql/Utils.kt
@@ -5,6 +5,7 @@ import org.assertj.core.api.Assertions
fun verifyException(
exType: Class,
causeType: Class? = null,
+ containedInMessage: String? = null,
body: () -> Unit
): Throwable {
try {
@@ -13,6 +14,7 @@ fun verifyException(
} catch (e: Exception) {
// e.printStackTrace()
Assertions.assertThat(e::class.java).isEqualTo(exType)
+ containedInMessage?.let { Assertions.assertThat(e.message).contains(it) }
causeType?.let { Assertions.assertThat(e.cause!!::class.java).isEqualTo(it) }
return e.cause ?: e
}
diff --git a/postgresql-async/src/main/java/com/github/jasync/sql/db/postgresql/PostgreSQLConnection.kt b/postgresql-async/src/main/java/com/github/jasync/sql/db/postgresql/PostgreSQLConnection.kt
index 81ba5e56..b7145eb6 100644
--- a/postgresql-async/src/main/java/com/github/jasync/sql/db/postgresql/PostgreSQLConnection.kt
+++ b/postgresql-async/src/main/java/com/github/jasync/sql/db/postgresql/PostgreSQLConnection.kt
@@ -190,7 +190,7 @@ class PostgreSQLConnection @JvmOverloads constructor(
if (holder.paramsCount != params.values.length) {
this.clearQueryPromise()
- throw InsufficientParametersException(holder.paramsCount, params.values)
+ throw InsufficientParametersException(params.query, holder.paramsCount, params.values)
}
this.currentPreparedStatement = Optional.of(holder)
diff --git a/postgresql-async/src/test/java/com/github/aysnc/sql/db/Utils.kt b/postgresql-async/src/test/java/com/github/aysnc/sql/db/Utils.kt
index bc7d16d6..cafea1ba 100644
--- a/postgresql-async/src/test/java/com/github/aysnc/sql/db/Utils.kt
+++ b/postgresql-async/src/test/java/com/github/aysnc/sql/db/Utils.kt
@@ -5,6 +5,7 @@ import org.assertj.core.api.Assertions
fun verifyException(
exType: Class,
causeType: Class? = null,
+ containedInMessage: String? = null,
body: () -> Unit
): Throwable {
try {
@@ -12,6 +13,7 @@ fun verifyException(
throw Exception("Expected exception was not thrown: ${exType.simpleName}->${causeType?.simpleName}")
} catch (e: Exception) {
Assertions.assertThat(e::class.java).isEqualTo(exType)
+ containedInMessage?.let { Assertions.assertThat(e.message).contains(it) }
causeType?.let { Assertions.assertThat(e.cause!!::class.java).isEqualTo(it) }
return e.cause ?: e
}
diff --git a/postgresql-async/src/test/java/com/github/aysnc/sql/db/integration/PreparedStatementSpec.kt b/postgresql-async/src/test/java/com/github/aysnc/sql/db/integration/PreparedStatementSpec.kt
index 97339a07..051b6933 100644
--- a/postgresql-async/src/test/java/com/github/aysnc/sql/db/integration/PreparedStatementSpec.kt
+++ b/postgresql-async/src/test/java/com/github/aysnc/sql/db/integration/PreparedStatementSpec.kt
@@ -77,7 +77,7 @@ class PreparedStatementSpec : DatabaseTestHelper() {
fun `prepared statements should raise an exception if the parameter count is different from the given parameters count`() {
withHandler { handler ->
executeDdl(handler, this.messagesCreate)
- verifyException(InsufficientParametersException::class.java) {
+ verifyException(InsufficientParametersException::class.java, containedInMessage = this.messagesSelectOne) {
executePreparedStatement(handler, this.messagesSelectOne)
}
}
@@ -268,9 +268,10 @@ class PreparedStatementSpec : DatabaseTestHelper() {
fun `prepared statements should fail if prepared statement has more variables than it was given`() {
withHandler { handler ->
executeDdl(handler, messagesCreate)
- verifyException(InsufficientParametersException::class.java) {
+ val query = "SELECT * FROM messages WHERE content = ? AND moment = ?"
+ verifyException(InsufficientParametersException::class.java, containedInMessage = query) {
handler.sendPreparedStatement(
- "SELECT * FROM messages WHERE content = ? AND moment = ?",
+ query,
listOf("some content")
)
}
diff --git a/r2dbc-mysql/src/main/java/JasyncClientConnection.kt b/r2dbc-mysql/src/main/java/JasyncClientConnection.kt
index 456d6d99..901821e5 100644
--- a/r2dbc-mysql/src/main/java/JasyncClientConnection.kt
+++ b/r2dbc-mysql/src/main/java/JasyncClientConnection.kt
@@ -43,8 +43,6 @@ class JasyncClientConnection(
override fun beginTransaction(definition: TransactionDefinition): Publisher {
return Mono.defer {
- val setAutoCommit = Mono.from(setAutoCommit(false))
-
val setLockWaitTimeout = Mono.justOrEmpty(definition.getAttribute(TransactionDefinition.LOCK_WAIT_TIMEOUT))
.flatMap { timeout -> Mono.from(setLockWaitTimeout(timeout)) }
@@ -53,8 +51,7 @@ class JasyncClientConnection(
val startTransaction = Mono.from(beginTransaction())
- return@defer Mono.from(setAutoCommit)
- .then(setLockWaitTimeout)
+ return@defer Mono.from(setLockWaitTimeout)
.then(changeIsolationLevel)
.then(startTransaction)
.then()
diff --git a/r2dbc-mysql/src/main/java/JasyncRow.kt b/r2dbc-mysql/src/main/java/JasyncRow.kt
index d272c9c0..ba74c74a 100644
--- a/r2dbc-mysql/src/main/java/JasyncRow.kt
+++ b/r2dbc-mysql/src/main/java/JasyncRow.kt
@@ -30,6 +30,14 @@ class JasyncRow(private val rowData: RowData, private val metadata: JasyncMetada
return when {
requestedType == Object::class.java -> value
requestedType == String::class.java -> value?.toString()
+ requestedType == java.lang.Boolean::class.java -> {
+ when (value) {
+ is Number -> value.toInt() != 0
+ is String -> value.toBoolean()
+ is Boolean -> value
+ else -> throw IllegalStateException("Cannot convert ${value?.javaClass?.simpleName} to Boolean")
+ }
+ }
value is Number -> {
when (requestedType) {
java.lang.Long::class.java -> value.toLong()
@@ -54,6 +62,12 @@ class JasyncRow(private val rowData: RowData, private val metadata: JasyncMetada
else -> throw IllegalStateException("unmatched requested type ${requestedType.simpleName}")
}
}
+ value is Boolean && requestedType.isPrimitive -> {
+ when (requestedType.name) {
+ "boolean" -> value
+ else -> throw IllegalStateException("Cannot convert Boolean to ${requestedType.name}")
+ }
+ }
value is LocalDateTime -> {
when (requestedType) {
LocalDate::class.java -> value.toLocalDate()
diff --git a/r2dbc-mysql/src/main/java/MysqlConnectionFactoryProvider.kt b/r2dbc-mysql/src/main/java/MysqlConnectionFactoryProvider.kt
index 38ea337c..67f3a07f 100644
--- a/r2dbc-mysql/src/main/java/MysqlConnectionFactoryProvider.kt
+++ b/r2dbc-mysql/src/main/java/MysqlConnectionFactoryProvider.kt
@@ -77,8 +77,8 @@ class MysqlConnectionFactoryProvider : ConnectionFactoryProvider {
password = connectionFactoryOptions.getValue(PASSWORD)?.toString(),
database = connectionFactoryOptions.getValue(DATABASE) as String?,
applicationName = connectionFactoryOptions.getValue(APPLICATION_NAME) as String?,
- connectionTimeout = (connectionFactoryOptions.getValue(CONNECT_TIMEOUT) as Duration?)?.toMillis()?.toInt() ?: 5000,
- queryTimeout = connectionFactoryOptions.getValue(STATEMENT_TIMEOUT) as Duration?,
+ connectionTimeout = connectionFactoryOptions.getValue(CONNECT_TIMEOUT)?.parseDuration()?.toMillis()?.toInt() ?: 5000,
+ queryTimeout = connectionFactoryOptions.getValue(STATEMENT_TIMEOUT)?.parseDuration(),
ssl = MysqlSSLConfigurationFactory.create(connectionFactoryOptions),
rsaPublicKey = (connectionFactoryOptions.getValue(SERVER_RSA_PUBLIC_KEY_FILE) as String?)?.let { Paths.get(it) }
)
@@ -97,3 +97,15 @@ class MysqlConnectionFactoryProvider : ConnectionFactoryProvider {
override fun getDriver(): String = MYSQL_DRIVER
}
+
+private fun Any.parseDuration(): Duration {
+ return when (this) {
+ is Duration -> {
+ this
+ }
+ is String -> {
+ Duration.parse(this)
+ }
+ else -> throw Exception("cant parse $this to Duration")
+ }
+}
diff --git a/r2dbc-mysql/src/test/java/com/github/jasync/r2dbc/mysql/JasyncRowTest.kt b/r2dbc-mysql/src/test/java/com/github/jasync/r2dbc/mysql/JasyncRowTest.kt
new file mode 100644
index 00000000..44ecad31
--- /dev/null
+++ b/r2dbc-mysql/src/test/java/com/github/jasync/r2dbc/mysql/JasyncRowTest.kt
@@ -0,0 +1,55 @@
+package com.github.jasync.r2dbc.mysql
+
+import com.github.jasync.sql.db.RowData
+import io.mockk.every
+import io.mockk.mockk
+import org.junit.Test
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+
+/**
+ * Unit tests for [JasyncRow].
+ */
+internal class JasyncRowTest {
+
+ @Test
+ fun testBooleanConversion() {
+ // Mock dependencies
+ val rowData = mockk()
+ val metadata = mockk()
+
+ // Setup mock values for different types of data
+ every { rowData["boolTrue"] } returns true
+ every { rowData["boolFalse"] } returns false
+ every { rowData["numZero"] } returns 0
+ every { rowData["numOne"] } returns 1
+ every { rowData["stringTrue"] } returns "true"
+ every { rowData["stringFalse"] } returns "false"
+ every { rowData[0] } returns true
+ every { rowData[1] } returns 0
+ every { rowData[2] } returns "true"
+
+ val row = JasyncRow(rowData, metadata)
+
+ // Test conversion from Boolean to Boolean
+ assertTrue(row.get("boolTrue", java.lang.Boolean::class.java) as Boolean)
+ assertFalse(row.get("boolFalse", java.lang.Boolean::class.java) as Boolean)
+
+ // Test conversion from Number to Boolean
+ assertFalse(row.get("numZero", java.lang.Boolean::class.java) as Boolean)
+ assertTrue(row.get("numOne", java.lang.Boolean::class.java) as Boolean)
+
+ // Test conversion from String to Boolean
+ assertTrue(row.get("stringTrue", java.lang.Boolean::class.java) as Boolean)
+ assertFalse(row.get("stringFalse", java.lang.Boolean::class.java) as Boolean)
+
+ // Test conversion from various types using index
+ assertTrue(row.get(0, java.lang.Boolean::class.java) as Boolean)
+ assertFalse(row.get(1, java.lang.Boolean::class.java) as Boolean)
+ assertTrue(row.get(2, java.lang.Boolean::class.java) as Boolean)
+
+ // Test conversion to primitive boolean - using Boolean class in Kotlin
+ assertTrue(row.get("boolTrue", java.lang.Boolean::class.java) as Boolean)
+ assertFalse(row.get("boolFalse", java.lang.Boolean::class.java) as Boolean)
+ }
+}
diff --git a/r2dbc-mysql/src/test/java/com/github/jasync/r2dbc/mysql/MysqlConnectionFactoryProviderTest.kt b/r2dbc-mysql/src/test/java/com/github/jasync/r2dbc/mysql/MysqlConnectionFactoryProviderTest.kt
index 24edfcf5..63753f6a 100644
--- a/r2dbc-mysql/src/test/java/com/github/jasync/r2dbc/mysql/MysqlConnectionFactoryProviderTest.kt
+++ b/r2dbc-mysql/src/test/java/com/github/jasync/r2dbc/mysql/MysqlConnectionFactoryProviderTest.kt
@@ -4,6 +4,7 @@ import com.github.jasync.sql.db.SSLConfiguration
import io.r2dbc.spi.ConnectionFactoryOptions
import org.junit.Assert.assertEquals
import org.junit.Test
+import java.time.Duration
class MysqlConnectionFactoryProviderTest {
@@ -63,4 +64,15 @@ class MysqlConnectionFactoryProviderTest {
// then
assertEquals("rsa.pem", result.mySQLConnectionFactory.configuration.rsaPublicKey.toString())
}
+
+ @Test
+ fun shouldUseTimeoutAsString() {
+ val options = ConnectionFactoryOptions.parse("r2dbc:mysql://user@host/db?connectTimeout=PT3S")
+
+ // when
+ val result = provider.create(options)
+
+ // then
+ assertEquals(Duration.parse("PT3S").toMillis().toInt(), result.mySQLConnectionFactory.configuration.connectionTimeout)
+ }
}
diff --git a/samples/spring-kotlin/README.md b/samples/spring-kotlin/README.md
index d3339887..a599471a 100644
--- a/samples/spring-kotlin/README.md
+++ b/samples/spring-kotlin/README.md
@@ -1,2 +1,2 @@
# spring-kotlin-jasync-sql
-reactive applcation base on Spring + Kotlin + [Jasync-sql](https://github.com/jasync-sql/jasync-sql)
+reactive application base on Spring + Kotlin + [Jasync-sql](https://github.com/jasync-sql/jasync-sql)
diff --git a/samples/spring-kotlin/build.gradle.kts b/samples/spring-kotlin/build.gradle.kts
index 365ca879..852c3b94 100644
--- a/samples/spring-kotlin/build.gradle.kts
+++ b/samples/spring-kotlin/build.gradle.kts
@@ -5,25 +5,30 @@ version = "1.0-SNAPSHOT"
plugins {
application
- kotlin("jvm") version "1.6.10"
- kotlin("plugin.spring") version "1.6.10"
- id("org.springframework.boot") version "2.6.3"
+ kotlin("jvm") version "1.9.25"
+ kotlin("plugin.spring") version "1.9.25"
+ id("org.springframework.boot") version "3.3.4"
+ id("io.spring.dependency-management") version "1.1.6"
}
-apply(plugin = "io.spring.dependency-management")
+java {
+ sourceCompatibility = JavaVersion.VERSION_17
+
+ toolchain {
+ languageVersion.set(JavaLanguageVersion.of(17))
+ }
+}
repositories {
mavenCentral()
}
dependencies {
- implementation(kotlin("stdlib-jdk8"))
- implementation(kotlin("reflect"))
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")
implementation("org.springframework.boot:spring-boot-starter-webflux")
testImplementation("org.springframework.boot:spring-boot-starter-test")
- runtimeOnly("com.github.jasync-sql:jasync-r2dbc-mysql:2.0.6")
+ runtimeOnly("com.github.jasync-sql:jasync-r2dbc-mysql:2.2.4")
}
tasks.test {
@@ -32,7 +37,6 @@ tasks.test {
tasks.withType {
kotlinOptions {
- jvmTarget = "1.8"
+ jvmTarget = "17"
}
}
-
diff --git a/samples/spring-kotlin/gradle/wrapper/gradle-wrapper.properties b/samples/spring-kotlin/gradle/wrapper/gradle-wrapper.properties
index cc321e65..d26953ab 100644
--- a/samples/spring-kotlin/gradle/wrapper/gradle-wrapper.properties
+++ b/samples/spring-kotlin/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
diff --git a/samples/spring-kotlin/src/main/resources/schema.sql b/samples/spring-kotlin/src/main/resources/schema.sql
new file mode 100644
index 00000000..109fd860
--- /dev/null
+++ b/samples/spring-kotlin/src/main/resources/schema.sql
@@ -0,0 +1,8 @@
+CREATE TABLE IF NOT EXISTS `user` (
+ `username` VARCHAR(20) NOT NULL,
+ `password` VARCHAR(100) NULL,
+ PRIMARY KEY (`username`)
+);
+
+INSERT INTO `user` (username, password) VALUES ('Bob', 'password1');
+INSERT INTO `user` (username, password) VALUES ('Alice', 'password2');