Skip to main content

Database

Struct Database 

Source
pub struct Database { /* private fields */ }
Expand description

Database represents a Stoolap database connection

This is the main entry point for using Stoolap. It wraps the storage engine and executor, providing a simple API for executing SQL queries.

§Thread Safety

Database is thread-safe and can be shared across threads via cloning. Each clone shares the same underlying storage engine.

§Examples

use stoolap::{Database, params};

// Open in-memory database
let db = Database::open("memory://")?;

// Create table
db.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)", ())?;

// Insert with parameters
db.execute("INSERT INTO users VALUES ($1, $2)", (1, "Alice"))?;

// Query
for row in db.query("SELECT * FROM users", ())? {
    let row = row?;
    println!("{}: {}", row.get::<i64>("id")?, row.get::<String>("name")?);
}

Implementations§

Source§

impl Database

Source

pub fn open(dsn: &str) -> Result<Self>

Open a database connection

The DSN (Data Source Name) specifies the database location:

  • memory:// - In-memory database (data lost when closed)
  • file:///path/to/db - Persistent database at the specified path
§Examples
// In-memory database
let db = Database::open("memory://")?;

// Persistent database
let db = Database::open("file:///tmp/mydb")?;
§Engine Reuse

Opening the same DSN multiple times returns the same engine instance. This ensures consistency and prevents data corruption.

Source

pub fn open_in_memory() -> Result<Self>

Open an in-memory database

This is a convenience method that creates a new in-memory database. Each call creates a unique instance (unlike open("memory://") which would share the same instance).

Source

pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<i64>

Execute a SQL statement

Use this for DDL (CREATE, DROP, ALTER) and DML (INSERT, UPDATE, DELETE) statements.

§Parameters

Parameters can be passed using:

  • Empty tuple () for no parameters
  • Tuple syntax (1, "Alice", 30) for multiple parameters
  • params! macro params![1, "Alice", 30]
§Returns

Returns the number of rows affected for DML statements, or 0 for DDL.

§Examples
// DDL - no parameters
db.execute("CREATE TABLE users (id INTEGER, name TEXT)", ())?;

// DML with tuple parameters
db.execute("INSERT INTO users VALUES ($1, $2)", (1, "Alice"))?;

// DML with params! macro
db.execute("INSERT INTO users VALUES ($1, $2)", params![2, "Bob"])?;

// Update with mixed types
let affected = db.execute(
    "UPDATE users SET name = $1 WHERE id = $2",
    ("Charlie", 1)
)?;
Source

pub fn query<P: Params>(&self, sql: &str, params: P) -> Result<Rows>

Execute a query that returns rows

§Parameters

Parameters can be passed using:

  • Empty tuple () for no parameters
  • Tuple syntax (value,) for single parameter (note trailing comma)
  • Tuple syntax (1, "Alice") for multiple parameters
  • params! macro params![1, "Alice"]
§Examples
// Query all rows
for row in db.query("SELECT * FROM users", ())? {
    let row = row?;
    let id: i64 = row.get(0)?;
    let name: String = row.get("name")?;
}

// Query with parameters
for row in db.query("SELECT * FROM users WHERE age > $1", (18,))? {
    // ...
}

// Collect into Vec
let users: Vec<_> = db.query("SELECT * FROM users", ())?
    .collect::<Result<Vec<_>, _>>()?;
Source

pub fn query_one<T: FromValue, P: Params>( &self, sql: &str, params: P, ) -> Result<T>

Execute a query and return a single value

This is a convenience method for queries that return a single row with a single column. Returns an error if the query returns no rows.

§Examples
let count: i64 = db.query_one("SELECT COUNT(*) FROM users", ())?;
let name: String = db.query_one("SELECT name FROM users WHERE id = $1", (1,))?;
Source

pub fn query_opt<T: FromValue, P: Params>( &self, sql: &str, params: P, ) -> Result<Option<T>>

Execute a query and return an optional single value

Like query_one, but returns None if no rows are returned.

§Examples
let name: Option<String> = db.query_opt("SELECT name FROM users WHERE id = $1", (999,))?;
assert!(name.is_none());
Source

pub fn execute_with_timeout<P: Params>( &self, sql: &str, params: P, timeout_ms: u64, ) -> Result<i64>

Execute a write statement with a timeout

Like execute, but cancels the query if it exceeds the timeout. Timeout is specified in milliseconds. Use 0 for no timeout.

§Examples
// Execute with 5 second timeout
db.execute_with_timeout("DELETE FROM large_table WHERE old = true", (), 5000)?;
Source

pub fn query_with_timeout<P: Params>( &self, sql: &str, params: P, timeout_ms: u64, ) -> Result<Rows>

Execute a query with a timeout

Like query, but cancels the query if it exceeds the timeout. Timeout is specified in milliseconds. Use 0 for no timeout.

§Examples
// Query with 10 second timeout
for row in db.query_with_timeout("SELECT * FROM large_table", (), 10000)? {
    // process row
}
Source

pub fn prepare(&self, sql: &str) -> Result<Statement>

Prepare a SQL statement for repeated execution

Prepared statements are more efficient when executing the same query multiple times with different parameters.

§Examples
let stmt = db.prepare("SELECT * FROM users WHERE id = $1")?;

// Execute multiple times with different parameters
for id in 1..=10 {
    for row in stmt.query((id,))? {
        // ...
    }
}
Source

pub fn execute_named(&self, sql: &str, params: NamedParams) -> Result<i64>

Execute a statement with named parameters

Named parameters use the :name syntax in SQL queries.

§Examples
use stoolap::{Database, named_params};

let db = Database::open("memory://")?;
db.execute("CREATE TABLE users (id INTEGER, name TEXT, age INTEGER)", ())?;

// Insert with named params
db.execute_named(
    "INSERT INTO users VALUES (:id, :name, :age)",
    named_params!{ id: 1, name: "Alice", age: 30 }
)?;

// Update with named params
db.execute_named(
    "UPDATE users SET name = :name WHERE id = :id",
    named_params!{ id: 1, name: "Alicia" }
)?;
Source

pub fn query_named(&self, sql: &str, params: NamedParams) -> Result<Rows>

Execute a query with named parameters

Named parameters use the :name syntax in SQL queries.

§Examples
use stoolap::{Database, named_params};

let db = Database::open("memory://")?;
db.execute("CREATE TABLE users (id INTEGER, name TEXT)", ())?;
db.execute("INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob')", ())?;

// Query with named params
for row in db.query_named(
    "SELECT * FROM users WHERE name = :name",
    named_params!{ name: "Alice" }
)? {
    let row = row?;
    println!("Found user: id={}", row.get::<i64>(0)?);
}
Source

pub fn query_one_named<T: FromValue>( &self, sql: &str, params: NamedParams, ) -> Result<T>

Execute a query with named parameters and return a single value

§Examples
use stoolap::{Database, named_params};

let count: i64 = db.query_one_named(
    "SELECT COUNT(*) FROM users WHERE age > :min_age",
    named_params!{ min_age: 18 }
)?;
Source

pub fn query_as<T: FromRow, P: Params>( &self, sql: &str, params: P, ) -> Result<Vec<T>>

Execute a query and map results to structs

This method executes a query and converts each row to a struct that implements the FromRow trait.

§Examples
use stoolap::{Database, FromRow, ResultRow, Result};

struct User {
    id: i64,
    name: String,
}

impl FromRow for User {
    fn from_row(row: &ResultRow) -> Result<Self> {
        Ok(User {
            id: row.get(0)?,
            name: row.get(1)?,
        })
    }
}

let db = Database::open("memory://")?;
db.execute("CREATE TABLE users (id INTEGER, name TEXT)", ())?;
db.execute("INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob')", ())?;

// Query and map to structs
let users: Vec<User> = db.query_as("SELECT id, name FROM users", ())?;
assert_eq!(users.len(), 2);
assert_eq!(users[0].name, "Alice");
Source

pub fn query_as_named<T: FromRow>( &self, sql: &str, params: NamedParams, ) -> Result<Vec<T>>

Execute a query with named parameters and map results to structs

§Examples
use stoolap::{Database, FromRow, ResultRow, Result, named_params};

struct Product {
    id: i64,
    name: String,
    price: f64,
}

impl FromRow for Product {
    fn from_row(row: &ResultRow) -> Result<Self> {
        Ok(Product {
            id: row.get(0)?,
            name: row.get(1)?,
            price: row.get(2)?,
        })
    }
}

let products: Vec<Product> = db.query_as_named(
    "SELECT id, name, price FROM products WHERE price > :min_price",
    named_params!{ min_price: 10.0 }
)?;
Source

pub fn begin(&self) -> Result<Transaction>

Begin a new transaction with default isolation level

§Examples
let tx = db.begin()?;
tx.execute("INSERT INTO users VALUES ($1, $2)", (1, "Alice"))?;
tx.commit()?;
Source

pub fn begin_with_isolation( &self, isolation: IsolationLevel, ) -> Result<Transaction>

Begin a new transaction with a specific isolation level

§Examples
use stoolap::IsolationLevel;

let tx = db.begin_with_isolation(IsolationLevel::Snapshot)?;
// All reads in this transaction see a consistent snapshot
tx.execute("UPDATE users SET balance = balance - 100 WHERE id = $1", (1,))?;
tx.commit()?;
Source

pub fn engine(&self) -> &Arc<MVCCEngine>

Get the underlying storage engine

This is primarily for advanced use cases and testing.

Source

pub fn close(&self) -> Result<()>

Close the database connection

This removes the database from the global registry and closes the engine, releasing the file lock immediately so another process can open the database.

Note: The engine is also closed automatically when all Database instances are dropped.

Source

pub fn cached_plan(&self, sql: &str) -> Result<CachedPlanRef>

Get a cached plan for a SQL statement (parse once, execute many times).

Returns a CachedPlanRef that can be stored and passed to execute_plan() / query_plan() for zero-lookup execution.

Source

pub fn execute_plan<P: Params>( &self, plan: &CachedPlanRef, params: P, ) -> Result<i64>

Execute a pre-cached plan with positional parameters (no parsing, no cache lookup).

Source

pub fn query_plan<P: Params>( &self, plan: &CachedPlanRef, params: P, ) -> Result<Rows>

Query using a pre-cached plan with positional parameters (no parsing, no cache lookup).

Source

pub fn execute_named_plan( &self, plan: &CachedPlanRef, params: NamedParams, ) -> Result<i64>

Execute a pre-cached plan with named parameters (no parsing, no cache lookup).

Source

pub fn query_named_plan( &self, plan: &CachedPlanRef, params: NamedParams, ) -> Result<Rows>

Query using a pre-cached plan with named parameters (no parsing, no cache lookup).

Source

pub fn table_exists(&self, name: &str) -> Result<bool>

Check if a table exists

Source

pub fn dsn(&self) -> &str

Get the DSN this database was opened with

Source

pub fn set_default_isolation_level(&self, level: IsolationLevel) -> Result<()>

Set the default isolation level for new transactions

Source

pub fn create_snapshot(&self) -> Result<()>

Create a point-in-time snapshot of the database

This creates snapshot files for each table that can be used to speed up database recovery. Instead of replaying the entire WAL, recovery can load the snapshot and only replay WAL entries after the snapshot.

Note: This is a no-op for in-memory databases.

Source

pub fn semantic_cache_stats(&self) -> Result<SemanticCacheStatsSnapshot>

Get semantic cache statistics

Returns statistics about the semantic query cache including hit rates, exact matches, and subsumption matches.

§Examples
let db = Database::open("memory://")?;
// ... execute some queries ...
let stats = db.semantic_cache_stats()?;
println!("Cache hits: {}", stats.hits);
println!("Subsumption hits: {}", stats.subsumption_hits);
Source

pub fn clear_semantic_cache(&self) -> Result<()>

Clear the semantic cache

This clears all cached query results. Useful for testing or when you want to force queries to re-execute.

Trait Implementations§

Source§

impl Clone for Database

Source§

fn clone(&self) -> Self

Clone the database handle.

Each cloned handle has its own executor with independent transaction state, but shares the same underlying storage engine. This ensures proper transaction isolation - a BEGIN on one handle won’t affect reads on another handle.

1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Drop for Database

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> CompactArcDrop for T

Source§

unsafe fn drop_and_dealloc(ptr: *mut u8)

Drop the contained data and deallocate the header+data allocation. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V