WASIX Rust guide

Use typed queries, transactions, extensions, backups, and async execution.

These recipes use a mutable synchronous db from the WASIX Rust quickstart. The async API exposes equivalent operations with .await.

Query application data

db.execute("CREATE TABLE IF NOT EXISTS notes (body text NOT NULL)")?;
db.execute_with_params("INSERT INTO notes (body) VALUES ($1)", ["First note"])?;
let result = db.query("SELECT body FROM notes")?;
let body: String = result.rows()[0].try_get("body")?;

Use bound parameters for values. Match Rust result types to PostgreSQL column types and use Option<T> for nullable values.

Run a transaction

db.transaction(|tx| {
    tx.execute_with_params("INSERT INTO notes (body) VALUES ($1)", ["First"])?;
    tx.execute_with_params("INSERT INTO notes (body) VALUES ($1)", ["Second"])?;
    Ok::<_, oliphaunt_wasix::Error>(())
})?;

Return Ok to commit or Err to roll back. Use the transaction handle for all callback SQL. Manual outer transaction-lifecycle SQL is unsupported; use the rollback API or savepoints instead.

Select extensions

Add the extension crate with its WASIX feature:

[dependencies]
oliphaunt-wasix = "0.3.0"
oliphaunt-extension-pgtap = { version = "0.3.0", default-features = false, features = ["wasix"] }

Select it before opening, then enable it with SQL:

use oliphaunt_wasix::Oliphaunt;

let mut db = Oliphaunt::builder()
    .extension(oliphaunt_extension_pgtap::PGTAP)
    .open()?;
db.execute("CREATE EXTENSION IF NOT EXISTS pgtap")?;

Reopen persistent databases with the same required extension selection. The extension catalog lists supported names and targets.

Back up and restore

let archive = db.backup()?;
db.close()?;
oliphaunt_wasix::Oliphaunt::restore("./data/restored", archive)?;

The destination must be new or empty. Use a compatible WASIX runtime for physical restore, and ship required extensions separately. For SQL export and upgrades, see Dump and restore.

Configure startup

Use the builder's startup_guc(name, value), username(...), and database(...) methods. Fresh roots use the postgres role and database. Selecting another identity does not create it.

Use async execution

Use AsyncOliphaunt to keep blocking guest execution off an async executor. Cloned handles share the same session. Closing any clone closes it for all callers.

The synchronous handle remains on one OS thread for its entire lifetime. Do not move it into a generic blocking pool between calls. See runtime ownership.

Errors and shutdown

Inspect error.kind() and error.postgres_error() for structured failures. PostgreSQL errors include SQLSTATE. Transaction errors preserve callback and rollback/database failures when both occur.

Close explicitly to observe shutdown errors. After a terminal failure, stop using the handle and reopen persistent storage when appropriate. The SDK does not expose direct-query cancellation; dropping a future does not guarantee that an already-running statement stops.

SymptomCheck
Cannot send the handle to another threadUse AsyncOliphaunt or keep the synchronous handle on its original thread
Directory is lockedAnother process, Worker, or binding owns the root
Extension constant is unavailableAdd the extension crate with its wasix feature
SQL dump fails to import through executeUse the psql tool to handle COPY and psql commands