diff options
| author | Gustav Sörnäs <gustav@sornas.net> | 2021-07-31 01:57:48 +0200 |
|---|---|---|
| committer | Gustav Sörnäs <gustav@sornas.net> | 2021-07-31 01:57:48 +0200 |
| commit | c5e306135b77ac9761ed41b2501b0563124ab703 (patch) | |
| tree | b889283ae5985ce483d16965e262ba6a9277ac1a | |
| parent | eb22945b21de880c294bb91bf0e8c1bb5a9e63d0 (diff) | |
| download | money-c5e306135b77ac9761ed41b2501b0563124ab703.tar.gz | |
add/subtract/only but working
| -rw-r--r-- | cli/src/search.rs | 191 |
1 files changed, 108 insertions, 83 deletions
diff --git a/cli/src/search.rs b/cli/src/search.rs index fd7407f..993a924 100644 --- a/cli/src/search.rs +++ b/cli/src/search.rs @@ -7,6 +7,7 @@ pub struct Search<'t> { transactions: Vec<&'t Transaction>, } +#[derive(Clone)] pub enum DateIsh { Absolute(NaiveDate), Relative(Duration), @@ -16,39 +17,90 @@ impl DateIsh { pub fn parse(s: &str) -> Self { DateIsh::Absolute(NaiveDate::parse_from_str(s, "%Y-%m-%d").unwrap()) } + + pub fn get(self) -> NaiveDate { + match self { + DateIsh::Absolute(date) => date, + DateIsh::Relative(offset) => chrono::offset::Local::today().naive_utc() + offset + } + } } pub enum Constraint { Category(Category), - Before(DateIsh, bool), - After(DateIsh, bool), + Before(DateIsh), + After(DateIsh), } -impl Constraint { - fn satisfies(&self, t: &Transaction) -> bool { +enum FilterType { + Add(Constraint), + Subtract(Constraint), + Only(Constraint), +} + +impl FilterType { + fn apply<'s>(&self, mut search: Search<'s>) -> Search<'s> { match self { - Constraint::Category(category) => category == &t.category, - Constraint::Before(DateIsh::Absolute(date), inclusive) => if *inclusive { - &t.date <= date - } else { - &t.date < date - }, - Constraint::After(DateIsh::Absolute(date), inclusive) => if *inclusive { - &t.date >= date - } else { - &t.date > date + FilterType::Add(_) => { + //TODO binary search and insert sorted + for idx in search + .transactions + .iter() + .enumerate() + .filter(|(_, t)| self.satisfies(t)) + .map(|(idx, _)| idx) + { + search.filtered.push(idx); + } + search.filtered.sort(); + search.filtered.dedup(); } - Constraint::Before(DateIsh::Relative(diff), inclusive) => if *inclusive { - t.date <= chrono::offset::Local::today().naive_utc() + *diff - } else { - t.date < chrono::offset::Local::today().naive_utc() + *diff + FilterType::Subtract(_) => { + search.filtered = search + .filtered + .iter() + .filter(|t| !self.satisfies(search.transactions[**t])) + .copied() + .collect(); } - Constraint::After(DateIsh::Relative(diff), inclusive) => if *inclusive { - t.date >= chrono::offset::Local::today().naive_utc() + *diff - } else { - t.date > chrono::offset::Local::today().naive_utc() + *diff + FilterType::Only(_) => { + search.filtered = search + .filtered + .iter() + .filter(|t| self.satisfies(search.transactions[**t])) + .copied() + .collect(); } } + search + } + + fn satisfies(&self, transaction: &Transaction) -> bool { + match self { + // Category + FilterType::Add(Constraint::Category(category)) + | FilterType::Subtract(Constraint::Category(category)) + | FilterType::Only(Constraint::Category(category)) + => &transaction.category == category, + + FilterType::Only(Constraint::Before(date)) + => transaction.date < date.clone().get(), + + FilterType::Only(Constraint::After(date)) + => transaction.date >= date.clone().get(), + + FilterType::Add(Constraint::Before(date)) + => transaction.date < date.clone().get(), + + FilterType::Add(Constraint::After(date)) + => transaction.date >= date.clone().get(), + + FilterType::Subtract(Constraint::Before(date)) + => transaction.date < date.clone().get(), + + FilterType::Subtract(Constraint::After(date)) + => transaction.date >= date.clone().get(), + } } } @@ -70,67 +122,40 @@ impl<'t> Search<'t> { .collect() } - pub fn parse(self, rules: String) -> Self { - let (sub, rules) = { - if rules.chars().nth(0).unwrap() == '-' { - (true, &rules[1..]) - } else { - (false, &rules[..]) - } - }; - - //TODO lexing - - // +category:a - //TODO: category:"foo bar" - - // before:2021-01-01 => + (* -> 2020-12-31) n-incl - // after:2021-01-01 => + (2021-01-01 -> *) incl - // -before:2021-01-01 => - (2021-01-01 -> *) incl - // -after:2021-01-01 => - (* -> 2021-12-31) n-incl - - //TODO: - // today is 2021-01-01: - // before:-1d => + (* -> 2020-12-31) n-incl - // after:-1d => + (2021-01-01 -> *) incl - // -before:-1d => - (2021-01-01 -> *) incl - // -after:-1d => - (* -> 2020-12-31) n-incl - - let constraint = match rules.split_once(':').unwrap() { - ("category", category) => Constraint::Category(category.to_string()), - ("before", date_ish) => Constraint::Before(DateIsh::parse(date_ish), sub), - ("after", date_ish) => Constraint::After(DateIsh::parse(date_ish), !sub), - _ => panic!(), - }; - - if sub { - self.subtract(constraint) - } else { - self.filter(constraint) - } - } - - pub fn subtract(self, constraint: Constraint) -> Self { - Self { - filtered: self - .filtered - .iter() - .copied() - .filter(|idx| !constraint.satisfies(self.transactions[*idx])) - .collect(), - transactions: self.transactions, - } - } - - pub fn filter(self, constraint: Constraint) -> Self { - Self { - filtered: self - .filtered - .iter() - .copied() - .filter(|idx| constraint.satisfies(self.transactions[*idx])) - .collect(), - transactions: self.transactions, + pub fn parse(mut self, rules: String) -> Self { + for rule in rules.split(' ') { + let (filter_type, rule): (fn(Constraint) -> FilterType, &str) = match rule.chars().nth(0).unwrap() { + '-' => (FilterType::Subtract, &rule[1..]), + '+' => (FilterType::Add, &rule[1..]), + _ => (FilterType::Only, &rule[..]), + }; + + //TODO lexing? can do a function for "spaces inside" instead + + // +category:a + //TODO: category:"foo bar" + + // before:2021-01-01 => + (* -> 2020-12-31) n-incl + // after:2021-01-01 => + (2021-01-01 -> *) incl + // -before:2021-01-01 => - (2021-01-01 -> *) incl + // -after:2021-01-01 => - (* -> 2021-12-31) n-incl + + //TODO: + // today is 2021-01-01: + // before:-1d => + (* -> 2020-12-31) n-incl + // after:-1d => + (2021-01-01 -> *) incl + // -before:-1d => - (2021-01-01 -> *) incl + // -after:-1d => - (* -> 2020-12-31) n-incl + + 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)), + _ => panic!(), + }; + + self = filter_type(constraint).apply(self); } + self } } |
