Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

db

The db module provides an embedded key-value database (backed by sled) with ACID transactions, typed trees, cursors, and reactive subscriptions. A transaction’s commit is on disk when it answers.

Tree key and value types are tracked at both compile time and run time — if a tree is reopened with different types, db::tree returns a DbErr.

Interface

/// An opaque handle to an embedded database.
type Db;

/// A typed view of a database tree (key-value namespace).
///
/// The type parameters 'k and 'v are tracked at compile time, but
/// also stored as metadata in the database. If a tree is reopened
/// with different key or value types, `tree` returns a `DbErr` at
/// run time.
///
/// Keys are kept in the language's order (as `<` orders them), which
/// first, last, get_lt, get_gt and cursor::range follow.
type Tree<'k, 'v>;

mod cursor;
mod txn;
mod subscription;

/// Get the stored type metadata for a tree, or null if none.
/// Pass null for the default tree.
val get_type: fn(db: Db, name: [string, null]) -> Result<[(string, string), null], `DbErr(string)>;

/// Open or create an embedded database at the given path.
val open: fn(path: string) -> Result<Db, `DbErr(string)>;

/// Flush all pending writes to disk.
val flush: fn(db: Db) -> Result<null, `DbErr(string)>;

/// Generate a monotonically increasing unique u64 ID.
val generate_id: fn(db: Db) -> Result<u64, `DbErr(string)>;

/// List the names of all trees in the database.
val tree_names: fn(db: Db) -> Result<Array<string>, `DbErr(string)>;

/// Drop a named tree from the database.
val drop_tree: fn(db: Db, name: string) -> Result<bool, `DbErr(string)>;

/// Open or create a named tree with typed keys and values.
/// Pass null for the default (unnamed) tree. The key and value
/// types are recorded on first open; reopening the same tree with
/// different types returns a `DbErr`.
val tree: fn<'k: Concrete + Ordered + Data, 'v: Concrete + Data>(db: Db, name: [string, null]) -> Result<Tree<'k, 'v>, `DbErr(string)>;

/// Get the value for a key, or null if not found.
val get: fn(t: Tree<'k, 'v>, key: 'k) -> Result<['v, null], `DbErr(string)>;

/// Insert a key-value pair. Returns the previous value, or null.
val insert: fn(t: Tree<'k, 'v>, key: 'k, value: 'v) -> Result<['v, null], `DbErr(string)>;

/// Remove a key. Returns the previous value, or null.
val remove: fn(t: Tree<'k, 'v>, key: 'k) -> Result<['v, null], `DbErr(string)>;

/// Check whether a key exists.
val contains_key: fn(t: Tree<'k, 'v>, key: 'k) -> Result<bool, `DbErr(string)>;

/// Batch get values for an array of keys. Returns values in input order, null for missing.
val get_many: fn(t: Tree<'k, 'v>, keys: Array<'k>) -> Result<Array<['v, null]>, `DbErr(string)>;

/// Get the first (minimum key) entry, or null if empty.
val first: fn(t: Tree<'k, 'v>) -> Result<[('k, 'v), null], `DbErr(string)>;

/// Get the last (maximum key) entry, or null if empty.
val last: fn(t: Tree<'k, 'v>) -> Result<[('k, 'v), null], `DbErr(string)>;

/// Atomically remove and return the minimum-key entry.
val pop_min: fn(t: Tree<'k, 'v>) -> Result<[('k, 'v), null], `DbErr(string)>;

/// Atomically remove and return the maximum-key entry.
val pop_max: fn(t: Tree<'k, 'v>) -> Result<[('k, 'v), null], `DbErr(string)>;

/// Get the entry with the greatest key strictly less than the given key.
val get_lt: fn(t: Tree<'k, 'v>, key: 'k) -> Result<[('k, 'v), null], `DbErr(string)>;

/// Get the entry with the smallest key strictly greater than the given key.
val get_gt: fn(t: Tree<'k, 'v>, key: 'k) -> Result<[('k, 'v), null], `DbErr(string)>;

/// Atomic compare-and-swap. Returns null on success,
/// or `Mismatch(current_value) if the current value didn't match.
val compare_and_swap: fn(t: Tree<'k, 'v>, key: 'k, old: ['v, null], new: ['v, null]) -> Result<[null, `Mismatch(['v, null])], `DbErr(string)>;

/// Atomically apply a batch of inserts and removes.
val batch: fn(t: Tree<'k, 'v>, ops: Array<[`Insert('k, 'v), `Remove('k)]>) -> Result<null, `DbErr(string)>;

/// Number of entries in the tree (O(n) scan).
val len: fn(t: Tree<'k, 'v>) -> Result<u64, `DbErr(string)>;

/// True if the tree has no entries.
val is_empty: fn(t: Tree<'k, 'v>) -> Result<bool, `DbErr(string)>;

/// Total size of the database on disk in bytes.
val size_on_disk: fn(db: Db) -> Result<u64, `DbErr(string)>;

/// True if the database was recovered after a crash.
val was_recovered: fn(db: Db) -> Result<bool, `DbErr(string)>;

/// CRC32 checksum of all keys and values (O(n)).
val checksum: fn(db: Db) -> Result<u32, `DbErr(string)>;

/// Export all database contents to a file.
val export: fn(db: Db, path: string) -> Result<null, `DbErr(string)>;

/// Import previously exported data from a file in one transaction.
/// Every imported key must be absent, including stored tree-type metadata:
/// opening a typed tree creates metadata even when that tree has no entries.
/// Malformed input and key collisions are refused without writing entries.
val import: fn(db: Db, path: string) -> Result<null, `DbErr(string)>;

db::cursor

Cursors iterate over tree entries reactively, advancing on each trigger.

use super::Tree;
/// A cursor for iterating over tree entries one at a time.
type Cursor<'k, 'v>;

/// Create a new cursor, optionally filtering by key prefix.
/// Strings and bytes match by their byte prefix, including in union key types.
/// Arrays match initial whole elements; maps match initial whole key/value pairs
/// in key order. Other keys match exactly. Use cursor::range for compound ranges.
/// A null prefix disables filtering, including when the key type contains null.
val new: fn(?#prefix: ['k, null], t: Tree<'k, 'v>) -> Cursor<'k, 'v>;

/// Create a cursor over a key range. Both bounds are optional (null = unbounded).
/// Use `Included(key) or `Excluded(key) to specify each bound.
val range: fn(?#start: [`Included('k), `Excluded('k), null], ?#end: [`Included('k), `Excluded('k), null], t: Tree<'k, 'v>) -> Cursor<'k, 'v>;

/// Read the next entry from the cursor. Advances on each trigger.
/// Returns a (key, value) tuple, or null when exhausted.
val read: fn(c: Cursor<'k, 'v>, trigger: Any) -> Result<[('k, 'v), null], `DbErr(string)>;

/// Read up to N entries from the cursor. Returns a shorter array when exhausted.
val read_many: fn(c: Cursor<'k, 'v>, n: i64) -> Result<Array<('k, 'v)>, `DbErr(string)>;

db::txn

Multi-tree ACID transactions, optimistic: an open transaction locks nothing. Its reads see the trees as they stand and its own writes, and its writes wait for the commit, which checks that every key it read still holds what it read and applies the writes atomically, or fails with `Conflict and applies none. A program that gets `Conflict runs the transaction again.

use super::Db;
/// An open transaction handle.
type Txn;

/// A tree view within a transaction.
/// Types are checked against stored metadata, just like db::tree.
type TxnTree<'k, 'v>;

/// Begin a multi-tree transaction on a database. Reads see the trees
/// as they stand and the transaction's own writes; writes are applied
/// at commit. Nothing is locked while it is open.
val begin: fn(db: Db) -> Result<Txn, `DbErr(string)>;

/// Open a tree within the transaction. Pass null for the default tree. A tree
/// that does not exist yet is created when the transaction commits, and not
/// at all when it rolls back or fails.
val tree: fn<'k: Concrete + Ordered + Data, 'v: Concrete + Data>(txn: Txn, name: [string, null]) -> Result<TxnTree<'k, 'v>, `DbErr(string)>;

/// Get a value within the transaction.
val get: fn(t: TxnTree<'k, 'v>, key: 'k) -> Result<['v, null], `DbErr(string)>;

/// Insert a key-value pair within the transaction.
val insert: fn(t: TxnTree<'k, 'v>, key: 'k, value: 'v) -> Result<['v, null], `DbErr(string)>;

/// Remove a key within the transaction.
val remove: fn(t: TxnTree<'k, 'v>, key: 'k) -> Result<['v, null], `DbErr(string)>;

/// Atomically apply a batch of inserts and removes within the transaction.
val batch: fn(t: TxnTree<'k, 'v>, ops: Array<[`Insert('k, 'v), `Remove('k)]>) -> Result<null, `DbErr(string)>;

/// Commit the transaction. All writes become visible atomically, or
/// none do: `Conflict when a key the transaction read has changed
/// since, after which the program may run the transaction again.
/// If you use any object created from this transaction after commit
/// or rollback you will receive a runtime error
val commit: fn(txn: Txn) -> Result<null, [`DbErr(string), `Conflict]>;

/// Abort the transaction. No changes are applied.
/// If you use any object created from this transaction after commit
/// or rollback you will receive a runtime error
val rollback: fn(txn: Txn) -> Result<null, `DbErr(string)>;

db::subscription

Reactive subscriptions fire when entries are inserted or removed. on_change carries both, each key’s in the order they happened, so a copy of a tree follows it; a commit may arrive across several cycles.

use super::Tree;
/// A reactive subscription to changes on a tree.
type Subscription<'k, 'v>;

/// Subscribe to changes on a tree, optionally filtering by key prefix.
/// Strings and bytes match by their byte prefix, including in union key types.
/// Arrays match initial whole elements; maps match initial whole key/value pairs
/// in key order. Other keys match exactly. Use cursor::range for compound ranges.
/// A null prefix disables filtering, including when the key type contains null.
/// Re-firing the same tree and prefix keeps the subscription. Changing either
/// discards pending events and starts a new watch.
val new: fn(?#prefix: ['k, null], t: Tree<'k, 'v>) -> Subscription<'k, 'v>;

/// Fires with the changes each delivery carries, each key's in the order
/// they were made, as the ops `db::batch` takes: a copy that applies each
/// delivery front to back holds what the tree holds once the deliveries
/// catch up. A commit or a batch may arrive across several deliveries.
val on_change: fn(sub: Subscription<'k, 'v>) -> Result<Array<[`Insert('k, 'v), `Remove('k)]>, `DbErr(string)>;

/// Fires reactively when inserts occur on the subscription. It drops the
/// removes, and with them the order of the two: a copy of the tree
/// follows `on_change`.
val on_insert: fn(sub: Subscription<'k, 'v>) -> Result<Array<{key: 'k, value: 'v}>, `DbErr(string)>;

/// Fires reactively when removes occur on the subscription. It drops the
/// inserts, and with them the order of the two: a copy of the tree
/// follows `on_change`.
val on_remove: fn(sub: Subscription<'k, 'v>) -> Result<Array<{key: 'k}>, `DbErr(string)>;