feature #6: Implement named parameters
This commit is contained in:
@@ -13,8 +13,11 @@ import java.util.concurrent.CompletableFuture
|
|||||||
|
|
||||||
interface Executable {
|
interface Executable {
|
||||||
fun <T, R : EntityI<T?>?> select(sql: String, typeReference: TypeReference<R>, values: List<Any?> = emptyList()): R?
|
fun <T, R : EntityI<T?>?> select(sql: String, typeReference: TypeReference<R>, values: List<Any?> = emptyList()): R?
|
||||||
|
fun <T, R : EntityI<T?>?> select(sql: String, typeReference: TypeReference<R>, values: Map<String, Any?>): R?
|
||||||
fun <T, R : List<EntityI<T?>?>> select(sql: String, typeReference: TypeReference<R>, values: List<Any?> = emptyList()): R?
|
fun <T, R : List<EntityI<T?>?>> select(sql: String, typeReference: TypeReference<R>, values: List<Any?> = emptyList()): R?
|
||||||
|
fun <T, R : List<EntityI<T?>?>> select(sql: String, typeReference: TypeReference<R>, values: Map<String, Any?>): R
|
||||||
fun exec(sql: String, values: List<Any?> = emptyList()): CompletableFuture<QueryResult>
|
fun exec(sql: String, values: List<Any?> = emptyList()): CompletableFuture<QueryResult>
|
||||||
|
fun exec(sql: String, values: Map<String, Any?>): CompletableFuture<QueryResult>
|
||||||
}
|
}
|
||||||
|
|
||||||
class Connection(
|
class Connection(
|
||||||
@@ -47,9 +50,21 @@ class Connection(
|
|||||||
serializer.deserialize(json, typeReference)
|
serializer.deserialize(json, typeReference)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <T, reified R : EntityI<T?>?> selectOne(sql: String, values: List<Any?> = emptyList()): R? = select(sql, object: TypeReference<R>() {}, values)
|
inline fun <T, reified R : EntityI<T?>?> selectOne(sql: String, values: List<Any?> = emptyList()): R? = select(sql, object: TypeReference<R>() {}, values)
|
||||||
|
|
||||||
|
override fun <T, R : EntityI<T?>?> select(sql: String, typeReference: TypeReference<R>, values: Map<String, Any?>): R? {
|
||||||
|
val args = compileArgs(values)
|
||||||
|
val replacedQuery = replaceArgs(sql, args)
|
||||||
|
val future = connect().sendPreparedStatement(replacedQuery.sql, replacedQuery.parameters)
|
||||||
|
val json = future.get().rows[0].getString(0)
|
||||||
|
return if (json === null) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
serializer.deserialize(json, typeReference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline fun <T, reified R : EntityI<T?>?> selectOne(sql: String, values: Map<String, Any?>): R? = select(sql, object: TypeReference<R>() {}, values)
|
||||||
|
|
||||||
override fun <T, R : List<EntityI<T?>?>> select(sql: String, typeReference: TypeReference<R>, values: List<Any?>): R {
|
override fun <T, R : List<EntityI<T?>?>> select(sql: String, typeReference: TypeReference<R>, values: List<Any?>): R {
|
||||||
val future = connect().sendPreparedStatement(sql, compileArgs(values))
|
val future = connect().sendPreparedStatement(sql, compileArgs(values))
|
||||||
val json = future.get().rows[0].getString(0)
|
val json = future.get().rows[0].getString(0)
|
||||||
@@ -59,13 +74,30 @@ class Connection(
|
|||||||
serializer.deserializeList(json, typeReference)
|
serializer.deserializeList(json, typeReference)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <T, reified R : List<EntityI<T?>?>> select(sql: String, values: List<Any?> = emptyList()): R = select(sql, object : TypeReference<R>() {}, values)
|
inline fun <T, reified R : List<EntityI<T?>?>> select(sql: String, values: List<Any?> = emptyList()): R = select(sql, object : TypeReference<R>() {}, values)
|
||||||
|
|
||||||
|
override fun <T, R : List<EntityI<T?>?>> select(sql: String, typeReference: TypeReference<R>, values: Map<String, Any?>): R {
|
||||||
|
val args = compileArgs(values)
|
||||||
|
val replacedQuery = replaceArgs(sql, args)
|
||||||
|
val future = connect().sendPreparedStatement(replacedQuery.sql, replacedQuery.parameters)
|
||||||
|
val json = future.get().rows[0].getString(0)
|
||||||
|
return if (json === null) {
|
||||||
|
listOf<EntityI<T?>?>() as R
|
||||||
|
} else {
|
||||||
|
serializer.deserializeList(json, typeReference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline fun <T, reified R : List<EntityI<T?>?>> select(sql: String, values: Map<String, Any?>): R = select(sql, object : TypeReference<R>() {}, values)
|
||||||
|
|
||||||
override fun exec(sql: String, values: List<Any?>): CompletableFuture<QueryResult> {
|
override fun exec(sql: String, values: List<Any?>): CompletableFuture<QueryResult> {
|
||||||
return connect().sendPreparedStatement(sql, compileArgs(values))
|
return connect().sendPreparedStatement(sql, compileArgs(values))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun exec(sql: String, values: Map<String, Any?>): CompletableFuture<QueryResult> {
|
||||||
|
val replacedQuery = replaceArgs(sql, values)
|
||||||
|
return exec(replacedQuery.sql, replacedQuery.parameters)
|
||||||
|
}
|
||||||
|
|
||||||
private fun compileArgs(values: List<Any?>): List<Any?> {
|
private fun compileArgs(values: List<Any?>): List<Any?> {
|
||||||
return values.map {
|
return values.map {
|
||||||
if (it is EntityI<*>) {
|
if (it is EntityI<*>) {
|
||||||
@@ -77,5 +109,36 @@ class Connection(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun compileArgs(values: Map<String, Any?>): Map<String, Any?> {
|
||||||
|
return values.map {(key, value) ->
|
||||||
|
if (value is EntityI<*>) {
|
||||||
|
val json = serializer.serialize(value)
|
||||||
|
serializer.collection.set<Any?, EntityI<Any?>>(value as EntityI<Any?>)
|
||||||
|
key to json
|
||||||
|
} else {
|
||||||
|
key to value
|
||||||
|
}
|
||||||
|
}.toMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun replaceArgs(sql: String, values: Map<String, Any?>): ParametersQuery {
|
||||||
|
val paramRegex = "(?<!:):([a-zA-Z0-9_-]+)".toRegex(RegexOption.IGNORE_CASE)
|
||||||
|
val newArgs = paramRegex.findAll(sql).map { match ->
|
||||||
|
val name = match.groups[1]!!.value
|
||||||
|
values[name] ?: error("Parameter $name missing")
|
||||||
|
}.toList()
|
||||||
|
|
||||||
|
var newSql = sql
|
||||||
|
values.forEach { (key, _) ->
|
||||||
|
val regex = ":$key".toRegex()
|
||||||
|
newSql = newSql.replace(regex, "?")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return ParametersQuery(newSql, newArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ParametersQuery(val sql: String, val parameters: List<Any?>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,18 +82,30 @@ class Requester (
|
|||||||
override fun <T, R : EntityI<T?>?> select(typeReference: TypeReference<R>, values: List<Any?>): R? {
|
override fun <T, R : EntityI<T?>?> select(typeReference: TypeReference<R>, values: List<Any?>): R? {
|
||||||
return connection.select(this.toString(), typeReference, values)
|
return connection.select(this.toString(), typeReference, values)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <T, reified R : EntityI<T?>?> selectOne(values: List<Any?> = emptyList()): R? = select(object: TypeReference<R>() {}, values)
|
inline fun <T, reified R : EntityI<T?>?> selectOne(values: List<Any?> = emptyList()): R? = select(object: TypeReference<R>() {}, values)
|
||||||
|
|
||||||
|
override fun <T, R: EntityI<T?>?> select(typeReference: TypeReference<R>, values: Map<String, Any?>): R? {
|
||||||
|
return connection.select(this.toString(), typeReference, values)
|
||||||
|
}
|
||||||
|
inline fun <T, reified R : EntityI<T?>?> selectOne(values: Map<String, Any?>): R? = select(object: TypeReference<R>() {}, values)
|
||||||
|
|
||||||
override fun <T, R : List<EntityI<T?>?>> select(typeReference: TypeReference<R>, values: List<Any?>): R? {
|
override fun <T, R : List<EntityI<T?>?>> select(typeReference: TypeReference<R>, values: List<Any?>): R? {
|
||||||
return connection.select(this.toString(), typeReference, values)
|
return connection.select(this.toString(), typeReference, values)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <T, reified R : List<EntityI<T?>?>> select(values: List<Any?> = emptyList()): R? = select(object: TypeReference<R>() {}, values)
|
inline fun <T, reified R : List<EntityI<T?>?>> select(values: List<Any?> = emptyList()): R? = select(object: TypeReference<R>() {}, values)
|
||||||
|
|
||||||
|
override fun <T, R: List<EntityI<T?>?>> select(typeReference: TypeReference<R>, values: Map<String, Any?>): R {
|
||||||
|
return connection.select(this.toString(), typeReference, values)
|
||||||
|
}
|
||||||
|
inline fun <T, reified R : List<EntityI<T?>?>> select(values: Map<String, Any?>): R? = select(object: TypeReference<R>() {}, values)
|
||||||
|
|
||||||
override fun exec(values: List<Any?>): CompletableFuture<QueryResult> {
|
override fun exec(values: List<Any?>): CompletableFuture<QueryResult> {
|
||||||
return connection.exec(sql, values)
|
return connection.exec(sql, values)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun exec(values: Map<String, Any?>): CompletableFuture<QueryResult> {
|
||||||
|
return connection.exec(sql, values)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Function(val definition: DefinitionFunction, override val connection : Connection): Executable {
|
class Function(val definition: DefinitionFunction, override val connection : Connection): Executable {
|
||||||
@@ -101,24 +113,50 @@ class Requester (
|
|||||||
return definition.name
|
return definition.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select One entity with list of parameters
|
||||||
|
*/
|
||||||
override fun <T, R : EntityI<T?>?> select(typeReference: TypeReference<R>, values: List<Any?>): R? {
|
override fun <T, R : EntityI<T?>?> select(typeReference: TypeReference<R>, values: List<Any?>): R? {
|
||||||
val args = compileArgs(values)
|
val args = compileArgs(values)
|
||||||
val sql = "SELECT * FROM ${definition.name} ($args)"
|
val sql = "SELECT * FROM ${definition.name} ($args)"
|
||||||
|
|
||||||
return connection.select(sql, typeReference, values)
|
return connection.select(sql, typeReference, values)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <T, reified R: EntityI<T?>?> selectOne(values: List<Any?> = emptyList()): R? = select(object: TypeReference<R>() {}, values)
|
inline fun <T, reified R: EntityI<T?>?> selectOne(values: List<Any?> = emptyList()): R? = select(object: TypeReference<R>() {}, values)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select One entity with named parameters
|
||||||
|
*/
|
||||||
|
override fun <T, R : EntityI<T?>?> select(typeReference: TypeReference<R>, values: Map<String, Any?>): R? {
|
||||||
|
val args = compileArgs(values)
|
||||||
|
val sql = "SELECT * FROM ${definition.name} ($args)"
|
||||||
|
|
||||||
|
return connection.select(sql, typeReference, values)
|
||||||
|
}
|
||||||
|
inline fun <T, reified R: EntityI<T?>?> selectOne(values: Map<String, Any?>): R? = select(object: TypeReference<R>() {}, values)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select list of entities with list of parameters
|
||||||
|
*/
|
||||||
override fun <T, R : List<EntityI<T?>?>> select(typeReference: TypeReference<R>, values: List<Any?>): R? {
|
override fun <T, R : List<EntityI<T?>?>> select(typeReference: TypeReference<R>, values: List<Any?>): R? {
|
||||||
val args = compileArgs(values)
|
val args = compileArgs(values)
|
||||||
val sql = "SELECT * FROM ${definition.name} ($args)"
|
val sql = "SELECT * FROM ${definition.name} ($args)"
|
||||||
|
|
||||||
return connection.select(sql, typeReference, values)
|
return connection.select(sql, typeReference, values)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <T, reified R: List<EntityI<T?>?>> select(values: List<Any?> = emptyList()): R? = select(object: TypeReference<R>() {}, values)
|
inline fun <T, reified R: List<EntityI<T?>?>> select(values: List<Any?> = emptyList()): R? = select(object: TypeReference<R>() {}, values)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select list of entities with named parameters
|
||||||
|
*/
|
||||||
|
override fun <T, R: List<EntityI<T?>?>> select(typeReference: TypeReference<R>, values: Map<String, Any?>): R {
|
||||||
|
val args = compileArgs(values)
|
||||||
|
val sql = "SELECT * FROM ${definition.name} ($args)"
|
||||||
|
|
||||||
|
return connection.select(sql, typeReference, values)
|
||||||
|
}
|
||||||
|
inline fun <T, reified R: List<EntityI<T?>?>> select(values: Map<String, Any?>): R? = select(object: TypeReference<R>() {}, values)
|
||||||
|
|
||||||
override fun exec(values: List<Any?>): CompletableFuture<QueryResult> {
|
override fun exec(values: List<Any?>): CompletableFuture<QueryResult> {
|
||||||
val args = compileArgs(values)
|
val args = compileArgs(values)
|
||||||
val sql = "SELECT * FROM ${definition.name} ($args)"
|
val sql = "SELECT * FROM ${definition.name} ($args)"
|
||||||
@@ -126,6 +164,13 @@ class Requester (
|
|||||||
return connection.exec(sql, values)
|
return connection.exec(sql, values)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun exec(values: Map<String, Any?>): CompletableFuture<QueryResult> {
|
||||||
|
val args = compileArgs(values)
|
||||||
|
val sql = "SELECT * FROM ${definition.name} ($args)"
|
||||||
|
|
||||||
|
return connection.exec(sql, values)
|
||||||
|
}
|
||||||
|
|
||||||
private fun compileArgs(values: List<Any?>): String {
|
private fun compileArgs(values: List<Any?>): String {
|
||||||
val placeholders = values
|
val placeholders = values
|
||||||
.filterIndexed { index, any ->
|
.filterIndexed { index, any ->
|
||||||
@@ -137,6 +182,21 @@ class Requester (
|
|||||||
|
|
||||||
return placeholders.joinToString(separator=", ")
|
return placeholders.joinToString(separator=", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun compileArgs(values: Map<String, Any?>): String {
|
||||||
|
val parameters = definition.getParametersIndexedByName()
|
||||||
|
val placeholders = values
|
||||||
|
.filter { entry ->
|
||||||
|
val parameter = parameters[entry.key] ?: error("Parameter ${entry.key} not exist")
|
||||||
|
parameter.default === null || entry.value !== null
|
||||||
|
}
|
||||||
|
.map { entry ->
|
||||||
|
val parameter = parameters[entry.key]!!
|
||||||
|
"${parameter.name} := :${parameter.name}::" + parameter.type
|
||||||
|
}
|
||||||
|
|
||||||
|
return placeholders.joinToString(separator=", ")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Executable {
|
interface Executable {
|
||||||
@@ -144,10 +204,13 @@ class Requester (
|
|||||||
override fun toString(): String
|
override fun toString(): String
|
||||||
|
|
||||||
fun <T, R : EntityI<T?>?> select(typeReference: TypeReference<R>, values: List<Any?> = emptyList()): R?
|
fun <T, R : EntityI<T?>?> select(typeReference: TypeReference<R>, values: List<Any?> = emptyList()): R?
|
||||||
|
fun <T, R : EntityI<T?>?> select(typeReference: TypeReference<R>, values: Map<String, Any?>): R?
|
||||||
|
|
||||||
fun <T, R : List<EntityI<T?>?>> select(typeReference: TypeReference<R>, values: List<Any?> = emptyList()): R?
|
fun <T, R : List<EntityI<T?>?>> select(typeReference: TypeReference<R>, values: List<Any?> = emptyList()): R?
|
||||||
|
fun <T, R : List<EntityI<T?>?>> select(typeReference: TypeReference<R>, values: Map<String, Any?>): R
|
||||||
|
|
||||||
fun exec(values: List<Any?> = emptyList()): CompletableFuture<QueryResult>
|
fun exec(values: List<Any?> = emptyList()): CompletableFuture<QueryResult>
|
||||||
|
fun exec(values: Map<String, Any?>): CompletableFuture<QueryResult>
|
||||||
}
|
}
|
||||||
|
|
||||||
class RequesterFactory(
|
class RequesterFactory(
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ open class Function (
|
|||||||
override var source: File? = null
|
override var source: File? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val functionRegex = """create .*(procedure|function) *(?<name>[^(\s]+)\s*\((?<params>(\s*((IN|OUT|INOUT|VARIADIC)?\s+)?([^\s,)]+\s+)?([^\s,)]+)(\s+(?:default\s|=)\s*[^\s,)]+)?\s*(,|(?=\))))*)\) *(?<return>RETURNS *[^ ]+)?"""
|
val functionRegex = """create (or replace )?(procedure|function) *(?<name>[^(\s]+)\s*\((?<params>(\s*((IN|OUT|INOUT|VARIADIC)?\s+)?([^\s,)]+\s+)?([^\s,)]+)(\s+(?:default\s|=)\s*[^\s,)]+)?\s*(,|(?=\))))*)\) *(?<return>RETURNS *[^ ]+)?"""
|
||||||
.toRegex(setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE))
|
.toRegex(setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE))
|
||||||
|
|
||||||
val paramsRegex = """\s*(?<param>((?<direction>IN|OUT|INOUT|VARIADIC)?\s+)?(?<name>[^\s,)]+\s+)?(?<type>[^\s,)]+)(\s+(?<default>default\s|=)\s*[^\s,)]+)?)\s*(,|$)"""
|
val paramsRegex = """\s*(?<param>((?<direction>IN|OUT|INOUT|VARIADIC)?\s+)?(?<name>[^\s,)]+\s+)?(?<type>[^\s,)]+)(\s+(?<default>default\s|=)\s*[^\s,)]+)?)\s*(,|$)"""
|
||||||
@@ -50,6 +50,12 @@ open class Function (
|
|||||||
return "$name (" + parameters.joinToString(", ") + ") $returns"
|
return "$name (" + parameters.joinToString(", ") + ") $returns"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getParametersIndexedByName(): Map<String, Parameter> {
|
||||||
|
return parameters.map {
|
||||||
|
it.name to it
|
||||||
|
}.toMap()
|
||||||
|
}
|
||||||
|
|
||||||
infix fun `has same definition` (other: Function): Boolean {
|
infix fun `has same definition` (other: Function): Boolean {
|
||||||
return other.getDefinition() == this.getDefinition()
|
return other.getDefinition() == this.getDefinition()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package fr.postgresjson
|
|||||||
import com.github.jasync.sql.db.util.isCompleted
|
import com.github.jasync.sql.db.util.isCompleted
|
||||||
import fr.postgresjson.connexion.Connection
|
import fr.postgresjson.connexion.Connection
|
||||||
import fr.postgresjson.entity.IdEntity
|
import fr.postgresjson.entity.IdEntity
|
||||||
import org.junit.jupiter.api.Assertions.*
|
import org.junit.Assert.*
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.TestInstance
|
import org.junit.jupiter.api.TestInstance
|
||||||
@@ -12,6 +12,7 @@ import org.junit.jupiter.api.TestInstance
|
|||||||
class ConnectionTest(): TestAbstract() {
|
class ConnectionTest(): TestAbstract() {
|
||||||
private class ObjTest(var name: String): IdEntity()
|
private class ObjTest(var name: String): IdEntity()
|
||||||
private class ObjTest2(var title: String, var test: ObjTest?): IdEntity()
|
private class ObjTest2(var title: String, var test: ObjTest?): IdEntity()
|
||||||
|
private class ObjTest3(var first: String, var seconde: String, var third: Int): IdEntity()
|
||||||
|
|
||||||
private lateinit var connection: Connection
|
private lateinit var connection: Connection
|
||||||
|
|
||||||
@@ -60,10 +61,10 @@ class ConnectionTest(): TestAbstract() {
|
|||||||
val o = ObjTest("myName")
|
val o = ObjTest("myName")
|
||||||
o.id = 88
|
o.id = 88
|
||||||
val obj: ObjTest? = connection.selectOne("select json_build_object('id', id, 'name', name) FROM json_to_record(?::json) as o(id int, name text);", listOf(o))
|
val obj: ObjTest? = connection.selectOne("select json_build_object('id', id, 'name', name) FROM json_to_record(?::json) as o(id int, name text);", listOf(o))
|
||||||
assertTrue(obj !== null)
|
assertNotNull(obj)
|
||||||
assertTrue(obj is ObjTest)
|
assertTrue(obj is ObjTest)
|
||||||
assertTrue(obj!!.id == 88)
|
assertEquals(obj!!.id, 88)
|
||||||
assertTrue(obj.name == "myName")
|
assertEquals(obj.name, "myName")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -73,4 +74,59 @@ class ConnectionTest(): TestAbstract() {
|
|||||||
future.join()
|
future.join()
|
||||||
assertTrue(future.isCompleted)
|
assertTrue(future.isCompleted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `select one with named parameters`() {
|
||||||
|
val result: ObjTest3? = connection.selectOne(
|
||||||
|
"SELECT json_build_object('first', :first::text, 'seconde', :seconde::text, 'third', :third::int)",
|
||||||
|
mapOf(
|
||||||
|
"first" to "ff",
|
||||||
|
"seconde" to "sec",
|
||||||
|
"third" to 123
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertEquals(result!!.first, "ff")
|
||||||
|
assertEquals(result.seconde, "sec")
|
||||||
|
assertEquals(result.third, 123)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `select with named parameters`() {
|
||||||
|
val params: Map<String, Any?> = mapOf(
|
||||||
|
"first" to "ff",
|
||||||
|
"third" to 123,
|
||||||
|
"seconde" to "sec"
|
||||||
|
)
|
||||||
|
val result: List<ObjTest3?> = connection.select(
|
||||||
|
"""
|
||||||
|
SELECT json_build_array(
|
||||||
|
json_build_object('first', :first::text, 'seconde', :seconde::text, 'third', :third::int),
|
||||||
|
json_build_object('first', :first::text, 'seconde', :seconde::text, 'third', :third::int)
|
||||||
|
)
|
||||||
|
""".trimIndent(),
|
||||||
|
params
|
||||||
|
)
|
||||||
|
assertEquals(result[0]!!.first, "ff")
|
||||||
|
assertEquals(result[0]!!.seconde, "sec")
|
||||||
|
assertEquals(result[0]!!.third, 123)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `selectOne with named parameters`() {
|
||||||
|
val params: Map<String, Any?> = mapOf(
|
||||||
|
"first" to "ff",
|
||||||
|
"third" to 123,
|
||||||
|
"seconde" to "sec"
|
||||||
|
)
|
||||||
|
val result: ObjTest3? = connection.selectOne(
|
||||||
|
"""
|
||||||
|
SELECT json_build_object('first', :first::text, 'seconde', :seconde::text, 'third', :third::int)
|
||||||
|
""".trimIndent(),
|
||||||
|
params
|
||||||
|
)
|
||||||
|
assertNotNull(result)
|
||||||
|
assertEquals(result!!.first, "ff")
|
||||||
|
assertEquals(result.seconde, "sec")
|
||||||
|
assertEquals(result.third, 123)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,11 +10,11 @@ import org.junit.jupiter.api.Test
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
class RequestTest: TestAbstract() {
|
class RequesterTest: TestAbstract() {
|
||||||
class ObjTest(var name:String): IdEntity(1)
|
class ObjTest(var name:String): IdEntity(1)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun getQueryFromFile() {
|
fun `get query from file`() {
|
||||||
val resources = File(this::class.java.getResource("/sql/query").toURI())
|
val resources = File(this::class.java.getResource("/sql/query").toURI())
|
||||||
val objTest: ObjTest? = Requester(getConnextion())
|
val objTest: ObjTest? = Requester(getConnextion())
|
||||||
.addQuery(resources)
|
.addQuery(resources)
|
||||||
@@ -26,7 +26,7 @@ class RequestTest: TestAbstract() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun getFunctionFromFile() {
|
fun `get function from file`() {
|
||||||
val resources = File(this::class.java.getResource("/sql/function").toURI())
|
val resources = File(this::class.java.getResource("/sql/function").toURI())
|
||||||
val objTest: ObjTest? = Requester(getConnextion())
|
val objTest: ObjTest? = Requester(getConnextion())
|
||||||
.addFunction(resources)
|
.addFunction(resources)
|
||||||
@@ -38,7 +38,7 @@ class RequestTest: TestAbstract() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun callExecOnQuery() {
|
fun `call exec on query`() {
|
||||||
val resources = File(this::class.java.getResource("/sql/query").toURI())
|
val resources = File(this::class.java.getResource("/sql/query").toURI())
|
||||||
val future: CompletableFuture<QueryResult> = Requester(getConnextion())
|
val future: CompletableFuture<QueryResult> = Requester(getConnextion())
|
||||||
.addQuery(resources)
|
.addQuery(resources)
|
||||||
@@ -50,7 +50,7 @@ class RequestTest: TestAbstract() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun callExecOnFunction() {
|
fun `call exec on function`() {
|
||||||
val resources = File(this::class.java.getResource("/sql/function").toURI())
|
val resources = File(this::class.java.getResource("/sql/function").toURI())
|
||||||
val future: CompletableFuture<QueryResult> = Requester(getConnextion())
|
val future: CompletableFuture<QueryResult> = Requester(getConnextion())
|
||||||
.addFunction(resources)
|
.addFunction(resources)
|
||||||
@@ -60,4 +60,37 @@ class RequestTest: TestAbstract() {
|
|||||||
future.join()
|
future.join()
|
||||||
Assertions.assertTrue(future.isCompleted)
|
Assertions.assertTrue(future.isCompleted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `call selectOne on function`() {
|
||||||
|
val resources = File(this::class.java.getResource("/sql/function").toURI())
|
||||||
|
val obj: ObjTest = Requester(getConnextion())
|
||||||
|
.addFunction(resources)
|
||||||
|
.getFunction("test_function")
|
||||||
|
.selectOne(mapOf("name" to "myName"))!!
|
||||||
|
|
||||||
|
assertEquals("myName", obj.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `call selectOne on query`() {
|
||||||
|
val resources = File(this::class.java.getResource("/sql/query").toURI())
|
||||||
|
val obj: ObjTest = Requester(getConnextion())
|
||||||
|
.addQuery(resources)
|
||||||
|
.getQuery("Test/selectOneWithParameters")
|
||||||
|
.selectOne(mapOf("name" to "myName"))!!
|
||||||
|
|
||||||
|
assertEquals("myName", obj.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `call select (multiple) on function`() {
|
||||||
|
val resources = File(this::class.java.getResource("/sql/function").toURI())
|
||||||
|
val obj: List<ObjTest>? = Requester(getConnextion())
|
||||||
|
.addFunction(resources)
|
||||||
|
.getFunction("test_function_multiple")
|
||||||
|
.select(mapOf("name" to "myName"))
|
||||||
|
|
||||||
|
assertEquals("myName", obj!![0].name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -33,6 +33,19 @@ CREATE OR REPLACE FUNCTION test_function (name text default 'plop', IN hi text d
|
|||||||
AS
|
AS
|
||||||
$$
|
$$
|
||||||
BEGIN
|
BEGIN
|
||||||
result = json_build_object('id', 3, 'name', 'test');
|
result = json_build_object('id', 3, 'name', name);
|
||||||
END;
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION test_function_multiple (name text default 'plop', IN hi text default 'hello', out result json)
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS
|
||||||
$$
|
$$
|
||||||
|
BEGIN
|
||||||
|
result = json_build_array(
|
||||||
|
json_build_object('id', 3, 'name', name),
|
||||||
|
json_build_object('id', 4, 'name', hi)
|
||||||
|
);
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
CREATE OR REPLACE FUNCTION test_function_multiple (name text default 'plop', IN hi text default 'hello', out result json)
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS
|
||||||
|
$$
|
||||||
|
BEGIN
|
||||||
|
result = json_build_array(
|
||||||
|
json_build_object('id', 3, 'name', name),
|
||||||
|
json_build_object('id', 4, 'name', hi)
|
||||||
|
);
|
||||||
|
END;
|
||||||
|
$$
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
select json_build_object('id', 2, 'name', :name::text);
|
||||||
Reference in New Issue
Block a user