test: cover parsesNotInSubquery and parsesExistsAndNotExists

This commit is contained in:
dualfroz committed 2026-09-09 16:21:10 +02:00
1 parent 7cbdfb2a0e
commit 742eeef126
1 file changed
+173
+173
View File
@@ -765,4 +765,177 @@ class ParserTest {
assertEquals(false, expression.negated)
}
@Test
fun parsesNotInSubquery() {
val expression = whereOf("SELECT 1 FROM t WHERE id NOT IN (SELECT id FROM other)") as InSubqueryExpression
assertEquals(true, expression.negated)
}
@Test
fun parsesExistsAndNotExists() {
val exists = whereOf("SELECT 1 FROM t WHERE EXISTS (SELECT 1 FROM other)") as ExistsExpression
assertEquals("other", tableName(exists.select))
val notExists = whereOf("SELECT 1 FROM t WHERE NOT EXISTS (SELECT 1 FROM other)") as UnaryExpression
assertEquals(UnaryOperator.Not, notExists.operator)
assertEquals("other", tableName((notExists.operand as ExistsExpression).select))
}
@Test
fun parenthesizedNonSelectExpressionIsStillJustGrouping() {
assertEquals(intLit(1), firstProjection("SELECT (1) FROM t"))
}
@Test
fun parsesCreateView() {
val statement = parseOne("CREATE VIEW adults AS SELECT id, name FROM users WHERE age >= 18") as CreateViewStatement
assertEquals("adults", statement.viewName)
assertEquals(false, statement.orReplace)
assertEquals("users", tableName(statement.query))
}
@Test
fun parsesCreateOrReplaceView() {
val statement = parseOne("CREATE OR REPLACE VIEW adults AS SELECT id FROM users") as CreateViewStatement
assertEquals(true, statement.orReplace)
}
@Test
fun orReplaceOnNonViewFails() {
assertFailsWith<ParseException> { parseOne("CREATE OR REPLACE TABLE t (id INTEGER)") }
}
@Test
fun parsesDropView() {
val statement = parseOne("DROP VIEW adults") as DropViewStatement
assertEquals("adults", statement.viewName)
assertEquals(DropMode.Restrict, statement.mode)
}
@Test
fun dropTableAndDropViewAcceptExplicitCascadeAndRestrict() {
assertEquals(DropMode.Cascade, (parseOne("DROP TABLE t CASCADE") as DropTableStatement).mode)
assertEquals(DropMode.Restrict, (parseOne("DROP TABLE t RESTRICT") as DropTableStatement).mode)
assertEquals(DropMode.Cascade, (parseOne("DROP VIEW v CASCADE") as DropViewStatement).mode)
assertEquals(DropMode.Restrict, (parseOne("DROP VIEW v RESTRICT") as DropViewStatement).mode)
}
@Test
fun parsesTruncateWithAndWithoutTheTableKeyword() {
val withKeyword = parseOne("TRUNCATE TABLE t") as TruncateTableStatement
assertEquals(listOf("t"), withKeyword.tableNames)
assertEquals(false, withKeyword.restartIdentity)
assertEquals(DropMode.Restrict, withKeyword.mode)
val withoutKeyword = parseOne("TRUNCATE t") as TruncateTableStatement
assertEquals(listOf("t"), withoutKeyword.tableNames)
}
@Test
fun parsesTruncateWithMultipleTableNames() {
val statement = parseOne("TRUNCATE TABLE a, b, c") as TruncateTableStatement
assertEquals(listOf("a", "b", "c"), statement.tableNames)
}
@Test
fun parsesTruncateRestartIdentityAndContinueIdentity() {
assertEquals(true, (parseOne("TRUNCATE TABLE t RESTART IDENTITY") as TruncateTableStatement).restartIdentity)
assertEquals(false, (parseOne("TRUNCATE TABLE t CONTINUE IDENTITY") as TruncateTableStatement).restartIdentity)
assertEquals(false, (parseOne("TRUNCATE TABLE t") as TruncateTableStatement).restartIdentity)
}
@Test
fun parsesTruncateCascadeAndRestrictAfterAnIdentityClause() {
val statement = parseOne("TRUNCATE TABLE t RESTART IDENTITY CASCADE") as TruncateTableStatement
assertEquals(true, statement.restartIdentity)
assertEquals(DropMode.Cascade, statement.mode)
}
@Test
fun parsesMergeWithATableSourceAndAnUpdateClause() {
val statement = parseOne(
"MERGE INTO accounts USING staging ON accounts.id = staging.id " +
"WHEN MATCHED THEN UPDATE SET balance = staging.balance"
) as MergeStatement
assertEquals("accounts", statement.targetTable)
assertNull(statement.targetAlias)
val source = statement.source as TableSource
assertEquals("staging", source.name)
assertNull(source.alias)
assertTrue(statement.onCondition is BinaryExpression)
assertEquals(1, statement.whenClauses.size)
val clause = statement.whenClauses.single() as MergeMatchedUpdate
assertNull(clause.condition)
assertEquals(listOf(Assignment("balance", ColumnExpression("balance", "staging"))), clause.assignments)
}
@Test
fun parsesMergeTargetAndSourceAliasesWithAndWithoutAs() {
val explicitAs = parseOne(
"MERGE INTO accounts AS acc USING staging AS s ON acc.id = s.id WHEN MATCHED THEN DELETE"
) as MergeStatement
assertEquals("acc", explicitAs.targetAlias)
assertEquals("s", (explicitAs.source as TableSource).alias)
val bareAlias = parseOne(
"MERGE INTO accounts acc USING staging s ON acc.id = s.id WHEN MATCHED THEN DELETE"
) as MergeStatement
assertEquals("acc", bareAlias.targetAlias)
assertEquals("s", (bareAlias.source as TableSource).alias)
}
@Test
fun parsesMergeUsingADerivedTableSubquerySource() {
val statement = parseOne(
"MERGE INTO accounts USING (SELECT id FROM staging) AS s ON accounts.id = s.id WHEN MATCHED THEN DELETE"
) as MergeStatement
val source = statement.source as SubquerySource
assertEquals("s", source.alias)
assertTrue(source.select is SelectStatement)
}
@Test
fun parsesMergeWhenMatchedDeleteWithAnAndCondition() {
val statement = parseOne(
"MERGE INTO t USING s ON t.id = s.id WHEN MATCHED AND s.flag THEN DELETE"
) as MergeStatement
val clause = statement.whenClauses.single() as MergeMatchedDelete
assertEquals(ColumnExpression("flag", "s"), clause.condition)
}
@Test
fun parsesMergeWhenNotMatchedInsertWithAndWithoutAColumnList() {
val withColumns = parseOne(
"MERGE INTO t USING s ON t.id = s.id WHEN NOT MATCHED THEN INSERT (id, label) VALUES (s.id, s.label)"
) as MergeStatement
val withColumnsClause = withColumns.whenClauses.single() as MergeNotMatchedInsert
assertEquals(listOf("id", "label"), withColumnsClause.columns)
assertEquals(listOf(ColumnExpression("id", "s"), ColumnExpression("label", "s")), withColumnsClause.values)
val withoutColumns = parseOne(
"MERGE INTO t USING s ON t.id = s.id WHEN NOT MATCHED THEN INSERT VALUES (s.id, DEFAULT)"
) as MergeStatement
val withoutColumnsClause = withoutColumns.whenClauses.single() as MergeNotMatchedInsert
assertNull(withoutColumnsClause.columns)
assertEquals(listOf<Expression?>(ColumnExpression("id", "s"), null), withoutColumnsClause.values)
}
@Test
fun parsesMergeWhenNotMatchedWithAnAndCondition() {
val statement = parseOne(
"MERGE INTO t USING s ON t.id = s.id WHEN NOT MATCHED AND s.active THEN INSERT (id) VALUES (s.id)"
) as MergeStatement
val clause = statement.whenClauses.single() as MergeNotMatchedInsert
assertEquals(ColumnExpression("active", "s"), clause.condition)
}
@Test
fun parsesMergeWithMultipleWhenClausesInWrittenOrder() {
val statement = parseOne(
"MERGE INTO t USING s ON t.id = s.id " +
"WHEN MATCHED AND s.gone THEN DELETE " +
"WHEN MATCHED THEN UPDATE SET v = s.v " +
"WHEN NOT MATCHED THEN INSERT (id) VALUES (s.id)"
) as MergeStatement
assertEquals(3, statement.whenClauses.size)
assertTrue(statement.whenClauses[0] is MergeMatchedDelete)
}