apply "replaceNamedArgByQuestionMark" on exec() function

This commit is contained in:
2021-07-18 03:59:47 +02:00
parent 0288a57ed9
commit bd88e7938d
2 changed files with 50 additions and 24 deletions

View File

@@ -172,7 +172,7 @@ class Connection(
override fun exec(sql: String, values: List<Any?>): QueryResult { override fun exec(sql: String, values: List<Any?>): QueryResult {
val compiledValues = compileArgs(values) val compiledValues = compileArgs(values)
return stopwatchQuery(sql, compiledValues) { return stopwatchQuery(sql, compiledValues) {
connect().sendPreparedStatement(sql, compiledValues).join() connect().sendPreparedStatement(replaceNamedArgByQuestionMark(sql), compiledValues).join()
} }
} }
@@ -215,37 +215,41 @@ class Connection(
private fun <T> replaceArgs(sql: String, values: Map<String, Any?>, block: ParametersQuery.() -> T): T { private fun <T> replaceArgs(sql: String, values: Map<String, Any?>, block: ParametersQuery.() -> T): T {
val paramRegex = "(?<!:):([a-zA-Z0-9_-]+)".toRegex(RegexOption.IGNORE_CASE) val paramRegex = "(?<!:):([a-zA-Z0-9_-]+)".toRegex(RegexOption.IGNORE_CASE)
val newArgs = paramRegex.findAll(sql).map { match -> val orderedArgs = paramRegex.findAll(sql).map { match ->
val name = match.groups[1]!!.value val name = match.groups[1]!!.value
values[name] ?: values[name.trimStart('_')] ?: queryError("""Parameter "$name" missing""", sql, values) values[name] ?: values[name.trimStart('_')] ?: queryError("""Parameter "$name" missing""", sql, values)
}.toList() }.toList()
var newSql = sql return block(ParametersQuery(replaceNamedArgByQuestionMark(sql), orderedArgs))
values.forEach { (key, _) -> }
val regex = ":_?$key".toRegex()
newSql = newSql.replace(regex, "?")
}
return block(ParametersQuery(newSql, newArgs)) private fun replaceNamedArgByQuestionMark(sql: String): String =
"(?<!:):([a-zA-Z0-9_-]+)"
.toRegex(RegexOption.IGNORE_CASE)
.replace(sql, "?")
private fun insertArgsValuesIntoSql(sql: String, values: List<Any?>): String {
var i = 0
/* The regular expression matches a question mark "?" alone, not preceded or followed by another question mark */
return """(?<!\?)(\?)(?!\?)"""
.toRegex(RegexOption.IGNORE_CASE)
.replace(sql) {
values[i]
?.toString()
?.also { ++i }
?.let(this::escapeParameter)
?: queryError("Parameter $i missing", sql, values)
}
} }
private fun <T> replaceArgsIntoSql(sql: String, values: List<Any?>, block: (String) -> T): T { private fun <T> replaceArgsIntoSql(sql: String, values: List<Any?>, block: (String) -> T): T {
/* The regular expression matches a question mark "?" alone, not preceded or followed by another question mark */ return if (values.isNotEmpty()) {
val paramRegex = """(?<!\?)(\?)(?!\?)""".toRegex(RegexOption.IGNORE_CASE) sql
var i = 0 .let(this::replaceNamedArgByQuestionMark)
if (values.isNotEmpty()) { .let { insertArgsValuesIntoSql(it, values) }
/* for each question mark, replace by the value */ .let(block)
val newSql = paramRegex.replace(sql) { } else block(sql)
values[i] ?: queryError("Parameter $i missing", sql, values)
val valToReplace = values[i].toString()
++i
escapeParameter(valToReplace)
}
return block(newSql)
}
return block(sql)
} }
/** /**

View File

@@ -9,6 +9,7 @@ import fr.postgresjson.connexion.select
import fr.postgresjson.connexion.selectOne import fr.postgresjson.connexion.selectOne
import fr.postgresjson.connexion.update import fr.postgresjson.connexion.update
import fr.postgresjson.entity.UuidEntity import fr.postgresjson.entity.UuidEntity
import fr.postgresjson.serializer.deserialize
import org.junit.Assert import org.junit.Assert
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.Assertions.assertThrows
@@ -150,6 +151,16 @@ class RequesterTest : TestAbstract() {
assertEquals(1, result.rowsAffected) assertEquals(1, result.rowsAffected)
} }
@Test
fun `call exec on query with a list of arguments`() {
val resources = this::class.java.getResource("/sql/query")?.toURI()
val result = Requester(connection, queriesDirectory = resources)
.getQuery("selectOneWithParameters")
.exec(listOf("myName"))
assertEquals("myName", result.rows[0].getString(0)?.deserialize<ObjTest>()?.name)
}
@Test @Test
fun `call exec on function`() { fun `call exec on function`() {
val resources = this::class.java.getResource("/sql/function/Test")?.toURI() val resources = this::class.java.getResource("/sql/function/Test")?.toURI()
@@ -181,6 +192,17 @@ class RequesterTest : TestAbstract() {
} }
} }
@Test
fun `call sendQuery with same name of arguments as list`() {
val resources = this::class.java.getResource("/sql/query")?.toURI()
Requester(connection, queriesDirectory = resources)
.getQuery("selectMultipleWithSameArgs")
.sendQuery(listOf("myName", "myName2")).run {
assertEquals("myName", rows[0].getString("firstName"))
assertEquals("myName2", rows[0].getString("secondName"))
}
}
@Test @Test
fun `call sendQuery with arguments on not same orders`() { fun `call sendQuery with arguments on not same orders`() {
val resources = this::class.java.getResource("/sql/query")?.toURI() val resources = this::class.java.getResource("/sql/query")?.toURI()