test: cover scalarFunctionNotAllowedAsAggregateGroupingViolation

This commit is contained in:
dualfroz committed 2026-09-08 23:39:08 +02:00
1 parent f3a0059bc3
commit e1b4fd3b4c
1 file changed
+167
@@ -156,3 +156,170 @@ class ExpressionLanguageTest {
)
}
@Test
fun scalarFunctionNotAllowedAsAggregateGroupingViolation() {
seedUsers()
assertFailsWith<KestrelException> {
select("SELECT UPPER(name), COUNT(*) FROM users GROUP BY age")
}
}
@Test
fun newPredicateFormsCoexistWithIndexPushdownOnOtherConjuncts() {
seedUsers()
run("CREATE INDEX idxId ON users (id)")
val plan = (run("EXPLAIN SELECT name FROM users WHERE id = 1 AND age BETWEEN 1 AND 100").single() as ExplainResult).plan
assertTrue(plan.any { it.contains("Index Scan") }, "expected an index scan but was: $plan")
val result = select("SELECT name FROM users WHERE id = 1 AND age BETWEEN 1 AND 100")
assertEquals(listOf(listOf(text("ada"))), result.rows)
}
@Test
fun unknownFunctionNameReportsClearError() {
seedUsers()
assertFailsWith<KestrelException> { select("SELECT NOSUCHFUNC(name) FROM users") }
}
private fun decimal(value: String) = Value.DecimalValue(BigDecimal(value))
private fun date(value: String) = Value.DateValue(LocalDate.parse(value))
@Test
fun decimalColumnCoercesIntegerAndRealButRejectsBareText() {
run("CREATE TABLE orders (id INTEGER PRIMARY KEY, amount DECIMAL(10, 2))")
run("INSERT INTO orders VALUES (1, 5), (2, 5.5)")
val result = select("SELECT amount FROM orders ORDER BY id ASC")
assertEquals(listOf(listOf(decimal("5.00")), listOf(decimal("5.50"))), result.rows)
assertFailsWith<KestrelException> { run("INSERT INTO orders VALUES (3, '5.00')") }
}
@Test
fun dateColumnRequiresExplicitCastFromText() {
run("CREATE TABLE events (id INTEGER PRIMARY KEY, happened DATE)")
assertFailsWith<KestrelException> { run("INSERT INTO events VALUES (1, '2024-01-01')") }
run("INSERT INTO events VALUES (1, CAST('2024-01-01' AS DATE))")
val result = select("SELECT happened FROM events")
assertEquals(listOf(listOf(date("2024-01-01"))), result.rows)
}
@Test
fun decimalSumAndAverageStayExactAcrossGroupBy() {
run("CREATE TABLE orders (id INTEGER PRIMARY KEY, dept TEXT, amount DECIMAL(10, 2))")
run(
"INSERT INTO orders VALUES " +
"(1, 'eng', 10.10), (2, 'eng', 10.20), (3, 'eng', 10.30), (4, 'ops', 1.11)"
)
val result = select("SELECT dept, SUM(amount), AVG(amount) FROM orders GROUP BY dept ORDER BY dept ASC")
assertEquals(
listOf(
listOf(text("eng"), decimal("30.60"), decimal("10.20")),
listOf(text("ops"), decimal("1.11"), decimal("1.11"))
),
result.rows
)
}
@Test
fun dateArithmeticEndToEndThroughSelectAndWhere() {
run("CREATE TABLE events (id INTEGER PRIMARY KEY, happened DATE)")
run(
"INSERT INTO events VALUES " +
"(1, CAST('2024-01-01' AS DATE)), (2, CAST('2024-06-01' AS DATE))"
)
val projected = select("SELECT happened + 7 FROM events ORDER BY id ASC")
assertEquals(listOf(listOf(date("2024-01-08")), listOf(date("2024-06-08"))), projected.rows)
val filtered = select(
"SELECT id FROM events WHERE happened > CAST('2024-03-01' AS DATE)"
)
assertEquals(listOf(listOf(int(2))), filtered.rows)
}
@Test
fun castExpressionWorksInProjectionAndWhereAgainstOrdinaryColumns() {
seedUsers()
val projected = select("SELECT CAST(age AS TEXT) FROM users WHERE id = 1")
assertEquals(listOf(listOf(text("36"))), projected.rows)
val filtered = select("SELECT name FROM users WHERE CAST(age AS REAL) > 40.0 ORDER BY name ASC")
assertEquals(listOf(listOf(text("grace")), listOf(text("linus"))), filtered.rows)
}
@Test
fun dateComponentFunctionsEndToEndThroughSelectAndWhere() {
run("CREATE TABLE events (id INTEGER PRIMARY KEY, happened DATE)")
run(
"INSERT INTO events VALUES " +
"(1, CAST('2024-03-15' AS DATE)), (2, CAST('2023-11-02' AS DATE))"
)
val projected = select("SELECT YEAR(happened), MONTH(happened), DAY(happened) FROM events ORDER BY id ASC")
assertEquals(
listOf(listOf(int(2024), int(3), int(15)), listOf(int(2023), int(11), int(2))),
projected.rows
)
val filtered = select("SELECT id FROM events WHERE YEAR(happened) = 2023")
assertEquals(listOf(listOf(int(2))), filtered.rows)
val today = select("SELECT CURRENT_DATE() FROM events WHERE id = 1")
assertEquals(listOf(listOf(date(LocalDate.now().toString()))), today.rows)
}
@Test
fun dateAddDateSubAndDatediffEndToEndThroughSelectAndWhere() {
run("CREATE TABLE events (id INTEGER PRIMARY KEY, happened DATE)")
run(
"INSERT INTO events VALUES " +
"(1, CAST('2024-03-15' AS DATE)), (2, CAST('2024-03-20' AS DATE))"
)
val shifted = select(
"SELECT DATE_ADD(happened, 5), DATE_SUB(happened, 5) FROM events ORDER BY id ASC"
)
assertEquals(
listOf(
listOf(date("2024-03-20"), date("2024-03-10")),
listOf(date("2024-03-25"), date("2024-03-15"))
),
shifted.rows
)
val diff = select(
"SELECT DATEDIFF((SELECT happened FROM events WHERE id = 2), happened) FROM events WHERE id = 1"
)
assertEquals(listOf(listOf(int(5))), diff.rows)
val filtered = select("SELECT id FROM events WHERE DATE_ADD(happened, 5) = CAST('2024-03-25' AS DATE)")
assertEquals(listOf(listOf(int(2))), filtered.rows)
}
@Test
fun repeatLpadAndRpadEndToEndThroughSelectAndUpdate() {
run("CREATE TABLE codes (id INTEGER PRIMARY KEY, code TEXT)")
run("INSERT INTO codes VALUES (1, '7'), (2, '42')")
val padded = select("SELECT id, LPAD(code, 4, '0') FROM codes ORDER BY id ASC")
assertEquals(listOf(listOf(int(1), text("0007")), listOf(int(2), text("0042"))), padded.rows)
run("UPDATE codes SET code = RPAD(code, 5, '-') WHERE id = 1")
assertEquals(listOf(listOf(text("7----"))), select("SELECT code FROM codes WHERE id = 1").rows)
val separator = select("SELECT REPEAT('-', 3) FROM codes WHERE id = 2")
assertEquals(listOf(listOf(text("---"))), separator.rows)
}
@Test
fun signTruncGreatestAndLeastEndToEndThroughSelectWhereAndUpdate() {
run("CREATE TABLE accounts (id INTEGER PRIMARY KEY, balance INTEGER, limitAmount INTEGER, ratio REAL)")
run("INSERT INTO accounts VALUES (1, -50, 100, 0.0), (2, 75, 40, 0.0), (3, 0, 0, 0.0)")
val signs = select("SELECT id, SIGN(balance) FROM accounts ORDER BY id ASC")
assertEquals(listOf(listOf(int(1), int(-1)), listOf(int(2), int(1)), listOf(int(3), int(0))), signs.rows)
val capped = select("SELECT id, LEAST(balance, limitAmount) FROM accounts ORDER BY id ASC")
assertEquals(listOf(listOf(int(1), int(-50)), listOf(int(2), int(40)), listOf(int(3), int(0))), capped.rows)
val overLimit = select("SELECT id FROM accounts WHERE GREATEST(balance, 0) > limitAmount")
assertEquals(listOf(listOf(int(2))), overLimit.rows)
run("UPDATE accounts SET ratio = TRUNC(balance / 3.0) WHERE id = 2")
assertEquals(listOf(listOf(Value.RealValue(25.0))), select("SELECT ratio FROM accounts WHERE id = 2").rows)
}
}