dw_query/
datatype.rs

1use std::collections::HashMap;
2use std::convert::{TryFrom, TryInto};
3use std::fmt;
4
5use super::functions;
6use super::QueryError;
7use dw_models::Event;
8use dw_transform::classify::{RegexRule, Rule};
9
10use serde::{Serialize, Serializer};
11use serde_json::value::Value;
12use serde_json::Number;
13
14// TODO: greater/less comparisons
15
16#[derive(Clone, Serialize)]
17#[serde(untagged)]
18pub enum DataType {
19    None(),
20    Bool(bool),
21    Number(f64),
22    String(String),
23    Event(Event),
24    List(Vec<DataType>),
25    Dict(HashMap<String, DataType>),
26    #[serde(serialize_with = "serialize_function")]
27    Function(String, functions::QueryFn),
28}
29
30#[allow(clippy::trivially_copy_pass_by_ref)]
31fn serialize_function<S>(
32    _element: &str,
33    _fun: &functions::QueryFn,
34    _serializer: S,
35) -> Result<S::Ok, S::Error>
36where
37    S: Serializer,
38{
39    panic!("Query function was unevaluated and was attempted to be serialized, panic!");
40    //element.id.serialize(serializer)
41}
42
43// Needed because of a limitation in rust where you cannot derive(Debug) on a
44// enum which has a fn with reference parameters which our QueryFn has
45// https://stackoverflow.com/questions/53380040/function-pointer-with-a-reference-argument-cannot-derive-debug
46impl fmt::Debug for DataType {
47    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48        match self {
49            DataType::None() => write!(f, "None()"),
50            DataType::Bool(b) => write!(f, "Bool({})", b),
51            DataType::Number(n) => write!(f, "Number({})", n),
52            DataType::String(s) => write!(f, "String({})", s),
53            DataType::Event(e) => write!(f, "Event({:?})", e),
54            DataType::List(l) => write!(f, "List({:?})", l),
55            DataType::Dict(d) => write!(f, "Dict({:?})", d),
56            DataType::Function(name, _fun) => write!(f, "Function({})", name),
57        }
58    }
59}
60
61/* Like eq, but raises an error when comparing between different types.
62 * Should be used as often as possible */
63impl DataType {
64    pub fn query_eq(&self, other: &DataType) -> Result<bool, QueryError> {
65        match (self, other) {
66            // TODO: Comparisons of bool == num, bool == str
67            (DataType::None(), DataType::None()) => Ok(false),
68            (DataType::Bool(b1), DataType::Bool(b2)) => Ok(b1 == b2),
69            (DataType::Number(n1), DataType::Number(n2)) => Ok(n1 == n2),
70            (DataType::String(s1), DataType::String(s2)) => Ok(s1 == s2),
71            (DataType::Event(e1), DataType::Event(e2)) => Ok(e1 == e2),
72            (DataType::List(l1), DataType::List(l2)) => Ok(l1 == l2),
73            (DataType::Dict(d1), DataType::Dict(d2)) => Ok(d1 == d2),
74            // We do not care about comparing functions
75            _ => Err(QueryError::InvalidType(format!(
76                "Cannot compare values of different types {:?} and {:?}",
77                self, other
78            ))),
79        }
80    }
81}
82
83/* Required for query_eq when comparing two dicts */
84impl PartialEq for DataType {
85    fn eq(&self, other: &DataType) -> bool {
86        match (self, other) {
87            (DataType::None(), DataType::None()) => true,
88            // TODO: Comparisons of bool == num, bool == str
89            (DataType::Bool(b1), DataType::Bool(b2)) => b1 == b2,
90            (DataType::Number(n1), DataType::Number(n2)) => n1 == n2,
91            (DataType::String(s1), DataType::String(s2)) => s1 == s2,
92            (DataType::Event(e1), DataType::Event(e2)) => e1 == e2,
93            (DataType::List(l1), DataType::List(l2)) => l1 == l2,
94            (DataType::Dict(d1), DataType::Dict(d2)) => d1 == d2,
95            // We do not care about comparing functions
96            _ => false,
97        }
98    }
99}
100
101impl TryFrom<&DataType> for Vec<DataType> {
102    type Error = QueryError;
103    fn try_from(value: &DataType) -> Result<Self, Self::Error> {
104        match value {
105            DataType::List(ref s) => Ok(s.clone()),
106            ref invalid_type => Err(QueryError::InvalidFunctionParameters(format!(
107                "Expected function parameter of type List, got {:?}",
108                invalid_type
109            ))),
110        }
111    }
112}
113
114impl TryFrom<&DataType> for String {
115    type Error = QueryError;
116    fn try_from(value: &DataType) -> Result<Self, Self::Error> {
117        match value {
118            DataType::String(s) => Ok(s.clone()),
119            ref invalid_type => Err(QueryError::InvalidFunctionParameters(format!(
120                "Expected function parameter of type String, list contains {:?}",
121                invalid_type
122            ))),
123        }
124    }
125}
126
127impl TryFrom<&DataType> for Vec<String> {
128    type Error = QueryError;
129    fn try_from(value: &DataType) -> Result<Self, Self::Error> {
130        let mut tagged_strings: Vec<DataType> = value.try_into()?;
131        let mut strings = Vec::new();
132        for string in tagged_strings.drain(..) {
133            let s: String = (&string).try_into()?;
134            strings.push(s);
135        }
136        Ok(strings)
137    }
138}
139
140impl TryFrom<&DataType> for Vec<Event> {
141    type Error = QueryError;
142    fn try_from(value: &DataType) -> Result<Self, Self::Error> {
143        let mut tagged_events: Vec<DataType> = value.try_into()?;
144        let mut events = Vec::new();
145        for event in tagged_events.drain(..) {
146            match event {
147                DataType::Event(e) => events.push(e.clone()),
148                ref invalid_type => {
149                    return Err(QueryError::InvalidFunctionParameters(format!(
150                        "Expected function parameter of type List of Events, list contains {:?}",
151                        invalid_type
152                    )))
153                }
154            }
155        }
156        Ok(events)
157    }
158}
159
160impl TryFrom<&DataType> for Vec<(String, Rule)> {
161    type Error = QueryError;
162    fn try_from(value: &DataType) -> Result<Self, Self::Error> {
163        let mut tagged_lists: Vec<DataType> = value.try_into()?;
164        let mut lists: Vec<(String, Rule)> = Vec::new();
165        for list in tagged_lists.drain(..) {
166            match list {
167                DataType::List(ref l) => {
168                    let tag: String = match l.get(0) {
169                        Some(tag) => tag.try_into()?,
170                        None => return Err(QueryError::InvalidFunctionParameters(
171                            format!("Expected function parameter of type list of (tag, rule) tuples, list contains {:?}", l)))
172                    };
173                    let rule: Rule = match l.get(1) {
174                        Some(rule) => rule.try_into()?,
175                        None => return Err(QueryError::InvalidFunctionParameters(
176                            format!("Expected function parameter of type list of (tag, rule) tuples, list contains {:?}", l)))
177                    };
178                    lists.push((tag, rule));
179                }
180                ref invalid_type => {
181                    return Err(QueryError::InvalidFunctionParameters(format!(
182                        "Expected function parameter of type list of (tag, rule) tuples, got {:?}",
183                        invalid_type
184                    )))
185                }
186            }
187        }
188        Ok(lists)
189    }
190}
191
192impl TryFrom<&DataType> for Vec<(Vec<String>, Rule)> {
193    type Error = QueryError;
194    fn try_from(value: &DataType) -> Result<Self, Self::Error> {
195        let mut tagged_lists: Vec<DataType> = value.try_into()?;
196        let mut lists: Vec<(Vec<String>, Rule)> = Vec::new();
197        for list in tagged_lists.drain(..) {
198            match list {
199                DataType::List(ref l) => {
200                    let category: Vec<String> = match l.get(0) {
201                        Some(category) => category.try_into()?,
202                        None => return Err(QueryError::InvalidFunctionParameters(
203                            format!("Expected function parameter of type list of (category, rule) tuples, list contains {:?}", l)))
204                    };
205                    let rule: Rule = match l.get(1) {
206                        Some(rule) => rule.try_into()?,
207                        None => return Err(QueryError::InvalidFunctionParameters(
208                            format!("Expected function parameter of type list of (category, rule) tuples, list contains {:?}", l)))
209                    };
210                    lists.push((category, rule));
211                }
212                ref invalid_type => {
213                    return Err(QueryError::InvalidFunctionParameters(format!(
214                    "Expected function parameter of type list of (category, rule) tuples, got {:?}",
215                    invalid_type
216                )))
217                }
218            }
219        }
220        Ok(lists)
221    }
222}
223
224impl TryFrom<&DataType> for f64 {
225    type Error = QueryError;
226    fn try_from(value: &DataType) -> Result<Self, Self::Error> {
227        match value {
228            DataType::Number(f) => Ok(*f),
229            ref invalid_type => Err(QueryError::InvalidFunctionParameters(format!(
230                "Expected function parameter of type Number, got {:?}",
231                invalid_type
232            ))),
233        }
234    }
235}
236
237impl TryFrom<&DataType> for usize {
238    type Error = QueryError;
239    fn try_from(value: &DataType) -> Result<Self, Self::Error> {
240        let f: f64 = value.try_into()?;
241        Ok(f as usize)
242    }
243}
244
245impl TryFrom<&DataType> for Value {
246    type Error = QueryError;
247    fn try_from(value: &DataType) -> Result<Self, Self::Error> {
248        match value {
249            DataType::None() => Ok(Value::Null),
250            DataType::Bool(b) => Ok(Value::Bool(*b)),
251            DataType::Number(n) => Ok(Value::Number(Number::from_f64(*n).unwrap())),
252            DataType::String(s) => Ok(Value::String(s.to_string())),
253            DataType::List(_l) => {
254                let mut tagged_values: Vec<DataType> = value.try_into()?;
255                let mut values: Vec<Value> = Vec::new();
256                for value in tagged_values.drain(..) {
257                    values.push((&value).try_into()?);
258                }
259                Ok(Value::Array(values))
260            }
261            ref invalid_type => Err(QueryError::InvalidFunctionParameters(format!(
262                "Query2 support for parsing values is limited, does not support parsing {:?}",
263                invalid_type
264            ))),
265        }
266    }
267}
268
269impl TryFrom<&DataType> for Vec<Value> {
270    type Error = QueryError;
271    fn try_from(value: &DataType) -> Result<Self, Self::Error> {
272        let mut tagged_values: Vec<DataType> = value.try_into()?;
273        let mut values: Vec<Value> = Vec::new();
274        for value in tagged_values.drain(..) {
275            values.push((&value).try_into()?);
276        }
277        Ok(values)
278    }
279}
280
281impl TryFrom<&DataType> for Rule {
282    type Error = QueryError;
283
284    fn try_from(data: &DataType) -> Result<Self, Self::Error> {
285        let obj = match data {
286            DataType::Dict(dict) => dict,
287            _ => {
288                return Err(QueryError::InvalidFunctionParameters(format!(
289                    "Expected rule dict, got {:?}",
290                    data
291                )))
292            }
293        };
294        let rtype_val = match obj.get("type") {
295            Some(rtype) => rtype,
296            None => {
297                return Err(QueryError::InvalidFunctionParameters(
298                    "rule does not have a type".to_string(),
299                ))
300            }
301        };
302        let rtype = match rtype_val {
303            DataType::String(s) => s,
304            _ => {
305                return Err(QueryError::InvalidFunctionParameters(
306                    "rule type is not a string".to_string(),
307                ))
308            }
309        };
310        if rtype == "none" {
311            Ok(Self::None)
312        } else if rtype == "regex" {
313            let regex_val = match obj.get("regex") {
314                Some(regex_val) => regex_val,
315                None => {
316                    return Err(QueryError::InvalidFunctionParameters(
317                        "regex rule is missing the 'regex' field".to_string(),
318                    ))
319                }
320            };
321            let regex_str = match regex_val {
322                DataType::String(s) => s,
323                _ => {
324                    return Err(QueryError::InvalidFunctionParameters(
325                        "the regex field of the regex rule is not a string".to_string(),
326                    ))
327                }
328            };
329            let ignore_case_val = match obj.get("ignore_case") {
330                Some(case_val) => case_val,
331                None => &DataType::Bool(false),
332            };
333            let ignore_case = match ignore_case_val {
334                DataType::Bool(b) => b,
335                _ => {
336                    return Err(QueryError::InvalidFunctionParameters(
337                        "the ignore_case field of the regex rule is not a bool".to_string(),
338                    ))
339                }
340            };
341            let regex_rule = match RegexRule::new(regex_str, *ignore_case) {
342                Ok(regex_rule) => regex_rule,
343                Err(err) => {
344                    return Err(QueryError::RegexCompileError(format!(
345                        "Failed to compile regex string '{}': '{:?}",
346                        regex_str, err
347                    )))
348                }
349            };
350            Ok(Self::Regex(regex_rule))
351        } else {
352            Err(QueryError::InvalidFunctionParameters(format!(
353                "Unknown rule type '{}'",
354                rtype
355            )))
356        }
357    }
358}