Tursox

Hex.pmHexDocsCILicense: MIT

Tursox is an Elixir wrapper around the embedded Turso engine. It preserves Turso's ownership model: one database derives independent connections, real prepared statements, and bounded row cursors. Optional shared-handle DBConnection pools and caller-supervised multi-database managers build on the same resources. There is no global registry.

Version 0.1.0 pins Turso 0.7.2 and Rust 1.91.0. MVCC is explicit and remains experimental upstream. See the capability matrix and compatibility notes.

Installation

After release, add:

def deps, do: [{:tursox, "~> 0.1.0"}]

Supported targets use NIF 2.16 precompiled binaries after their published checksums are committed. Set TURSOX_BUILD=1 to force a source build with the pinned Rust toolchain. A missing or invalid precompiled artifact fails loudly; it never silently falls back to an unverified binary.

Direct resources

{:ok, database} = Tursox.Database.open("data/app.db", journal_mode: :wal)
{:ok, connection} = Tursox.Database.connect(database, busy_timeout: 5_000)
:ok = Tursox.Connection.execute(connection, "CREATE TABLE IF NOT EXISTS users (id INTEGER, name TEXT)")
{:ok, statement} = Tursox.Connection.prepare(connection, "INSERT INTO users VALUES (?, ?)")
{:ok, _result} = Tursox.Statement.execute(statement, [1, "Ada"])
{:ok, cursor} = Tursox.Connection.query(connection, "SELECT id, name FROM users ORDER BY id")
{:done, rows} = Tursox.Cursor.fetch(cursor, 100)
:ok = Tursox.Connection.close(connection)
:ok = Tursox.Database.close(database)

Rows are ordered lists. Parameters are strict positional lists or named maps; use {:blob, binary} for BLOBs. Fetches are bounded to 10,000 rows. For details, see databases and connections, queries and cursors, and transactions and MVCC.

Pool and manager

{:ok, pool} = Tursox.Pool.start_link(database: "data/app.db", pool_size: 4)
{:ok, result} = Tursox.Pool.execute(pool, "UPDATE users SET name = ? WHERE id = ?", ["Grace", 1])
{:ok, manager} = Tursox.Manager.start_link(max_databases: 100)
{:ok, tenant_pool} = Tursox.Manager.open(manager, tenant_id, "data/tenant.db", pool_size: 4)

One pool owns one database and derives N workers from that shared handle. A manager atomically enforces tenant IDs, canonical paths, and capacity without creating dynamic atoms. See pools and managers.

Runtime and observability

Native work runs on dirty schedulers through one process-lifetime Tokio runtime. Resource close is logical, idempotent, ancestry-aware, and inspect-safe. Telemetry events under [:tursox, ...] include durations and result classes but never SQL, parameters, rows, tokens, or database contents. Tursox.resources/0 returns logical native resource gauges.

Development

bin/qa_check.sh

No sibling checkout or network service is required for normal QA. Precompiled release publication is a separate manual workflow and is never implied by a source commit.

License

MIT. See LICENSE and THIRD_PARTY_NOTICES.md.