1use std::ops::Deref;
2use std::str::FromStr;
3
4use nom::Finish;
5use rust_decimal::Decimal;
6
7use super::filter;
8use crate::Error;
9
10#[derive(Debug, PartialEq)]
11pub enum Filter<'a> {
12 AttrExp(AttrExpData<'a>),
13 LogExp(LogExpData<'a>),
14 ValuePath(ValuePathData<'a>),
15 Sub(bool, Box<Filter<'a>>),
16}
17
18impl<'a> Filter<'a> {
19 pub fn sub_filter((not, filter): (bool, Filter<'a>)) -> Self {
20 Self::Sub(not, Box::new(filter))
21 }
22}
23
24#[derive(Debug, PartialEq)]
25pub enum AttrExpData<'a> {
26 Present(AttrPath),
27 Compare(AttrPath, CompareOp, CompValue<'a>),
28}
29
30#[derive(Debug, PartialEq)]
31pub struct AttrPath {
32 uri: Option<Uri>,
33 attr_name: AttrName,
34 sub_attr: Option<SubAttr>,
35}
36
37impl AttrPath {
38 pub fn new((uri, attr_name, sub_attr): (Option<Uri>, AttrName, Option<SubAttr>)) -> Self {
39 Self {
40 uri,
41 attr_name,
42 sub_attr,
43 }
44 }
45
46 pub fn attr_name(&self) -> &AttrName {
47 &self.attr_name
48 }
49 pub fn sub_attr(&self) -> &Option<SubAttr> {
50 &self.sub_attr
51 }
52}
53
54#[derive(Debug, Copy, Clone, PartialEq)]
55pub enum CompareOp {
56 Equal,
57 NotEqual,
58 Contains,
59 StartsWith,
60 EndsWith,
61 GreaterThan,
62 GreaterThanOrEqual,
63 LessThan,
64 LessThanOrEqual,
65}
66
67impl FromStr for CompareOp {
68 type Err = String;
69
70 fn from_str(s: &str) -> Result<Self, Self::Err> {
71 match s.to_lowercase().as_str() {
72 "eq" => Ok(Self::Equal),
73 "ne" => Ok(Self::NotEqual),
74 "co" => Ok(Self::Contains),
75 "sw" => Ok(Self::StartsWith),
76 "ew" => Ok(Self::EndsWith),
77 "gt" => Ok(Self::GreaterThan),
78 "ge" => Ok(Self::GreaterThanOrEqual),
79 "lt" => Ok(Self::LessThan),
80 "le" => Ok(Self::LessThanOrEqual),
81 _ => Err(format!("{} is not a valid operator", s)),
82 }
83 }
84}
85
86pub type Uri = String;
88
89#[derive(Debug, PartialEq)]
90pub struct AttrName(pub(crate) String);
91
92impl AttrName {
93 pub fn new<'a>((initial, name_chars): (Alpha<'a>, Vec<NameChar<'a>>)) -> Self {
94 Self(format!(
95 "{}{}",
96 initial,
97 name_chars.into_iter().collect::<String>()
98 ))
99 }
100
101 #[cfg(test)]
102 pub fn from_str<'a>(name: &str) -> Self {
103 Self(name.to_string())
104 }
105}
106
107impl Deref for AttrName {
108 type Target = str;
109
110 fn deref(&self) -> &Self::Target {
111 self.0.as_str()
112 }
113}
114
115type Alpha<'a> = &'a str;
116
117pub type NameChar<'a> = &'a str;
118
119pub type SubAttr = AttrName;
120
121#[derive(Clone, Debug, PartialEq)]
123pub enum CompValue<'a> {
124 False,
125 Null,
126 True,
127 Number(Decimal),
128 String(&'a str),
129}
130
131#[derive(Debug, PartialEq)]
132pub struct LogExpData<'a> {
133 pub left: Box<Filter<'a>>,
134 pub log_exp_operator: LogExpOperator,
135 pub right: Box<Filter<'a>>,
136}
137
138impl<'a> LogExpData<'a> {
139 pub fn new((left, log_exp_operator, right): (Filter<'a>, LogExpOperator, Filter<'a>)) -> Self {
140 Self {
141 left: Box::new(left),
142 log_exp_operator,
143 right: Box::new(right),
144 }
145 }
146}
147
148#[derive(Clone, Debug, PartialEq)]
149pub enum LogExpOperator {
150 And,
151 Or,
152}
153
154impl LogExpOperator {
155 pub fn is_or(&self) -> bool {
156 match self {
157 LogExpOperator::And => false,
158 LogExpOperator::Or => true,
159 }
160 }
161
162 pub fn is_and(&self) -> bool {
163 !self.is_or()
164 }
165}
166
167#[derive(Debug, PartialEq)]
168pub struct ValuePathData<'a> {
169 attr_path: AttrPath,
170 val_filter: ValFilter<'a>,
171}
172
173impl<'a> ValuePathData<'a> {
174 pub fn new((attr_path, val_filter): (AttrPath, ValFilter<'a>)) -> Self {
175 Self {
176 attr_path,
177 val_filter,
178 }
179 }
180 pub fn attr_path(&self) -> &AttrPath {
181 &self.attr_path
182 }
183 pub fn val_filter(&self) -> &ValFilter<'a> {
184 &self.val_filter
185 }
186}
187
188#[derive(Debug, PartialEq)]
189pub enum ValFilter<'a> {
190 AttrExp(AttrExpData<'a>),
191 LogExp(LogExpData<'a>),
192 SubFilter(bool, Box<ValFilter<'a>>),
193}
194
195impl<'a> ValFilter<'a> {
196 pub fn attr_exp(data: AttrExpData<'a>) -> Self {
197 ValFilter::AttrExp(data)
198 }
199
200 pub fn log_exp(data: LogExpData<'a>) -> Self {
201 Self::LogExp(data)
202 }
203
204 pub fn sub_filter((not, val_filter): (bool, ValFilter<'a>)) -> Self {
205 Self::SubFilter(not, Box::new(val_filter))
206 }
207}
208
209pub(crate) fn scim_filter_parser(input: &str) -> Result<Filter, Error> {
212 let (remain, expression) = filter(input).map_err(|e| e.to_owned()).finish()?;
213 if !remain.is_empty() {
214 return Err(Error::WrongFilterFormat(
215 input.to_owned(),
216 remain.to_owned(),
217 ));
218 }
219 Ok(expression)
220}