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 super::*;
77
78 #[test]
79 fn name_filter() {
80 let input = ".a_name";
81 let expected = vec![Field::new("a_name")];
82 let fields = parse_filter(input).expect("parse error");
83 assert_eq!(expected, fields);
84 }
85
86 #[test]
87 fn invalid_name_filter() {
88 let input = ".4foo";
89 let result = parse_filter(input);
90 assert!(result.is_err());
91 }
92
93 #[test]
94 fn label_filter() {
95 let input = ".a_name{\"a_label\"}";
96 let expected = vec![Field::labeled("a_name", &["a_label"])];
97 let fields = parse_filter(input).expect("parse error");
98 assert_eq!(expected, fields);
99 }
100
101 #[test]
102 fn traversal_filter() {
103 let input = ".a_name{\"a_label\"}.another_name{\"another_label\"}.third_name";
104 let expected = vec![
105 Field::labeled("a_name", &["a_label"]),
106 Field::labeled("another_name", &["another_label"]),
107 Field::new("third_name"),
108 ];
109 let fields = parse_filter(input).expect("parse error");
110 assert_eq!(expected, fields);
111 }
112}