guardian_db/
data_store.rs1use crate::error::Result as DbResult;
2use std::fmt::{Display, Formatter, Result as FmtResult};
3
4#[async_trait::async_trait]
9pub trait Datastore: Send + Sync + std::any::Any {
10 async fn get(&self, key: &[u8]) -> DbResult<Option<Vec<u8>>>;
12
13 async fn put(&self, key: &[u8], value: &[u8]) -> DbResult<()>;
15
16 async fn has(&self, key: &[u8]) -> DbResult<bool>;
18
19 async fn delete(&self, key: &[u8]) -> DbResult<()>;
21
22 async fn query(&self, query: &Query) -> DbResult<Results>;
24
25 async fn list_keys(&self, prefix: &[u8]) -> DbResult<Vec<Key>>;
27
28 fn as_any(&self) -> &dyn std::any::Any;
30}
31
32#[derive(Clone, PartialEq, Eq, Hash, Debug)]
37pub struct Key {
38 segments: Vec<String>,
39}
40
41impl Key {
42 pub fn new<S: Into<String>>(path: S) -> Self {
52 let s = path.into();
53 let segments = s
54 .split('/')
55 .filter(|p| !p.is_empty())
56 .map(|p| p.trim().to_string())
57 .filter(|p| !p.is_empty()) .collect();
59 Self { segments }
60 }
61
62 #[allow(dead_code)]
64 pub fn root() -> Self {
65 Self { segments: vec![] }
66 }
67
68 pub fn child<S: Into<String>>(&self, name: S) -> Self {
70 let child_name = name.into().trim().to_string();
71 if child_name.is_empty() {
72 return self.clone();
73 }
74
75 let mut segs = self.segments.clone();
76 segs.push(child_name);
77 Self { segments: segs }
78 }
79
80 #[allow(dead_code)]
82 pub fn parent(&self) -> Option<Self> {
83 if self.segments.is_empty() {
84 None
85 } else {
86 let mut segs = self.segments.clone();
87 segs.pop();
88 Some(Self { segments: segs })
89 }
90 }
91
92 pub fn is_empty(&self) -> bool {
94 self.segments.is_empty()
95 }
96
97 pub fn name(&self) -> Option<&str> {
99 self.segments.last().map(|s| s.as_str())
100 }
101
102 pub fn segments(&self) -> &[String] {
104 &self.segments
105 }
106
107 pub fn depth(&self) -> usize {
109 self.segments.len()
110 }
111
112 pub fn is_descendant_of(&self, other: &Key) -> bool {
114 if other.segments.len() >= self.segments.len() {
115 return false;
116 }
117
118 self.segments[..other.segments.len()] == other.segments
119 }
120
121 pub fn as_str(&self) -> String {
123 if self.segments.is_empty() {
124 "/".to_string()
125 } else {
126 format!("/{}", self.segments.join("/"))
127 }
128 }
129
130 #[allow(dead_code)]
132 pub fn as_bytes(&self) -> Vec<u8> {
133 self.as_str().into_bytes()
134 }
135}
136
137impl Display for Key {
138 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
139 f.write_str(&self.as_str())
140 }
141}
142
143impl From<&str> for Key {
144 fn from(path: &str) -> Self {
145 Key::new(path)
146 }
147}
148
149impl From<String> for Key {
150 fn from(path: String) -> Self {
151 Key::new(path)
152 }
153}
154
155#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
157pub enum Order {
158 #[default]
159 Asc,
160 Desc,
161}
162
163#[derive(Clone, Debug, Default)]
167pub struct Query {
168 pub prefix: Option<Key>,
170 pub limit: Option<usize>,
172 pub order: Order,
174 pub offset: Option<usize>,
176}
177
178impl Query {
179 pub fn builder() -> QueryBuilder {
181 QueryBuilder::default()
182 }
183
184 pub fn with_prefix<K: Into<Key>>(prefix: K) -> Self {
186 Self {
187 prefix: Some(prefix.into()),
188 limit: None,
189 order: Order::default(),
190 offset: None,
191 }
192 }
193
194 #[allow(dead_code)]
196 pub fn all() -> Self {
197 Self::default()
198 }
199}
200
201#[derive(Default)]
203pub struct QueryBuilder {
204 prefix: Option<Key>,
205 limit: Option<usize>,
206 order: Order,
207 offset: Option<usize>,
208}
209
210impl QueryBuilder {
211 pub fn prefix<K: Into<Key>>(mut self, prefix: K) -> Self {
213 self.prefix = Some(prefix.into());
214 self
215 }
216
217 pub fn limit(mut self, n: usize) -> Self {
219 self.limit = Some(n);
220 self
221 }
222
223 #[allow(dead_code)]
225 pub fn order(mut self, o: Order) -> Self {
226 self.order = o;
227 self
228 }
229
230 pub fn offset(mut self, n: usize) -> Self {
232 self.offset = Some(n);
233 self
234 }
235
236 pub fn build(self) -> Query {
238 Query {
239 prefix: self.prefix,
240 limit: self.limit,
241 order: self.order,
242 offset: self.offset,
243 }
244 }
245}
246
247#[derive(Clone, Debug)]
251pub struct ResultItem {
252 pub key: Key,
253 pub value: Vec<u8>,
254}
255
256impl ResultItem {
257 pub fn new(key: Key, value: Vec<u8>) -> Self {
259 Self { key, value }
260 }
261
262 pub fn value_as_string(&self) -> std::result::Result<String, std::string::FromUtf8Error> {
264 String::from_utf8(self.value.clone())
265 }
266
267 pub fn is_empty(&self) -> bool {
269 self.value.is_empty()
270 }
271
272 pub fn size(&self) -> usize {
274 self.value.len()
275 }
276}
277
278pub type Results = Vec<ResultItem>;
280
281pub trait ResultsExt {
283 fn filter_by_min_size(&self, min_size: usize) -> Results;
285
286 fn keys(&self) -> Vec<Key>;
288
289 fn total_size(&self) -> usize;
291}
292
293impl ResultsExt for Results {
294 fn filter_by_min_size(&self, min_size: usize) -> Results {
295 self.iter()
296 .filter(|item| item.value.len() >= min_size)
297 .cloned()
298 .collect()
299 }
300
301 fn keys(&self) -> Vec<Key> {
302 self.iter().map(|item| item.key.clone()).collect()
303 }
304
305 fn total_size(&self) -> usize {
306 self.iter().map(|item| item.value.len()).sum()
307 }
308}
309
310#[cfg(test)]
311mod tests {
312 use super::*;
313
314 #[test]
315 fn test_key_creation() {
316 let key = Key::new("/users/alice/profile");
317 assert_eq!(key.segments(), &["users", "alice", "profile"]);
318 assert_eq!(key.as_str(), "/users/alice/profile");
319 assert_eq!(key.depth(), 3);
320 }
321
322 #[test]
323 fn test_key_operations() {
324 let root = Key::root();
325 assert!(root.is_empty());
326 assert_eq!(root.as_str(), "/");
327
328 let child = root.child("config").child("database");
329 assert_eq!(child.as_str(), "/config/database");
330
331 let parent = child.parent().unwrap();
332 assert_eq!(parent.as_str(), "/config");
333
334 assert_eq!(child.name().unwrap(), "database");
335 }
336
337 #[test]
338 fn test_key_hierarchy() {
339 let parent = Key::new("/users/alice");
340 let child = Key::new("/users/alice/profile");
341 let other = Key::new("/users/bob");
342
343 assert!(child.is_descendant_of(&parent));
344 assert!(!other.is_descendant_of(&parent));
345 assert!(!parent.is_descendant_of(&child));
346 }
347
348 #[test]
349 fn test_query_builder() {
350 let query = Query::builder()
351 .prefix("/users")
352 .limit(10)
353 .order(Order::Desc)
354 .offset(5)
355 .build();
356
357 assert_eq!(query.prefix.as_ref().unwrap().as_str(), "/users");
358 assert_eq!(query.limit, Some(10));
359 assert_eq!(query.order, Order::Desc);
360 assert_eq!(query.offset, Some(5));
361 }
362
363 #[test]
364 fn test_result_item() {
365 let key = Key::new("/test/key");
366 let value = b"test value".to_vec();
367 let item = ResultItem::new(key.clone(), value.clone());
368
369 assert_eq!(item.key, key);
370 assert_eq!(item.value, value);
371 assert_eq!(item.size(), 10);
372 assert!(!item.is_empty());
373 assert_eq!(item.value_as_string().unwrap(), "test value");
374 }
375
376 #[test]
377 fn test_results_ext() {
378 let results = vec![
379 ResultItem::new(Key::new("/small"), b"hi".to_vec()),
380 ResultItem::new(Key::new("/large"), b"hello world".to_vec()),
381 ResultItem::new(Key::new("/medium"), b"hello".to_vec()),
382 ];
383
384 let filtered = results.filter_by_min_size(5);
385 assert_eq!(filtered.len(), 2);
386
387 let keys = results.keys();
388 assert_eq!(keys.len(), 3);
389
390 let total = results.total_size();
391 assert_eq!(total, 2 + 11 + 5); }
393}