use crate::{ cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO, DbDupCursorRW}, transaction::{DbTx, DbTxMut}, DatabaseError, }; use serde::{Deserialize, Serialize}; use std::fmt::Debug; /// Trait that will transform the data to be saved in the DB in a (ideally) compressed format pub trait Compress: Send + Sync + Sized + Debug { /// Compressed type. type Compressed: bytes::BufMut + AsRef<[u8]> + AsMut<[u8]> + Into> + Default + Send + Sync + Debug; /// If the type cannot be compressed, return its inner reference as `Some(self.as_ref())` fn uncompressable_ref(&self) -> Option<&[u8]> { None } /// Compresses data going into the database. fn compress(self) -> Self::Compressed { let mut buf = Self::Compressed::default(); self.compress_to_buf(&mut buf); buf } /// Compresses data to a given buffer. fn compress_to_buf>(self, buf: &mut B); } /// Trait that will transform the data to be read from the DB. pub trait Decompress: Send + Sync + Sized + Debug { /// Decompresses data coming from the database. fn decompress>(value: B) -> Result; /// Decompresses owned data coming from the database. fn decompress_owned(value: Vec) -> Result { Self::decompress(value) } } /// Trait that will transform the data to be saved in the DB. pub trait Encode: Send + Sync + Sized + Debug { /// Encoded type. type Encoded: AsRef<[u8]> + Into> + Send + Sync + Ord + Debug; /// Encodes data going into the database. fn encode(self) -> Self::Encoded; } /// Trait that will transform the data to be read from the DB. pub trait Decode: Send + Sync + Sized + Debug { /// Decodes data coming from the database. fn decode>(value: B) -> Result; } /// Generic trait that enforces the database key to implement [`Encode`] and [`Decode`]. pub trait Key: Encode + Decode + Ord + Clone + Serialize + for<'a> Deserialize<'a> {} impl Key for T where T: Encode + Decode + Ord + Clone + Serialize + for<'a> Deserialize<'a> {} /// Generic trait that enforces the database value to implement [`Compress`] and [`Decompress`]. pub trait Value: Compress + Decompress + Serialize {} impl Value for T where T: Compress + Decompress + Serialize {} /// Generic trait that a database table should follow. /// /// The [`Table::Key`] and [`Table::Value`] types should implement [`Encode`] and /// [`Decode`] when appropriate. These traits define how the data is stored and read from the /// database. /// /// It allows for the use of codecs. See [`crate::models::ShardedKey`] for a custom /// implementation. pub trait Table: Send + Sync + Debug + 'static { /// The table's name. const NAME: &'static str; /// Key element of `Table`. /// /// Sorting should be taken into account when encoding this. type Key: Key; /// Value element of `Table`. type Value: Value; } /// Tuple with `T::Key` and `T::Value`. pub type TableRow = (::Key, ::Value); /// `DupSort` allows for keys to be repeated in the database. /// /// Upstream docs: pub trait DupSort: Table { /// The table subkey. This type must implement [`Encode`] and [`Decode`]. /// /// Sorting should be taken into account when encoding this. /// /// Upstream docs: type SubKey: Key; } /// Allows duplicating tables across databases pub trait TableImporter: DbTxMut { /// Imports all table data from another transaction. fn import_table(&self, source_tx: &R) -> Result<(), DatabaseError> { let mut destination_cursor = self.cursor_write::()?; for kv in source_tx.cursor_read::()?.walk(None)? { let (k, v) = kv?; destination_cursor.append(k, v)?; } Ok(()) } /// Imports table data from another transaction within a range. fn import_table_with_range( &self, source_tx: &R, from: Option<::Key>, to: ::Key, ) -> Result<(), DatabaseError> where T::Key: Default, { let mut destination_cursor = self.cursor_write::()?; let mut source_cursor = source_tx.cursor_read::()?; let source_range = match from { Some(from) => source_cursor.walk_range(from..=to), None => source_cursor.walk_range(..=to), }; for row in source_range? { let (key, value) = row?; destination_cursor.append(key, value)?; } Ok(()) } /// Imports all dupsort data from another transaction. fn import_dupsort(&self, source_tx: &R) -> Result<(), DatabaseError> { let mut destination_cursor = self.cursor_dup_write::()?; let mut cursor = source_tx.cursor_dup_read::()?; while let Some((k, _)) = cursor.next_no_dup()? { for kv in cursor.walk_dup(Some(k), None)? { let (k, v) = kv?; destination_cursor.append_dup(k, v)?; } } Ok(()) } }