test: cover parsesScalarFunctionCallWithMultipleArguments

This commit is contained in:
dualfroz committed 2026-09-09 15:48:33 +02:00
1 parent e8d6bf0db5
commit b05e8b2e37
1 file changed
+173
+173
View File
@@ -419,4 +419,177 @@ class ParserTest {
fun reportsUnknownStatement() { fun reportsUnknownStatement() {
assertFailsWith<ParseException> { parse("EXPLAIN users") } assertFailsWith<ParseException> { parse("EXPLAIN users") }
} }
@Test
fun parsesScalarFunctionCallWithMultipleArguments() {
val expression = firstProjection("SELECT SUBSTR(name, 1, 3) FROM t")
assertEquals(
CallExpression("SUBSTR", listOf(ColumnExpression("name"), intLit(1), intLit(3))),
expression
)
}
@Test
fun parsesScalarFunctionCallWithNoArguments() {
assertEquals(CallExpression("NOW", emptyList()), firstProjection("SELECT NOW() FROM t"))
}
@Test
fun aggregateFunctionWithWrongArityFails() {
assertFailsWith<ParseException> { parse("SELECT SUM(a, b) FROM t") }
assertFailsWith<ParseException> { parse("SELECT COUNT() FROM t") }
}
@Test
fun stringAggParsesTheValueAndSeparatorWithNoOrderByLeavingItEmpty() {
val expression = firstProjection("SELECT STRING_AGG(name, ', ') FROM t")
assertEquals(
FunctionExpression(
"STRING_AGG",
ColumnExpression("name"),
star = false,
separator = LiteralExpression(Value.TextValue(", ")),
orderBy = emptyList()
),
expression
)
}
@Test
fun stringAggParsesAnInternalOrderByWithMultipleKeysAndExplicitDirections() {
val expression = firstProjection("SELECT STRING_AGG(name, ',' ORDER BY dept ASC, name DESC) FROM t")
assertEquals(
FunctionExpression(
"STRING_AGG",
ColumnExpression("name"),
star = false,
separator = LiteralExpression(Value.TextValue(",")),
orderBy = listOf(
OrderKey(ColumnExpression("dept"), descending = false),
OrderKey(ColumnExpression("name"), descending = true)
)
),
expression
)
}
@Test
fun stringAggParsesAnExplicitNullsLastInsideItsInternalOrderBy() {
val expression = firstProjection("SELECT STRING_AGG(name, ',' ORDER BY dept NULLS LAST) FROM t")
assertEquals(
FunctionExpression(
"STRING_AGG",
ColumnExpression("name"),
star = false,
separator = LiteralExpression(Value.TextValue(",")),
orderBy = listOf(OrderKey(ColumnExpression("dept"), descending = false, nullsFirst = false))
),
expression
)
}
@Test
fun stringAggRequiresBothAValueAndASeparatorArgument() {
assertFailsWith<ParseException> { parse("SELECT STRING_AGG(name) FROM t") }
assertFailsWith<ParseException> { parse("SELECT STRING_AGG() FROM t") }
}
@Test
fun stringAggCannotBeUsedAsAWindowFunction() {
assertFailsWith<ParseException> { parse("SELECT STRING_AGG(name, ',') OVER () FROM t") }
}
@Test
fun countDistinctSetsTheDistinctFlagWithTheGivenArgumentAsTheSoleArgument() {
val expression = firstProjection("SELECT COUNT(DISTINCT dept) FROM t")
assertEquals(
FunctionExpression("COUNT", ColumnExpression("dept"), star = false, distinct = true),
expression
)
}
@Test
fun sumAvgMinMaxAcceptDistinctTooNotJustCount() {
for (name in listOf("SUM", "AVG", "MIN", "MAX")) {
val expression = firstProjection("SELECT $name(DISTINCT amount) FROM t")
assertEquals(
FunctionExpression(name, ColumnExpression("amount"), star = false, distinct = true),
expression
)
}
}
@Test
fun plainAggregateCallsDefaultDistinctToFalse() {
val expression = firstProjection("SELECT COUNT(dept) FROM t") as FunctionExpression
assertEquals(false, expression.distinct)
}
@Test
fun countDistinctStarIsRejected() {
assertFailsWith<ParseException> { parse("SELECT COUNT(DISTINCT *) FROM t") }
}
@Test
fun countDistinctWithMultipleArgumentsIsRejected() {
assertFailsWith<ParseException> { parse("SELECT COUNT(DISTINCT dept, region) FROM t") }
}
@Test
fun distinctAggregateCannotBeUsedAsAWindowFunction() {
assertFailsWith<ParseException> { parse("SELECT COUNT(DISTINCT dept) OVER () FROM t") }
assertFailsWith<ParseException> { parse("SELECT SUM(DISTINCT amount) OVER () FROM t") }
}
@Test
fun aggregateFilterSetsTheFilterFieldToTheWhereCondition() {
val expression = firstProjection("SELECT COUNT(dept) FILTER (WHERE amount > 100) FROM t")
assertEquals(
FunctionExpression(
"COUNT",
ColumnExpression("dept"),
star = false,
filter = BinaryExpression(BinaryOperator.Greater, ColumnExpression("amount"), LiteralExpression(Value.IntegerValue(100)))
),
expression
)
}
@Test
fun countStarFilterKeepsStarTrueAlongsideTheFilter() {
val expression = firstProjection("SELECT COUNT(*) FILTER (WHERE amount > 0) FROM t") as FunctionExpression
assertEquals(true, expression.star)
assertEquals(true, expression.filter != null)
}
@Test
fun plainAggregateCallsDefaultFilterToNull() {
val expression = firstProjection("SELECT COUNT(dept) FROM t") as FunctionExpression
assertEquals(null, expression.filter)
}
@Test
fun filterCanBeCombinedWithDistinct() {
val expression = firstProjection("SELECT COUNT(DISTINCT dept) FILTER (WHERE amount > 0) FROM t") as FunctionExpression
assertEquals(true, expression.distinct)
assertEquals(true, expression.filter != null)
}
@Test
fun filterRequiresAWhereClauseInsideItsParentheses() {
assertFailsWith<ParseException> { parse("SELECT COUNT(dept) FILTER (amount > 100) FROM t") }
}
@Test
fun filterIsRejectedOnNonAggregateFunctions() {
assertFailsWith<ParseException> { parse("SELECT UPPER(dept) FILTER (WHERE amount > 0) FROM t") }
}
@Test
fun filterCannotBeUsedWithAWindowFunction() {
assertFailsWith<ParseException> { parse("SELECT COUNT(dept) FILTER (WHERE amount > 0) OVER () FROM t") }
}
@Test
fun filterColumnNamedFilterIsStillUsableAsAPlainIdentifier() {
} }