use std::borrow::Borrow;
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use sled::{Db, Tree};
use crate::database::{
self, CompareAndSwapTransaction, Createable, DatabaseError, EntryId, Mergeable, Patchable,
deserialize_from_ivec, library_db, sled_get_all_raw, sled_get_batch_raw, sled_get_raw,
sled_version_from_raw,
transaction_args::{apply_cas_tx, db_transaction},
};
pub trait DatabaseEntry:
Serialize + DeserializeOwned + for<'de> Deserialize<'de> + Clone + std::fmt::Debug + 'static
{
type Id: EntryId<Entry = Self>;
const VERSION_NUMBER: u32;
fn db_check(id: Self::Id) -> database::Result<bool> {
let db = library_db();
Ok(Self::tree(&db).contains_key(id.as_bytes())?)
}
fn db_check_version(id: Self::Id) -> Result<Option<u32>, DatabaseError> {
let db = library_db();
Ok(sled_get_raw(&Self::tree(&db), id.as_bytes())?.map(sled_version_from_raw))
}
fn db_create(args: <Self as Createable>::CreateArgs) -> database::Result<Self>
where
Self: Createable,
{
let mut cas_tx = CompareAndSwapTransaction::new();
let created_id = Self::tx_create(&mut cas_tx, args)?;
apply_cas_tx(cas_tx, false)?;
Ok(Self::db_get(created_id)?.expect("Item was just created"))
}
fn db_get(id: Self::Id) -> database::Result<Option<Self>> {
let db = library_db();
Ok(sled_get_raw(&Self::tree(&db), id.as_bytes())?.map(deserialize_from_ivec))
}
fn db_get_all() -> database::Result<Vec<Self>> {
let db = library_db();
Ok(sled_get_all_raw(&Self::tree(&db))?
.into_iter()
.map(deserialize_from_ivec)
.collect())
}
fn db_get_batch<I, A>(ids: I) -> database::Result<Vec<Self>>
where
I: IntoIterator<Item = A>,
A: Borrow<Self::Id>,
{
let db = library_db();
let items = sled_get_batch_raw(
&Self::tree(&db),
ids.into_iter().map(|a| *a.borrow().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), None, false)?;
Ok(())
}
fn db_patch(&mut self) -> database::Result<()>
where
Self: Patchable<Self>,
{
let db = library_db();
let old_raw = Self::tree(&db).get(self.id().as_bytes())?;
let old: Option<Self> = old_raw.clone().map(deserialize_from_ivec);
if let Some(mut old) = old {
old.patch(self.clone());
old.db_upsert()
} else {
self.db_upsert()
}
}
fn pre_upsert(&mut self, _cas_tx: &CompareAndSwapTransaction) -> Result<(), DatabaseError> {
Ok(())
}
fn db_upsert(&self) -> database::Result<()> {
db_transaction(
|cas_tx| cas_tx.tx_upsert(self.id(), Some(self.clone())),
None,
false,
)
}
fn id(&self) -> Self::Id;
fn tree(db: &Db) -> Tree;
}