test: cover createTableAcceptsANamedTableLevelCheckConstraint

This commit is contained in:
dualfroz committed 2026-09-08 17:13:46 +02:00
1 parent 68e2600e76
commit b832700fb4
1 file changed
+157
+157
View File
@@ -790,3 +790,160 @@ class AlterTableTest {
assertTrue(error.message!!.contains("c1"), error.message!!) assertTrue(error.message!!.contains("c1"), error.message!!)
} }
@Test
fun createTableAcceptsANamedTableLevelCheckConstraint() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, age INTEGER, CONSTRAINT chk_age CHECK (age > 0))")
val error = assertFailsWith<KestrelException> { run("INSERT INTO t VALUES (1, -1)") }
assertTrue(error.message!!.contains("chk_age"), error.message!!)
}
@Test
fun createTableAcceptsANamedTableLevelUniqueConstraint() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, email TEXT, CONSTRAINT uq_email UNIQUE (email))")
run("INSERT INTO t VALUES (1, 'a@x.com')")
val error = assertFailsWith<KestrelException> { run("INSERT INTO t VALUES (2, 'a@x.com')") }
assertTrue(error.message!!.contains("uq_email"), error.message!!)
}
@Test
fun createTableAcceptsANamedTableLevelForeignKeyConstraint() {
run("CREATE TABLE departments (id INTEGER PRIMARY KEY)")
run(
"CREATE TABLE employees (id INTEGER PRIMARY KEY, dept_id INTEGER, " +
"CONSTRAINT fk_dept FOREIGN KEY (dept_id) REFERENCES departments (id))"
)
run("INSERT INTO departments VALUES (1)")
val error = assertFailsWith<KestrelException> { run("INSERT INTO employees VALUES (1, 99)") }
assertTrue(error.message!!.contains("FOREIGN KEY constraint failed"), error.message!!)
}
@Test
fun dropConstraintRemovesANamedCheckConstraint() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, age INTEGER, CONSTRAINT chk_age CHECK (age > 0))")
exec("ALTER TABLE t DROP CONSTRAINT chk_age")
run("INSERT INTO t VALUES (1, -5)")
assertEquals(listOf(listOf(int(1))), select("SELECT id FROM t").rows)
}
@Test
fun dropConstraintRemovesANamedUniqueConstraint() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, email TEXT, CONSTRAINT uq_email UNIQUE (email))")
run("INSERT INTO t VALUES (1, 'a@x.com')")
exec("ALTER TABLE t DROP CONSTRAINT uq_email")
run("INSERT INTO t VALUES (2, 'a@x.com')")
assertEquals(2, select("SELECT id FROM t").rows.size)
}
@Test
fun dropConstraintRemovesANamedForeignKeyConstraint() {
run("CREATE TABLE departments (id INTEGER PRIMARY KEY)")
run(
"CREATE TABLE employees (id INTEGER PRIMARY KEY, dept_id INTEGER, " +
"CONSTRAINT fk_dept FOREIGN KEY (dept_id) REFERENCES departments (id))"
)
exec("ALTER TABLE employees DROP CONSTRAINT fk_dept")
run("INSERT INTO employees VALUES (1, 99)")
assertEquals(listOf(listOf(int(1))), select("SELECT id FROM employees").rows)
}
@Test
fun dropConstraintFailsForAnUnknownName() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY)")
val error = assertFailsWith<KestrelException> { run("ALTER TABLE t DROP CONSTRAINT nope") }
assertTrue(error.message!!.contains("no such constraint"), error.message!!)
}
@Test
fun dropConstraintRestrictsWhenAnotherTablesForeignKeyDependsOnTheUniqueConstraint() {
run("CREATE TABLE departments (id INTEGER PRIMARY KEY, code TEXT, CONSTRAINT uq_code UNIQUE (code))")
run(
"CREATE TABLE employees (id INTEGER PRIMARY KEY, dept_code TEXT, " +
"CONSTRAINT fk_dept_code FOREIGN KEY (dept_code) REFERENCES departments (code))"
)
val error = assertFailsWith<KestrelException> { run("ALTER TABLE departments DROP CONSTRAINT uq_code") }
assertTrue(error.message!!.contains("employees"), error.message!!)
}
@Test
fun dropConstraintCascadeRemovesTheDependentForeignKeyOnAnotherTable() {
run("CREATE TABLE departments (id INTEGER PRIMARY KEY, code TEXT, CONSTRAINT uq_code UNIQUE (code))")
run(
"CREATE TABLE employees (id INTEGER PRIMARY KEY, dept_code TEXT, " +
"CONSTRAINT fk_dept_code FOREIGN KEY (dept_code) REFERENCES departments (code))"
)
exec("ALTER TABLE departments DROP CONSTRAINT uq_code CASCADE")
run("INSERT INTO employees VALUES (1, 'nonexistent')")
assertEquals(listOf(listOf(int(1))), select("SELECT id FROM employees").rows)
}
@Test
fun dropConstraintRestrictsASelfReferencingForeignKeyDependentOnItsOwnUniqueConstraint() {
run(
"CREATE TABLE t (id INTEGER PRIMARY KEY, code TEXT, parent_code TEXT, " +
"CONSTRAINT uq_code UNIQUE (code), CONSTRAINT fk_parent FOREIGN KEY (parent_code) REFERENCES t (code))"
)
val error = assertFailsWith<KestrelException> { run("ALTER TABLE t DROP CONSTRAINT uq_code") }
assertTrue(error.message!!.contains("FOREIGN KEY"), error.message!!)
}
@Test
fun dropConstraintCascadeRemovesASelfReferencingForeignKeyThatDependedOnTheDroppedUniqueConstraint() {
run(
"CREATE TABLE t (id INTEGER PRIMARY KEY, code TEXT, parent_code TEXT, " +
"CONSTRAINT uq_code UNIQUE (code), CONSTRAINT fk_parent FOREIGN KEY (parent_code) REFERENCES t (code))"
)
exec("ALTER TABLE t DROP CONSTRAINT uq_code CASCADE")
run("INSERT INTO t VALUES (1, 'a', 'nonexistent')")
assertEquals(listOf(listOf(int(1))), select("SELECT id FROM t").rows)
}
@Test
fun dropConstraintAllowsDroppingAUniqueConstraintWhenAnotherRemainingGroupStillCoversTheSameColumns() {
run(
"CREATE TABLE departments (id INTEGER PRIMARY KEY, code TEXT, " +
"CONSTRAINT uq_code_a UNIQUE (code), CONSTRAINT uq_code_b UNIQUE (code))"
)
run(
"CREATE TABLE employees (id INTEGER PRIMARY KEY, dept_code TEXT, " +
"CONSTRAINT fk_dept_code FOREIGN KEY (dept_code) REFERENCES departments (code))"
)
exec("ALTER TABLE departments DROP CONSTRAINT uq_code_a")
val error = assertFailsWith<KestrelException> { run("INSERT INTO employees VALUES (1, 'nonexistent')") }
assertTrue(error.message!!.contains("FOREIGN KEY constraint failed"), error.message!!)
}
// ---- ALTER COLUMN TYPE ----
@Test
fun changeColumnTypeWideningIntegerToRealCoercesExistingRowsWithNoExplicitUsing() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, score INTEGER)")
run("INSERT INTO t VALUES (1, 10), (2, 20)")
val result = exec("ALTER TABLE t ALTER COLUMN score TYPE REAL")
assertEquals(AlterTableResult("t"), result)
assertEquals(listOf(listOf(real(10.0)), listOf(real(20.0))), select("SELECT score FROM t ORDER BY id ASC").rows)
}
@Test
fun changeColumnTypeWideningIntegerToDecimalCoercesExistingRows() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, amount INTEGER)")
run("INSERT INTO t VALUES (1, 42)")
exec("ALTER TABLE t ALTER COLUMN amount TYPE DECIMAL(10, 2)")
assertEquals(listOf(listOf(decimal("42.00"))), select("SELECT amount FROM t").rows)
}
@Test
fun changeColumnTypeWithUsingConvertsTextToIntegerViaCast() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, code TEXT)")
run("INSERT INTO t VALUES (1, '100'), (2, '200')")
exec("ALTER TABLE t ALTER COLUMN code TYPE INTEGER USING CAST(code AS INTEGER)")
assertEquals(listOf(listOf(int(100)), listOf(int(200))), select("SELECT code FROM t ORDER BY id ASC").rows)
}
@Test
fun changeColumnTypeWithUsingCanReferenceTheRowsOtherColumns() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, price INTEGER, quantity INTEGER)")
run("INSERT INTO t VALUES (1, 10, 3)")
exec("ALTER TABLE t ALTER COLUMN price TYPE INTEGER USING price * quantity")
assertEquals(listOf(listOf(int(30))), select("SELECT price FROM t").rows)
}