rpytest_core/storage/
sled_backend.rs1use std::path::Path;
4
5use sled::Db;
6
7use super::traits::{StorageBackend, StorageError, StorageResult};
8
9pub struct SledBackend {
11 db: Db,
12}
13
14impl StorageBackend for SledBackend {
15 fn open(path: &Path) -> StorageResult<Self>
16 where
17 Self: Sized,
18 {
19 let db = sled::open(path).map_err(|e| StorageError::Backend(e.to_string()))?;
20 Ok(Self { db })
21 }
22
23 fn get(&self, key: &[u8]) -> StorageResult<Option<Vec<u8>>> {
24 self.db
25 .get(key)
26 .map(|opt| opt.map(|v| v.to_vec()))
27 .map_err(|e| StorageError::Backend(e.to_string()))
28 }
29
30 fn set(&self, key: &[u8], value: &[u8]) -> StorageResult<()> {
31 self.db
32 .insert(key, value)
33 .map_err(|e| StorageError::Backend(e.to_string()))?;
34 Ok(())
35 }
36
37 fn delete(&self, key: &[u8]) -> StorageResult<()> {
38 self.db
39 .remove(key)
40 .map_err(|e| StorageError::Backend(e.to_string()))?;
41 Ok(())
42 }
43
44 fn flush(&self) -> StorageResult<()> {
45 self.db
46 .flush()
47 .map_err(|e| StorageError::Backend(e.to_string()))?;
48 Ok(())
49 }
50
51 fn scan_prefix(&self, prefix: &[u8]) -> StorageResult<Vec<(Vec<u8>, Vec<u8>)>> {
52 let results: Result<Vec<_>, _> = self
53 .db
54 .scan_prefix(prefix)
55 .map(|res| res.map(|(k, v)| (k.to_vec(), v.to_vec())))
56 .collect();
57
58 results.map_err(|e| StorageError::Backend(e.to_string()))
59 }
60
61 fn clear(&self) -> StorageResult<()> {
62 self.db
63 .clear()
64 .map_err(|e| StorageError::Backend(e.to_string()))?;
65 Ok(())
66 }
67}
68
69impl SledBackend {
70 pub fn inner(&self) -> &Db {
72 &self.db
73 }
74
75 pub fn is_empty(&self) -> StorageResult<bool> {
77 Ok(self.db.is_empty())
78 }
79
80 pub fn len(&self) -> StorageResult<usize> {
82 Ok(self.db.len())
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use tempfile::TempDir;
90
91 fn create_test_db() -> (SledBackend, TempDir) {
92 let tmp = TempDir::new().unwrap();
93 let backend = SledBackend::open(tmp.path()).unwrap();
94 (backend, tmp)
95 }
96
97 #[test]
98 fn test_basic_operations() {
99 let (db, _tmp) = create_test_db();
100
101 db.set(b"key1", b"value1").unwrap();
103 assert_eq!(db.get(b"key1").unwrap(), Some(b"value1".to_vec()));
104
105 assert!(db.contains(b"key1").unwrap());
107 assert!(!db.contains(b"nonexistent").unwrap());
108
109 db.delete(b"key1").unwrap();
111 assert_eq!(db.get(b"key1").unwrap(), None);
112 }
113
114 #[test]
115 fn test_scan_prefix() {
116 let (db, _tmp) = create_test_db();
117
118 db.set(b"inv:test1", b"data1").unwrap();
119 db.set(b"inv:test2", b"data2").unwrap();
120 db.set(b"dur:test1", b"100").unwrap();
121
122 let inv_results = db.scan_prefix(b"inv:").unwrap();
123 assert_eq!(inv_results.len(), 2);
124
125 let dur_results = db.scan_prefix(b"dur:").unwrap();
126 assert_eq!(dur_results.len(), 1);
127 }
128
129 #[test]
130 fn test_clear() {
131 let (db, _tmp) = create_test_db();
132
133 db.set(b"key1", b"value1").unwrap();
134 db.set(b"key2", b"value2").unwrap();
135 assert!(!db.is_empty().unwrap());
136
137 db.clear().unwrap();
138 assert!(db.is_empty().unwrap());
139 }
140
141 #[test]
142 fn test_persistence() {
143 let tmp = TempDir::new().unwrap();
144
145 {
147 let db = SledBackend::open(tmp.path()).unwrap();
148 db.set(b"persistent", b"data").unwrap();
149 db.flush().unwrap();
150 }
151
152 {
154 let db = SledBackend::open(tmp.path()).unwrap();
155 assert_eq!(db.get(b"persistent").unwrap(), Some(b"data".to_vec()));
156 }
157 }
158}