1use pest::Parser;
2use pest_derive::Parser;
3
4use super::error::FilterError;
5
6#[derive(Parser)]
7#[grammar = "filter/grammar.pest"]
8pub struct Filter {}
9
10#[derive(Clone, Debug, PartialEq)]
17pub struct Field {
18 pub name: String,
20 pub labels: Vec<String>,
22}
23
24impl Field {
25 pub fn new(name: &str) -> Self {
26 Field {
27 name: name.to_string(),
28 labels: Vec::new(),
29 }
30 }
31
32 pub fn labeled(name: &str, labels: &[&str]) -> Self {
33 Field {
34 name: name.to_string(),
35 labels: labels.iter().map(|label| label.to_string()).collect(),
36 }
37 }
38}
39
40pub fn parse_filter(input: &str) -> Result<Vec<Field>, Box<FilterError<Rule>>> {
44 let mut fields = Vec::new();
45 let pairs = Filter::parse(Rule::filter, input)?;
46 for pair in pairs {
47 let mut name = String::new();
48 let mut labels = Vec::new();
49
50 let inner_pairs = pair.into_inner();
51 for inner in inner_pairs {
52 match inner.as_rule() {
53 Rule::name => {
54 inner.as_str().clone_into(&mut name);
57 }
58 Rule::quoted_name => {
59 inner.as_str().clone_into(&mut name);
60 }
61 Rule::label => {
62 labels.push(inner.as_str().to_owned());
63 }
64 _ => {}
65 }
66 }
67 if !name.is_empty() {
68 fields.push(Field { name, labels });
69 }
70 }
71 Ok(fields)
72}
73
74#[cfg(test)]
75mod tests {
76 use std::error::Error;
77
78 use super::*;
79
80 #[test]
81 fn name_filter() -> Result<(), Box<dyn Error>> {
82 let input = ".a_name";
83 let expected = vec![Field::new("a_name")];
84 let fields = parse_filter(input)?;
85 assert_eq!(expected, fields);
86 Ok(())
87 }
88
89 #[test]
90 fn label_filter() -> Result<(), Box<dyn Error>> {
91 let input = ".a_name{\"a_label\"}";
92 let expected = vec![Field::labeled("a_name", &["a_label"])];
93 let fields = parse_filter(input)?;
94 assert_eq!(expected, fields);
95 Ok(())
96 }
97
98 #[test]
99 fn traversal_filter() -> Result<(), Box<dyn Error>> {
100 let input = ".a_name{\"a_label\"}.another_name{\"another_label\"}.third_name";
101 let expected = vec![
102 Field::labeled("a_name", &["a_label"]),
103 Field::labeled("another_name", &["another_label"]),
104 Field::new("third_name"),
105 ];
106 let fields = parse_filter(input)?;
107 assert_eq!(expected, fields);
108 Ok(())
109 }
110}