test(sql): cover whereFiltersRowsUsingTheSharedEvaluator
This commit is contained in:
1 parent
8858671825
commit
ae50dd1aa7
1 file changed
+157
@@ -153,3 +153,160 @@ class DiskExecutorTest {
|
|||||||
assertTrue(listOf(int(1), text("ada"), int(36)) in result.rows)
|
assertTrue(listOf(int(1), text("ada"), int(36)) in result.rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whereFiltersRowsUsingTheSharedEvaluator() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedUsers()
|
||||||
|
val result = db.select("SELECT name FROM users WHERE age > 40")
|
||||||
|
assertEquals(setOf(text("linus"), text("grace")), result.rows.map { it.single() }.toSet())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun orderByAndLimitApplyAfterFilteringAndBeforeProjection() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedUsers()
|
||||||
|
val result = db.select("SELECT name, age FROM users ORDER BY age DESC LIMIT 2")
|
||||||
|
assertEquals(listOf(listOf(text("grace"), int(85)), listOf(text("linus"), int(54))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun offsetSkipsLeadingRowsWithoutALimit() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedUsers()
|
||||||
|
val result = db.select("SELECT name FROM users ORDER BY age ASC OFFSET 1")
|
||||||
|
assertEquals(listOf(listOf(text("linus")), listOf(text("grace"))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun limitAndOffsetTogetherPageThroughTheOrderedResult() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedUsers()
|
||||||
|
val result = db.select("SELECT name FROM users ORDER BY age ASC LIMIT 1 OFFSET 1")
|
||||||
|
assertEquals(listOf(listOf(text("linus"))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun offsetWrittenBeforeLimitStillAppliesLimitAfterTheSkip() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedUsers()
|
||||||
|
val result = db.select("SELECT name FROM users ORDER BY age ASC OFFSET 1 LIMIT 1")
|
||||||
|
assertEquals(listOf(listOf(text("linus"))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun offsetPastTheEndOfTheResultReturnsNoRows() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedUsers()
|
||||||
|
val result = db.select("SELECT name FROM users ORDER BY age ASC OFFSET 100")
|
||||||
|
assertEquals(emptyList<List<Value>>(), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun offsetSurvivesCloseAndReopen() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedUsers()
|
||||||
|
db.reopen()
|
||||||
|
val result = db.select("SELECT name FROM users ORDER BY age ASC LIMIT 1 OFFSET 1")
|
||||||
|
assertEquals(listOf(listOf(text("linus"))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun expressionProjectionEvaluatesFunctionsAndUsesAliasesOrGeneratedLabels() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedUsers()
|
||||||
|
val result = db.select("SELECT UPPER(name) AS loud, age + 1 FROM users WHERE id = 1")
|
||||||
|
assertEquals(listOf("loud", "column2"), result.columns)
|
||||||
|
assertEquals(listOf(listOf(text("ADA"), int(37))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun updateAppliesExpressionsAgainstTheOldRowAndReportsMatchedCount() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedUsers()
|
||||||
|
val updated = db.run("UPDATE users SET age = age + 1 WHERE age > 40").single()
|
||||||
|
assertEquals(UpdateResult(2), updated)
|
||||||
|
val ages = db.select("SELECT name, age FROM users ORDER BY name").rows.associate { (it[0] as Value.TextValue).value to it[1] }
|
||||||
|
assertEquals(mapOf("ada" to int(36), "linus" to int(55), "grace" to int(86)), ages)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun updateSetToDefaultKeywordResetsTheColumn() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedUsers()
|
||||||
|
db.run("UPDATE users SET age = DEFAULT WHERE id = 2")
|
||||||
|
assertEquals(int(0), db.select("SELECT age FROM users WHERE id = 2").rows.single().single())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun deleteRemovesMatchingRowsAndReportsCount() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedUsers()
|
||||||
|
val deleted = db.run("DELETE FROM users WHERE age > 40").single()
|
||||||
|
assertEquals(DeleteResult(2), deleted)
|
||||||
|
assertEquals(listOf(listOf(int(1), text("ada"), int(36))), db.select("SELECT * FROM users").rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dropTableRemovesItFromTheCatalog() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
|
||||||
|
val dropped = db.run("DROP TABLE users").single()
|
||||||
|
assertEquals(DropTableResult("users"), dropped)
|
||||||
|
assertFailsWith<DiskCatalogException> { db.select("SELECT * FROM users") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun aFailedStatementInAMultiRowInsertLeavesNoPartialRowsBehind() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
|
||||||
|
// The second row duplicates the first row's primary key: DiskTable rejects it mid-batch,
|
||||||
|
// so the whole INSERT statement (including the already-applied first row) must abort.
|
||||||
|
assertFailsWith<DiskTableException> {
|
||||||
|
db.run("INSERT INTO users VALUES (1, 'ada'), (1, 'ada-again')")
|
||||||
|
}
|
||||||
|
assertEquals(emptyList<List<Value>>(), db.select("SELECT * FROM users").rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun notNullViolationOnUpdateAbortsTheWholeStatement() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
|
||||||
|
db.run("INSERT INTO users VALUES (1, 'ada'), (2, 'linus')")
|
||||||
|
assertFailsWith<DiskTableException> { db.run("UPDATE users SET name = NULL") }
|
||||||
|
// Neither row's name was actually cleared, because the failure aborted the transaction.
|
||||||
|
assertEquals(setOf(text("ada"), text("linus")), db.select("SELECT name FROM users").rows.map { it.single() }.toSet())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun integerLiteralIsCoercedToRealForARealColumn() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE readings (id INTEGER PRIMARY KEY, value REAL NOT NULL)")
|
||||||
|
db.run("INSERT INTO readings VALUES (1, 5)")
|
||||||
|
assertEquals(Value.RealValue(5.0), db.select("SELECT value FROM readings").rows.single().single())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun textLiteralIntoAnIntegerColumnIsRejectedWithATypeMismatch() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
|
||||||
|
assertFailsWith<DiskExecutorException> { db.run("INSERT INTO users VALUES ('x', 'ada')") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dataSurvivesClosingAndReopeningTheCatalogInWhatActsAsAFreshProcess() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedUsers()
|
||||||
|
db.run("UPDATE users SET age = 100 WHERE id = 1")
|
||||||
|
db.reopen()
|
||||||
|
val ages = db.select("SELECT name, age FROM users ORDER BY name").rows
|
||||||
|
assertEquals(listOf(listOf(text("ada"), int(100)), listOf(text("grace"), int(85)), listOf(text("linus"), int(54))), ages)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Database.seedOrders() {
|
||||||
|
run("CREATE TABLE customers (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
|
||||||
|
run("INSERT INTO customers VALUES (1, 'ada'), (2, 'linus'), (3, 'grace')")
|
||||||
|
run("CREATE TABLE orders (id INTEGER PRIMARY KEY, customer_id INTEGER NOT NULL, amount INTEGER NOT NULL)")
|
||||||
|
// grace (id 3) has no orders, so LEFT JOIN has something to pad and INNER JOIN has something to drop.
|
||||||
|
run("INSERT INTO orders VALUES (1, 1, 100), (2, 1, 50), (3, 2, 200)")
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user