ghee_lang/
predicate.rs

1use std::ffi::OsStr;
2
3use clap::{builder::TypedValueParser, Arg, Command};
4use nom::{
5    sequence::{pair, terminated},
6    IResult,
7};
8
9use crate::Record;
10
11use super::{
12    relation::{parse_relation, Relation},
13    space,
14    xattr::{parse_xattr, Xattr},
15};
16
17#[derive(Clone, Debug, PartialEq)]
18pub struct Predicate {
19    pub xattr: Xattr,
20    pub relation: Relation,
21}
22
23impl Predicate {
24    pub fn new(xattr: Xattr, relation: Relation) -> Self {
25        Self { xattr, relation }
26    }
27    pub fn satisfied(&self, values: &Record) -> bool {
28        values
29            .get(&self.xattr)
30            .map_or(false, |v| self.relation.satisfied_by(v.clone()))
31    }
32}
33
34// fn parse_predicate<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Predicate, E> {
35//     pair(parse_xattr, parse_relation)(i)
36//         .map(|(i, (xattr, relation))| (i, Predicate { xattr, relation }))
37// }
38
39pub fn parse_predicate(i: &[u8]) -> IResult<&[u8], Predicate> {
40    pair(terminated(parse_xattr, space), parse_relation)(i)
41        .map(|(i, (xattr, relation))| (i, Predicate { xattr, relation }))
42}
43
44#[derive(Clone)]
45pub struct PredicateParser;
46impl TypedValueParser for PredicateParser {
47    type Value = Predicate;
48
49    fn parse_ref(
50        &self,
51        _cmd: &Command,
52        _arg: Option<&Arg>,
53        value: &OsStr,
54    ) -> Result<Self::Value, clap::error::Error<clap::error::RichFormatter>> {
55        parse_predicate(value.to_string_lossy().as_bytes())
56            .map(|(_remainder, predicate)| predicate)
57            .map_err(|e| {
58                clap::error::Error::raw(
59                    clap::error::ErrorKind::InvalidValue,
60                    format!("Malformed WHERE clause: {}\n", e),
61                )
62            })
63    }
64}
65
66#[cfg(test)]
67mod test {
68    use crate::parser::{
69        relation::Relation,
70        xattr::{Namespace, Xattr},
71    };
72
73    use super::{parse_predicate, Predicate};
74    #[test]
75    fn test_parse_predicate() {
76        assert!(parse_predicate(b"").is_err());
77        assert!(parse_predicate(b"a + b").is_err());
78        assert!(parse_predicate(b"fakenamespace.lmnop").is_err());
79        assert_eq!(
80            parse_predicate(b"amplitude>=-2.4343").unwrap().1,
81            Predicate {
82                xattr: Xattr::new(Namespace::User, "amplitude"),
83                relation: Relation::gte(-2.4343f64)
84            }
85        );
86        assert_eq!(
87            parse_predicate(b"system.security <= -2").unwrap().1,
88            Predicate {
89                xattr: Xattr::new(Namespace::System, "security"),
90                relation: Relation::lte(-2f64)
91            }
92        );
93        assert_eq!(
94            parse_predicate(b"security.lmnop in [1,2,3]"),
95            Ok((
96                b"".as_slice(),
97                Predicate {
98                    xattr: Xattr::new(Namespace::Security, "lmnop"),
99                    relation: Relation::in_(vec![1f64, 2f64, 3f64])
100                }
101            ))
102        );
103        assert_eq!(
104            parse_predicate(b"trusted.trustfulness > 4"),
105            Ok((
106                b"".as_slice(),
107                Predicate {
108                    xattr: Xattr::new(Namespace::Trusted, "trustfulness"),
109                    relation: Relation::gt(4f64)
110                }
111            ))
112        );
113        assert_eq!(
114            parse_predicate(b"user.grumpiness < 4"),
115            Ok((
116                b"".as_slice(),
117                Predicate {
118                    xattr: Xattr::new(Namespace::User, "grumpiness"),
119                    relation: Relation::lt(4f64)
120                }
121            ))
122        );
123    }
124}