summaryrefslogtreecommitdiffstats
path: root/cli/src/search.rs
diff options
context:
space:
mode:
authorGustav Sörnäs <gustav@sornas.net>2021-07-31 01:57:48 +0200
committerGustav Sörnäs <gustav@sornas.net>2021-07-31 01:57:48 +0200
commitc5e306135b77ac9761ed41b2501b0563124ab703 (patch)
treeb889283ae5985ce483d16965e262ba6a9277ac1a /cli/src/search.rs
parenteb22945b21de880c294bb91bf0e8c1bb5a9e63d0 (diff)
downloadmoney-c5e306135b77ac9761ed41b2501b0563124ab703.tar.gz
add/subtract/only but working
Diffstat (limited to 'cli/src/search.rs')
-rw-r--r--cli/src/search.rs191
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
}
}