glimr_sqlite/db/pool
SQLite Connection Pool
Opening a new SQLite connection per query adds file I/O overhead and risks hitting OS file descriptor limits under load. A pool keeps a fixed set of connections open and lends them out on demand, so queries execute against already-open handles and callers never need to manage connection lifecycle themselves.
Types
Re-exporting sqlight.Connection under a local alias lets the rest of the codebase reference Connection without depending on sqlight directly, so swapping the underlying driver only requires changes here.
pub type Connection =
sqlight.Connection
Re-exporting DbError here keeps downstream modules from importing db just for the error type, reducing coupling to the framework internals.
pub type DbError =
db.DbError
The pool must be opaque so callers can’t bypass the checkout/checkin protocol by accessing the raw connections directly. Storing closures rather than an Erlang PID keeps the Erlang pool internals hidden from Gleam code.
pub opaque type Pool
The Erlang FFI returns closures that capture the pool handle internally, so a named record type is needed to receive them across the FFI boundary. This stays public so the FFI module can construct it.
pub type PoolOps {
PoolOps(
checkout: fn() -> Result(
#(sqlight.Connection, fn() -> Nil),
String,
),
stop: fn() -> Nil,
)
}
Constructors
-
PoolOps( checkout: fn() -> Result( #(sqlight.Connection, fn() -> Nil), String, ), stop: fn() -> Nil, )
Values
pub fn get_connection(
pool: Pool,
f: fn(sqlight.Connection) -> a,
) -> a
A callback-based API guarantees the connection is returned to the pool even if the function crashes, preventing connection leaks that would eventually exhaust the pool under sustained traffic.
pub fn raw_checkout(
pool: Pool,
) -> #(
fn() -> Result(#(sqlight.Connection, fn() -> Nil), String),
fn() -> Nil,
)
The framework’s driver-agnostic Pool vtable needs the raw checkout and stop closures to wire SQLite into the shared db interface. Returning a tuple avoids exposing the opaque Pool internals.
pub fn start_pool(config: db.Config) -> Result(Pool, db.DbError)
Wrapping the FFI result in the opaque Pool type ensures callers interact with the pool only through the public API. The Config is validated inside start, so errors from misconfiguration surface here rather than later.