test: cover CompoundQueryTest and run
This commit is contained in:
1 parent
eb56dc4b87
commit
eef86e62ef
1 file changed
+162
@@ -0,0 +1,162 @@
|
||||
package kestrel
|
||||
|
||||
import kestrel.catalog.Catalog
|
||||
import kestrel.engine.ExplainResult
|
||||
import kestrel.engine.Executor
|
||||
import kestrel.engine.SelectResult
|
||||
import kestrel.engine.StatementResult
|
||||
import kestrel.sql.lexer.Lexer
|
||||
import kestrel.sql.parser.Parser
|
||||
import kestrel.storage.Value
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class CompoundQueryTest {
|
||||
private val catalog = Catalog()
|
||||
private val executor = Executor(catalog)
|
||||
|
||||
private fun run(sql: String): List<StatementResult> =
|
||||
Parser(Lexer(sql).tokenize()).parseProgram().map { executor.execute(it) }
|
||||
|
||||
private fun select(sql: String): SelectResult = run(sql).single() as SelectResult
|
||||
|
||||
private fun int(value: Long) = Value.IntegerValue(value)
|
||||
private fun text(value: String) = Value.TextValue(value)
|
||||
|
||||
private fun seed() {
|
||||
run("CREATE TABLE dual (x INTEGER)")
|
||||
run("INSERT INTO dual VALUES (1)")
|
||||
run("CREATE TABLE t1 (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
|
||||
run("CREATE TABLE t2 (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
|
||||
run("INSERT INTO t1 VALUES (1, 'ada'), (2, 'linus')")
|
||||
run("INSERT INTO t2 VALUES (2, 'linus'), (3, 'grace')")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun unionRemovesDuplicateRows() {
|
||||
seed()
|
||||
val result = select("SELECT name FROM t1 UNION SELECT name FROM t2 ORDER BY name")
|
||||
assertEquals(listOf(listOf(text("ada")), listOf(text("grace")), listOf(text("linus"))), result.rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun unionAllKeepsDuplicateRows() {
|
||||
seed()
|
||||
val result = select("SELECT name FROM t1 UNION ALL SELECT name FROM t2 ORDER BY name")
|
||||
assertEquals(
|
||||
listOf(listOf(text("ada")), listOf(text("grace")), listOf(text("linus")), listOf(text("linus"))),
|
||||
result.rows
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun intersectReturnsRowsPresentInBothQueries() {
|
||||
seed()
|
||||
val result = select("SELECT name FROM t1 INTERSECT SELECT name FROM t2")
|
||||
assertEquals(listOf(listOf(text("linus"))), result.rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun exceptReturnsRowsOnlyInTheLeftQuery() {
|
||||
seed()
|
||||
val result = select("SELECT name FROM t1 EXCEPT SELECT name FROM t2")
|
||||
assertEquals(listOf(listOf(text("ada"))), result.rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun intersectAllKeepsDuplicatesUpToTheMinimumCountInEitherSide() {
|
||||
run("CREATE TABLE bag_a (v INTEGER)")
|
||||
run("CREATE TABLE bag_b (v INTEGER)")
|
||||
run("INSERT INTO bag_a VALUES (1), (1), (1), (2)")
|
||||
run("INSERT INTO bag_b VALUES (1), (1), (2), (2), (3)")
|
||||
val result = select("SELECT v FROM bag_a INTERSECT ALL SELECT v FROM bag_b ORDER BY v")
|
||||
assertEquals(listOf(listOf(int(1)), listOf(int(1)), listOf(int(2))), result.rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun exceptAllKeepsLeftDuplicatesNotConsumedByTheRightSide() {
|
||||
run("CREATE TABLE bag_a (v INTEGER)")
|
||||
run("CREATE TABLE bag_b (v INTEGER)")
|
||||
run("INSERT INTO bag_a VALUES (1), (1), (1), (2)")
|
||||
run("INSERT INTO bag_b VALUES (1), (1), (2), (2), (3)")
|
||||
val result = select("SELECT v FROM bag_a EXCEPT ALL SELECT v FROM bag_b ORDER BY v")
|
||||
assertEquals(listOf(listOf(int(1))), result.rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mismatchedColumnCountsFail() {
|
||||
seed()
|
||||
assertFailsWith<KestrelException> {
|
||||
select("SELECT id, name FROM t1 UNION SELECT id FROM t2")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun compoundOperatorsChainLeftAssociatively() {
|
||||
seed()
|
||||
run("CREATE TABLE t3 (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
|
||||
run("INSERT INTO t3 VALUES (2, 'linus')")
|
||||
val result = select("SELECT name FROM t1 UNION ALL SELECT name FROM t2 INTERSECT SELECT name FROM t3 ORDER BY name")
|
||||
assertEquals(listOf(listOf(text("linus"))), result.rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun orderByAndLimitApplyToTheWholeCompoundResult() {
|
||||
seed()
|
||||
val result = select("SELECT name FROM t1 UNION ALL SELECT name FROM t2 ORDER BY name DESC LIMIT 2")
|
||||
assertEquals(listOf(listOf(text("linus")), listOf(text("linus"))), result.rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun offsetSkipsRowsOfTheWholeCompoundResultBeforeLimitApplies() {
|
||||
seed()
|
||||
val result = select("SELECT name FROM t1 UNION ALL SELECT name FROM t2 ORDER BY name DESC LIMIT 2 OFFSET 1")
|
||||
assertEquals(listOf(listOf(text("linus")), listOf(text("grace"))), result.rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun compoundQueryWorksAsDerivedTableInFrom() {
|
||||
seed()
|
||||
val result = select("SELECT count(*) FROM (SELECT name FROM t1 UNION SELECT name FROM t2) AS u")
|
||||
assertEquals(listOf(listOf(int(3))), result.rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun compoundQueryWorksAsViewBody() {
|
||||
seed()
|
||||
run("CREATE VIEW combined AS SELECT name FROM t1 UNION SELECT name FROM t2")
|
||||
val result = select("SELECT name FROM combined ORDER BY name")
|
||||
assertEquals(listOf(listOf(text("ada")), listOf(text("grace")), listOf(text("linus"))), result.rows)
|
||||
run("INSERT INTO t1 VALUES (4, 'margaret')")
|
||||
val refreshed = select("SELECT name FROM combined ORDER BY name")
|
||||
assertEquals(4, refreshed.rows.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun explainDescribesCompoundQuery() {
|
||||
seed()
|
||||
val plan = (run("EXPLAIN SELECT name FROM t1 UNION SELECT name FROM t2").single() as ExplainResult).plan
|
||||
assertTrue(plan.isNotEmpty())
|
||||
assertTrue(plan.any { it.contains("Union") })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun withClauseMakesACteAvailableInFrom() {
|
||||
seed()
|
||||
run("WITH recent AS (SELECT id, name FROM t1) SELECT name FROM recent WHERE id = 1")
|
||||
val result = select("WITH recent AS (SELECT id, name FROM t1) SELECT name FROM recent WHERE id = 1")
|
||||
assertEquals(listOf(listOf(text("ada"))), result.rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun laterCteCanReferenceAnEarlierCteInTheSameWithClause() {
|
||||
seed()
|
||||
val result = select(
|
||||
"WITH first_cte AS (SELECT id, name FROM t1), second_cte AS (SELECT name FROM first_cte WHERE id = 2) " +
|
||||
"SELECT name FROM second_cte"
|
||||
)
|
||||
assertEquals(listOf(listOf(text("linus"))), result.rows)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user