Module: Sqlite
- Defined in:
- lib/tep/sqlite.rb
Overview
Tep::SQLite – a thin wrapper around the system libsqlite3 for spinel-AOT’d apps. Uses tep_sqlite.c (compiled to tep_sqlite.o) as a stable C ABI surface, exposed via spinel’s ‘ffi_func` DSL.
Why not the ‘sqlite3` gem? It’s a CRuby-MRI native extension (loadable .so/.bundle), which spinel can’t link – spinel produces a single static binary with everything resolved at compile time. The C-shim approach (same pattern as tep’s HTTP server in sphttp.c) replaces “load a gem at runtime” with “link a .o at compile time.”
Usage
db = Tep::SQLite.new
db.open("./app.db")
db.exec("CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT)")
# Parameterised insert: prepare once, bind, step, finalize.
db.prepare("INSERT INTO notes (body) VALUES (?)")
db.bind_str(1, "hello")
db.step
db.finalize
id = db.last_rowid
# Single-row, single-column read.
body = db.first_str("SELECT body FROM notes WHERE id = ?", id.to_s)
# Iterating rows.
db.prepare("SELECT id, body FROM notes ORDER BY id")
while db.step == 1
puts db.col_int(0).to_s + ": " + db.col_str(1)
end
db.finalize
Constraints
- One in-flight cursor per process (the `prepare`/`step`/`finalize`
trio shares a single C-side `sqlite3_stmt *`). Nesting one
query inside another's loop will overwrite the parent cursor.
The framework runs handlers serially per worker so this is
fine for "one DB call per request".
- Columns are read as either str or int. Floats / blobs / NULL
aren't first-class -- a NULL column returns "" (str) or 0 (int).
- The C side caps a single col_str result at 64 KiB. Large blobs
would truncate.
All FFI plumbing lives at the top level (parallel to ‘Sock`) so spinel’s name resolver finds it from anywhere in the Tep tree.