Reference / Store API for Rust
Store API for Rust
Every public type, trait and function of the store in tinystore, generated from its source. The Store guide explains how to use them, and the Bun and Node, Python and Go pages list the same API.
Clock
pub trait ClockWhere a store reads the time. Every engine reads it through the store, so a test that moves one clock moves them all.
Clock.now
fn now(&self) -> SystemTimeSystemClock
pub struct SystemClockThe system's clock.
TestClock
pub struct TestClock { /* private fields */ }A clock a test moves by hand. It never moves backwards: engines keep watermarks and leases by it, and a step back would make them lie.
TestClock.new
pub fn new(start: SystemTime) -> SelfTestClock.advance
pub fn advance(&self, by: Duration)TestClock.set
pub fn set(&self, to: SystemTime) -> Result<()>unix_millis
pub fn unix_millis(time: SystemTime) -> i64Milliseconds since the Unix epoch; negative before it.
unix_nanos
pub fn unix_nanos(time: SystemTime) -> i64Nanoseconds since the Unix epoch; negative before it.
Constraint
pub struct Constraint {
pub kind: ConstraintKind,
pub table: Option<String>,
pub columns: Vec<String>,
pub name: Option<String>,
}A constraint a write broke, as SQLite names it: its kind always, and the table and the columns, or the constraint's own name, when SQLite says them.
ConstraintKind
pub enum ConstraintKind {
Unique,
PrimaryKey,
ForeignKey,
Check,
NotNull,
}A unique or a primary key already held is conflict; any other is
invalid.
ConstraintKind.as_str
pub fn as_str(self) -> &'static strThe kind as the wire and every SDK say it: primaryKey.
Error
pub struct Error { /* private fields */ }An error that names what failed: kv bucket sessions: key "a": not found.
Error.new
pub fn new(kind: ErrorKind, what: impl Into<String>) -> SelfError.invalid
pub fn invalid(what: impl Into<String>) -> SelfError.not_found
pub fn not_found(what: impl Into<String>) -> SelfError.closed
pub fn closed(what: impl Into<String>) -> SelfError.limit
pub fn limit(what: impl Into<String>) -> SelfError.corrupt
pub fn corrupt(what: impl Into<String>) -> SelfError.internal
pub fn internal(what: impl Into<String>) -> SelfError.io
pub fn io(what: impl Into<String>, source: Error) -> SelfError.with_source
pub fn with_source(self, source: impl Into<Box<dyn StdError + Send + Sync>>) -> SelfError.within
pub fn within(self, outer: impl Display) -> SelfThe same error, said of what contains it: kv bucket sessions around
key "a" reads kv bucket sessions: key "a".
Error.duplicate
pub fn duplicate(&self) -> SelfA copy for each of several callers one failure answers, its cause kept as text.
Error.fact
pub fn fact(&self, name: &str) -> Option<&str>A fact the error carries by name: a limit's limit, wanted and
bound; a broken constraint's constraint, table, columns and
name, which Error::constraint reads as one.
Error.constraint
pub fn constraint(&self) -> Option<Constraint>The constraint a write broke, as SQLite names it:
match db.exec(sql!("insert into users (email) values (?)", "ann@example.com")) {
Err(error) if error.constraint().is_some_and(|broken| broken.columns == ["email"]) => {
println!("that email is taken")
}
done => drop(done?),
}Error.kind
pub fn kind(&self) -> ErrorKindError.what
pub fn what(&self) -> &strErrorKind
pub enum ErrorKind {
Invalid,
NotFound,
Conflict,
TooOld,
TooNew,
Limit,
Closed,
Corrupt,
InUse,
Suspended,
Unavailable,
Cancelled,
OutcomeUnknown,
CommittedLocally,
Lost,
Io,
Internal,
}What went wrong, with the same meaning in every engine, on the wire and in every SDK.
ErrorKind.as_str
pub fn as_str(self) -> &'static strResult
pub type Result<T, E> = Result<T, E>Key
pub trait KeyWhat names a key, an owner or a folder: text, or an integer spelled in
decimal, so that 42 and "42" are one key.
Key.text
fn text(&self) -> Cow<'_, str>Memory
pub struct Memory { /* private fields */ }Memory.new
pub fn new(limit: u64) -> Arc<Self>Memory.limit
pub fn limit(&self) -> u64Memory.used
pub fn used(&self) -> u64Memory.bounded
pub fn bounded(&self) -> boolWhether the store was given a budget; without one, work reserves nothing and pays nothing for it.
Memory.try_reserve
pub fn try_reserve(self: &Arc<Self>, bytes: u64, what: &str) -> Result<Reservation>Takes bytes now, or fails with Limit.
Memory.nothing
pub fn nothing(self: &Arc<Self>) -> ReservationA reservation of nothing yet, which grows as its work holds more.
Memory.reserve
pub fn reserve(self: &Arc<Self>, bytes: u64, what: &str, patience: Duration) -> Result<Reservation>Takes bytes, waiting up to patience for other work to give them back.
Reservation
pub struct Reservation { /* private fields */ }Bytes taken from a store's memory, given back when dropped.
Reservation.bytes
pub fn bytes(&self) -> u64Reservation.grow
pub fn grow(&mut self, bytes: u64, what: &str) -> Result<()>Takes bytes more now, or fails with Limit and keeps what it held.
Reservation.shrink
pub fn shrink(&mut self, to: u64)Gives back what the work turned out not to need.
Durability
pub enum Durability {
Full,
Os,
}How far a commit goes before it returns: a setting of a store's files,
kv.db, jobs.db and each database's, which Options
gives for them all and a database may say for itself.
Options
pub struct Options {
pub memory: Option<u64>,
pub clock: Option<Arc<dyn Clock>>,
pub background: bool,
pub durability: Option<Durability>,
pub keep_free: u64,
pub encryption_key_file: Option<PathBuf>,
pub node: Option<Node>,
pub self_metrics: Option<SelfMetrics>,
}How a store opens.
Store
pub struct Store { /* private fields */ }One directory of engine files, held by one store at a time through its
LOCK. Engines open against a store and close with it, the last opened
first: at close, or when the last clone of the store is dropped.
Store.open
pub fn open(dir: impl AsRef<Path>, options: Options) -> Result<Store>Opens the store in dir, creating the directory when it is missing.
Another store holding the directory, in this process or another, makes
it an InUse error.
Store.open_beside
pub fn open_beside(dir: impl AsRef<Path>) -> Result<Store>Opens the store in dir to read beside the process that holds it, a
server or a program: no lock taken, no background work, each file read
through readers alone, none written and none checkpointed. A write is
refused, Invalid, and a file the store does not hold is NotFound
rather than made. What the holder commits meanwhile, a read sees.
Store.dir
pub fn dir(&self) -> &PathStore.is_beside
pub fn is_beside(&self) -> boolWhether the store was opened beside its holder, to read only.
Store.keep_free
pub fn keep_free(&self) -> u64The bytes of the disk the store keeps free, as its options said.
Store.now
pub fn now(&self) -> SystemTimeStore.clock_moved
pub fn clock_moved(&self)Tells every engine that a test moved the store's clock by hand, so that what sleeps until a time reads it again: a worker waiting for a job due in an hour runs it once the clock is an hour on.
Store.memory
pub fn memory(&self) -> &Arc<Memory>Store.close
pub fn close(&self) -> Result<()>Stops background work, waiting for the task under way, closes every engine, the last opened first, and lets go of the directory. The first engine that fails to close is the error; the others still close. A second call does nothing, and neither does the last clone's drop after.
Store.tx
pub fn tx<T, E: From<Error>>(&self, work: impl FnOnce(&Tx<'_>) -> Result<T, E>) -> Result<T, E>Runs work in one transaction of one of the store's own files, kv.db
or jobs.db: the file of the first handle tx.with takes in, whose
writer it then holds alone, so that what it reads cannot change before
it writes. Two orders cannot both take the last item, and a hundred
jobs are added together or not at all. It commits when work returns
Ok and rolls back when it returns an error or panics.
Inside, every call on the store's buckets and queues goes through the
transaction, tx.with(&bucket): one made around it would not see what
it wrote, or would wait for the writer it holds, and fails Invalid
instead. A bucket and a queue of the store are two files, and no write
is atomic across two: a handle kept in another file than the first is
Invalid, and to commit keys and jobs together a program opens both
from a database. Writes that need no reads need no transaction, since
separate calls already share commits.
Tx
pub struct Tx<'a> { /* private fields */ }A transaction of the store, given to the function Store::tx runs.
Tx.with
pub fn with<'h, H: TxHandle>(&self, handle: &'h H) -> <H as >::InTxThe calls of handle inside this transaction: what they read sees what
the transaction wrote, and what they write commits with it or not at
all. A handle kept in another file is refused at its first call.
Transaction
pub struct Transaction<'t> { /* private fields */ }A transaction as the handles it takes in see it: the writer it holds, the file a handle must be kept in, the bound it ends within, and what runs once it ends.
TxHandle
pub trait TxHandleA handle a transaction of its file takes in with tx.with(&handle): a
bucket or counters, and a queue, from the store or from a database.
sql
macro_rules! sqlA statement and the values of its ?s, in order:
sql!("select * from notes where author_id = ? and done = ?", user_id, false).