Skip to main content
Version: v1.3.0

Rust

The zova crate is the normal safe Rust interface. It wraps database, statement, writer, listener, vector, graph, and operational results with owned Rust types and deterministic cleanup. zova-sys exposes the raw C ABI for lower-level integration.

Install and open​

cargo add zova@1.3.0
use zova::Database;

let mut db = Database::create("app.zova")?;
db.exec(
"create table settings(\
key text primary key,\
value text not null\
)",
)?;

Use Database::create for a new destination and Database::open for an existing Zova file. Open options support read-only handles. Zova does not install a nonzero SQLite busy timeout unless the application requests one.

Choose the ownership model​

Database suits single-owner code and exposes mutating operations through a mutable reference. SharedDatabase is a cloneable Send + Sync handle whose calls are serialized by an internal mutex.

Serialization makes one handle safe to share; it does not provide parallel SQLite calls. Open multiple database handles when true SQLite concurrency is required, then account for normal SQLite locking and configure a busy timeout deliberately.

Use SharedDatabase::with_exclusive, transaction, or transaction_immediate when a multi-call unit on the shared handle must not interleave with other callers.

Work with statements​

use zova::Step;

let mut insert = db.prepare(
"insert into settings(key, value) values (?1, ?2)",
)?;
insert.bind_text(1, "theme")?;
insert.bind_text(2, "sage")?;
assert_eq!(insert.step()?, Step::Done);
drop(insert);

let mut query = db.prepare(
"select value from settings where key = ?1",
)?;
query.bind_text(1, "theme")?;
assert_eq!(query.step()?, Step::Row);
assert_eq!(query.column_text(0)?, Some("sage"));

Dropping statements and result owners releases their native resources. Do not try to use a database mutably while a statement still holds the corresponding borrow; finish or drop the statement first.

Transactions and scoped work​

The crate exposes transactions, immediate transactions, named savepoints, and closure-based savepoint helpers. On a shared handle, scoped guards keep the mutex for the complete unit so another clone cannot interleave calls in the middle.

Since 1.2.0, transaction, transaction_immediate, and with_savepoint roll their scope back when the closure returns an error and also when it panics. The rollback happens before the connection lock is released, then the panic propagates unchanged; use std::panic::catch_unwind to recover from it. This does not apply to panic = "abort" profiles or process termination. If a rollback fails, that SharedDatabase handle is retired and its later calls fail; open a new one.

Use the transaction APIs rather than issuing raw transaction SQL when app events or Zova's transaction-aware behavior must track the scope.

Specialized storage​

The safe crate covers:

  • complete and streaming objects, range reads, chunks, and assembly;
  • transactional binary KV and in-memory databases;
  • typed vector collections, CRUD, batch writes, and exact search;
  • graphs, nodes, edges, neighbors, and bounded walks;
  • SQL-native vector and graph helpers through prepared statements;
  • same-process app events; and
  • backup, compact, restore, and bundled extension lifecycle.

After opening a main database with bound stores, the same object, vector, and graph methods route transparently. Creating, binding, splitting, and unbinding stores remains CLI/native Zig-only in v1.3.0.

Native packaging and extensions​

The crate selects a target-specific generated-C companion crate, so supported consumers need Rust 1.79+ and a C compiler but not Zig or a build-time source download. Bundled extensions such as trgm are available through safe lifecycle methods.

Since 1.2.0, the safe crate selects trusted .zovaext bundles at create/open:

let extensions = zova::ExtensionOptions {
bundle_paths: vec!["./search.zovaext".into()],
trust_store_path: None,
};
let mut db = zova::Database::create_with_extensions("app.zova", &extensions)?;
db.install_extension("search")?;
// Reopen with Database::open_with_extensions(path, OpenOptions, &extensions).

Trust the bundle first with zova extension trust ./search.zovaext; opening never grants trust or selects code from database metadata. SharedDatabase provides the same constructors. Child handles keep the connection and loaded libraries alive. Bundles and their runtime dependencies must match the host OS, CPU, and deployment target.

Scalar callback registration, explicit extension-data upgrades, linked plugin descriptors, and extension-aware migration are exposed only at the raw zova-sys boundary.

Raw zova-sys also declares the opaque graph key, edge payload, topology scan, prepared build, and fresh-build session APIs. The safe zova crate deliberately does not wrap those low-level publication surfaces.

See Build your first database for an end-to-end Rust example and the individual core chapters for storage semantics.