diff options
| -rw-r--r-- | cli/src/search.rs | 79 |
1 files changed, 40 insertions, 39 deletions
diff --git a/cli/src/search.rs b/cli/src/search.rs index eaf1d06..6692b00 100644 --- a/cli/src/search.rs +++ b/cli/src/search.rs @@ -5,6 +5,7 @@ use nom::character::complete::{alphanumeric1, anychar, char, digit1}; use nom::combinator::{map, map_res, recognize}; use nom::sequence::{delimited, pair, preceded}; use rust_decimal::Decimal; +use std::convert::TryFrom; use std::str::FromStr; use crate::transaction::{Category, Transaction}; @@ -67,22 +68,40 @@ pub enum Comparison { LessOrEqual, } -fn parse_comparison(s: &str) -> Option<(Decimal, Comparison)> { - if s.starts_with(">=") { - Some((Decimal::from_str(&s[2..]).ok()?, Comparison::GreaterOrEqual)) - } else if s.starts_with("<=") { - Some((Decimal::from_str(&s[2..]).ok()?, Comparison::LessOrEqual)) - } else if s.starts_with("=") { - Some((Decimal::from_str(&s[1..]).ok()?, Comparison::Equal)) - } else if s.starts_with(">") { - Some((Decimal::from_str(&s[1..]).ok()?, Comparison::Greater)) - } else if s.starts_with("<") { - Some((Decimal::from_str(&s[1..]).ok()?, Comparison::Less)) - } else { - None +impl TryFrom<&str> for Comparison { + type Error = (); + + fn try_from(s: &str) -> Result<Self, Self::Error> { + match s { + "=" | "==" => Ok(Comparison::Equal), + ">" => Ok(Comparison::Greater), + ">=" => Ok(Comparison::GreaterOrEqual), + "<" => Ok(Comparison::Less), + "<=" => Ok(Comparison::LessOrEqual), + _ => Err(()), + } } } +fn parse_comparison(i: &str) -> nom::IResult<&str, (Decimal, Comparison)> { + let (i, comparison) = map( + alt(( + tag("="), + tag("=="), + tag(">"), + tag(">="), + tag("<"), + tag("<="), + )), + |comparison| Comparison::try_from(comparison).unwrap() + )(i)?; + let (i, amount) = map_res( + digit1, + Decimal::from_str + )(i)?; + Ok((i, (amount, comparison))) +} + #[derive(Clone)] #[derive(Debug)] pub enum Constraint { @@ -151,6 +170,13 @@ impl Constraint { ), Constraint::On ), + map( + preceded( + tag("amount:"), + parse_comparison, + ), + |(amount, comparison)| Constraint::AmountCompare(amount, comparison) + ) ))(i) } } @@ -253,32 +279,7 @@ impl<'t> Search<'t> { } pub fn parse(mut self, rules: String) -> Self { - for rule in rules.split(' ') { - let (filter, rule): (fn(Constraint) -> Filter, &str) = match rule.chars().nth(0).unwrap() { - '-' => (Filter::Subtract, &rule[1..]), - '+' => (Filter::Union, &rule[1..]), - _ => (Filter::Intersect, &rule[..]), - }; - - //TODO lexing? can do a function for "spaces inside" instead - - //TODO category:"foo bar" - - let constraint = match rule.split_once(':').unwrap() { - // ("category", category) => Constraint::Category(category.to_string()), - // ("before", date_ish) => Constraint::Before(DateIsh::parse(date_ish)), - // ("after", date_ish) => Constraint::After(DateIsh::parse(date_ish)), - // ("on", date_ish) => Constraint::On(DateIsh::parse(date_ish)), - ("amount", comparison) => { - let (amount, comparison) = parse_comparison(comparison).unwrap(); - Constraint::AmountCompare(amount, comparison) - } - _ => panic!(), - }; - - self = self.apply(filter(constraint)); - } - self + todo!() } } |
