diff --git a/docs/installation.md b/docs/installation.md index 9c2d9a5..aad5ed6 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -3,6 +3,20 @@ ## Gradle ```kotlin // 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 { implementation("com.github.flecomte:postgres-json:+") } diff --git a/src/main/kotlin/fr/postgresjson/connexion/Function.kt b/src/main/kotlin/fr/postgresjson/connexion/Function.kt index 83096f6..482747b 100644 --- a/src/main/kotlin/fr/postgresjson/connexion/Function.kt +++ b/src/main/kotlin/fr/postgresjson/connexion/Function.kt @@ -97,7 +97,7 @@ class Function(val definition: Function, override val connection: Connection) : } private fun compileArgs(values: Map): String { - val parameters = definition.getParametersIndexedByName() + val parameters = definition.parametersIndexedByName val placeholders = values .filter { entry -> val parameter = parameters[entry.key] ?: parameters["_" + entry.key] ?: error("Parameter ${entry.key} of function ${definition.name} not exist") diff --git a/src/main/kotlin/fr/postgresjson/connexion/Requester.kt b/src/main/kotlin/fr/postgresjson/connexion/Requester.kt index 75626a4..85c771b 100644 --- a/src/main/kotlin/fr/postgresjson/connexion/Requester.kt +++ b/src/main/kotlin/fr/postgresjson/connexion/Requester.kt @@ -63,6 +63,10 @@ class Requester( fun getQuery(path: String): Query = queries[path] ?: throw NoQueryDefined(path) + fun inTransaction(block: Requester.() -> A?): A? = connection.inTransaction { + this@Requester.block() + } + class NoFunctionDefined(name: String) : Exception("No function defined for $name") class NoQueryDefined(path: String) : Exception("No query defined in $path") } diff --git a/src/main/kotlin/fr/postgresjson/definition/Function.kt b/src/main/kotlin/fr/postgresjson/definition/Function.kt index 1afa240..707a6eb 100644 --- a/src/main/kotlin/fr/postgresjson/definition/Function.kt +++ b/src/main/kotlin/fr/postgresjson/definition/Function.kt @@ -1,5 +1,7 @@ package fr.postgresjson.definition +import fr.postgresjson.utils.Algorithm.MD5 +import fr.postgresjson.utils.hash import java.nio.file.Path class Function( @@ -48,19 +50,26 @@ class Function( class FunctionNotFound(cause: Throwable? = null) : Resource.ParseException("Function not found in script", cause) - fun getDefinition(): String { - return parameters - .filter { it.direction == Parameter.Direction.IN } - .joinToString(", ") { "${it.name} ${it.type}" } - .let { "$name ($it)" } - } + val definition: String + get() { + return parameters + .filter { it.direction == Parameter.Direction.IN } + .joinToString(", ") { "${it.name} ${it.type}" } + .let { "$name ($it)" } + } - fun getParametersIndexedByName(): Map { - return parameters.associateBy { it.name } - } + val definitionHash: String + get() { + return definition.hash(MD5) + } + + val parametersIndexedByName: Map + get() { + return parameters.associateBy { it.name } + } 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 { diff --git a/src/main/kotlin/fr/postgresjson/migration/Function.kt b/src/main/kotlin/fr/postgresjson/migration/Function.kt index 73f445a..a0a71aa 100644 --- a/src/main/kotlin/fr/postgresjson/migration/Function.kt +++ b/src/main/kotlin/fr/postgresjson/migration/Function.kt @@ -43,14 +43,14 @@ data class Function( } catch (e: CompletionException) { val cause = e.cause 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) } } this::class.java.classLoader .getResource("sql/migration/insertFunction.sql")!!.readText() - .let { connection.selectOne(it, listOf(up.name, up.getDefinition(), up.script, down.script)) } + .let { connection.selectOne(it, listOf(up.name, up.definition, up.script, down.script)) } ?.let { function -> executedAt = function.executedAt doExecute = Action.OK diff --git a/src/main/kotlin/fr/postgresjson/migration/Migrations.kt b/src/main/kotlin/fr/postgresjson/migration/Migrations.kt index 4c7d2cb..e864862 100644 --- a/src/main/kotlin/fr/postgresjson/migration/Migrations.kt +++ b/src/main/kotlin/fr/postgresjson/migration/Migrations.kt @@ -133,17 +133,17 @@ class Migrations private constructor( Throwable("The file $path was not found", cause) 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) { - val oldDefinition = functions[newDefinition.name]?.up ?: newDefinition - functions[newDefinition.name] = Function(newDefinition, oldDefinition, connection).apply { + val oldDefinition = functions[newDefinition.definitionHash]?.up ?: newDefinition + functions[newDefinition.definitionHash] = Function(newDefinition, oldDefinition, connection).apply { doExecute = Action.UP } } else { - functions[newDefinition.name]?.doExecute = Action.OK + functions[newDefinition.definitionHash]?.doExecute = Action.OK } - callback(functions[newDefinition.name]!!) + callback(functions[newDefinition.definitionHash]!!) return this } @@ -215,7 +215,7 @@ class Migrations private constructor( return list.toMap() } - internal fun down(force: Boolean = false): Map { + fun down(force: Boolean = false): Map { val list: MutableMap = mutableMapOf() migrationsScripts.forEach { it.value.let { query -> diff --git a/src/main/kotlin/fr/postgresjson/utils/md5.kt b/src/main/kotlin/fr/postgresjson/utils/md5.kt new file mode 100644 index 0000000..d7bbba7 --- /dev/null +++ b/src/main/kotlin/fr/postgresjson/utils/md5.kt @@ -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') +}