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.