use grovedb_costs::{
cost_return_on_error, storage_cost::key_value_cost::KeyValueStorageCost, CostResult, CostsExt,
OperationCost,
};
use grovedb_path::SubtreePath;
use grovedb_storage::{Storage, StorageContext};
use grovedb_version::version::GroveVersion;
use crate::{util::TxRef, Element, Error, GroveDb, TransactionArg};
impl GroveDb {
pub fn put_aux<K: AsRef<[u8]>>(
&self,
key: K,
value: &[u8],
cost_info: Option<KeyValueStorageCost>,
transaction: TransactionArg,
) -> CostResult<(), Error> {
let mut cost = OperationCost::default();
let tx = TxRef::new(&self.db, transaction);
let batch = Default::default();
let aux_storage = self
.db
.get_transactional_storage_context(SubtreePath::empty(), Some(&batch), tx.as_ref())
.unwrap_add_cost(&mut cost);
cost_return_on_error!(
&mut cost,
aux_storage
.put_aux(key.as_ref(), value, cost_info)
.map_err(Into::into)
);
cost_return_on_error!(
&mut cost,
self.db
.commit_multi_context_batch(batch, Some(tx.as_ref()))
.map_err(Into::into)
);
tx.commit_local().wrap_with_cost(cost)
}
pub fn delete_aux<K: AsRef<[u8]>>(
&self,
key: K,
cost_info: Option<KeyValueStorageCost>,
transaction: TransactionArg,
) -> CostResult<(), Error> {
let mut cost = OperationCost::default();
let tx = TxRef::new(&self.db, transaction);
let batch = Default::default();
let aux_storage = self
.db
.get_transactional_storage_context(SubtreePath::empty(), Some(&batch), tx.as_ref())
.unwrap_add_cost(&mut cost);
cost_return_on_error!(
&mut cost,
aux_storage
.delete_aux(key.as_ref(), cost_info)
.map_err(|e| e.into())
);
cost_return_on_error!(
&mut cost,
self.db
.commit_multi_context_batch(batch, Some(tx.as_ref()))
.map_err(Into::into)
);
tx.commit_local().wrap_with_cost(cost)
}
pub fn get_aux<K: AsRef<[u8]>>(
&self,
key: K,
transaction: TransactionArg,
) -> CostResult<Option<Vec<u8>>, Error> {
let mut cost = OperationCost::default();
let tx = TxRef::new(&self.db, transaction);
let aux_storage = self
.db
.get_transactional_storage_context(SubtreePath::empty(), None, tx.as_ref())
.unwrap_add_cost(&mut cost);
aux_storage
.get_aux(key.as_ref())
.map_err(|e| e.into())
.add_cost(cost)
}
pub fn find_subtrees<B: AsRef<[u8]>>(
&self,
path: &SubtreePath<B>,
transaction: TransactionArg,
grove_version: &GroveVersion,
) -> CostResult<Vec<Vec<Vec<u8>>>, Error> {
let mut cost = OperationCost::default();
let mut queue: Vec<Vec<Vec<u8>>> = vec![path.to_vec()];
let mut result: Vec<Vec<Vec<u8>>> = queue.clone();
let tx = TxRef::new(&self.db, transaction);
while let Some(q) = queue.pop() {
let subtree_path: SubtreePath<Vec<u8>> = q.as_slice().into();
let storage = self
.db
.get_transactional_storage_context(subtree_path, None, tx.as_ref())
.unwrap_add_cost(&mut cost);
let mut raw_iter = Element::iterator(storage.raw_iter()).unwrap_add_cost(&mut cost);
while let Some((key, value)) =
cost_return_on_error!(&mut cost, raw_iter.next_element(grove_version))
{
if value.is_any_tree() {
let mut sub_path = q.clone();
sub_path.push(key.to_vec());
queue.push(sub_path.clone());
result.push(sub_path);
}
}
}
Ok(result).wrap_with_cost(cost)
}
}