ruled_router/parser/
query.rs1use crate::error::{ParseError, ParseResult};
6use crate::utils::{format_query_string, parse_query_string};
7use std::collections::HashMap;
8
9#[derive(Debug, Clone)]
13pub struct QueryParser {
14 raw_query: String,
16 params: HashMap<String, Vec<String>>,
18}
19
20impl QueryParser {
21 pub fn new(query: &str) -> ParseResult<Self> {
39 let params = parse_query_string(query)?;
40 Ok(Self {
41 raw_query: query.to_string(),
42 params,
43 })
44 }
45
46 pub fn from_params(params: HashMap<String, Vec<String>>) -> Self {
56 let raw_query = format_query_string(¶ms);
57 Self { raw_query, params }
58 }
59
60 pub fn get(&self, key: &str) -> Option<&str> {
81 self.params.get(key)?.first().map(|s| s.as_str())
82 }
83
84 pub fn get_all(&self, key: &str) -> &[String] {
104 self.params.get(key).map(|v| v.as_slice()).unwrap_or(&[])
105 }
106
107 pub fn contains(&self, key: &str) -> bool {
117 self.params.contains_key(key)
118 }
119
120 pub fn get_parsed<T>(&self, key: &str) -> ParseResult<T>
142 where
143 T: crate::traits::FromParam,
144 {
145 let value = self.get(key).ok_or_else(|| ParseError::missing_parameter(key.to_string()))?;
146 T::from_param(value)
147 }
148
149 pub fn get_optional<T>(&self, key: &str) -> ParseResult<Option<T>>
171 where
172 T: crate::traits::FromParam,
173 {
174 match self.get(key) {
175 Some(value) => T::from_param(value).map(Some),
176 None => Ok(None),
177 }
178 }
179
180 pub fn get_with_default<T>(&self, key: &str, default: T) -> ParseResult<T>
203 where
204 T: crate::traits::FromParam,
205 {
206 match self.get(key) {
207 Some(value) => T::from_param(value),
208 None => Ok(default),
209 }
210 }
211
212 pub fn get_all_parsed<T>(&self, key: &str) -> ParseResult<Vec<T>>
232 where
233 T: crate::traits::FromParam,
234 {
235 let values = self.get_all(key);
236 values.iter().map(|s| T::from_param(s)).collect::<ParseResult<Vec<_>>>()
237 }
238
239 pub fn set<T>(&mut self, key: &str, value: T)
246 where
247 T: crate::traits::ToParam,
248 {
249 let value_str = value.to_param();
250 self.params.insert(key.to_string(), vec![value_str]);
251 self.update_raw_query();
252 }
253
254 pub fn add<T>(&mut self, key: &str, value: T)
261 where
262 T: crate::traits::ToParam,
263 {
264 let value_str = value.to_param();
265 self.params.entry(key.to_string()).or_default().push(value_str);
266 self.update_raw_query();
267 }
268
269 pub fn remove(&mut self, key: &str) -> Option<Vec<String>> {
279 let result = self.params.remove(key);
280 self.update_raw_query();
281 result
282 }
283
284 pub fn clear(&mut self) {
286 self.params.clear();
287 self.raw_query.clear();
288 }
289
290 pub fn keys(&self) -> Vec<&str> {
296 self.params.keys().map(|s| s.as_str()).collect()
297 }
298
299 pub fn is_empty(&self) -> bool {
305 self.params.is_empty()
306 }
307
308 pub fn len(&self) -> usize {
314 self.params.len()
315 }
316
317 pub fn format(&self) -> String {
335 self.raw_query.clone()
336 }
337
338 pub fn raw(&self) -> &str {
340 &self.raw_query
341 }
342
343 pub fn params(&self) -> &HashMap<String, Vec<String>> {
345 &self.params
346 }
347
348 fn update_raw_query(&mut self) {
350 self.raw_query = format_query_string(&self.params);
351 }
352}
353
354#[derive(Debug, Default)]
358pub struct QueryBuilder {
359 params: HashMap<String, Vec<String>>,
360}
361
362impl QueryBuilder {
363 pub fn new() -> Self {
365 Self::default()
366 }
367
368 pub fn set<T>(mut self, key: &str, value: T) -> Self
370 where
371 T: crate::traits::ToParam,
372 {
373 let value_str = value.to_param();
374 self.params.insert(key.to_string(), vec![value_str]);
375 self
376 }
377
378 pub fn add<T>(mut self, key: &str, value: T) -> Self
380 where
381 T: crate::traits::ToParam,
382 {
383 let value_str = value.to_param();
384 self.params.entry(key.to_string()).or_default().push(value_str);
385 self
386 }
387
388 pub fn build(self) -> QueryParser {
390 QueryParser::from_params(self.params)
391 }
392
393 pub fn build_string(self) -> String {
395 format_query_string(&self.params)
396 }
397}
398
399#[cfg(test)]
400mod tests {
401 use super::*;
402
403 #[test]
404 fn test_parse_simple_query() {
405 let parser = QueryParser::new("q=rust&page=2").unwrap();
406
407 assert_eq!(parser.get("q"), Some("rust"));
408 assert_eq!(parser.get("page"), Some("2"));
409 assert_eq!(parser.get("missing"), None);
410 }
411
412 #[test]
413 fn test_parse_multi_value_query() {
414 let parser = QueryParser::new("tags=web&tags=backend&tags=rust").unwrap();
415
416 let tags = parser.get_all("tags");
417 assert_eq!(tags, &["web", "backend", "rust"]);
418
419 assert_eq!(parser.get("tags"), Some("web")); }
421
422 #[test]
423 fn test_empty_query() {
424 let parser = QueryParser::new("").unwrap();
425
426 assert!(parser.is_empty());
427 assert_eq!(parser.len(), 0);
428 assert_eq!(parser.keys(), Vec::<&str>::new());
429 }
430
431 #[test]
432 fn test_query_with_empty_values() {
433 let parser = QueryParser::new("flag&empty=").unwrap();
434
435 assert_eq!(parser.get("flag"), Some(""));
436 assert_eq!(parser.get("empty"), Some(""));
437 }
438
439 #[test]
440 fn test_url_encoded_query() {
441 let parser = QueryParser::new("q=hello%20world&name=John%2BDoe&test=hello+world").unwrap();
442
443 assert_eq!(parser.get("q"), Some("hello world"));
444 assert_eq!(parser.get("name"), Some("John+Doe")); assert_eq!(parser.get("test"), Some("hello world")); }
447
448 #[test]
449 fn test_query_modification() {
450 let mut parser = QueryParser::new("q=rust").unwrap();
451
452 parser.set("page", 2u32);
453 parser.add("tags", "web");
454 parser.add("tags", "backend");
455
456 assert_eq!(parser.get("page"), Some("2"));
457 assert_eq!(parser.get_all("tags"), &["web", "backend"]);
458
459 parser.remove("q");
460 assert_eq!(parser.get("q"), None);
461 }
462
463 #[test]
464 fn test_query_builder() {
465 let query = QueryBuilder::new()
466 .set("q", "rust")
467 .set("page", 2u32)
468 .add("tags", "web")
469 .add("tags", "backend")
470 .build_string();
471
472 assert!(query.contains("q=rust"));
474 assert!(query.contains("page=2"));
475 assert!(query.contains("tags=web"));
476 assert!(query.contains("tags=backend"));
477 }
478
479 #[test]
480 fn test_contains_and_keys() {
481 let parser = QueryParser::new("q=rust&page=2&tags=web").unwrap();
482
483 assert!(parser.contains("q"));
484 assert!(parser.contains("page"));
485 assert!(parser.contains("tags"));
486 assert!(!parser.contains("missing"));
487
488 let mut keys = parser.keys();
489 keys.sort(); assert_eq!(keys, vec!["page", "q", "tags"]);
491 }
492}