From 6e9175d84f5077228789d57d97c2d4ed5b9463ff Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Sat, 17 Jul 2021 18:51:28 +0200 Subject: [PATCH] create Exception QueryError test select paginated without total --- .../fr/postgresjson/connexion/Connection.kt | 56 +++++++++++++++++-- .../kotlin/fr/postgresjson/ConnectionTest.kt | 53 ++++++++++++++++++ 2 files changed, 104 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/fr/postgresjson/connexion/Connection.kt b/src/main/kotlin/fr/postgresjson/connexion/Connection.kt index f04118d..fdb4bb1 100644 --- a/src/main/kotlin/fr/postgresjson/connexion/Connection.kt +++ b/src/main/kotlin/fr/postgresjson/connexion/Connection.kt @@ -3,6 +3,8 @@ package fr.postgresjson.connexion import com.fasterxml.jackson.core.type.TypeReference import com.github.jasync.sql.db.Connection import com.github.jasync.sql.db.QueryResult +import com.github.jasync.sql.db.ResultSet +import com.github.jasync.sql.db.general.ArrayRowData import com.github.jasync.sql.db.pool.ConnectionPool import com.github.jasync.sql.db.postgresql.PostgreSQLConnection import com.github.jasync.sql.db.postgresql.PostgreSQLConnectionBuilder @@ -12,6 +14,7 @@ import fr.postgresjson.entity.Serializable import fr.postgresjson.serializer.Serializer import fr.postgresjson.utils.LoggerDelegate import org.slf4j.Logger +import java.lang.ClassCastException import java.util.concurrent.CompletableFuture typealias SelectOneCallback = QueryResult.(T?) -> Unit @@ -142,8 +145,15 @@ class Connection( } return line.run { - val json = rows[0].getString(0) - val entities = if (json === null) { + val firstLine = rows.firstOrNull() ?: queryError("The query has no return", sql, newValues) + if (!(firstLine as ArrayRowData).mapping.keys.contains("total")) queryError("""The query not return the "total" column""", sql, newValues, rows) + val total = try { + firstLine.getInt("total") ?: queryError("The query return \"total\" must not be null", sql, newValues, rows) + } catch (e: ClassCastException) { + queryError("""Column "total" must be an integer""", sql, newValues, rows) + } + val json = firstLine.getString(0) + val entities = if (json == null) { listOf() as List } else { serializer.deserializeList(json, typeReference) @@ -152,7 +162,7 @@ class Connection( entities, offset, limit, - rows[0].getInt("total") ?: error("The query not return total") + total ) }.also { block(line, it) @@ -201,7 +211,7 @@ class Connection( val paramRegex = "(? val name = match.groups[1]!!.value - values[name] ?: values[name.trimStart('_')] ?: error("Parameter $name missing") + values[name] ?: values[name.trimStart('_')] ?: queryError("Parameter $name missing", sql, values) }.toList() var newSql = sql @@ -218,7 +228,7 @@ class Connection( var i = 0 if (values.isNotEmpty()) { val newSql = paramRegex.replace(sql) { - values[i] ?: error("Parameter $i missing") + values[i] ?: queryError("Parameter $i missing", sql, values) val valToReplace = values[i].toString() ++i "'$valToReplace'" @@ -266,4 +276,40 @@ class Connection( throw e } } + + class QueryError(msg: String) : Exception(msg) + + private fun queryError( + msg: String, + sql: String, + parameters: List, + result: ResultSet? = null + ): Nothing = throw QueryError( + """ + |$msg + | + |${parameters.joinToString(", ") { it.toString() }.prependIndent(" > ")} + |${sql.prependIndent(" > ")} + |${result?.let { "-----" }?.prependIndent(" > ")} + |${result?.columnNames()?.joinToString(" | ")?.prependIndent(" > ")} + |${result?.map { it.joinToString(" | ") }?.joinToString("\n")?.prependIndent(" > ")} + """.trimMargin().trim(' ', '\n') + ) + + private fun queryError( + msg: String, + sql: String, + parameters: Map, + result: ResultSet? = null + ): Nothing = throw QueryError( + """ + |$msg + | + |${parameters.map { it.key + ": " + it.value }.joinToString(", ").prependIndent(" > ")} + |${sql.prependIndent(" > ")} + |${result?.let { "-----" }?.prependIndent(" > ")} + |${result?.columnNames()?.joinToString(" | ")?.prependIndent(" > ")} + |${result?.map { it.joinToString(" | ") }?.joinToString("\n")?.prependIndent(" > ")} + """.trimMargin().trim(' ') + ) } diff --git a/src/test/kotlin/fr/postgresjson/ConnectionTest.kt b/src/test/kotlin/fr/postgresjson/ConnectionTest.kt index 887cba6..817d402 100644 --- a/src/test/kotlin/fr/postgresjson/ConnectionTest.kt +++ b/src/test/kotlin/fr/postgresjson/ConnectionTest.kt @@ -1,6 +1,7 @@ package fr.postgresjson import com.fasterxml.jackson.core.type.TypeReference +import fr.postgresjson.connexion.Connection.QueryError import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.select import fr.postgresjson.connexion.selectOne @@ -14,6 +15,7 @@ import org.junit.Assert.assertTrue import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.assertThrows import java.util.UUID import kotlin.test.assertNull @@ -197,6 +199,57 @@ class ConnectionTest : TestAbstract() { assertEquals(result.offset, 0) } + @Test + fun `test select paginated without result`() { + val result: Paginated = connection.select( + """ + SELECT null, + 10 as total + LIMIT :limit + OFFSET :offset + """.trimIndent(), + 1, + 2, + object : TypeReference>() {} + ) + assertNotNull(result) + assertTrue(result.result.isEmpty()) + assertEquals(0, result.result.size) + assertEquals(result.total, 10) + assertEquals(result.offset, 0) + } + + @Test + fun `test select paginated without total`() { + val exception = assertThrows { + val result: Paginated = connection.select( + """ + SELECT null + LIMIT :limit + OFFSET :offset + """.trimIndent(), + 1, + 2, + object : TypeReference>() {} + ) + } + + assertEquals( + """ + |The query not return the "total" column + | + | > offset: 0, limit: 2 + | > SELECT null + | > LIMIT :limit + | > OFFSET :offset + | > ----- + | > ?column? + | > null + """.trimMargin(), + exception.message + ) + } + @Test fun `selectOne with extra parameters`() { val params: Map = mapOf(