db/storage/
ds.rs

1use crate::model::DatastoreAdapter;
2use crate::Error;
3use crate::Transaction;
4
5#[cfg(feature = "kv-redb")]
6use super::ReDBAdapter;
7
8#[cfg(feature = "kv-rocksdb")]
9use super::RocksDBAdapter;
10use super::SledAdapter;
11
12#[derive(Copy, Clone)]
13pub struct DatastoreRef<'a> {
14	pub db: &'a Datastore,
15}
16
17impl<'a> DatastoreRef<'a> {
18	pub fn new(db: &'a Datastore) -> Self {
19		DatastoreRef {
20			db,
21		}
22	}
23}
24
25#[allow(clippy::large_enum_variant)]
26pub enum Inner {
27	#[cfg(feature = "kv-rocksdb")]
28	RocksDB(RocksDBAdapter),
29	#[cfg(feature = "kv-redb")]
30	ReDB(ReDBAdapter),
31	#[cfg(feature = "kv-sled")]
32	Sled(SledAdapter),
33}
34
35pub struct Datastore {
36	pub inner: Inner,
37}
38
39impl Default for Datastore {
40	fn default() -> Self {
41		Datastore::new("default")
42	}
43}
44
45impl Datastore {
46	pub fn new(path: &str) -> Datastore {
47		match path {
48			#[cfg(feature = "kv-rocksdb")]
49			s if s.starts_with("rocksdb:") => {
50				let db = RocksDBAdapter::new(s, None).unwrap();
51
52				Datastore {
53					inner: Inner::RocksDB(db),
54				}
55			}
56			#[cfg(feature = "kv-redb")]
57			s if s.starts_with("redb:") => {
58				let db = ReDBAdapter::new(s).unwrap();
59
60				Datastore {
61					inner: Inner::ReDB(db),
62				}
63			}
64			#[cfg(feature = "kv-sled")]
65			s if s.starts_with("sled:") => {
66				let db = SledAdapter::new(s).unwrap();
67
68				Datastore {
69					inner: Inner::Sled(db),
70				}
71			}
72			_ => unimplemented!(),
73		}
74	}
75
76	pub fn borrow(&self) -> DatastoreRef {
77		DatastoreRef::new(self)
78	}
79
80	pub fn path(&self) -> &str {
81		macro_rules! impl_transaction_method {
82			($($x: ident feat $f: expr),*) => {
83				match &self.inner {
84					$(
85						#[cfg(feature = $f)]
86						Inner::$x(v) => {
87							v.path()
88						}
89					)*
90				}
91			};
92		}
93		impl_transaction_method!(
94			RocksDB feat "kv-rocksdb",
95			ReDB feat "kv-redb",
96			Sled feat "kv-sled"
97		)
98	}
99
100	pub async fn transaction(&self, write: bool) -> Result<Transaction, Error> {
101		macro_rules! impl_transaction_method {
102			($($x: ident feat $f: expr),*) => {
103				match &self.inner {
104					$(
105						#[cfg(feature = $f)]
106						Inner::$x(v) => {
107							let tx = v.transaction(write).await?;
108							Ok(Transaction {
109								inner: super::tx::Inner::$x(tx),
110							})
111						}
112					)*
113				}
114			};
115		}
116		impl_transaction_method!(
117			RocksDB feat "kv-rocksdb",
118			ReDB feat "kv-redb",
119			Sled feat "kv-sled"
120		)
121	}
122}
123
124#[cfg(test)]
125mod test {
126	use crate::{
127		constant::{ColumnFamily, KEYSPACES},
128		tag, SimpleTransaction,
129	};
130
131	use super::Datastore;
132
133	#[tokio::test]
134	async fn should_rocksdb_create_with_cf() {
135		let db = Datastore::new("rocksdb:../temp/cf");
136		assert!(db.transaction(false).await.is_ok());
137
138		// Seeding database
139		let cf_name = KEYSPACES.get(&ColumnFamily::TestSuite).unwrap();
140		let key1 = i32::to_be_bytes(2100);
141		let key2 = "cf => hello world";
142		let key3 = "cf => this is a key";
143
144		let val1 = "cf => mock value";
145		let val2 = "cf => mock value 2";
146		let val3 = "cf => this is a new value";
147
148		let mut tx = db.transaction(true).await.unwrap();
149		let tags = tag!("column_family" => cf_name.clone());
150		tx.set(key1, val1, tags.clone()).await.unwrap();
151		tx.set(key2, val2, tags.clone()).await.unwrap();
152		tx.set(key3, val3, tags.clone()).await.unwrap();
153		let iter = tx.iterate(tags.clone()).await.unwrap();
154		assert!(iter.len() == 3);
155		tx.commit().await.unwrap();
156	}
157
158	#[tokio::test]
159	async fn should_redb_create() {
160		let db = Datastore::new("redb:../temp/redb");
161		assert!(db.transaction(false).await.is_ok());
162
163		let key1 = i32::to_be_bytes(2001);
164		let key2 = "new key new data hehe";
165		let key3 = "this is a key";
166
167		let val1 = "mock value";
168		let val2 = "mock value mock data hehe";
169		let val3 = "this is a new value";
170
171		let mut tx = db.transaction(true).await.unwrap();
172		tx.set(key1, val1, tag!()).await.unwrap();
173		tx.set(key2, val2, tag!()).await.unwrap();
174		tx.set(key3, val3, tag!()).await.unwrap();
175		let iter = tx.iterate(tag!()).await.unwrap();
176		assert!(iter.len() == 3);
177		tx.commit().await.unwrap();
178	}
179
180	#[tokio::test]
181	async fn should_sled_create() {
182		let db = Datastore::new("sled:../temp");
183		assert!(db.transaction(false).await.is_ok());
184
185		// Seeding database
186		let key1 = i32::to_be_bytes(2100);
187		let key2 = "hello world";
188		let key3 = "this is a key";
189
190		let val1 = "mock value";
191		let val2 = "mock value 2";
192		let val3 = "this is a new value";
193
194		let mut tx = db.transaction(true).await.unwrap();
195		tx.set(key1, val1, tag!()).await.unwrap();
196		tx.set(key2, val2, tag!()).await.unwrap();
197		tx.set(key3, val3, tag!()).await.unwrap();
198		let iter = tx.iterate(tag!()).await.unwrap();
199		assert!(iter.len() == 3);
200		tx.commit().await.unwrap();
201	}
202
203	#[tokio::test]
204	async fn should_sled_create_tree() {
205		let db = Datastore::new("sled:../temp/cf");
206		assert!(db.transaction(false).await.is_ok());
207
208		// Seeding database
209		let tree_name = KEYSPACES.get(&ColumnFamily::TestSuite).unwrap();
210		let key1 = i32::to_be_bytes(2100);
211		let key2 = "tree => hello world";
212		let key3 = "tree => this is a key";
213
214		let val1 = "tree => mock value";
215		let val2 = "tree => mock value 2";
216		let val3 = "tree => this is a new value";
217
218		let mut tx = db.transaction(true).await.unwrap();
219		let tags = tag!("tree" => tree_name.clone());
220		tx.set(key1, val1, tags.clone()).await.unwrap();
221		tx.set(key2, val2, tags.clone()).await.unwrap();
222		tx.set(key3, val3, tags.clone()).await.unwrap();
223		let iter = tx.iterate(tags.clone()).await.unwrap();
224		assert!(iter.len() == 3);
225		tx.commit().await.unwrap();
226	}
227}