jpx_engine/
query_store.rs1use serde::{Deserialize, Serialize};
37use std::collections::HashMap;
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct StoredQuery {
56 pub name: String,
58 pub expression: String,
60 #[serde(skip_serializing_if = "Option::is_none")]
62 pub description: Option<String>,
63}
64
65#[derive(Debug, Default)]
100pub struct QueryStore {
101 queries: HashMap<String, StoredQuery>,
102}
103
104impl QueryStore {
105 pub fn new() -> Self {
107 Self::default()
108 }
109
110 pub fn define(&mut self, query: StoredQuery) -> Option<StoredQuery> {
119 self.queries.insert(query.name.clone(), query)
120 }
121
122 pub fn get(&self, name: &str) -> Option<&StoredQuery> {
128 self.queries.get(name)
129 }
130
131 pub fn delete(&mut self, name: &str) -> Option<StoredQuery> {
137 self.queries.remove(name)
138 }
139
140 pub fn list(&self) -> Vec<&StoredQuery> {
142 let mut queries: Vec<_> = self.queries.values().collect();
143 queries.sort_by(|a, b| a.name.cmp(&b.name));
144 queries
145 }
146
147 pub fn len(&self) -> usize {
149 self.queries.len()
150 }
151
152 pub fn is_empty(&self) -> bool {
154 self.queries.is_empty()
155 }
156
157 pub fn clear(&mut self) {
159 self.queries.clear();
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn test_define_and_get() {
169 let mut store = QueryStore::new();
170
171 let query = StoredQuery {
172 name: "count".to_string(),
173 expression: "length(@)".to_string(),
174 description: Some("Count items".to_string()),
175 };
176
177 assert!(store.define(query.clone()).is_none());
178 assert_eq!(store.len(), 1);
179
180 let retrieved = store.get("count").unwrap();
181 assert_eq!(retrieved.name, "count");
182 assert_eq!(retrieved.expression, "length(@)");
183 assert_eq!(retrieved.description, Some("Count items".to_string()));
184 }
185
186 #[test]
187 fn test_define_overwrites() {
188 let mut store = QueryStore::new();
189
190 let query1 = StoredQuery {
191 name: "test".to_string(),
192 expression: "length(@)".to_string(),
193 description: None,
194 };
195
196 let query2 = StoredQuery {
197 name: "test".to_string(),
198 expression: "keys(@)".to_string(),
199 description: Some("Updated".to_string()),
200 };
201
202 assert!(store.define(query1).is_none());
203 let old = store.define(query2).unwrap();
204 assert_eq!(old.expression, "length(@)");
205
206 let current = store.get("test").unwrap();
207 assert_eq!(current.expression, "keys(@)");
208 }
209
210 #[test]
211 fn test_delete() {
212 let mut store = QueryStore::new();
213
214 let query = StoredQuery {
215 name: "to_delete".to_string(),
216 expression: "`null`".to_string(),
217 description: None,
218 };
219
220 store.define(query);
221 assert_eq!(store.len(), 1);
222
223 let deleted = store.delete("to_delete").unwrap();
224 assert_eq!(deleted.name, "to_delete");
225 assert_eq!(store.len(), 0);
226
227 assert!(store.delete("nonexistent").is_none());
228 }
229
230 #[test]
231 fn test_list() {
232 let mut store = QueryStore::new();
233
234 store.define(StoredQuery {
235 name: "zebra".to_string(),
236 expression: "`1`".to_string(),
237 description: None,
238 });
239 store.define(StoredQuery {
240 name: "alpha".to_string(),
241 expression: "`2`".to_string(),
242 description: None,
243 });
244 store.define(StoredQuery {
245 name: "beta".to_string(),
246 expression: "`3`".to_string(),
247 description: None,
248 });
249
250 let list = store.list();
251 assert_eq!(list.len(), 3);
252 assert_eq!(list[0].name, "alpha");
254 assert_eq!(list[1].name, "beta");
255 assert_eq!(list[2].name, "zebra");
256 }
257
258 #[test]
259 fn test_clear() {
260 let mut store = QueryStore::new();
261
262 store.define(StoredQuery {
263 name: "a".to_string(),
264 expression: "`1`".to_string(),
265 description: None,
266 });
267 store.define(StoredQuery {
268 name: "b".to_string(),
269 expression: "`2`".to_string(),
270 description: None,
271 });
272
273 assert_eq!(store.len(), 2);
274 store.clear();
275 assert!(store.is_empty());
276 }
277
278 #[test]
279 fn test_get_nonexistent() {
280 let store = QueryStore::new();
281 assert!(store.get("never_defined").is_none());
282 }
283
284 #[test]
285 fn test_empty_name() {
286 let mut store = QueryStore::new();
287
288 store.define(StoredQuery {
289 name: "".to_string(),
290 expression: "length(@)".to_string(),
291 description: Some("Empty name query".to_string()),
292 });
293
294 assert_eq!(store.len(), 1);
295
296 let retrieved = store.get("").unwrap();
297 assert_eq!(retrieved.name, "");
298 assert_eq!(retrieved.expression, "length(@)");
299 assert_eq!(retrieved.description, Some("Empty name query".to_string()));
300 }
301
302 #[test]
303 fn test_is_empty() {
304 let mut store = QueryStore::new();
305 assert!(store.is_empty());
306
307 store.define(StoredQuery {
308 name: "q".to_string(),
309 expression: "@".to_string(),
310 description: None,
311 });
312 assert!(!store.is_empty());
313
314 store.clear();
315 assert!(store.is_empty());
316 }
317
318 #[test]
319 fn test_list_ordering_stability() {
320 let mut store = QueryStore::new();
321
322 store.define(StoredQuery {
324 name: "c".to_string(),
325 expression: "`3`".to_string(),
326 description: None,
327 });
328 store.define(StoredQuery {
329 name: "b".to_string(),
330 expression: "`2`".to_string(),
331 description: None,
332 });
333 store.define(StoredQuery {
334 name: "a".to_string(),
335 expression: "`1`".to_string(),
336 description: None,
337 });
338
339 let list = store.list();
340 assert_eq!(list.len(), 3);
341 assert_eq!(list[0].name, "a");
342 assert_eq!(list[1].name, "b");
343 assert_eq!(list[2].name, "c");
344 }
345}