test: cover defaultAppliesIndependentlyToEachOmittedColumn

This commit is contained in:
dualfroz committed 2026-09-08 16:51:21 +02:00
1 parent f8d57f5621
commit 4216c1c5eb
1 file changed
+163
+163
View File
@@ -470,3 +470,166 @@ class AlterTableTest {
assertEquals(listOf(listOf(Value.NullValue)), select("SELECT status FROM t").rows) assertEquals(listOf(listOf(Value.NullValue)), select("SELECT status FROM t").rows)
} }
@Test
fun defaultAppliesIndependentlyToEachOmittedColumn() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, status TEXT DEFAULT 'new', score INTEGER DEFAULT 0)")
run("INSERT INTO t (id) VALUES (1)")
val result = exec("INSERT INTO t (id) VALUES (2)")
assertEquals(InsertResult(1), result)
assertEquals(
listOf(listOf(text("new"), int(0)), listOf(text("new"), int(0))),
select("SELECT status, score FROM t ORDER BY id ASC").rows
)
}
@Test
fun createTableRejectsColumnReferenceInDefault() {
val error = assertFailsWith<KestrelException> {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, twice INTEGER DEFAULT id)")
}
assertTrue(error.message!!.contains("DEFAULT"))
}
@Test
fun createTableRejectsSubqueryInDefault() {
run("CREATE TABLE other (x INTEGER)")
assertFailsWith<KestrelException> {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, x INTEGER DEFAULT (SELECT COUNT(*) FROM other))")
}
}
@Test
fun createTableRejectsAggregateInDefault() {
val error = assertFailsWith<KestrelException> {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, x INTEGER DEFAULT COUNT(*))")
}
assertTrue(error.message!!.contains("aggregate"))
}
@Test
fun createTableValidatesDefaultTypeEagerly() {
assertFailsWith<KestrelException> {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, age INTEGER DEFAULT 'not a number')")
}
}
// ---- DEFAULT (UPDATE) ----
@Test
fun updateSetToDefaultResetsTheColumnToItsDeclaredDefault() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, status TEXT DEFAULT 'pending')")
run("INSERT INTO t VALUES (1, 'shipped')")
val result = exec("UPDATE t SET status = DEFAULT WHERE id = 1")
assertEquals(UpdateResult(1), result)
assertEquals(listOf(listOf(text("pending"))), select("SELECT status FROM t").rows)
}
@Test
fun updateSetToDefaultFallsBackToNullWhenTheColumnHasNoDeclaredDefault() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, note TEXT)")
run("INSERT INTO t VALUES (1, 'keep me')")
run("UPDATE t SET note = DEFAULT WHERE id = 1")
assertEquals(listOf(listOf(Value.NullValue)), select("SELECT note FROM t").rows)
}
@Test
fun updateSetToDefaultIsEvaluatedFreshPerRowJustLikeInsert() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, score INTEGER DEFAULT 0)")
run("INSERT INTO t VALUES (1, 10), (2, 20), (3, 30)")
val result = exec("UPDATE t SET score = DEFAULT WHERE id IN (1, 2)")
assertEquals(UpdateResult(2), result)
assertEquals(
listOf(listOf(int(1), int(0)), listOf(int(2), int(0)), listOf(int(3), int(30))),
select("SELECT id, score FROM t ORDER BY id ASC").rows
)
}
@Test
fun updateCanMixADefaultAssignmentWithARegularAssignmentInTheSameStatement() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT, status TEXT DEFAULT 'pending')")
run("INSERT INTO t VALUES (1, 'ada', 'shipped')")
run("UPDATE t SET name = 'grace', status = DEFAULT WHERE id = 1")
assertEquals(listOf(listOf(text("grace"), text("pending"))), select("SELECT name, status FROM t").rows)
}
@Test
fun updateSetToDefaultFailsNotNullValidationWhenThereIsNoDefaultToFallBackOn() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, status TEXT NOT NULL)")
run("INSERT INTO t VALUES (1, 'shipped')")
val error = assertFailsWith<KestrelException> {
run("UPDATE t SET status = DEFAULT WHERE id = 1")
}
assertTrue(error.message!!.contains("status"), error.message!!)
}
@Test
fun updateSetToDefaultRoundTripsThroughSqlWriter() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, status TEXT DEFAULT 'pending')")
run("INSERT INTO t VALUES (1, 'shipped')")
val statement = Parser(Lexer("UPDATE t SET status = DEFAULT WHERE id = 1").tokenize()).parseProgram().single()
val rendered = SqlWriter.write(statement)
assertTrue(rendered.contains("status = DEFAULT"), rendered)
run(rendered)
assertEquals(listOf(listOf(text("pending"))), select("SELECT status FROM t").rows)
}
// ---- DEFAULT (INSERT VALUES) ----
@Test
fun insertValuesWithLiteralDefaultUsesTheColumnsDeclaredDefault() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, status TEXT DEFAULT 'pending')")
val result = exec("INSERT INTO t VALUES (1, DEFAULT)")
assertEquals(InsertResult(1), result)
assertEquals(listOf(listOf(text("pending"))), select("SELECT status FROM t").rows)
}
@Test
fun insertValuesWithLiteralDefaultFallsBackToNullWhenTheColumnHasNoDeclaredDefault() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, note TEXT)")
run("INSERT INTO t VALUES (1, DEFAULT)")
assertEquals(listOf(listOf(Value.NullValue)), select("SELECT note FROM t").rows)
}
@Test
fun insertValuesLiteralDefaultIsDistinctFromAnExplicitNullLiteral() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, status TEXT DEFAULT 'pending')")
run("INSERT INTO t VALUES (1, NULL)")
assertEquals(listOf(listOf(Value.NullValue)), select("SELECT status FROM t").rows)
}
@Test
fun insertValuesLiteralDefaultAppliesIndependentlyToEachRowInAMultiRowInsert() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, score INTEGER DEFAULT 0)")
run("INSERT INTO t VALUES (1, DEFAULT), (2, 20), (3, DEFAULT)")
assertEquals(
listOf(listOf(int(1), int(0)), listOf(int(2), int(20)), listOf(int(3), int(0))),
select("SELECT id, score FROM t ORDER BY id ASC").rows
)
}
@Test
fun insertValuesLiteralDefaultWorksWithAnExplicitColumnList() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT, status TEXT DEFAULT 'pending')")
run("INSERT INTO t (id, status, name) VALUES (1, DEFAULT, 'ada')")
assertEquals(listOf(listOf(text("ada"), text("pending"))), select("SELECT name, status FROM t").rows)
}
@Test
fun insertValuesLiteralDefaultFailsNotNullValidationWhenThereIsNoDefaultToFallBackOn() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, status TEXT NOT NULL)")
val error = assertFailsWith<KestrelException> {
run("INSERT INTO t VALUES (1, DEFAULT)")
}
assertTrue(error.message!!.contains("status"), error.message!!)
}
@Test
fun insertValuesLiteralDefaultRoundTripsThroughSqlWriter() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, status TEXT DEFAULT 'pending')")
val statement = Parser(Lexer("INSERT INTO t VALUES (1, DEFAULT)").tokenize()).parseProgram().single()
val rendered = SqlWriter.write(statement)
assertTrue(rendered.contains("DEFAULT"), rendered)
run(rendered)
assertEquals(listOf(listOf(text("pending"))), select("SELECT status FROM t").rows)
}