mlua_batteries_sqlite/lib.rs
1//! SQLite bridge for [`mlua-batteries`](https://crates.io/crates/mlua-batteries):
2//! the `std.sql` and `std.kv` Lua modules, built on
3//! [`rusqlite`](https://crates.io/crates/rusqlite) and
4//! `tokio::task::spawn_blocking`.
5//!
6//! ```rust,ignore
7//! use std::sync::{Arc, Mutex};
8//! use mlua::prelude::*;
9//! use mlua_batteries_sqlite::rusqlite::Connection;
10//!
11//! let lua = Lua::new();
12//! mlua_batteries::register_all(&lua, "std")?;
13//! mlua_batteries::task::register(&lua)?;
14//!
15//! let conn = Connection::open_in_memory()?;
16//! let interrupt = Arc::new(conn.get_interrupt_handle());
17//! let conn = Arc::new(Mutex::new(conn));
18//! mlua_batteries_sqlite::sql::register(&lua, conn.clone(), interrupt.clone())?;
19//! mlua_batteries_sqlite::kv::register(&lua, conn, interrupt)?;
20//! // Lua: std.sql.query("SELECT 1 AS n")
21//! ```
22//!
23//! # Why this is a separate crate
24//!
25//! `libsqlite3-sys` declares `links = "sqlite3"`, so a build graph can hold
26//! exactly one of its major versions — and cargo enforces that while
27//! *resolving* dependencies, which means no crate can offer several clusters
28//! behind mutually exclusive features. Keeping the SQLite dependency on this
29//! small bridge leaves `mlua-batteries` itself free of a C library, and
30//! leaves its version line free for its own features. The `rusqlite` this
31//! crate is built against is re-exported as [`rusqlite`]; name the host's
32//! types through it.
33//!
34//! Hosts that already run SQLite on a
35//! [`rusqlite-isle`](https://crates.io/crates/rusqlite-isle) connection thread
36//! want
37//! [`mlua-batteries-sqlite-isle`](https://crates.io/crates/mlua-batteries-sqlite-isle)
38//! instead — the same Lua API on an `AsyncIsle`, on the same rusqlite cluster.
39//!
40//! # Wiring
41//!
42//! The host owns the [`rusqlite::Connection`] (file path, `busy_timeout` and
43//! `journal_mode` are host-side concerns) and its
44//! [`rusqlite::InterruptHandle`], and passes them wrapped in `Arc<Mutex<_>>`
45//! / `Arc<_>`. This crate does not open the database, does not read
46//! environment variables, and does not attempt to recover from a corrupt
47//! connection.
48//!
49//! Statements run inside `tokio::task::spawn_blocking`, with the mutex taken
50//! inside the blocking closure so no lock guard is held across an `.await`.
51//! Every query races the enclosing `task.scope` / `task.with_timeout` cancel
52//! token and the [`SqlConfig`] query timeout; when either fires the bridge
53//! calls `sqlite3_interrupt` through the stored handle so the blocking thread
54//! returns and releases the connection.
55//!
56//! `std.sql` and `std.kv` are typically given **separate** connections:
57//! keeping KV scratch state out of the user database keeps their backup /
58//! WAL / page-cache lifecycles from colliding.
59
60pub mod kv;
61pub mod sql;
62mod sqlite_backend;
63
64/// The `rusqlite` this crate is built against.
65///
66/// Name the host's types through this re-export instead of declaring a second
67/// `rusqlite` dependency, which could drift onto another cluster.
68pub use sqlite_backend::rusqlite;
69
70pub use sql::SqlConfig;