test: cover parsesNotInSubquery and parsesExistsAndNotExists
This commit is contained in:
1 parent
7cbdfb2a0e
commit
742eeef126
1 file changed
+173
@@ -765,4 +765,177 @@ class ParserTest {
|
|||||||
assertEquals(false, expression.negated)
|
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)
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user