Skip to main content

vantage_redb/redb/
mod.rs

1//! Redb data source — thin wrapper around an `Arc<redb::Database>`, plus
2//! the shared read/write helpers consumed by the trait impls in `impls/`.
3
4pub mod impls;
5
6pub(crate) mod helpers;
7pub(crate) mod indexes;
8pub(crate) mod query;
9
10use redb::{Database, ReadTransaction, TableDefinition, WriteTransaction};
11use std::path::Path;
12use std::sync::Arc;
13
14use vantage_core::{Result, error};
15
16/// Embedded redb data source. Cloneable (shares the inner `Arc<Database>`).
17#[derive(Clone, Debug)]
18pub struct Redb {
19    db: Arc<Database>,
20}
21
22impl Redb {
23    /// Open or create a redb database at the given path.
24    pub fn create<P: AsRef<Path>>(path: P) -> Result<Self> {
25        let db = Database::create(path)
26            .map_err(|e| error!("Failed to create redb database", details = e.to_string()))?;
27        Ok(Self { db: Arc::new(db) })
28    }
29
30    /// Open an existing redb database. Errors if the file doesn't exist.
31    pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
32        let db = Database::open(path)
33            .map_err(|e| error!("Failed to open redb database", details = e.to_string()))?;
34        Ok(Self { db: Arc::new(db) })
35    }
36
37    /// Wrap an existing `redb::Database` (e.g. for in-memory tests via builder).
38    pub fn from_database(db: Database) -> Self {
39        Self { db: Arc::new(db) }
40    }
41
42    /// Borrow the underlying database.
43    pub fn database(&self) -> &Database {
44        &self.db
45    }
46
47    pub(crate) fn begin_read(&self) -> Result<ReadTransaction> {
48        self.db
49            .begin_read()
50            .map_err(|e| error!("Failed to begin redb read txn", details = e.to_string()))
51    }
52
53    pub(crate) fn begin_write(&self) -> Result<WriteTransaction> {
54        self.db
55            .begin_write()
56            .map_err(|e| error!("Failed to begin redb write txn", details = e.to_string()))
57    }
58}
59
60// Table-definition helpers — keep the name → TableDefinition mapping in one place.
61//
62// The K/V type parameters need an explicit `'static` lifetime because redb's
63// `open_table` requires `K: Key + 'static` and `V: Value + 'static`. Without
64// the annotation Rust infers them as the lifetime of the `name` argument,
65// which is what produced the "borrowed data escapes" errors.
66
67/// Main row store: `id (utf-8 string) → cbor row body`.
68pub(crate) fn main_table_def(name: &str) -> TableDefinition<'_, &'static str, &'static [u8]> {
69    TableDefinition::new(name)
70}
71
72/// Secondary index: `(cbor value bytes, id) → ()`. Composite key gives us
73/// non-unique indexes for free via redb's range scan.
74pub(crate) fn index_table_name(table_name: &str, column_name: &str) -> String {
75    format!("{}__idx__{}", table_name, column_name)
76}
77
78pub(crate) fn index_table_def(
79    name: &str,
80) -> TableDefinition<'_, (&'static [u8], &'static str), ()> {
81    TableDefinition::new(name)
82}