moon-sqlite

SQLite driver for moondb/moonorm — native FFI, amalgamation vendored here (isolated).

sqlite
database
driver
moondb
moonorm
ffi
native
moon add Lfan-ke/moon-sqlite@0.2.0
Download zip
Author
Version
0.2.0
License
Apache-2.0
Last updated
17 days ago
Downloads
116

Dependencies

README

#moon-sqlite

The native SQLite driver for moondbimpl @moondb.Driver.

Check and Test License mooncakes

moon-sqlite implements the moondb Driver interface over the vendored SQLite amalgamation (sqlite/sqlite3.c, public domain). Any moondb-based query layer — moonorm's Session, or a hand-written statement — runs against a real SQLite database through it, unchanged.

This is the only C-touching package in the moondb / moonorm stack. The amalgamation is isolated here so everything above it stays pure MoonBit; the package is native-gated (supported_targets = "native") because it links C.

#Quickstart

The package name is hyphenated, so import it under an alias in moon.pkg.json {"path": "Lfan-ke/moon-sqlite", "alias": "sqlite"} — and reach it as @sqlite (as below). Value constructors come from @moondb (moon add Lfan-ke/moondb).

// native target only — this package links the vendored amalgamation.
fn demo() -> Unit raise @moondb.DbError {
let db = @sqlite.SqliteDriver::open(":memory:") // implements @moondb.Driver
db.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)", [])
|> ignore

// Bound params map to SQLite storage classes — never spliced into the SQL text.
db.execute("INSERT INTO users (name, age) VALUES (?, ?)", [
@moondb.Text("alice"), @moondb.Int(30),
]) |> ignore

// Result columns decode back into @moondb.Value by their runtime type.
let rows = db.query("SELECT name, age FROM users WHERE age > ?", [@moondb.Int(18)])
let _ = rows[0].text(0) // "alice"
let _ = rows[0].int(1) // 30
db.close()
}

SqliteDriver implements the full @moondb.Driver contract — execute, query, begin / commit / rollback, and close — plus an exec_script helper that runs a semicolon-separated DDL block in one call. Every fallible operation raises @moondb.DbError; the backend's own message rides through on QueryError.

#Using it with moonorm

let sess = @moonorm.Session::new(@sqlite.SqliteDriver::open("app.db"))
sess.add(@moonorm.insert("users").set("name", @moondb.Text("bob"))) |> ignore
let rows = sess.fetch(@moonorm.select("users").where_("name", "=", @moondb.Text("bob")))

The query builder is dialect-neutral and pure; this driver adapts it to SQLite's wire. Because moonorm and moon-sqlite both speak @moondb, swapping SQLite for another backend is a one-line change at Session::new.

#Design & boundaries (honest)

  • Isolated C. The amalgamation and a thin FFI stub (sqlite/stub.c) live in sqlite/, marked linguist-vendored so GitHub reports this as a MoonBit project. Nothing outside this package touches C.
  • Handles are integers. Opaque sqlite3* / sqlite3_stmt* pointers cross the FFI as Int64 (their pointer bits), inert to the GC — the native runtime never reference-counts or frees a foreign pointer.
  • Injection-safe to the wire. Values are bound out-of-band by SQLite (sqlite3_bind_*), never interpolated into the SQL string. Text, integers, doubles, blobs, booleans (as 0/1), and NULL all round-trip.
  • Real, verified execution. The integration tests open an actual in-memory SQLite database and assert on rows read back across CREATE / INSERT / SELECT / UPDATE / DELETE, transactions, blob round-trips, and error propagation. They are mutation-verified: neutering the C bind path turns them red, so "it runs" is proven, not claimed.

#License

Apache-2.0. The bundled SQLite amalgamation (sqlite/sqlite3.c, sqlite/sqlite3.h) is public domain, vendored here unmodified.

#
SqliteCursor

type SqliteCursor

A streaming cursor over a live prepared statement: each next steps SQLite once and materialises a single row, so a large result is consumed row by row (moondb's query_stream) rather than buffered by query. The statement is finalised at the end of the result or on close.

#
SqliteDriver

pub struct SqliteDriver {
handle : Int64
closed : Bool
}

A live connection to a SQLite database. Open it with SqliteDriver::open; it implements @moondb.Driver, so a moondb query layer can drive it directly. The opaque sqlite3* is carried as its pointer bits in handle.

#
SqliteDriver::exec_script

fn SqliteDriver::exec_script(self : SqliteDriver, script : String) -> Unit raise
DbError

Run a semicolon-separated script (e.g. a schema DDL block) in one call. Unlike execute, this uses SQLite's multi-statement exec path and binds no parameters. Raises @moondb.QueryError with SQLite's message on failure.

#
SqliteDriver::is_closed

fn SqliteDriver::is_closed(self : SqliteDriver) -> Bool

Whether close has been called. Once closed, every statement raises @moondb.Closed rather than touching the freed sqlite3*.

#
SqliteDriver::open

Open (or create) the database at path. Use ":memory:" for a private in-memory database. Raises @moondb.ConnectError if the file cannot be opened.

Source Files