use crate::{
access::{Access, FromAccess},
views::IndexType,
BinaryKey, BinaryValue, Entry, Group, IndexAddress, KeySetIndex, ListIndex, MapIndex,
SparseListIndex,
};
pub trait CopyAccessExt: Access + Copy {
fn get_group<K, I>(self, name: impl Into<String>) -> Group<Self, K, I>
where
K: BinaryKey + ?Sized,
I: FromAccess<Self>,
{
Group::from_access(self, IndexAddress::from_root(name))
.unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
}
fn get_entry<I, V>(self, addr: I) -> Entry<Self::Base, V>
where
I: Into<IndexAddress>,
V: BinaryValue,
{
Entry::from_access(self, addr.into()).unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
}
fn get_list<I, V>(self, addr: I) -> ListIndex<Self::Base, V>
where
I: Into<IndexAddress>,
V: BinaryValue,
{
ListIndex::from_access(self, addr.into())
.unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
}
fn get_map<I, K, V>(self, addr: I) -> MapIndex<Self::Base, K, V>
where
I: Into<IndexAddress>,
K: BinaryKey + ?Sized,
V: BinaryValue,
{
MapIndex::from_access(self, addr.into()).unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
}
fn get_sparse_list<I, V>(self, addr: I) -> SparseListIndex<Self::Base, V>
where
I: Into<IndexAddress>,
V: BinaryValue,
{
SparseListIndex::from_access(self, addr.into())
.unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
}
fn get_key_set<I, K>(self, addr: I) -> KeySetIndex<Self::Base, K>
where
I: Into<IndexAddress>,
K: BinaryKey + ?Sized,
{
KeySetIndex::from_access(self, addr.into())
.unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
}
fn index_type<I>(self, addr: I) -> Option<IndexType>
where
I: Into<IndexAddress>,
{
self.get_index_metadata(addr.into())
.unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
.map(|metadata| metadata.index_type())
}
}
impl<T: Access + Copy> CopyAccessExt for T {}
pub trait AccessExt: Access {
fn get_group<K, I>(&self, name: impl Into<String>) -> Group<Self, K, I>
where
K: BinaryKey + ?Sized,
I: FromAccess<Self>,
{
Group::from_access(self.clone(), IndexAddress::from_root(name))
.unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
}
fn get_entry<I, V>(&self, addr: I) -> Entry<Self::Base, V>
where
I: Into<IndexAddress>,
V: BinaryValue,
{
Entry::from_access(self.clone(), addr.into())
.unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
}
fn get_list<I, V>(&self, addr: I) -> ListIndex<Self::Base, V>
where
I: Into<IndexAddress>,
V: BinaryValue,
{
ListIndex::from_access(self.clone(), addr.into())
.unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
}
fn get_map<I, K, V>(&self, addr: I) -> MapIndex<Self::Base, K, V>
where
I: Into<IndexAddress>,
K: BinaryKey + ?Sized,
V: BinaryValue,
{
MapIndex::from_access(self.clone(), addr.into())
.unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
}
fn get_sparse_list<I, V>(&self, addr: I) -> SparseListIndex<Self::Base, V>
where
I: Into<IndexAddress>,
V: BinaryValue,
{
SparseListIndex::from_access(self.clone(), addr.into())
.unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
}
fn get_key_set<I, K>(&self, addr: I) -> KeySetIndex<Self::Base, K>
where
I: Into<IndexAddress>,
K: BinaryKey + ?Sized,
{
KeySetIndex::from_access(self.clone(), addr.into())
.unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
}
fn index_type<I>(&self, addr: I) -> Option<IndexType>
where
I: Into<IndexAddress>,
{
self.clone()
.get_index_metadata(addr.into())
.unwrap_or_else(|e| panic!("MerkleDB error: {}", e))
.map(|metadata| metadata.index_type())
}
}
impl<T: Access> AccessExt for T {}
#[cfg(test)]
mod tests {
use super::{AccessExt, CopyAccessExt, IndexType};
use crate::{access::Prefixed, migration::Migration, Database, TemporaryDB};
#[test]
fn index_type_works() {
let db = TemporaryDB::new();
let fork = db.fork();
fork.get_list("list").extend(vec![1, 2, 3]);
assert_eq!(fork.index_type("list"), Some(IndexType::List));
fork.get_map(("fam", &0_u8)).put(&1_u8, 2_u8);
assert_eq!(fork.index_type(("fam", &0_u8)), Some(IndexType::Map));
assert_eq!(fork.index_type(("fam", &1_u8)), None);
let patch = fork.into_patch();
assert_eq!(patch.index_type("list"), Some(IndexType::List));
assert_eq!(patch.index_type(("fam", &0_u8)), Some(IndexType::Map));
assert_eq!(patch.index_type(("fam", &1_u8)), None);
db.merge(patch).unwrap();
let snapshot = db.snapshot();
assert_eq!(snapshot.index_type("list"), Some(IndexType::List));
assert_eq!(snapshot.index_type(("fam", &0_u8)), Some(IndexType::Map));
assert_eq!(snapshot.index_type(("fam", &1_u8)), None);
}
#[test]
fn index_type_in_migration() {
let db = TemporaryDB::new();
let mut fork = db.fork();
fork.get_list("some.list").extend(vec![1, 2, 3]);
fork.get_entry(("some.entry", &0_u8)).set("!".to_owned());
fork.get_entry(("some.entry", &1_u8)).set("!!".to_owned());
{
let migration = Migration::new("some", &fork);
migration.get_list("list").extend(vec![4, 5, 6]);
migration.create_tombstone(("entry", &0_u8));
assert_eq!(migration.index_type("list"), Some(IndexType::List));
assert_eq!(
migration.index_type(("entry", &0_u8)),
Some(IndexType::Tombstone)
);
assert_eq!(migration.index_type(("entry", &1_u8)), None);
}
fork.flush_migration("some");
let patch = fork.into_patch();
let ns = Prefixed::new("some", &patch);
assert_eq!(ns.clone().index_type("list"), Some(IndexType::List));
assert_eq!(ns.clone().index_type(("entry", &0_u8)), None);
assert_eq!(
ns.clone().index_type(("entry", &1_u8)),
Some(IndexType::Entry)
);
db.merge(patch).unwrap();
let snapshot = db.snapshot();
assert_eq!(snapshot.index_type("some.list"), Some(IndexType::List));
assert_eq!(snapshot.index_type(("some.entry", &0_u8)), None);
assert_eq!(
snapshot.index_type(("some.entry", &1_u8)),
Some(IndexType::Entry)
);
}
}