use blake3::Hash;
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use sled::Tree;
use crate::database::{
self, CompareAndSwapTransaction, Createable, DatabaseError, Mergeable, Patchable,
deserialize_from_ivec, serialize_to_ivec, sled_get_all_raw, sled_get_batch_raw, sled_get_raw,
sled_upsert,
transaction_args::{apply_cas_tx, db_transaction},
};
pub trait DatabaseEntry: Serialize + DeserializeOwned + for<'de> Deserialize<'de> + Clone {
type Id: std::ops::Deref<Target = Hash> + Copy;
const VERSION_NUMBER: u32;
fn tree() -> Tree;
fn db_check(id: Self::Id) -> database::Result<bool> {
Ok(Self::tree().contains_key(id.as_bytes())?)
}
fn db_upsert(&self) -> database::Result<()> {
sled_upsert(&Self::tree(), self.id().as_bytes(), serialize_to_ivec(self))?;
Ok(())
}
fn tx_insert(&self, cas_tx: &mut CompareAndSwapTransaction) -> database::Result<()> {
let self_request = cas_tx.get_or_new_request(Self::tree());
if self_request.tree().contains_key(self.id().as_bytes())? {
return Err(DatabaseError::AlreadyInDatabase);
}
self_request.swaps.insert(
*self.id().as_bytes(),
database::CompareAndSwapValue {
old: None,
new: Some(serialize_to_ivec(self)),
},
);
Ok(())
}
fn db_create(args: <Self as Createable>::CreateArgs) -> database::Result<Self>
where
Self: Createable,
{
let mut cas_tx = CompareAndSwapTransaction::new();
let returned = Self::create(&mut cas_tx, args)?;
apply_cas_tx(cas_tx)?;
Ok(returned)
}
fn db_get(id: Self::Id) -> database::Result<Option<Self>> {
Ok(sled_get_raw(&Self::tree(), id.as_bytes())?.map(deserialize_from_ivec))
}
fn db_get_all() -> database::Result<Vec<Self>> {
Ok(sled_get_all_raw(&Self::tree())?
.into_iter()
.map(deserialize_from_ivec)
.collect())
}
fn db_get_batch(ids: &[Self::Id]) -> database::Result<Vec<Self>> {
let items = sled_get_batch_raw(&Self::tree(), ids.iter().map(|a| a.as_bytes()))?;
Ok(items.into_iter().map(deserialize_from_ivec).collect())
}
fn db_merge(&self, into: Self::Id) -> database::Result<()>
where
Self: Mergeable,
{
db_transaction(|cas_tx| self.tx_merge(into, cas_tx))?;
Ok(())
}
fn db_patch(&self) -> database::Result<()>
where
Self: Patchable<Self>,
{
loop {
let old_raw = Self::tree().get(self.id().as_bytes())?;
let old: Option<Self> = old_raw.clone().map(deserialize_from_ivec);
let patched = if let Some(mut old) = old {
old.patch(self.clone());
serialize_to_ivec(&old)
} else {
serialize_to_ivec(self)
};
if let Ok(()) =
Self::tree().compare_and_swap(self.id().as_bytes(), old_raw, Some(patched))?
{
break;
}
}
Ok(())
}
fn tx_patch(&self, cas_tx: &mut CompareAndSwapTransaction) -> database::Result<()>
where
Self: Patchable<Self>,
{
let old_raw = Self::tree().get(self.id().as_bytes())?;
let item: Option<Self> = old_raw.clone().map(deserialize_from_ivec);
let patched = if let Some(mut item) = item {
item.patch(self.clone());
serialize_to_ivec(&item)
} else {
serialize_to_ivec(self)
};
let self_request = cas_tx.get_or_new_request(Self::tree());
self_request.swaps.insert(
*self.id().as_bytes(),
database::CompareAndSwapValue {
old: old_raw,
new: Some(patched),
},
);
Ok(())
}
fn id(&self) -> Self::Id;
}