Lua runner with rich builtin stdlib
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
a/lua/test_sqlite.lua

115 lines
4.1 KiB

-- Exercise of the sqlite stdlib module.
local function assert_eq(actual, expected, msg)
if actual ~= expected then
error(
string.format("%s: expected %s, got %s", msg or "assertion failed", tostring(expected), tostring(actual)),
2
)
end
end
print("=== connect (in-memory) ===")
local con = sqlite.connect(":memory:")
print("=== CREATE TABLE / INSERT ===")
con:execute([[
CREATE TABLE people (
id INTEGER PRIMARY KEY,
name TEXT,
age INTEGER,
score REAL,
vip INTEGER,
notes TEXT
)
]])
-- Positional params, every supported type.
local changed = con:execute(
"INSERT INTO people (name, age, score, vip, notes) VALUES (?, ?, ?, ?, ?)",
{ "Alice", 30, 9.5, true, "first" }
)
assert_eq(changed, 1, "execute returns rows changed")
assert_eq(con:changes(), 1, "changes() after insert")
local first_id = con:lastInsertRowid()
assert_eq(first_id, 1, "lastInsertRowid")
-- Named params (mix of :name in SQL).
con:execute(
"INSERT INTO people (name, age, score, vip, notes) VALUES (:name, :age, :score, :vip, :notes)",
{ name = "Bob", age = 42, score = 7.25, vip = false, notes = utils.NULL }
)
assert_eq(con:lastInsertRowid(), 2, "lastInsertRowid after second insert")
print("=== SELECT (query) ===")
local rows = con:query("SELECT * FROM people ORDER BY id")
assert_eq(#rows, 2, "query returns 2 rows")
assert_eq(rows[1].name, "Alice", "row 1 name")
assert_eq(rows[1].age, 30, "row 1 age (integer round-trip)")
assert_eq(rows[1].score, 9.5, "row 1 score (real round-trip)")
assert_eq(rows[1].vip, 1, "row 1 vip (boolean stored as 1)")
assert_eq(rows[1].notes, "first", "row 1 notes (text round-trip)")
-- A SQL NULL comes back as nil (absent key).
assert_eq(rows[2].notes, nil, "row 2 notes is nil (NULL round-trip)")
print("=== queryOne ===")
local bob = con:queryOne("SELECT * FROM people WHERE name = ?", { "Bob" })
assert(bob ~= nil, "queryOne found Bob")
assert_eq(bob.age, 42, "queryOne Bob age")
local missing = con:queryOne("SELECT * FROM people WHERE name = ?", { "Nobody" })
assert_eq(missing, nil, "queryOne returns nil for no match")
print("=== UPDATE / DELETE ===")
local n = con:execute("UPDATE people SET age = age + 1 WHERE name = :who", { who = "Alice" })
assert_eq(n, 1, "update affected 1 row")
assert_eq(con:queryOne("SELECT age FROM people WHERE name = ?", { "Alice" }).age, 31, "age incremented")
n = con:execute("DELETE FROM people WHERE name = ?", { "Bob" })
assert_eq(n, 1, "delete affected 1 row")
assert_eq(#con:query("SELECT * FROM people"), 1, "one row left after delete")
print("=== transaction(fn) — commit ===")
con:transaction(function()
con:execute("INSERT INTO people (name, age) VALUES (?, ?)", { "Carol", 25 })
con:execute("INSERT INTO people (name, age) VALUES (?, ?)", { "Dave", 28 })
end)
assert_eq(#con:query("SELECT * FROM people"), 3, "two rows committed")
print("=== transaction(fn) — rollback on error ===")
local ok, err = pcall(function()
con:transaction(function()
con:execute("INSERT INTO people (name, age) VALUES (?, ?)", { "Eve", 99 })
error("boom")
end)
end)
assert_eq(ok, false, "transaction propagated the error")
assert(tostring(err):find("boom"), "original error message preserved")
assert_eq(#con:query("SELECT * FROM people"), 3, "failed transaction rolled back")
print("=== manual begin / commit ===")
con:begin()
con:execute("INSERT INTO people (name, age) VALUES (?, ?)", { "Frank", 50 })
con:commit()
assert_eq(#con:query("SELECT * FROM people"), 4, "manual commit persisted")
print("=== manual begin / rollback ===")
con:begin()
con:execute("INSERT INTO people (name, age) VALUES (?, ?)", { "Grace", 60 })
con:rollback()
assert_eq(#con:query("SELECT * FROM people"), 4, "manual rollback discarded")
print("=== mixed param table is rejected ===")
local mixed_ok = pcall(function()
con:query("SELECT 1 WHERE 1 = ?", { 1, key = "x" })
end)
assert_eq(mixed_ok, false, "mixed positional/named params error")
print("=== close ===")
con:close()
local closed_ok = pcall(function()
con:query("SELECT 1")
end)
assert_eq(closed_ok, false, "use after close errors")
print("\nAll sqlite checks passed.")