Fix/function with same name #34

Open
flecomte wants to merge 3 commits from fix/function_with_same_name into master
7 changed files with 58 additions and 19 deletions

View File

@@ -3,6 +3,20 @@
## Gradle ## Gradle
```kotlin ```kotlin
// build.gradle.kts // build.gradle.kts
buildscript {
repositories {
maven { url = uri("https://jitpack.io") }
}
dependencies {
classpath("com.github.flecomte:postgres-json:+")
}
}
repositories {
maven { url = uri("https://jitpack.io") }
}
dependencies { dependencies {
implementation("com.github.flecomte:postgres-json:+") implementation("com.github.flecomte:postgres-json:+")
} }

View File

@@ -97,7 +97,7 @@ class Function(val definition: Function, override val connection: Connection) :
} }
private fun compileArgs(values: Map<String, Any?>): String { private fun compileArgs(values: Map<String, Any?>): String {
val parameters = definition.getParametersIndexedByName() val parameters = definition.parametersIndexedByName
val placeholders = values val placeholders = values
.filter { entry -> .filter { entry ->
val parameter = parameters[entry.key] ?: parameters["_" + entry.key] ?: error("Parameter ${entry.key} of function ${definition.name} not exist") val parameter = parameters[entry.key] ?: parameters["_" + entry.key] ?: error("Parameter ${entry.key} of function ${definition.name} not exist")

View File

@@ -63,6 +63,10 @@ class Requester(
fun getQuery(path: String): Query = queries[path] ?: throw NoQueryDefined(path) fun getQuery(path: String): Query = queries[path] ?: throw NoQueryDefined(path)
fun <A> inTransaction(block: Requester.() -> A?): A? = connection.inTransaction {
this@Requester.block()
}
class NoFunctionDefined(name: String) : Exception("No function defined for $name") class NoFunctionDefined(name: String) : Exception("No function defined for $name")
class NoQueryDefined(path: String) : Exception("No query defined in $path") class NoQueryDefined(path: String) : Exception("No query defined in $path")
} }

View File

@@ -1,5 +1,7 @@
package fr.postgresjson.definition package fr.postgresjson.definition
import fr.postgresjson.utils.Algorithm.MD5
import fr.postgresjson.utils.hash
import java.nio.file.Path import java.nio.file.Path
class Function( class Function(
@@ -48,19 +50,26 @@ class Function(
class FunctionNotFound(cause: Throwable? = null) : Resource.ParseException("Function not found in script", cause) class FunctionNotFound(cause: Throwable? = null) : Resource.ParseException("Function not found in script", cause)
fun getDefinition(): String { val definition: String
return parameters get() {
.filter { it.direction == Parameter.Direction.IN } return parameters
.joinToString(", ") { "${it.name} ${it.type}" } .filter { it.direction == Parameter.Direction.IN }
.let { "$name ($it)" } .joinToString(", ") { "${it.name} ${it.type}" }
} .let { "$name ($it)" }
}
fun getParametersIndexedByName(): Map<String, Parameter> { val definitionHash: String
return parameters.associateBy { it.name } get() {
} return definition.hash(MD5)
}
val parametersIndexedByName: Map<String, Parameter>
get() {
return parameters.associateBy { it.name }
}
infix fun `has same definition`(other: Function): Boolean { infix fun `has same definition`(other: Function): Boolean {
return other.getDefinition() == this.getDefinition() return other.definition == this.definition
} }
infix fun `is different from`(other: Function): Boolean { infix fun `is different from`(other: Function): Boolean {

View File

@@ -43,14 +43,14 @@ data class Function(
} catch (e: CompletionException) { } catch (e: CompletionException) {
val cause = e.cause val cause = e.cause
if (cause is GenericDatabaseException && cause.errorMessage.fields['C'] == "42P13") { if (cause is GenericDatabaseException && cause.errorMessage.fields['C'] == "42P13") {
connection.sendQuery("drop function ${down.getDefinition()}") connection.sendQuery("drop function ${down.definition}")
connection.sendQuery(up.script) connection.sendQuery(up.script)
} }
} }
this::class.java.classLoader this::class.java.classLoader
.getResource("sql/migration/insertFunction.sql")!!.readText() .getResource("sql/migration/insertFunction.sql")!!.readText()
.let { connection.selectOne<MigrationEntity>(it, listOf(up.name, up.getDefinition(), up.script, down.script)) } .let { connection.selectOne<MigrationEntity>(it, listOf(up.name, up.definition, up.script, down.script)) }
?.let { function -> ?.let { function ->
executedAt = function.executedAt executedAt = function.executedAt
doExecute = Action.OK doExecute = Action.OK

View File

@@ -133,17 +133,17 @@ class Migrations private constructor(
Throwable("The file $path was not found", cause) Throwable("The file $path was not found", cause)
fun addFunction(newDefinition: DefinitionFunction, callback: (Function) -> Unit = {}): Migrations { fun addFunction(newDefinition: DefinitionFunction, callback: (Function) -> Unit = {}): Migrations {
val currentFunction = functions[newDefinition.name] val currentFunction = functions[newDefinition.definitionHash]
if (currentFunction === null || currentFunction `is different from` newDefinition) { if (currentFunction === null || currentFunction `is different from` newDefinition) {
val oldDefinition = functions[newDefinition.name]?.up ?: newDefinition val oldDefinition = functions[newDefinition.definitionHash]?.up ?: newDefinition
functions[newDefinition.name] = Function(newDefinition, oldDefinition, connection).apply { functions[newDefinition.definitionHash] = Function(newDefinition, oldDefinition, connection).apply {
doExecute = Action.UP doExecute = Action.UP
} }
} else { } else {
functions[newDefinition.name]?.doExecute = Action.OK functions[newDefinition.definitionHash]?.doExecute = Action.OK
} }
callback(functions[newDefinition.name]!!) callback(functions[newDefinition.definitionHash]!!)
return this return this
} }
@@ -215,7 +215,7 @@ class Migrations private constructor(
return list.toMap() return list.toMap()
} }
internal fun down(force: Boolean = false): Map<String, Status> { fun down(force: Boolean = false): Map<String, Status> {
val list: MutableMap<String, Status> = mutableMapOf() val list: MutableMap<String, Status> = mutableMapOf()
migrationsScripts.forEach { migrationsScripts.forEach {
it.value.let { query -> it.value.let { query ->

View File

@@ -0,0 +1,12 @@
package fr.postgresjson.utils
import java.math.BigInteger
import java.security.MessageDigest
internal enum class Algorithm(name: String) {
MD5("MD5")
}
internal fun String.hash(algorithm: Algorithm): String {
val md = MessageDigest.getInstance(algorithm.name)
return BigInteger(1, md.digest(toByteArray())).toString(16).padStart(32, '0')
}