diff --git a/src/main/kotlin/fr/postgresjson/definition/parse/ParsingFunction.kt b/src/main/kotlin/fr/postgresjson/definition/parse/ParsingFunction.kt index 375a7dc..6f3845b 100644 --- a/src/main/kotlin/fr/postgresjson/definition/parse/ParsingFunction.kt +++ b/src/main/kotlin/fr/postgresjson/definition/parse/ParsingFunction.kt @@ -106,7 +106,7 @@ private class ParameterNameMalformed(val script: ScriptPart, cause: Throwable) : @Throws(ParameterTypeMalformed::class) private fun ScriptPart.getParameterType(): NextScript { val fullType = try { - val endTextList = arrayOf(" default ", "=", ")") + val endTextList = arrayOf(" default ", "=") getNextScript { afterBeginBy(texts = endTextList) } } catch (e: ParseError) { throw ParameterTypeMalformed(this, e) @@ -115,20 +115,26 @@ private fun ScriptPart.getParameterType(): NextScript { var rest: ScriptPart = fullType.valueAsScriptPart() val name = rest - .getNextScript { afterBeginBy("(") } + .getNextScript { afterBeginBy("(", "[") } .apply { rest = nextScriptPart } + rest = rest.trimStart(' ', '\n', '\t', ',', '(') val precision = rest .getNextInteger() .apply { rest = nextScriptPart } + rest = rest.trimStart(' ', '\n', '\t', ',') val scale = rest .getNextInteger() .apply { rest = nextScriptPart } + rest = rest.trimStart(' ', '\n', '\t', ')') + + val isArray = rest.restOfScript.contains("[]") return NextScript( ParameterType( - name = name.value.trim(), + name = name.value.trim().trim('[', ']'), precision = precision.value, - scale = scale.value + scale = scale.value, + isArray = isArray ), fullType.nextScriptPart.restOfScript ) diff --git a/src/main/kotlin/fr/postgresjson/definition/parse/ParsingHelper.kt b/src/main/kotlin/fr/postgresjson/definition/parse/ParsingHelper.kt index 3809ed7..e718113 100644 --- a/src/main/kotlin/fr/postgresjson/definition/parse/ParsingHelper.kt +++ b/src/main/kotlin/fr/postgresjson/definition/parse/ParsingHelper.kt @@ -60,12 +60,20 @@ internal fun ScriptPart.getNextScript(isEnd: Context.() -> Boolean = { false }): } if (isEnd(Context(index, c, status.copy(), restOfScript))) { - return NextScript(restOfScript.take(index + 1).unescape(), restOfScript.drop(index + 1)) + return NextScript( + restOfScript.take(index + 1).unescape(), + restOfScript.drop(index + 1), + ) } } + if (status.isNotEscaped()) { - return NextScript(restOfScript.trim(), "").trimSpace() + return NextScript( + restOfScript.trim(), + "", + ) } + throw ParseError() } @@ -99,6 +107,10 @@ internal fun NextScript.trim(vararg chars: Char): NextScript { return NextScript(value, restOfScript.apply { dropWhile { it in chars } }) } +internal fun ScriptPart.trimStart(vararg chars: Char): ScriptPart { + return this.change { dropWhile { it in chars } } +} + internal fun ScriptPart.trimEnd(vararg chars: Char): ScriptPart { return this.change { dropLastWhile { it in chars } } } @@ -131,9 +143,8 @@ internal inline fun ScriptPart.change(block: String.() -> String): ScriptPart { } internal fun ScriptPart.getNextInteger(): NextScript { - val trimmed = restOfScript.trimStart { !it.isDigit() } - val digits = trimmed.takeWhile { it.isDigit() } - val restOfScript = trimmed.trimStart { it.isDigit() } + val digits = restOfScript.takeWhile { it.isDigit() } + val restOfScript = restOfScript.trimStart { it.isDigit() } return NextScript(digits.toIntOrNull(), restOfScript).trimSpace() } diff --git a/src/test/kotlin/fr/postgresjson/definition/FunctionTest.kt b/src/test/kotlin/fr/postgresjson/definition/FunctionTest.kt index f88e51e..c158495 100644 --- a/src/test/kotlin/fr/postgresjson/definition/FunctionTest.kt +++ b/src/test/kotlin/fr/postgresjson/definition/FunctionTest.kt @@ -309,6 +309,78 @@ class FunctionTest : FreeSpec({ param[3].direction shouldBe IN } } + + "Parameters with type array of numeric" - { + val param = parseFunction( + // language=PostgreSQL + """ + create or replace function myfun(one numeric(10, 2)[]) language plpgsql as + $$ begin end;$$; + """.trimIndent() + ).parameters + + "should have 1 parameters" { + param shouldHaveSize 1 + } + + "should have parameter name" { + param[0].name shouldBe "one" + } + + "should have parameter type is array" { + param[0].type.isArray shouldBe true + } + + "should have parameter type name" { + param[0].type.name shouldBe "numeric" + } + + "should have parameter type precision" { + param[0].type.precision shouldBe 10 + } + + "should have parameter type scale" { + param[0].type.scale shouldBe 2 + } + } + + "Parameters with type array of text" - { + val param = parseFunction( + // language=PostgreSQL + """ + create or replace function myfun(one text[], two int[], three text) language plpgsql as + $$ begin end;$$; + """.trimIndent() + ).parameters + + "should have 2 parameters" { + param shouldHaveSize 3 + } + + "should have parameter name" { + param[0].name shouldBe "one" + param[1].name shouldBe "two" + param[2].name shouldBe "three" + } + + "should have parameter type is array" { + param[0].type.isArray shouldBe true + param[1].type.isArray shouldBe true + param[2].type.isArray shouldBe false + } + + "should have parameter type name" { + param[0].type.name shouldBe "text" + param[1].type.name shouldBe "int" + param[2].type.name shouldBe "text" + } + + "should have parameter direction" { + param[0].direction shouldBe IN + param[1].direction shouldBe IN + param[2].direction shouldBe IN + } + } } "Function Returns" - {