glite

glite: a SQLite driver for Gleam on the Erlang VM.

One connection is one actor that owns the SQLite handle and runs every call on it, one at a time. Share a Connection between processes freely: calls queue up, and a transaction runs as one call, so nothing else can mix into it.

import glite
import glite/config
import glite/decode

pub fn main() {
  let assert Ok(conn) = glite.connect(config.new("app.db"))
  let assert Ok(Nil) =
    glite.exec_script(conn, "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
  let assert Ok(id) =
    glite.query_one(
      conn,
      "INSERT INTO users (name) VALUES (?) RETURNING id",
      [glite.text("Alice")],
      {
        use id <- decode.element(0, decode.int)
        decode.success(id)
      },
    )
  let assert Ok(Nil) = glite.disconnect(conn)
}

Types

What backup wrote.

pub type Backup {
  Backup(path: String, bytes: Int)
}

Constructors

  • Backup(path: String, bytes: Int)

A connection to one SQLite database.

pub opaque type Connection

A message to a connection’s actor. Use it to name a supervised connection: process.new_name("db") gives a Name(glite.Message).

pub type Message =
  @internal Message

A query parameter.

pub type Param =
  value.Value

Column names and raw rows from query_rows.

pub type Rows =
  @internal Rows

Why a transaction did not commit.

pub type TransactionError(e) {
  RolledBack(e)
  Database(error.Error)
}

Constructors

  • RolledBack(e)

    The callback returned Error(e); everything it did was rolled back.

  • Database(error.Error)

    The database or the connection failed; nothing was committed.

How a transaction takes its locks.

pub type TransactionMode {
  Immediate
  Deferred
  Exclusive
}

Constructors

  • Immediate

    Take the write lock at BEGIN. Use this for any transaction that writes: it can’t fail halfway through because another connection wrote first.

  • Deferred

    Take locks as statements need them. Fine for read-only transactions.

  • Exclusive

    Take the write lock at BEGIN and keep readers out (outside WAL mode).

Values

pub fn backup(
  conn: Connection,
  to path: String,
) -> Result(Backup, error.Error)

Write a consistent copy of the database to path with VACUUM INTO, check the copy with PRAGMA integrity_check, and fsync it. path must not exist yet. Writers wait while the copy is made.

pub fn blob(value: BitArray) -> value.Value
pub fn bool(value: Bool) -> value.Value

A boolean, stored as the integer 0 or 1.

pub fn connect(
  config: config.Config,
) -> Result(Connection, error.Error)

Open a database and start its actor, linked to the calling process. Every setting in the config is checked after opening; if SQLite didn’t apply one, such as WAL mode, this returns PragmaMismatch.

pub fn disconnect(conn: Connection) -> Result(Nil, error.Error)

Close the database and stop the actor. Closing a connection that is already closed returns Ok(Nil). Stopping a supervised connection makes its supervisor start a new one; stop the supervisor instead.

pub fn exec(
  conn: Connection,
  sql: String,
  params: List(value.Value),
) -> Result(Int, error.Error)

Run one statement and return the number of rows it changed: always 0 for statements other than INSERT, UPDATE, DELETE and REPLACE.

The SQL must be one statement, with exactly as many parameters as it has placeholders.

pub fn exec_many(
  conn: Connection,
  sql: String,
  params: List(List(value.Value)),
) -> Result(Int, error.Error)

Run one statement once per parameter list, all or nothing: if one run fails, the runs before it are rolled back. Returns the rows changed in total.

pub fn exec_script(
  conn: Connection,
  sql: String,
) -> Result(Nil, error.Error)

Run a script of several statements, without parameters, such as a schema migration.

pub fn float(value: Float) -> value.Value
pub fn int(value: Int) -> value.Value
pub fn named(name: process.Name(Message)) -> Connection

A connection to the supervised actor registered under name. Calls return ConnectionClosed while no actor is registered.

pub fn null() -> value.Value
pub fn nullable(
  value: option.Option(a),
  to_param: fn(a) -> value.Value,
) -> value.Value

None becomes NULL; Some(x) becomes to_param(x).

pub fn query(
  conn: Connection,
  sql: String,
  params: List(value.Value),
  decoder: decode.RowDecoder(a),
) -> Result(List(a), error.Error)

Run a query and decode every row. More than max_rows rows is an error.

pub fn query_one(
  conn: Connection,
  sql: String,
  params: List(value.Value),
  decoder: decode.RowDecoder(a),
) -> Result(a, error.Error)

Run a query that returns exactly one row, and decode it. No rows, or more than one, is a Decode error.

pub fn query_rows(
  conn: Connection,
  sql: String,
  params: List(value.Value),
) -> Result(Rows, error.Error)

Run a query and return its column names and raw rows.

pub fn set_user_version(
  conn: Connection,
  version: Int,
) -> Result(Nil, error.Error)

Set the database’s user_version.

pub fn supervised(
  config: config.Config,
  name: process.Name(Message),
) -> supervision.ChildSpecification(Connection)

A child specification for a supervisor. The connection’s actor registers under name; get a Connection for it with named. If the actor crashes, the supervisor restarts it, which opens the database again.

let db_name = process.new_name("db")
let assert Ok(_) =
  static_supervisor.new(static_supervisor.OneForOne)
  |> static_supervisor.add(glite.supervised(config, db_name))
  |> static_supervisor.start
let conn = glite.named(db_name)
pub fn text(value: String) -> value.Value
pub fn transaction(
  conn: Connection,
  mode: TransactionMode,
  body: fn(tx.Tx) -> Result(a, e),
) -> Result(a, TransactionError(e))

Run body in a transaction: commit if it returns Ok, roll back if it returns Error or panics. A panic is rolled back and then re-raised in the calling process.

The body runs inside the connection’s actor, so no other caller’s statements can mix into the transaction. Use the Tx it gets, not the Connection: calling the connection from inside the body panics.

The whole transaction must finish within call_timeout_ms. If it doesn’t, its running statement is interrupted, it is rolled back, and the result is Database(Timeout(_)).

pub fn user_version(conn: Connection) -> Result(Int, error.Error)

The database’s user_version, for schema migrations.

✨ Search Document