Luau Bindings — db

The require("db") script API — raw DBFS/SQLite access. This is the layer beneath fs: fs gives you files, metadata, tags, and the safe fs.query catalogue search; db gives you arbitrary SQL against the same SQLite database — for custom application tables and queries fs.query can't express. Every function is [antos]. Design & native core: antos_db.

local db = require("db")
local n = db.scalar("SELECT count(*) FROM files WHERE kind = ?", { "dir" })

db operates on the active DBFS (sys.db on D:) by default. All calls are D:-only — off DBFS they return nil, err. Always parameterise — bind values as ? (positional, from an array) or :name (named, from a table); never concatenate values into SQL.


Querying

Function Behaviour
db.query(sql [, params]) Run a SELECT; returns an array of row tables, or nil, err.
db.rows(sql [, params]) Iterator over result rows — streams, for large result sets.
db.get(sql [, params]) First row as a table, or nil.
db.scalar(sql [, params]) First column of the first row (a single value), or nil.
db.exec(sql [, params]) Run INSERT/UPDATE/DELETE/DDL; returns { changes, last_rowid }, or nil, err.
local db = require("db")

-- a custom application table (prefix keeps it clear of system tables)
db.exec("CREATE TABLE IF NOT EXISTS app_notes_items (id INTEGER PRIMARY KEY, body TEXT, done INTEGER DEFAULT 0)")
db.exec("INSERT INTO app_notes_items (body) VALUES (?)", { "buy milk" })

for row in db.rows("SELECT id, body FROM app_notes_items WHERE done = 0") do
  print(row.id, row.body)
end

Prepared statements

Function Behaviour
db.prepare(sql) Compile once → a statement handle for repeated execution.

Handle methods: stmt:query(params), stmt:rows(params), stmt:get(params), stmt:scalar(params), stmt:exec(params), stmt:close().

local ins = db.prepare("INSERT INTO app_log_lines (ts, msg) VALUES (?, ?)")
for _, m in ipairs(messages) do ins:exec({ os.time(), m }) end
ins:close()

Transactions

Function Behaviour
db.transaction(fn) Run fn inside a transaction — commits if it returns normally, rolls back if it errors or returns false. Returns fn's result.
db.begin() · db.commit() · db.rollback() Manual control, when the scoped form doesn't fit.
db.transaction(function()
  db.exec("UPDATE app_bank SET balance = balance - ? WHERE id = ?", { 10, 1 })
  db.exec("UPDATE app_bank SET balance = balance + ? WHERE id = ?", { 10, 2 })
end)   -- both apply, or neither

Schema & introspection

Function Behaviour
db.tables() Array of table names.
db.columns(table) Column info for a table.
db.schema_version() (alias db.schemaVersion()) The DBFS schema version.

Other databases

Function Behaviour
db.open(path) Open another DBFS / SQLite file → a db handle with the same methods; handle:close(). Default target is the active sys.db.

Notes

  • db and fs are two views of one database. Prefer fs for files, metadata, and tags, and fs.query for catalogue search; reach for db when you need custom tables or SQL fs.query can't express.
  • Name custom tables to avoid collisions with system tables (convention: app_<name>_…). Writing directly to the system catalogue tables is unsupported — use fs for files and tags.
  • db writes go through the same DBFS path as everything else, so they are transactional and covered by the D!: shadow backup — a db insert is as durable as a file write.

Related

Important: The Ant64 family of home computers are at early design/prototype stage, everything you see here is subject to change.