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 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 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 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}