Drop function if already exists and conflict

This commit is contained in:
2019-09-20 02:27:15 +02:00
parent 88c45aaf77
commit 8810c1f08d
7 changed files with 60 additions and 11 deletions

View File

@@ -1,9 +1,11 @@
package fr.postgresjson.migration package fr.postgresjson.migration
import com.github.jasync.sql.db.postgresql.exceptions.GenericDatabaseException
import fr.postgresjson.connexion.Connection import fr.postgresjson.connexion.Connection
import fr.postgresjson.migration.Migration.Action import fr.postgresjson.migration.Migration.Action
import fr.postgresjson.migration.Migration.Status import fr.postgresjson.migration.Migration.Status
import java.util.* import java.util.*
import java.util.concurrent.CompletionException
import fr.postgresjson.definition.Function as DefinitionFunction import fr.postgresjson.definition.Function as DefinitionFunction
data class Function( data class Function(
@@ -34,7 +36,15 @@ data class Function(
) )
override fun up(): Status { override fun up(): Status {
connection.sendQuery(up.script) try {
connection.sendQuery(up.script)
} catch (e: CompletionException) {
val cause = e.cause
if (cause is GenericDatabaseException && cause.errorMessage.fields['C'] == "42P13") {
connection.sendQuery("drop function ${down.getDefinition()}")
connection.sendQuery(up.script)
}
}
this::class.java.classLoader.getResource("sql/migration/insertFunction.sql")!!.readText().let { this::class.java.classLoader.getResource("sql/migration/insertFunction.sql")!!.readText().let {
connection.selectOne<MigrationEntity>(it, listOf(up.name, up.getDefinition(), up.script, down.script))?.let { function -> connection.selectOne<MigrationEntity>(it, listOf(up.name, up.getDefinition(), up.script, down.script))?.let { function ->

View File

@@ -137,7 +137,8 @@ data class Migrations private constructor(
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.name]
if (currentFunction === null || currentFunction `is different from` newDefinition) { if (currentFunction === null || currentFunction `is different from` newDefinition) {
functions[newDefinition.name] = Function(newDefinition, newDefinition, connection).apply { val oldDefinition = functions[newDefinition.name]?.up ?: newDefinition
functions[newDefinition.name] = Function(newDefinition, oldDefinition, connection).apply {
doExecute = Action.UP doExecute = Action.UP
} }
} else { } else {

View File

@@ -79,7 +79,7 @@ class MigrationTest(): TestAbstract() {
@Test @Test
fun `run migrations force down`() { fun `run migrations force down`() {
val resources = File(this::class.java.getResource("/sql/real_migrations").toURI()) val resources = File(this::class.java.getResource("/sql/real_migrations").toURI())
val resourcesFunctions = File(this::class.java.getResource("/sql/function").toURI()) val resourcesFunctions = File(this::class.java.getResource("/sql/function/Test").toURI())
Migrations(listOf(resources, resourcesFunctions), connection).apply { Migrations(listOf(resources, resourcesFunctions), connection).apply {
up().apply { up().apply {
size `should be equal to` 6 size `should be equal to` 6
@@ -94,7 +94,7 @@ class MigrationTest(): TestAbstract() {
@Test @Test
fun `run functions migrations`() { fun `run functions migrations`() {
val resources = File(this::class.java.getResource("/sql/function").toURI()) val resources = File(this::class.java.getResource("/sql/function/Test").toURI())
Migrations(resources, connection).apply { Migrations(resources, connection).apply {
run().size `should be equal to` 5 run().size `should be equal to` 5
} }
@@ -107,4 +107,26 @@ class MigrationTest(): TestAbstract() {
Assertions.assertEquals(objTest!!.id, 3) Assertions.assertEquals(objTest!!.id, 3)
Assertions.assertEquals(objTest.name, "test") Assertions.assertEquals(objTest.name, "test")
} }
@Test
fun `run functions migrations and drop if exist`() {
val resources = File(this::class.java.getResource("/sql/function/Test1").toURI())
Migrations(resources, connection).apply {
run().size `should be equal to` 1
}
val objTest: RequesterTest.ObjTest? = Requester(connection)
.addFunction(resources)
.getFunction("test_function_duplicate")
.selectOne(listOf("test"))
Assertions.assertEquals(objTest!!.id, 3)
Assertions.assertEquals(objTest.name, "test")
val resources2 = File(this::class.java.getResource("/sql/function/Test2").toURI())
Migrations(resources2, connection).apply {
run().size `should be equal to` 1
}
}
} }

View File

@@ -25,7 +25,7 @@ class RequesterTest: TestAbstract() {
@Test @Test
fun `get function from file`() { fun `get function from file`() {
val resources = File(this::class.java.getResource("/sql/function").toURI()) val resources = File(this::class.java.getResource("/sql/function/Test").toURI())
val objTest: ObjTest? = Requester(connection) val objTest: ObjTest? = Requester(connection)
.addFunction(resources) .addFunction(resources)
.getFunction("test_function") .getFunction("test_function")
@@ -48,7 +48,7 @@ class RequesterTest: TestAbstract() {
@Test @Test
fun `call exec on function`() { fun `call exec on function`() {
val resources = File(this::class.java.getResource("/sql/function").toURI()) val resources = File(this::class.java.getResource("/sql/function/Test").toURI())
val result = Requester(connection) val result = Requester(connection)
.addFunction(resources) .addFunction(resources)
.getFunction("test_function") .getFunction("test_function")
@@ -70,7 +70,7 @@ class RequesterTest: TestAbstract() {
@Test @Test
fun `call sendQuery on function`() { fun `call sendQuery on function`() {
val resources = File(this::class.java.getResource("/sql/function").toURI()) val resources = File(this::class.java.getResource("/sql/function/Test").toURI())
val result = Requester(connection) val result = Requester(connection)
.addFunction(resources) .addFunction(resources)
.getFunction("function_void") .getFunction("function_void")
@@ -81,7 +81,7 @@ class RequesterTest: TestAbstract() {
@Test @Test
fun `call selectOne on function`() { fun `call selectOne on function`() {
val resources = File(this::class.java.getResource("/sql/function").toURI()) val resources = File(this::class.java.getResource("/sql/function/Test").toURI())
val obj: ObjTest = Requester(connection) val obj: ObjTest = Requester(connection)
.addFunction(resources) .addFunction(resources)
.getFunction("test_function") .getFunction("test_function")
@@ -92,7 +92,7 @@ class RequesterTest: TestAbstract() {
@Test @Test
fun `call selectOne on function with object`() { fun `call selectOne on function with object`() {
val resources = File(this::class.java.getResource("/sql/function").toURI()) val resources = File(this::class.java.getResource("/sql/function/Test").toURI())
val obj2 = ObjTest("original") val obj2 = ObjTest("original")
val obj: ObjTest = Requester(connection) val obj: ObjTest = Requester(connection)
.addFunction(resources) .addFunction(resources)
@@ -116,7 +116,7 @@ class RequesterTest: TestAbstract() {
@Test @Test
fun `call select (multiple) on function`() { fun `call select (multiple) on function`() {
val resources = File(this::class.java.getResource("/sql/function").toURI()) val resources = File(this::class.java.getResource("/sql/function/Test").toURI())
val obj: List<ObjTest>? = Requester(connection) val obj: List<ObjTest>? = Requester(connection)
.addFunction(resources) .addFunction(resources)
.getFunction("test_function_multiple") .getFunction("test_function_multiple")

View File

@@ -9,7 +9,7 @@ import java.io.File
@TestInstance(PER_CLASS) @TestInstance(PER_CLASS)
abstract class TestAbstract { abstract class TestAbstract {
protected val connection = Connection(database = "test", username = "test", password = "test") protected val connection = Connection(database = "test_json", username = "test", password = "test")
@BeforeEach @BeforeEach
fun beforeAll() { fun beforeAll() {

View File

@@ -0,0 +1,8 @@
CREATE OR REPLACE FUNCTION test_function_duplicate (name text default 'plop', out result json)
LANGUAGE plpgsql
AS
$$
BEGIN
result = json_build_object('id', 3, 'name', name);
END;
$$

View File

@@ -0,0 +1,8 @@
CREATE OR REPLACE FUNCTION test_function_duplicate (name text default 'plop') returns text
LANGUAGE plpgsql
AS
$$
BEGIN
return name;
END;
$$