package fr.postgresjson.connexion import com.fasterxml.jackson.core.type.TypeReference import com.github.jasync.sql.db.QueryResult import fr.postgresjson.definition.Function import fr.postgresjson.entity.EntityI class Function(val definition: Function, override val connection: Connection) : EmbedExecutable { override fun toString(): String { return definition.name } override val name: String = definition.name /* Select One */ /** * Select One entity with list of parameters */ override fun select( typeReference: TypeReference, values: List, block: (QueryResult, R?) -> Unit ): R? { val args = compileArgs(values) val sql = "SELECT * FROM ${definition.name} ($args)" return connection.select(sql, typeReference, values, block) } inline fun selectOne( values: List = emptyList(), noinline block: SelectOneCallback = {} ): R? = select(object : TypeReference() {}, values, block) inline fun selectOne( value: R, noinline block: SelectOneCallback = {} ): R? = select(object : TypeReference() {}, listOf(value), block) /** * Select One entity with named parameters */ override fun select( typeReference: TypeReference, values: Map, block: (QueryResult, R?) -> Unit ): R? { val args = compileArgs(values) val sql = "SELECT * FROM ${definition.name} ($args)" return connection.select(sql, typeReference, values, block) } inline fun selectOne( values: Map, noinline block: SelectOneCallback = {} ): R? = select(object : TypeReference() {}, values, block) inline fun selectOne( vararg values: Pair, noinline block: SelectOneCallback = {} ): R? = selectOne(values.toMap(), block) /* Select Multiples */ /** * Select list of entities with list of parameters */ override fun select( typeReference: TypeReference>, values: List, block: (QueryResult, List) -> Unit ): List { val args = compileArgs(values) val sql = "SELECT * FROM ${definition.name} ($args)" return connection.select(sql, typeReference, values, block) } inline fun select( values: List = emptyList(), noinline block: SelectCallback = {} ): List = select(object : TypeReference>() {}, values, block) /** * Select list of entities with named parameters */ override fun select( typeReference: TypeReference>, values: Map, block: (QueryResult, List) -> Unit ): List { val args = compileArgs(values) val sql = "SELECT * FROM ${definition.name} ($args)" return connection.select(sql, typeReference, values, block) } inline fun select( values: Map, noinline block: SelectCallback = {} ): List = select(object : TypeReference>() {}, values, block) inline fun select( vararg values: Pair, noinline block: SelectCallback = {} ): List = select(values.toMap(), block) /* Select Paginated */ /** * Select Multiple with pagination */ override fun select( page: Int, limit: Int, typeReference: TypeReference>, values: Map, block: (QueryResult, Paginated) -> Unit ): Paginated { val offset = (page - 1) * limit val newValues = values .plus("offset" to offset) .plus("limit" to limit) val args = compileArgs(newValues) val sql = "SELECT * FROM ${definition.name} ($args)" return connection.select(sql, page, limit, typeReference, values, block) } inline fun select( page: Int, limit: Int, values: Map = emptyMap(), noinline block: SelectPaginatedCallback = {} ): Paginated = select(page, limit, object : TypeReference>() {}, values, block) inline fun select( page: Int, limit: Int, vararg values: Pair, noinline block: SelectPaginatedCallback = {} ): Paginated = select(page, limit, object : TypeReference>() {}, values.toMap(), block) /* Execute function without traitements */ override fun exec(values: List): QueryResult { val args = compileArgs(values) val sql = "SELECT * FROM ${definition.name} ($args)" return connection.exec(sql, values) } override fun exec(values: Map): QueryResult { val args = compileArgs(values) val sql = "SELECT * FROM ${definition.name} ($args)" return connection.exec(sql, values) } override fun sendQuery(values: List): Int { exec(values) return 0 } override fun sendQuery(values: Map): Int { exec(values) return 0 } private fun compileArgs(values: List): String { val placeholders = values .filterIndexed { index, value -> definition.parameters[index].default === null || value != null } .mapIndexed { index, _ -> "?::" + definition.parameters[index].type } return placeholders.joinToString(separator = ", ") } private fun compileArgs(values: Map): String { val parameters = definition.getParametersIndexedByName() val placeholders = values .filter { entry -> val parameter = parameters[entry.key] ?: parameters["_" + entry.key] ?: error("Parameter ${entry.key} of function ${definition.name} not exist") parameter.default === null || entry.value !== null } .map { entry -> val parameter = parameters[entry.key] ?: parameters["_" + entry.key] ?: error("Parameter ${entry.key} of function ${definition.name} not exist") """"${parameter.name}" := :${parameter.name}::${parameter.type}""" } return placeholders.joinToString(separator = ", ") } }