Skip to main content

ave_core/
db.rs

1//! # Store module.
2//!
3
4use crate::config::{AveInternalDBConfig, AveInternalDBFeatureConfig};
5
6#[cfg(feature = "sqlite")]
7use ave_actors::SqliteManager;
8use ave_actors::{Actor, ActorContext, ActorError, EncryptedKey, MachineSpec};
9use ave_actors::{Collection, DbManager, PersistentActor, State, StoreError};
10#[cfg(feature = "rocksdb")]
11use ave_actors::{RocksDbManager, RocksDbStore};
12
13use async_trait::async_trait;
14use borsh::{BorshDeserialize, BorshSerialize};
15
16#[derive(Clone)]
17pub enum Database {
18    #[cfg(feature = "rocksdb")]
19    RocksDb(RocksDbManager),
20    #[cfg(feature = "sqlite")]
21    SQLite(SqliteManager),
22}
23
24impl Database {
25    pub fn open(
26        config: &AveInternalDBConfig,
27        spec: Option<MachineSpec>,
28    ) -> Result<Self, StoreError> {
29        match &config.db {
30            #[cfg(feature = "rocksdb")]
31            AveInternalDBFeatureConfig::Rocksdb { path } => {
32                let manager =
33                    RocksDbManager::new(path, config.durability, spec)?;
34                Ok(Database::RocksDb(manager))
35            }
36            #[cfg(feature = "sqlite")]
37            AveInternalDBFeatureConfig::Sqlite { path } => {
38                let manager =
39                    SqliteManager::new(path, config.durability, spec)?;
40                Ok(Self::SQLite(manager))
41            }
42        }
43    }
44}
45
46impl DbManager<DbCollection, DbCollection> for Database {
47    fn create_collection(
48        &self,
49        name: &str,
50        prefix: &str,
51    ) -> Result<DbCollection, StoreError> {
52        match self {
53            #[cfg(feature = "rocksdb")]
54            Database::RocksDb(manager) => {
55                let store = manager.create_collection(name, prefix)?;
56                Ok(DbCollection::RocksDb(store))
57            }
58            #[cfg(feature = "sqlite")]
59            Self::SQLite(manager) => {
60                let store = manager.create_collection(name, prefix)?;
61                Ok(DbCollection::SQLite(store))
62            }
63        }
64    }
65
66    fn create_state(
67        &self,
68        name: &str,
69        prefix: &str,
70    ) -> Result<DbCollection, StoreError> {
71        match self {
72            #[cfg(feature = "rocksdb")]
73            Database::RocksDb(manager) => {
74                let store = manager.create_state(name, prefix)?;
75                Ok(DbCollection::RocksDb(store))
76            }
77            #[cfg(feature = "sqlite")]
78            Self::SQLite(manager) => {
79                let store = manager.create_state(name, prefix)?;
80                Ok(DbCollection::SQLite(store))
81            }
82        }
83    }
84
85    fn stop(&mut self) -> Result<(), StoreError> {
86        match self {
87            #[cfg(feature = "rocksdb")]
88            Database::RocksDb(manager) => manager.stop(),
89            #[cfg(feature = "sqlite")]
90            Self::SQLite(manager) => manager.stop(),
91        }
92    }
93}
94
95pub enum DbCollection {
96    #[cfg(feature = "rocksdb")]
97    RocksDb(RocksDbStore),
98    #[cfg(feature = "sqlite")]
99    SQLite(ave_actors::SqliteCollection),
100}
101
102impl Collection for DbCollection {
103    fn name(&self) -> &str {
104        match self {
105            #[cfg(feature = "rocksdb")]
106            DbCollection::RocksDb(store) => Collection::name(store),
107            #[cfg(feature = "sqlite")]
108            Self::SQLite(store) => Collection::name(store),
109        }
110    }
111
112    fn get(&self, key: &str) -> Result<Vec<u8>, StoreError> {
113        match self {
114            #[cfg(feature = "rocksdb")]
115            DbCollection::RocksDb(store) => Collection::get(store, key),
116            #[cfg(feature = "sqlite")]
117            Self::SQLite(store) => Collection::get(store, key),
118        }
119    }
120
121    fn put(&mut self, key: &str, data: &[u8]) -> Result<(), StoreError> {
122        match self {
123            #[cfg(feature = "rocksdb")]
124            DbCollection::RocksDb(store) => Collection::put(store, key, data),
125            #[cfg(feature = "sqlite")]
126            Self::SQLite(store) => Collection::put(store, key, data),
127        }
128    }
129
130    fn del(&mut self, key: &str) -> Result<(), StoreError> {
131        match self {
132            #[cfg(feature = "rocksdb")]
133            DbCollection::RocksDb(store) => Collection::del(store, key),
134            #[cfg(feature = "sqlite")]
135            Self::SQLite(store) => Collection::del(store, key),
136        }
137    }
138
139    fn iter<'a>(
140        &'a self,
141        reverse: bool,
142    ) -> Result<
143        Box<dyn Iterator<Item = Result<(String, Vec<u8>), StoreError>> + 'a>,
144        StoreError,
145    > {
146        match self {
147            #[cfg(feature = "rocksdb")]
148            DbCollection::RocksDb(store) => Collection::iter(store, reverse),
149            #[cfg(feature = "sqlite")]
150            Self::SQLite(store) => Collection::iter(store, reverse),
151        }
152    }
153
154    fn purge(&mut self) -> Result<(), StoreError> {
155        match self {
156            #[cfg(feature = "rocksdb")]
157            DbCollection::RocksDb(store) => Collection::purge(store),
158            #[cfg(feature = "sqlite")]
159            Self::SQLite(store) => Collection::purge(store),
160        }
161    }
162
163    fn last(&self) -> Result<Option<(String, Vec<u8>)>, StoreError> {
164        match self {
165            #[cfg(feature = "rocksdb")]
166            DbCollection::RocksDb(store) => Collection::last(store),
167            #[cfg(feature = "sqlite")]
168            Self::SQLite(store) => Collection::last(store),
169        }
170    }
171}
172
173impl State for DbCollection {
174    fn name(&self) -> &str {
175        match self {
176            #[cfg(feature = "rocksdb")]
177            DbCollection::RocksDb(store) => State::name(store),
178            #[cfg(feature = "sqlite")]
179            Self::SQLite(store) => State::name(store),
180        }
181    }
182
183    fn get(&self) -> Result<Vec<u8>, StoreError> {
184        match self {
185            #[cfg(feature = "rocksdb")]
186            DbCollection::RocksDb(store) => State::get(store),
187            #[cfg(feature = "sqlite")]
188            Self::SQLite(store) => State::get(store),
189        }
190    }
191
192    fn put(&mut self, data: &[u8]) -> Result<(), StoreError> {
193        match self {
194            #[cfg(feature = "rocksdb")]
195            DbCollection::RocksDb(store) => State::put(store, data),
196            #[cfg(feature = "sqlite")]
197            Self::SQLite(store) => State::put(store, data),
198        }
199    }
200
201    fn del(&mut self) -> Result<(), StoreError> {
202        match self {
203            #[cfg(feature = "rocksdb")]
204            DbCollection::RocksDb(store) => State::del(store),
205            #[cfg(feature = "sqlite")]
206            Self::SQLite(store) => State::del(store),
207        }
208    }
209
210    fn purge(&mut self) -> Result<(), StoreError> {
211        match self {
212            #[cfg(feature = "rocksdb")]
213            DbCollection::RocksDb(store) => State::purge(store),
214            #[cfg(feature = "sqlite")]
215            Self::SQLite(store) => State::purge(store),
216        }
217    }
218}
219
220#[async_trait]
221pub trait Storable: PersistentActor
222where
223    <Self as Actor>::Event: BorshSerialize + BorshDeserialize,
224{
225    async fn init_store(
226        &mut self,
227        name: &str,
228        prefix: Option<String>,
229        encrypt: bool,
230        ctx: &mut ActorContext<Self>,
231    ) -> Result<(), ActorError> {
232        // Gets database
233        let db = match ctx.system().get_helper::<Database>("store").await {
234            Some(db) => db,
235            None => {
236                return Err(ActorError::Helper {
237                    name: "store".to_string(),
238                    reason: "Not found".to_string(),
239                });
240            }
241        };
242        // Encrypted store?
243        let encrypt_key = if encrypt {
244            if let Some(encrypt_key) = ctx
245                .system()
246                .get_helper::<EncryptedKey>("encrypted_key")
247                .await
248            {
249                Some(encrypt_key)
250            } else {
251                return Err(ActorError::Helper {
252                    name: "encrypted_key".to_string(),
253                    reason: "Not found".to_string(),
254                });
255            }
256        } else {
257            None
258        };
259
260        // Start store
261        self.start_store(name, prefix, ctx, db, encrypt_key).await?;
262        Ok(())
263    }
264}