amaters_sdk_rust/
query.rs

1//! Query builder for fluent API construction
2
3use amaters_core::{CipherBlob, ColumnRef, Key, Predicate, Query, Update};
4
5/// Query builder with fluent API
6pub struct FluentQueryBuilder {
7    collection: String,
8}
9
10impl FluentQueryBuilder {
11    /// Create a new query builder for a collection
12    pub fn new(collection: impl Into<String>) -> Self {
13        Self {
14            collection: collection.into(),
15        }
16    }
17
18    /// Build a Get query
19    pub fn get(self, key: Key) -> Query {
20        Query::Get {
21            collection: self.collection,
22            key,
23        }
24    }
25
26    /// Build a Set query
27    pub fn set(self, key: Key, value: CipherBlob) -> Query {
28        Query::Set {
29            collection: self.collection,
30            key,
31            value,
32        }
33    }
34
35    /// Build a Delete query
36    pub fn delete(self, key: Key) -> Query {
37        Query::Delete {
38            collection: self.collection,
39            key,
40        }
41    }
42
43    /// Build a Filter query
44    pub fn filter(self, predicate: Predicate) -> Query {
45        Query::Filter {
46            collection: self.collection,
47            predicate,
48        }
49    }
50
51    /// Build an Update query
52    pub fn update(self, predicate: Predicate, updates: Vec<Update>) -> Query {
53        Query::Update {
54            collection: self.collection,
55            predicate,
56            updates,
57        }
58    }
59
60    /// Build a Range query
61    pub fn range(self, start: Key, end: Key) -> Query {
62        Query::Range {
63            collection: self.collection,
64            start,
65            end,
66        }
67    }
68
69    /// Start building a filter with predicate builder
70    pub fn where_clause(self) -> PredicateBuilder {
71        PredicateBuilder::new(self.collection)
72    }
73}
74
75/// Predicate builder for constructing complex predicates
76pub struct PredicateBuilder {
77    collection: String,
78}
79
80impl PredicateBuilder {
81    /// Create a new predicate builder
82    pub fn new(collection: impl Into<String>) -> Self {
83        Self {
84            collection: collection.into(),
85        }
86    }
87
88    /// Create an equality predicate
89    pub fn eq(self, column: ColumnRef, value: CipherBlob) -> FilterBuilder {
90        FilterBuilder::new(self.collection, Predicate::Eq(column, value))
91    }
92
93    /// Create a greater than predicate
94    pub fn gt(self, column: ColumnRef, value: CipherBlob) -> FilterBuilder {
95        FilterBuilder::new(self.collection, Predicate::Gt(column, value))
96    }
97
98    /// Create a less than predicate
99    pub fn lt(self, column: ColumnRef, value: CipherBlob) -> FilterBuilder {
100        FilterBuilder::new(self.collection, Predicate::Lt(column, value))
101    }
102
103    /// Create a greater than or equal predicate
104    pub fn gte(self, column: ColumnRef, value: CipherBlob) -> FilterBuilder {
105        FilterBuilder::new(self.collection, Predicate::Gte(column, value))
106    }
107
108    /// Create a less than or equal predicate
109    pub fn lte(self, column: ColumnRef, value: CipherBlob) -> FilterBuilder {
110        FilterBuilder::new(self.collection, Predicate::Lte(column, value))
111    }
112}
113
114/// Filter builder for combining predicates
115pub struct FilterBuilder {
116    collection: String,
117    predicate: Predicate,
118}
119
120impl FilterBuilder {
121    /// Create a new filter builder
122    fn new(collection: String, predicate: Predicate) -> Self {
123        Self {
124            collection,
125            predicate,
126        }
127    }
128
129    /// Add an AND condition
130    pub fn and(mut self, other: Predicate) -> Self {
131        self.predicate = Predicate::And(Box::new(self.predicate), Box::new(other));
132        self
133    }
134
135    /// Add an OR condition
136    pub fn or(mut self, other: Predicate) -> Self {
137        self.predicate = Predicate::Or(Box::new(self.predicate), Box::new(other));
138        self
139    }
140
141    /// Add a NOT wrapper
142    #[allow(clippy::should_implement_trait)]
143    pub fn not(mut self) -> Self {
144        self.predicate = Predicate::Not(Box::new(self.predicate));
145        self
146    }
147
148    /// Build the filter query
149    pub fn build(self) -> Query {
150        Query::Filter {
151            collection: self.collection,
152            predicate: self.predicate,
153        }
154    }
155
156    /// Build an update query with this predicate
157    pub fn update(self, updates: Vec<Update>) -> Query {
158        Query::Update {
159            collection: self.collection,
160            predicate: self.predicate,
161            updates,
162        }
163    }
164}
165
166/// Helper function to create a query builder
167pub fn query(collection: impl Into<String>) -> FluentQueryBuilder {
168    FluentQueryBuilder::new(collection)
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174    use amaters_core::col;
175
176    #[test]
177    fn test_query_builder() {
178        let q = query("users").get(Key::from_str("user:1"));
179        match q {
180            Query::Get { collection, key } => {
181                assert_eq!(collection, "users");
182                assert_eq!(key.to_string_lossy(), "user:1");
183            }
184            _ => panic!("expected Get query"),
185        }
186    }
187
188    #[test]
189    fn test_filter_builder() {
190        let q = query("users")
191            .where_clause()
192            .eq(col("age"), CipherBlob::new(vec![1, 2, 3]))
193            .build();
194
195        match q {
196            Query::Filter {
197                collection,
198                predicate,
199            } => {
200                assert_eq!(collection, "users");
201                assert!(matches!(predicate, Predicate::Eq(_, _)));
202            }
203            _ => panic!("expected Filter query"),
204        }
205    }
206
207    #[test]
208    fn test_complex_filter() {
209        let q = query("users")
210            .where_clause()
211            .eq(col("status"), CipherBlob::new(vec![1]))
212            .and(Predicate::Gt(col("age"), CipherBlob::new(vec![18])))
213            .build();
214
215        match q {
216            Query::Filter {
217                collection,
218                predicate,
219            } => {
220                assert_eq!(collection, "users");
221                assert!(matches!(predicate, Predicate::And(_, _)));
222            }
223            _ => panic!("expected Filter query"),
224        }
225    }
226
227    #[test]
228    fn test_update_builder() {
229        let updates = vec![Update::Set(col("status"), CipherBlob::new(vec![2]))];
230
231        let q = query("users")
232            .where_clause()
233            .eq(col("id"), CipherBlob::new(vec![1]))
234            .update(updates);
235
236        match q {
237            Query::Update {
238                collection,
239                predicate,
240                updates,
241            } => {
242                assert_eq!(collection, "users");
243                assert!(matches!(predicate, Predicate::Eq(_, _)));
244                assert_eq!(updates.len(), 1);
245            }
246            _ => panic!("expected Update query"),
247        }
248    }
249
250    #[test]
251    fn test_range_query() {
252        let q = query("data").range(Key::from_str("a"), Key::from_str("z"));
253
254        match q {
255            Query::Range {
256                collection,
257                start,
258                end,
259            } => {
260                assert_eq!(collection, "data");
261                assert_eq!(start.to_string_lossy(), "a");
262                assert_eq!(end.to_string_lossy(), "z");
263            }
264            _ => panic!("expected Range query"),
265        }
266    }
267}