libmdbx 0.6.6

Idiomatic and safe MDBX wrapper.
Documentation
use super::{cursor::*, traits::*};
use crate::{RO, RW, Stat, TransactionKind, WriteFlags, WriteMap};
use anyhow::Context;
use std::{collections::HashMap, marker::PhantomData};

#[derive(Debug)]
pub struct Transaction<'db, K>
where
    K: TransactionKind,
{
    pub(crate) inner: crate::Transaction<'db, K, WriteMap>,
}

impl Transaction<'_, RO> {
    pub fn table_sizes(&self) -> anyhow::Result<HashMap<String, u64>> {
        let mut out = HashMap::new();
        let main_table = self.inner.open_table(None)?;
        let mut cursor = self.inner.cursor(&main_table)?;
        while let Some((table, _)) = cursor.next_nodup::<Vec<u8>, ()>()? {
            let table = String::from_utf8(table)?;
            let db = self
                .inner
                .open_table(Some(&table))
                .with_context(|| format!("failed to open table: {table}"))?;
            let stats = self
                .inner
                .table_stat(&db)
                .with_context(|| format!("failed to get stats for table: {table}"))?;

            out.insert(table, stats.total_size());

            unsafe {
                self.inner.close_table(db)?;
            }
        }

        Ok(out)
    }
}

impl<'db, K> Transaction<'db, K>
where
    K: TransactionKind,
{
    pub fn table_stat<T>(&self) -> Result<Stat, crate::Error>
    where
        T: Table,
    {
        self.inner
            .table_stat(&self.inner.open_table(Some(T::NAME))?)
    }

    pub fn cursor<'tx, T>(&'tx self) -> anyhow::Result<Cursor<'tx, K, T>>
    where
        'db: 'tx,
        T: Table,
    {
        Ok(Cursor {
            inner: self.inner.cursor(&self.inner.open_table(Some(T::NAME))?)?,
            _marker: PhantomData,
        })
    }

    pub fn get<T>(&self, key: T::Key) -> anyhow::Result<Option<T::Value>>
    where
        T: Table,
    {
        Ok(self
            .inner
            .get::<DecodableWrapper<_>>(
                &self.inner.open_table(Some(T::NAME))?,
                key.encode().as_ref(),
            )?
            .map(|v| v.0))
    }
}

impl Transaction<'_, RW> {
    pub fn upsert<T>(&self, key: T::Key, value: T::Value) -> anyhow::Result<()>
    where
        T: Table,
    {
        Ok(self.inner.put(
            &self.inner.open_table(Some(T::NAME))?,
            key.encode(),
            value.encode(),
            WriteFlags::UPSERT,
        )?)
    }

    pub fn delete<T>(&self, key: T::Key, value: Option<T::Value>) -> anyhow::Result<bool>
    where
        T: Table,
    {
        let mut vref = None;
        let value = value.map(Encodable::encode);

        if let Some(v) = &value {
            vref = Some(v.as_ref());
        };
        Ok(self
            .inner
            .del(&self.inner.open_table(Some(T::NAME))?, key.encode(), vref)?)
    }

    pub fn clear_table<T>(&self) -> anyhow::Result<()>
    where
        T: Table,
    {
        self.inner
            .clear_table(&self.inner.open_table(Some(T::NAME))?)?;

        Ok(())
    }

    pub fn commit(self) -> anyhow::Result<()> {
        self.inner.commit()?;

        Ok(())
    }
}