Skip to main content

selene_core/database/
database_entry.rs

1use std::borrow::Borrow;
2
3use serde::{Deserialize, Serialize, de::DeserializeOwned};
4use sled::{Db, Tree};
5
6use crate::database::{
7    self, CompareAndSwapTransaction, Createable, DatabaseError, EntryId, Mergeable, Patchable,
8    deserialize_from_ivec, library_db, sled_get_all_raw, sled_get_batch_raw, sled_get_raw,
9    sled_version_from_raw,
10    transaction_args::{apply_cas_tx, db_transaction},
11};
12
13pub trait DatabaseEntry:
14    Serialize + DeserializeOwned + for<'de> Deserialize<'de> + Clone + std::fmt::Debug + 'static
15{
16    type Id: EntryId<Entry = Self>;
17    /// The current version number of the struct, used for updating
18    const VERSION_NUMBER: u32;
19
20    /// Checks if an item exists in the database as lightly as possible
21    ///
22    /// # Errors
23    ///
24    /// Errors if [`sled`] fails to read the entry at the `id`
25    fn db_check(id: Self::Id) -> database::Result<bool> {
26        let db = library_db();
27        Ok(Self::tree(&db).contains_key(id.as_bytes())?)
28    }
29
30    fn db_check_version(id: Self::Id) -> Result<Option<u32>, DatabaseError> {
31        let db = library_db();
32        Ok(sled_get_raw(&Self::tree(&db), id.as_bytes())?.map(sled_version_from_raw))
33    }
34
35    /// Creates a new [`Self`] in the database using [`Self::CreateArgs`][`Createable::CreateArgs`]
36    fn db_create(args: <Self as Createable>::CreateArgs) -> database::Result<Self>
37    where
38        Self: Createable,
39    {
40        let mut cas_tx = CompareAndSwapTransaction::new();
41        let created_id = Self::tx_create(&mut cas_tx, args)?;
42        apply_cas_tx(cas_tx, false)?;
43
44        Ok(Self::db_get(created_id)?.expect("Item was just created"))
45    }
46
47    /// Gets the entry of [`Self`] with the given `id`
48    ///
49    /// # Errors
50    ///
51    /// Errors if [`sled`] fails to retrieve the entry
52    fn db_get(id: Self::Id) -> database::Result<Option<Self>> {
53        let db = library_db();
54        Ok(sled_get_raw(&Self::tree(&db), id.as_bytes())?.map(deserialize_from_ivec))
55    }
56
57    /// Gets all entries of [`Self`] in the database
58    ///
59    /// # Errors
60    ///
61    /// Errors if [`sled`] fails to retrieve any entry
62    fn db_get_all() -> database::Result<Vec<Self>> {
63        let db = library_db();
64        Ok(sled_get_all_raw(&Self::tree(&db))?
65            .into_iter()
66            .map(deserialize_from_ivec)
67            .collect())
68    }
69
70    /// Gets all entries of [`Self`] in the database with the matching `ids`
71    ///
72    /// # Errors
73    ///
74    /// Errors if [`sled`] fails to retrieve any entry
75    fn db_get_batch<I, A>(ids: I) -> database::Result<Vec<Self>>
76    where
77        I: IntoIterator<Item = A>,
78        A: Borrow<Self::Id>,
79    {
80        let db = library_db();
81        let items = sled_get_batch_raw(
82            &Self::tree(&db),
83            ids.into_iter().map(|a| *a.borrow().as_bytes()),
84        )?;
85
86        Ok(items.into_iter().map(deserialize_from_ivec).collect())
87    }
88
89    /// Merges `self` into `into` in the database.
90    ///
91    /// All items that point to `self` will be relinked to `into` and `self` will be deleted from the database
92    fn db_merge(&self, into: Self::Id) -> database::Result<()>
93    where
94        Self: Mergeable,
95    {
96        db_transaction(|cas_tx| self.tx_merge(into, cas_tx), None, false)?;
97        Ok(())
98    }
99
100    /// Patches or inserts [`Self`] into the database
101    ///
102    /// Patching rules depend on how [`Self`] implements [`Patchable<Self>`]
103    fn db_patch(&mut self) -> database::Result<()>
104    where
105        Self: Patchable<Self>,
106    {
107        let db = library_db();
108        let old_raw = Self::tree(&db).get(self.id().as_bytes())?;
109        let old: Option<Self> = old_raw.clone().map(deserialize_from_ivec);
110
111        if let Some(mut old) = old {
112            old.patch(self.clone());
113            old.db_upsert()
114        } else {
115            self.db_upsert()
116        }
117    }
118
119    fn pre_upsert(&mut self, _cas_tx: &CompareAndSwapTransaction) -> Result<(), DatabaseError> {
120        Ok(())
121    }
122
123    fn db_upsert(&self) -> database::Result<()> {
124        db_transaction(
125            |cas_tx| cas_tx.tx_upsert(self.id(), Some(self.clone())),
126            None,
127            false,
128        )
129    }
130
131    fn id(&self) -> Self::Id;
132
133    fn tree(db: &Db) -> Tree;
134}