odata_params/filters/
parse.rs1use super::{CompareOperator, Expr, ParseError, Value};
2use bigdecimal::BigDecimal;
3use chrono::{DateTime, FixedOffset, NaiveDate, NaiveTime, Utc};
4use std::str::FromStr;
5use uuid::Uuid;
6
7pub fn parse_str(query: impl AsRef<str>) -> Result<Expr, ParseError> {
18 match odata_filter::parse_str(query.as_ref().trim()) {
19 Ok(expr) => expr,
20 Err(_error) => Err(ParseError::Parsing),
21 }
22}
23
24enum AfterValueExpr {
25 Compare(CompareOperator, Box<Expr>),
26 In(Vec<Expr>),
27 End,
28}
29
30peg::parser! {
31 grammar odata_filter() for str {
33 use super::{Expr, CompareOperator, Value, ParseError};
34
35 pub(super) rule parse_str() -> Result<Expr, ParseError>
37 = filter()
38
39 rule filter() -> Result<Expr, ParseError>
41 = "not" _ e:filter() { Ok(Expr::Not(Box::new(e?))) }
42 / l:any_expr() _ "or" _ r:filter() { Ok(Expr::Or(Box::new(l?), Box::new(r?))) }
43 / l:any_expr() _ "and" _ r:filter() { Ok(Expr::And(Box::new(l?), Box::new(r?))) }
44 / any_expr()
45
46 rule any_expr() -> Result<Expr, ParseError>
48 = "(" _ e:filter() _ ")" { e }
49 / l:value_expr() _ r:after_value_expr() { Ok(match r? {
50 AfterValueExpr::Compare(op, r) => Expr::Compare(Box::new(l?), op, r),
51 AfterValueExpr::In(r) => Expr::In(Box::new(l?), r),
52 AfterValueExpr::End => l?,
53 }) }
54
55 rule after_value_expr() -> Result<AfterValueExpr, ParseError>
57 = op:comparison_op() _ r:value_expr() { Ok(AfterValueExpr::Compare(op, Box::new(r?))) }
58 / "in" _ "(" _ r:filter_list() _ ")" { Ok(AfterValueExpr::In(r?)) }
59 / { Ok(AfterValueExpr::End) }
60
61 rule value_expr() -> Result<Expr, ParseError>
63 = function_call()
64 / v:value() { Ok(Expr::Value(v?)) }
65 / i:identifier() { Ok(Expr::Identifier(i)) }
66
67 rule comparison_op() -> CompareOperator
69 = "eq" { CompareOperator::Equal }
70 / "ne" { CompareOperator::NotEqual }
71 / "gt" { CompareOperator::GreaterThan }
72 / "ge" { CompareOperator::GreaterOrEqual }
73 / "lt" { CompareOperator::LessThan }
74 / "le" { CompareOperator::LessOrEqual }
75
76 rule function_call() -> Result<Expr, ParseError>
78 = f:identifier() _ "(" _ l:filter_list() _ ")" { Ok(Expr::Function(f, l?)) }
79
80 rule identifier() -> String
82 = s:$(['a'..='z'|'A'..='Z'|'_']['a'..='z'|'A'..='Z'|'_'|'0'..='9']+) { s.to_string() }
83
84 rule value() -> Result<Value, ParseError>
86 = string_value()
87 / datetime_value()
88 / date_value()
89 / time_value()
90 / uuid_value()
91 / number_value()
92 / v:bool_value() { Ok(v) }
93 / v:null_value() { Ok(v) }
94
95 rule bool_value() -> Value
97 = ['t'|'T']['r'|'R']['u'|'U']['e'|'E'] { Value::Bool(true) }
98 / ['f'|'F']['a'|'A']['l'|'L']['s'|'S']['e'|'E'] { Value::Bool(false) }
99
100 rule number_value() -> Result<Value, ParseError>
102 = n:$(['0'..='9']+ ("." ['0'..='9']*)?) { Ok(Value::Number(BigDecimal::from_str(n).map_err(|_| ParseError::ParsingNumber)?)) }
103
104 rule uuid_value() -> Result<Value, ParseError>
106 = id:$(hex()*<8> "-" hex()*<4> "-" hex()*<4> "-" hex()*<4> "-" hex()*<12> ) { Ok(Value::Uuid(Uuid::parse_str(id).map_err(|_| ParseError::ParsingUuid)?)) }
107
108 rule hex() -> char
110 = ['0'..='9'|'a'..='f'|'A'..='F']
111
112 rule time() -> Result<NaiveTime, ParseError>
114 = hm:$($(['0'..='9']*<1,2>) ":" $(['0'..='9']*<2>)) s:$(":" $(['0'..='9']*<2>))? ms:$("." $(['0'..='9']*<1,9>))? {
115 match (s, ms) {
116 (Some(s), Some(ms)) => NaiveTime::parse_from_str(&format!("{hm}{s}{ms}"), "%H:%M:%S%.f"),
117 (Some(s), None) => NaiveTime::parse_from_str(&format!("{hm}{s}"), "%H:%M:%S"),
118 (None, _) => NaiveTime::parse_from_str(hm, "%H:%M"),
119 }.map_err(|_| ParseError::ParsingTime)
120 }
121
122 rule time_value() -> Result<Value, ParseError>
124 = t:time() { Ok(Value::Time(t?)) }
125
126 rule date() -> Result<NaiveDate, ParseError>
128 = d:$($(['0'..='9']*<4>) "-" $(['0'..='9']*<2>) "-" $(['0'..='9']*<2>)) { NaiveDate::parse_from_str(d, "%Y-%m-%d").map_err(|_| ParseError::ParsingDate) }
129
130 rule date_value() -> Result<Value, ParseError>
132 = d:date() { Ok(Value::Date(d?)) }
133
134 rule timezone_name() -> Result<chrono_tz::Tz, ParseError>
136 = z:$(['a'..='z'|'A'..='Z'|'-'|'_'|'/'|'+']['a'..='z'|'A'..='Z'|'-'|'_'|'/'|'+'|'0'..='9']+) { z.parse::<chrono_tz::Tz>().map_err(|_| ParseError::ParsingTimeZoneNamed) }
137
138 rule timezone_offset() -> Result<FixedOffset, ParseError>
140 = "Z" { "+0000".parse().map_err(|_| ParseError::ParsingTimeZone) }
141 / z:$($(['-'|'+']) $(['0'..='9']*<2>) ":"? $(['0'..='9']*<2>)) { z.parse().map_err(|_| ParseError::ParsingTimeZone) }
142 / z:$($(['-'|'+']) $(['0'..='9']*<2>)) { format!("{z}00").parse().map_err(|_| ParseError::ParsingTimeZone) }
143
144 rule datetime() -> Result<DateTime<Utc>, ParseError>
146 = d:date() "T" t:time() z:timezone_offset() { Ok(d?.and_time(t?).and_local_timezone(z?).earliest().ok_or(ParseError::ParsingDateTime)?.to_utc()) }
147 / d:date() "T" t:time() z:timezone_name() { Ok(d?.and_time(t?).and_local_timezone(z?).earliest().ok_or(ParseError::ParsingDateTime)?.to_utc()) }
148
149 rule datetime_value() -> Result<Value, ParseError>
151 = dt:datetime() { Ok(Value::DateTime(dt?)) }
152
153 rule string_value() -> Result<Value, ParseError>
155 = "'" s:quote_escaped_string_content()* "'" { Ok(Value::String(s.into_iter().collect::<Result<Vec<_>, _>>()?.into_iter().collect())) }
156
157 rule quote_escaped_string_content() -> Result<char, ParseError>
158 = r"\" e:escape_character() { e }
159 / c:[^'\''] { Ok(c) }
160
161 rule escape_character() -> Result<char, ParseError>
162 = "'" { Ok('\'') }
163 / "n" { Ok('\n') }
164 / "r" { Ok('\r') }
165 / "t" { Ok('\t') }
166 / r"\" { Ok('\\') }
167 / "u" sequence:$(hex()*<1,8>) {
168 u32::from_str_radix(sequence, 16).ok().and_then(char::from_u32).ok_or(ParseError::ParsingUnicodeCodePoint)
169 }
170
171 rule null_value() -> Value
173 = ['n'|'N']['u'|'U']['l'|'L']['l'|'L'] { Value::Null }
174
175 rule value_list() -> Result<Vec<Expr>, ParseError>
177 = v:value_expr() ** ( _ "," _ ) { v.into_iter().collect() }
178
179 rule filter_list() -> Result<Vec<Expr>, ParseError>
181 = v:filter() ** ( _ "," _ ) { v.into_iter().collect() }
182
183 rule _()
185 = [' '|'\t'|'\n'|'\r']*
186 }
187}