test: cover leftParsesAsAScalarFunctionCallDespiteAlsoBeingTheLeftJoi...

This commit is contained in:
dualfroz committed 2026-09-09 15:59:05 +02:00
1 parent b05e8b2e37
commit 7cbdfb2a0e
1 file changed
+173
+173
View File
@@ -592,4 +592,177 @@ class ParserTest {
@Test @Test
fun filterColumnNamedFilterIsStillUsableAsAPlainIdentifier() { fun filterColumnNamedFilterIsStillUsableAsAPlainIdentifier() {
val expression = firstProjection("SELECT filter FROM t") as ColumnExpression
assertEquals("filter", expression.name)
}
// LEFT/RIGHT are otherwise reserved (LEFT/RIGHT JOIN), so LEFT(str, n)/RIGHT(str, n) as scalar
// functions each need their own disambiguation in the parser.
@Test
fun leftParsesAsAScalarFunctionCallDespiteAlsoBeingTheLeftJoinKeyword() {
val expression = firstProjection("SELECT LEFT(name, 3) FROM t")
assertEquals(CallExpression("LEFT", listOf(ColumnExpression("name"), intLit(3))), expression)
}
@Test
fun rightParsesAsAScalarFunctionCallDespiteAlsoBeingTheRightJoinKeyword() {
val expression = firstProjection("SELECT RIGHT(name, 3) FROM t")
assertEquals(CallExpression("RIGHT", listOf(ColumnExpression("name"), intLit(3))), expression)
}
@Test
fun leftJoinStillParsesAsAJoinNotAFunctionCall() {
val statement = parseOne("SELECT * FROM t LEFT JOIN u ON t.id = u.id") as SelectStatement
assertEquals(1, statement.joins.size)
assertEquals(JoinType.Left, statement.joins[0].type)
}
@Test
fun bareLeftKeywordWithoutAFollowingParenIsAParseError() {
assertFailsWith<ParseException> { parse("SELECT LEFT FROM t") }
}
@Test
fun bareRightKeywordWithoutAFollowingParenIsAParseError() {
assertFailsWith<ParseException> { parse("SELECT RIGHT FROM t") }
}
@Test
fun rightJoinAndFullJoinParseWithOptionalOuter() {
val right = parseOne("SELECT * FROM t RIGHT JOIN u ON t.id = u.id") as SelectStatement
assertEquals(JoinType.Right, right.joins[0].type)
val rightOuter = parseOne("SELECT * FROM t RIGHT OUTER JOIN u ON t.id = u.id") as SelectStatement
assertEquals(JoinType.Right, rightOuter.joins[0].type)
val full = parseOne("SELECT * FROM t FULL JOIN u ON t.id = u.id") as SelectStatement
assertEquals(JoinType.Full, full.joins[0].type)
val fullOuter = parseOne("SELECT * FROM t FULL OUTER JOIN u ON t.id = u.id") as SelectStatement
assertEquals(JoinType.Full, fullOuter.joins[0].type)
}
@Test
fun rightAndFullJoinLateralAreRejected() {
assertFailsWith<ParseException> {
parse("SELECT * FROM t RIGHT JOIN LATERAL (SELECT * FROM u WHERE u.id = t.id) x ON true")
}
assertFailsWith<ParseException> {
parse("SELECT * FROM t FULL JOIN LATERAL (SELECT * FROM u WHERE u.id = t.id) x ON true")
}
}
@Test
fun crossJoinParsesWithoutAnOnClauseAndOnIsNull() {
val statement = parseOne("SELECT * FROM t CROSS JOIN u") as SelectStatement
assertEquals(JoinType.Cross, statement.joins[0].type)
assertEquals(null, statement.joins[0].on)
}
@Test
fun crossJoinWithAnExplicitOnClauseIsAParseError() {
assertFailsWith<ParseException> { parse("SELECT * FROM t CROSS JOIN u ON t.id = u.id") }
}
@Test
fun crossJoinLateralIsAccepted() {
val statement = parseOne(
"SELECT * FROM t CROSS JOIN LATERAL (SELECT * FROM u WHERE u.id = t.id) x"
) as SelectStatement
assertEquals(JoinType.Cross, statement.joins[0].type)
assertEquals(null, statement.joins[0].on)
}
@Test
fun parsesIsNullAndIsNotNull() {
assertEquals(IsNullExpression(ColumnExpression("age"), negated = false), whereOf("SELECT 1 FROM t WHERE age IS NULL"))
assertEquals(
IsNullExpression(ColumnExpression("age"), negated = true),
whereOf("SELECT 1 FROM t WHERE age IS NOT NULL")
)
}
@Test
fun parsesInAndNotIn() {
assertEquals(
InExpression(ColumnExpression("id"), listOf(intLit(1), intLit(2), intLit(3)), negated = false),
whereOf("SELECT 1 FROM t WHERE id IN (1, 2, 3)")
)
assertEquals(
InExpression(ColumnExpression("id"), listOf(intLit(1)), negated = true),
whereOf("SELECT 1 FROM t WHERE id NOT IN (1)")
)
}
@Test
fun parsesBetweenAndNotBetween() {
assertEquals(
BetweenExpression(ColumnExpression("age"), intLit(18), intLit(65), negated = false),
whereOf("SELECT 1 FROM t WHERE age BETWEEN 18 AND 65")
)
assertEquals(
BetweenExpression(ColumnExpression("age"), intLit(18), intLit(65), negated = true),
whereOf("SELECT 1 FROM t WHERE age NOT BETWEEN 18 AND 65")
)
}
@Test
fun parsesLikeAndNotLike() {
assertEquals(
LikeExpression(ColumnExpression("name"), LiteralExpression(Value.TextValue("a%")), negated = false),
whereOf("SELECT 1 FROM t WHERE name LIKE 'a%'")
)
assertEquals(
LikeExpression(ColumnExpression("name"), LiteralExpression(Value.TextValue("a%")), negated = true),
whereOf("SELECT 1 FROM t WHERE name NOT LIKE 'a%'")
)
}
@Test
fun notInWithoutInOrBetweenOrLikeFails() {
assertFailsWith<ParseException> { parse("SELECT 1 FROM t WHERE id NOT = 1") }
}
@Test
fun parsesSearchedCaseExpression() {
val expression = firstProjection(
"SELECT CASE WHEN age < 18 THEN 'minor' WHEN age < 65 THEN 'adult' ELSE 'senior' END FROM t"
) as CaseExpression
assertNull(expression.operand)
assertEquals(2, expression.branches.size)
assertEquals(LiteralExpression(Value.TextValue("senior")), expression.elseExpression)
}
@Test
fun parsesSimpleCaseExpressionWithoutElse() {
val expression = firstProjection("SELECT CASE grade WHEN 1 THEN 'a' END FROM t") as CaseExpression
assertEquals(ColumnExpression("grade"), expression.operand)
assertEquals(1, expression.branches.size)
assertNull(expression.elseExpression)
}
@Test
fun caseWithoutWhenClauseFails() {
assertFailsWith<ParseException> { parse("SELECT CASE WHEN THEN 1 END FROM t") }
assertFailsWith<ParseException> { parse("SELECT CASE ELSE 1 END FROM t") }
}
@Test
fun caseMissingEndFails() {
assertFailsWith<ParseException> { parse("SELECT CASE WHEN 1 THEN 2 FROM t") }
}
@Test
fun parsesScalarSubqueryInWhereClause() {
val expression = whereOf("SELECT 1 FROM t WHERE age > (SELECT AVG(age) FROM t)") as BinaryExpression
val subquery = expression.right as ScalarSubqueryExpression
assertEquals("t", tableName(subquery.select))
assertEquals(BinaryOperator.Greater, expression.operator)
}
@Test
fun parsesInSubquery() {
val expression = whereOf("SELECT 1 FROM t WHERE id IN (SELECT id FROM other)") as InSubqueryExpression
assertEquals(ColumnExpression("id"), expression.operand)
assertEquals("other", tableName(expression.select))
assertEquals(false, expression.negated)
}
} }