guardian_db/
data_store.rs

1use crate::error::Result as DbResult;
2use std::fmt::{Display, Formatter, Result as FmtResult};
3
4/// Trait principal para operações de datastore
5///
6/// Fornece uma interface assíncrona para operações CRUD básicas
7/// e queries com filtros avançados.
8#[async_trait::async_trait]
9pub trait Datastore: Send + Sync + std::any::Any {
10    /// Recupera um valor associado à chave
11    async fn get(&self, key: &[u8]) -> DbResult<Option<Vec<u8>>>;
12
13    /// Armazena um valor com a chave especificada
14    async fn put(&self, key: &[u8], value: &[u8]) -> DbResult<()>;
15
16    /// Verifica se uma chave existe no datastore
17    async fn has(&self, key: &[u8]) -> DbResult<bool>;
18
19    /// Remove uma chave e seu valor do datastore
20    async fn delete(&self, key: &[u8]) -> DbResult<()>;
21
22    /// Executa uma query com filtros e retorna resultados paginados
23    async fn query(&self, query: &Query) -> DbResult<Results>;
24
25    /// Retorna todas as chaves com um determinado prefixo
26    async fn list_keys(&self, prefix: &[u8]) -> DbResult<Vec<Key>>;
27
28    /// Método auxiliar para downcast
29    fn as_any(&self) -> &dyn std::any::Any;
30}
31
32/// Representa uma chave hierárquica no datastore
33///
34/// Permite navegar por uma estrutura de diretórios com operações
35/// de pai/filho e conversões para diferentes formatos.
36#[derive(Clone, PartialEq, Eq, Hash, Debug)]
37pub struct Key {
38    segments: Vec<String>,
39}
40
41impl Key {
42    /// Cria uma nova chave a partir de um caminho
43    ///
44    /// # Exemplos
45    /// ```ignore
46    /// use guardian_db::data_store::Key;
47    ///
48    /// let key = Key::new("/users/alice/profile");
49    /// let key = Key::new("config/database/host");
50    /// ```
51    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()) // Remove segmentos vazios após trim
58            .collect();
59        Self { segments }
60    }
61
62    /// Cria uma chave raiz vazia
63    #[allow(dead_code)]
64    pub fn root() -> Self {
65        Self { segments: vec![] }
66    }
67
68    /// Cria uma chave filha adicionando um segmento
69    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    /// Retorna a chave pai, se existir
81    #[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    /// Verifica se a chave está vazia (raiz)
93    pub fn is_empty(&self) -> bool {
94        self.segments.is_empty()
95    }
96
97    /// Retorna o último segmento da chave
98    pub fn name(&self) -> Option<&str> {
99        self.segments.last().map(|s| s.as_str())
100    }
101
102    /// Retorna todos os segmentos da chave
103    pub fn segments(&self) -> &[String] {
104        &self.segments
105    }
106
107    /// Retorna a profundidade da chave (número de segmentos)
108    pub fn depth(&self) -> usize {
109        self.segments.len()
110    }
111
112    /// Verifica se esta chave é descendente de outra
113    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    /// Converte para string com formato de caminho
122    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    /// Converte para bytes UTF-8
131    #[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/// Ordem de classificação para queries
156#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
157pub enum Order {
158    #[default]
159    Asc,
160    Desc,
161}
162
163/// Configuração de query para busca no datastore
164///
165/// Permite filtrar por prefixo, limitar resultados e definir ordenação.
166#[derive(Clone, Debug, Default)]
167pub struct Query {
168    /// Prefixo para filtrar chaves (None = todas as chaves)
169    pub prefix: Option<Key>,
170    /// Número máximo de resultados (None = sem limite)
171    pub limit: Option<usize>,
172    /// Ordem de classificação
173    pub order: Order,
174    /// Offset para paginação
175    pub offset: Option<usize>,
176}
177
178impl Query {
179    /// Cria um builder para construir queries complexas
180    pub fn builder() -> QueryBuilder {
181        QueryBuilder::default()
182    }
183
184    /// Cria uma query simples com apenas um prefixo
185    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    /// Cria uma query que retorna todos os itens
195    #[allow(dead_code)]
196    pub fn all() -> Self {
197        Self::default()
198    }
199}
200
201/// Builder para construir queries de forma fluente
202#[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    /// Define o prefixo para filtrar chaves
212    pub fn prefix<K: Into<Key>>(mut self, prefix: K) -> Self {
213        self.prefix = Some(prefix.into());
214        self
215    }
216
217    /// Define o número máximo de resultados
218    pub fn limit(mut self, n: usize) -> Self {
219        self.limit = Some(n);
220        self
221    }
222
223    /// Define a ordem de classificação
224    #[allow(dead_code)]
225    pub fn order(mut self, o: Order) -> Self {
226        self.order = o;
227        self
228    }
229
230    /// Define o offset para paginação
231    pub fn offset(mut self, n: usize) -> Self {
232        self.offset = Some(n);
233        self
234    }
235
236    /// Constrói a query final
237    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/// Item de resultado de uma query
248///
249/// Contém uma chave e seu valor associado.
250#[derive(Clone, Debug)]
251pub struct ResultItem {
252    pub key: Key,
253    pub value: Vec<u8>,
254}
255
256impl ResultItem {
257    /// Cria um novo item de resultado
258    pub fn new(key: Key, value: Vec<u8>) -> Self {
259        Self { key, value }
260    }
261
262    /// Converte o valor para string UTF-8, se possível
263    pub fn value_as_string(&self) -> std::result::Result<String, std::string::FromUtf8Error> {
264        String::from_utf8(self.value.clone())
265    }
266
267    /// Verifica se o valor está vazio
268    pub fn is_empty(&self) -> bool {
269        self.value.is_empty()
270    }
271
272    /// Retorna o tamanho do valor em bytes
273    pub fn size(&self) -> usize {
274        self.value.len()
275    }
276}
277
278/// Coleção de resultados de uma query
279pub type Results = Vec<ResultItem>;
280
281/// Extensões úteis para trabalhar com Results
282pub trait ResultsExt {
283    /// Filtra resultados por tamanho mínimo do valor
284    fn filter_by_min_size(&self, min_size: usize) -> Results;
285
286    /// Retorna apenas as chaves dos resultados
287    fn keys(&self) -> Vec<Key>;
288
289    /// Retorna o número total de bytes de todos os valores
290    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); // "hi" + "hello world" + "hello"
392    }
393}