refactoring: definition.Function

This commit is contained in:
2019-07-01 16:58:19 +02:00
parent ebc1a67420
commit 74c9543b6d
6 changed files with 67 additions and 46 deletions

View File

@@ -40,7 +40,7 @@ class Requester (
}
fun addFunction(sql: String): Requester {
DefinitionFunction.build(sql).forEach {
DefinitionFunction(sql).let {
functions[it.name] = Function(it, connection)
}
return this

View File

@@ -4,26 +4,22 @@ import java.io.File
open class Function (
override val name: String,
override val script: String,
override val parameters: List<Parameter>
override val script: String
) : Resource, ParametersInterface {
override val name: String
override val parameters: List<Parameter>
override var source: File? = null
companion object {
fun build(source: File): List<Function> {
return build(source.readText())
}
fun build(functionContent: String): List<Function> {
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 *[^ ]+)?"""
.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*(,|$)"""
.toRegex(setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE))
return functionRegex.findAll(functionContent).map { queryMatch ->
val functionName = queryMatch.groups["name"]?.value?.trim()
val queryMatch = functionRegex.find(script)
if (queryMatch !== null) {
val functionName = queryMatch.groups.get("name")?.value?.trim()
val functionParameters = queryMatch.groups["params"]?.value?.trim()
val returns = queryMatch.groups["return"]?.value?.trim()
@@ -40,9 +36,22 @@ open class Function (
} else {
listOf()
}
this.name = functionName!!
this.parameters = parameters
} else {
throw FunctionNotFound()
}
}
abstract class ParseException(message: String, cause: Throwable? = null): Exception(message, cause)
class FunctionNotFound(cause: Throwable? = null): ParseException("Function not found in script", cause)
Function(functionName!!, functionContent, parameters)
}.toList()
companion object {
fun build(source: File): List<Function> {
return source.readText()
.split("CREATE +(OR REPLACE +)?(PROCEDURE|FUNCTION)".toRegex(setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE)))
.map {
Function("CREATE OR REPLACE FUNCTION $it")
}
}
}
}

View File

@@ -4,12 +4,19 @@ import fr.postgresjson.connexion.Connection
import fr.postgresjson.definition.Function as DefinitionFunction
class Function(
private val up: DefinitionFunction,
private val down: DefinitionFunction,
val up: DefinitionFunction,
val down: DefinitionFunction,
private val connection: Connection
): Migration {
val name = up.name
enum class Status(i: Int) { OK(2), UP_FAIL(0), DOWN_FAIL(1) }
init {
if (up.name !== down.name) {
throw Exception("UP and DOWN migration must be the same")
}
}
override fun up(): Int {
connection.exec(up.script)
return 1

View File

@@ -17,6 +17,7 @@ interface Migration {
class Migrations(directory: File, private val connection: Connection): Migration {
private val queries: MutableList<Query> = mutableListOf()
private val functions: MutableMap<String, Function> = mutableMapOf()
private var initialized = false
init {
directory.walk().filter {
@@ -26,15 +27,15 @@ class Migrations(directory: File, private val connection: Connection): Migration
it.isFile
}.forEach { file ->
if (file.name.endsWith(".up.sql")) {
val up = file.readText()
val down = file.path.substring(0, file.path.size - 7).let {
file.path.substring(0, file.path.size - 7).let {
try {
File("$it.down.sql").readText()
val down = File("$it.down.sql").readText()
val up = file.readText()
addQuery(file.name, up, down)
} catch (e: FileNotFoundException) {
throw DownMigrationNotDefined("$it.down.sql", e)
}
}
addQuery(up, down)
} else if (file.name.endsWith(".down.sql")) {
// Nothing
} else {
@@ -53,14 +54,14 @@ class Migrations(directory: File, private val connection: Connection): Migration
}
fun addFunction(sql: String): Migrations {
DefinitionFunction.build(sql).forEach {
DefinitionFunction(sql).let {
functions[it.name] = Function(it, it, connection)
}
return this
}
fun addQuery(up: String, down: String): Migrations {
queries.add(Query(up, down, connection))
fun addQuery(name: String, up: String, down: String): Migrations {
queries.add(Query(name, up, down, connection))
return this
}

View File

@@ -3,8 +3,9 @@ package fr.postgresjson.migration
import fr.postgresjson.connexion.Connection
class Query(
private val up: String,
private val down: String,
val name: String,
val up: String,
val down: String,
private val connection: Connection
): Migration {
enum class Status(i: Int) { OK(2), UP_FAIL(0), DOWN_FAIL(1) }

View File

@@ -3,6 +3,9 @@
-- grant all privileges on database test to test;
-- ALTER SCHEMA public owner to test;
drop schema IF EXISTS public cascade;
create schema if not exists public;
create table if not exists test
(
id serial not null