Crate mylibsql

Source
Expand description

mylibsql is a personal take on libsql, built for full control over SQLite replication—without a dedicated server. It uses libsql’s virtual WAL to support a primary-replica model where applications handle their own checkpointing and WAL log storage.

§Basic Usage

use mylibsql::*;
use anyhow::Result;

async fn example() -> Result<()> {

    // Initialize a new database
    let (snapshot, log) = init(|conn| {
        conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)", [])?;
        Ok(())
    }).await?;

    // Snapshot and logs are supposed to be stored durably for later use
    todo!("store the snapshot and initial log durably somewhere for later use");

    // Open a primary database from the latest snapshot
    // Note: we don't specify the original log again, as it's already included in the snapshot
    // (but you can use it to recreate the first snapshot from a blank database)
    let primary = Primary::open(&snapshot, &[]).await?;

    // Write to the primary database
    let ack = primary.with_connection(|conn| {
        conn.execute("INSERT INTO users (name) VALUES (?)", ["Alice"])?;
        Ok(())
    }).await?;

    ack.await; // Ensures the write is safely checkpointed

    // Note: you can also peek the query result before it is checkpointed if you want
    dbg!(ack.peek());

    // Checkpoint the database by saving the log to a durable storage
    primary.checkpoint(|log| {
        Box::pin(async move {
            todo!("save log to storage");
        })
    }).await?;

    // Open a read-only replica from the snapshot and logs
    let (last_snapshot, logs): (Snapshot, Vec<Log>) = todo!("fetch snapshot and logs from somewhere");
    let mut replica = Replica::open(&last_snapshot, &logs).await?;

    // Query the replica
    let count: i32 = replica.with_connection(|conn| {
       Ok(conn.query_row("SELECT COUNT(*) FROM users", [], |row| row.get(0))?)
    }).await?;

    // When you receive a new log, you can apply it to the replica
    let new_log = todo!("fetch log from somewhere");
    replica.replicate(&new_log).await?;

    Ok(())
}

Re-exports§

pub use libsql_sys::rusqlite;

Structs§

Ack
A future that resolves when an operation is safely checkpointed
Frames
Live stream of frames from the primary database. Useful if you need a higher granularity than the checkpointing mechanism.
Log
A log file used to store SQLite WAL frames
Primary
A primary database with read-write access
Replica
A replica database with read-only access
Snapshot
A snapshot of a database

Functions§

init
Initializes a new database by running the provided initialization script and returns a snapshot and the first Log. Note: The snapshot already includes the initialization script, so the log should not be reapplied.