reth_db_api/
table.rs

1use crate::{
2    cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO, DbDupCursorRW},
3    transaction::{DbTx, DbTxMut},
4    DatabaseError,
5};
6
7use serde::{Deserialize, Serialize};
8use std::fmt::Debug;
9
10/// Trait that will transform the data to be saved in the DB in a (ideally) compressed format
11pub trait Compress: Send + Sync + Sized + Debug {
12    /// Compressed type.
13    type Compressed: bytes::BufMut
14        + AsRef<[u8]>
15        + AsMut<[u8]>
16        + Into<Vec<u8>>
17        + Default
18        + Send
19        + Sync
20        + Debug;
21
22    /// If the type cannot be compressed, return its inner reference as `Some(self.as_ref())`
23    fn uncompressable_ref(&self) -> Option<&[u8]> {
24        None
25    }
26
27    /// Compresses data going into the database.
28    fn compress(self) -> Self::Compressed {
29        let mut buf = Self::Compressed::default();
30        self.compress_to_buf(&mut buf);
31        buf
32    }
33
34    /// Compresses data to a given buffer.
35    fn compress_to_buf<B: bytes::BufMut + AsMut<[u8]>>(&self, buf: &mut B);
36}
37
38/// Trait that will transform the data to be read from the DB.
39pub trait Decompress: Send + Sync + Sized + Debug {
40    /// Decompresses data coming from the database.
41    fn decompress(value: &[u8]) -> Result<Self, DatabaseError>;
42
43    /// Decompresses owned data coming from the database.
44    fn decompress_owned(value: Vec<u8>) -> Result<Self, DatabaseError> {
45        Self::decompress(&value)
46    }
47}
48
49/// Trait that will transform the data to be saved in the DB.
50pub trait Encode: Send + Sync + Sized + Debug {
51    /// Encoded type.
52    type Encoded: AsRef<[u8]> + Into<Vec<u8>> + Send + Sync + Ord + Debug;
53
54    /// Encodes data going into the database.
55    fn encode(self) -> Self::Encoded;
56}
57
58/// Trait that will transform the data to be read from the DB.
59pub trait Decode: Send + Sync + Sized + Debug {
60    /// Decodes data coming from the database.
61    fn decode(value: &[u8]) -> Result<Self, DatabaseError>;
62
63    /// Decodes owned data coming from the database.
64    fn decode_owned(value: Vec<u8>) -> Result<Self, DatabaseError> {
65        Self::decode(&value)
66    }
67}
68
69/// Generic trait that enforces the database key to implement [`Encode`] and [`Decode`].
70pub trait Key: Encode + Decode + Ord + Clone + Serialize + for<'a> Deserialize<'a> {}
71
72impl<T> Key for T where T: Encode + Decode + Ord + Clone + Serialize + for<'a> Deserialize<'a> {}
73
74/// Generic trait that enforces the database value to implement [`Compress`] and [`Decompress`].
75pub trait Value: Compress + Decompress + Serialize {}
76
77impl<T> Value for T where T: Compress + Decompress + Serialize {}
78
79/// Generic trait that a database table should follow.
80///
81/// The [`Table::Key`] and [`Table::Value`] types should implement [`Encode`] and
82/// [`Decode`] when appropriate. These traits define how the data is stored and read from the
83/// database.
84///
85/// It allows for the use of codecs. See [`crate::models::ShardedKey`] for a custom
86/// implementation.
87pub trait Table: Send + Sync + Debug + 'static {
88    /// The table's name.
89    const NAME: &'static str;
90
91    /// Whether the table is also a `DUPSORT` table.
92    const DUPSORT: bool;
93
94    /// Key element of `Table`.
95    ///
96    /// Sorting should be taken into account when encoding this.
97    type Key: Key;
98
99    /// Value element of `Table`.
100    type Value: Value;
101}
102
103/// Trait that provides object-safe access to the table's metadata.
104pub trait TableInfo: Send + Sync + Debug + 'static {
105    /// The table's name.
106    fn name(&self) -> &'static str;
107
108    /// Whether the table is a `DUPSORT` table.
109    fn is_dupsort(&self) -> bool;
110}
111
112/// Tuple with `T::Key` and `T::Value`.
113pub type TableRow<T> = (<T as Table>::Key, <T as Table>::Value);
114
115/// `DupSort` allows for keys to be repeated in the database.
116///
117/// Upstream docs: <https://libmdbx.dqdkfa.ru/usage.html#autotoc_md48>
118pub trait DupSort: Table {
119    /// The table subkey. This type must implement [`Encode`] and [`Decode`].
120    ///
121    /// Sorting should be taken into account when encoding this.
122    ///
123    /// Upstream docs: <https://libmdbx.dqdkfa.ru/usage.html#autotoc_md48>
124    type SubKey: Key;
125}
126
127/// Allows duplicating tables across databases
128pub trait TableImporter: DbTxMut {
129    /// Imports all table data from another transaction.
130    fn import_table<T: Table, R: DbTx>(&self, source_tx: &R) -> Result<(), DatabaseError> {
131        let mut destination_cursor = self.cursor_write::<T>()?;
132
133        for kv in source_tx.cursor_read::<T>()?.walk(None)? {
134            let (k, v) = kv?;
135            destination_cursor.append(k, &v)?;
136        }
137
138        Ok(())
139    }
140
141    /// Imports table data from another transaction within a range.
142    fn import_table_with_range<T: Table, R: DbTx>(
143        &self,
144        source_tx: &R,
145        from: Option<<T as Table>::Key>,
146        to: <T as Table>::Key,
147    ) -> Result<(), DatabaseError>
148    where
149        T::Key: Default,
150    {
151        let mut destination_cursor = self.cursor_write::<T>()?;
152        let mut source_cursor = source_tx.cursor_read::<T>()?;
153
154        let source_range = match from {
155            Some(from) => source_cursor.walk_range(from..=to),
156            None => source_cursor.walk_range(..=to),
157        };
158        for row in source_range? {
159            let (key, value) = row?;
160            destination_cursor.append(key, &value)?;
161        }
162
163        Ok(())
164    }
165
166    /// Imports all dupsort data from another transaction.
167    fn import_dupsort<T: DupSort, R: DbTx>(&self, source_tx: &R) -> Result<(), DatabaseError> {
168        let mut destination_cursor = self.cursor_dup_write::<T>()?;
169        let mut cursor = source_tx.cursor_dup_read::<T>()?;
170
171        while let Some((k, _)) = cursor.next_no_dup()? {
172            for kv in cursor.walk_dup(Some(k), None)? {
173                let (k, v) = kv?;
174                destination_cursor.append_dup(k, v)?;
175            }
176        }
177
178        Ok(())
179    }
180}