use std::{borrow::Borrow, fmt::Debug, ops::RangeBounds};
use armour_derive::armour_metrics;
use fjall::{Readable, Slice};
use super::raw::TxRawTree;
use crate::{
Cid, DbError, DbResult, Entry, Record,
logdb::{ItemWithRaw, IterTree, TryIterTree, helpers::*},
};
#[derive(derive_more::Debug)]
pub struct TxReadTree<Item: Record> {
pub(crate) raw: TxRawTree,
pub(crate) phantom: std::marker::PhantomData<Item>,
}
impl<Item: Record> Clone for TxReadTree<Item> {
fn clone(&self) -> Self {
Self {
raw: self.raw.clone(),
phantom: std::marker::PhantomData,
}
}
}
impl<Item> TxReadTree<Item>
where
Item: Record<Value = Slice> + Debug,
{
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
#[armour_metrics(prefix = "armour_txdb_tree", name = self.raw.static_name())]
fn get_by_slice(&self, key: &[u8]) -> DbResult<Option<Item>> {
let val = self.raw.tree.get(key)?;
match val {
Some(val) => Ok(Some(Item::deser_owned(val))),
None => Ok(None),
}
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn get(&self, id: impl Borrow<Item::SelfId> + Debug) -> DbResult<Option<Item>> {
let key = Cid::encode(id.borrow());
self.get_by_slice(key.as_ref())
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn get_or_err(&self, id: impl Borrow<Item::SelfId> + Debug) -> DbResult<Item> {
let key = Cid::encode(id.borrow());
self.get_by_slice(key.as_ref())
.and_then(|item| item.ok_or(DbError::NotFound))
}
#[doc(alias = "exists")]
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
#[armour_metrics(prefix = "armour_txdb_tree", name = self.raw.static_name())]
pub fn contains(&self, id: impl Borrow<Item::SelfId> + Debug) -> DbResult<bool> {
let key = Cid::encode(id.borrow());
self.raw
.tree
.contains_key(key.as_ref())
.map_err(DbError::from)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
#[armour_metrics(prefix = "armour_txdb_tree", name = self.raw.static_name())]
pub fn size_of(&self, id: impl Borrow<Item::SelfId> + Debug) -> DbResult<Option<u32>> {
let key = Cid::encode(id.borrow());
self.raw.tree.size_of(key.as_ref()).map_err(DbError::from)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
#[armour_metrics(prefix = "armour_txdb_tree", name = self.raw.static_name())]
pub fn first(&self) -> DbResult<Option<Entry<Item>>> {
let val = self.raw.tree.first_key_value();
match val {
Some(val) => {
let (key, val) = val.into_inner()?;
let id = Item::deser_key(&key);
let value = Item::deser_owned(val);
Ok(Some(Entry::new(id, value)))
}
None => Ok(None),
}
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
#[armour_metrics(prefix = "armour_txdb_tree", name = self.raw.static_name())]
pub fn last(&self) -> DbResult<Option<Entry<Item>>> {
let val = self.raw.tree.last_key_value();
match val {
Some(val) => {
let (key, val) = val.into_inner()?;
let id = Item::deser_key(&key);
let value = Item::deser_owned(val);
Ok(Some(Entry::new(id, value)))
}
None => Ok(None),
}
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn iter(&self) -> IterTree<Entry<Item>> {
counter!("armour_txdb_tree_iter_total", "name" => self.raw.name.clone()).increment(1);
let tx = self.raw.db.db.read_tx();
tx.iter(&self.raw.tree).filter_map(entry_filter_map::<Item>)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn scan_prefix<P>(&self, prefix: P) -> IterTree<Entry<Item>>
where
P: AsRef<[u8]> + Debug,
{
counter!("armour_txdb_tree_scan_prefix_total", "name" => self.raw.name.clone())
.increment(1);
let tx = self.raw.db.db.read_tx();
tx.prefix(&self.raw.tree, prefix)
.filter_map(entry_filter_map::<Item>)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn scan_prefix_key<P>(&self, prefix: P) -> IterTree<Item::SelfId>
where
P: AsRef<[u8]> + Debug,
{
counter!("armour_txdb_tree_scan_prefix_key_total", "name" => self.raw.name.clone())
.increment(1);
let tx = self.raw.db.db.read_tx();
tx.prefix(&self.raw.tree, prefix)
.filter_map(entry_key_filter_map::<Item>)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn range_iter<K, R>(&self, range: R) -> IterTree<Entry<Item>>
where
K: AsRef<[u8]>,
R: RangeBounds<K> + Debug,
{
counter!("armour_txdb_tree_range_iter_total", "name" => self.raw.name.clone()).increment(1);
let tx = self.raw.db.db.read_tx();
tx.range(&self.raw.tree, range)
.filter_map(entry_filter_map::<Item>)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn try_scan_prefix<P>(&self, prefix: P) -> TryIterTree<Entry<Item>>
where
P: AsRef<[u8]> + Debug,
{
counter!("armour_txdb_tree_try_scan_prefix_total", "name" => self.raw.name.clone())
.increment(1);
let tx = self.raw.db.db.read_tx();
tx.prefix(&self.raw.tree, prefix).map(entry_map::<Item>)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn try_scan_prefix_with_raw<P>(&self, prefix: P) -> TryIterTree<ItemWithRaw<Item>>
where
P: AsRef<[u8]> + Debug,
{
counter!("armour_txdb_tree_try_scan_prefix_with_raw_total", "name" => self.raw.name.clone())
.increment(1);
let tx = self.raw.db.db.read_tx();
tx.prefix(&self.raw.tree, prefix)
.map(entry_map_with_raw::<Item>)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn try_range_iter<K, R>(&self, range: R) -> TryIterTree<ItemWithRaw<Item>>
where
K: AsRef<[u8]>,
R: RangeBounds<K> + Debug,
{
counter!("armour_txdb_tree_try_range_iter_total", "name" => self.raw.name.clone())
.increment(1);
let tx = self.raw.db.db.read_tx();
tx.range(&self.raw.tree, range)
.map(entry_map_with_raw::<Item>)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn iter_keys(&self) -> IterTree<Item::SelfId> {
counter!("armour_txdb_tree_iter_keys_total", "name" => self.raw.name.clone()).increment(1);
let tx = self.raw.db.db.read_tx();
tx.iter(&self.raw.tree)
.filter_map(entry_key_filter_map::<Item>)
}
}