use chrono::{naive::NaiveDate, Duration}; use crate::transaction::{Category, Transaction}; pub struct Search<'t> { filtered: Vec, transactions: Vec<&'t Transaction>, } pub enum DateFilter { Absolute { start: Option, end: Option, }, Relative { start: Option, end: Option, } } pub enum Constraint { Category(Category), Date(DateFilter), } impl Constraint { fn satisfies(&self, t: &Transaction) -> bool { match self { Constraint::Category(category) => category == &t.category, Constraint::Date(DateFilter::Relative { start, end, }) => { if let (Some(start), Some(end)) = (start, end) { assert!(start < end); } let now = chrono::offset::Local::today().naive_utc(); let start_valid = start.map(|start| t.date > now + start).unwrap_or(true); let end_valid = end.map(|end| t.date < now + end).unwrap_or(true); start_valid && end_valid }, Constraint::Date(DateFilter::Absolute { start, end, }) => { if let (Some(start), Some(end)) = (start, end) { assert!(start < end); } let now = chrono::offset::Local::today().naive_utc(); let start_valid = start.map(|start| t.date > start).unwrap_or(true); let end_valid = end.map(|end| t.date < end).unwrap_or(true); start_valid && end_valid }, } } } impl<'t> Search<'t> { pub fn new(transactions: Vec<&'t Transaction>) -> Self { Self { filtered: std::iter::successors(Some(0_usize), |n| Some(n.checked_add(1).unwrap())).take(transactions.len()).collect(), transactions, } } pub fn get(&self) -> Vec<&'t Transaction> { self .filtered .iter() .map(|idx| self.transactions[*idx]) .collect() } pub fn subtract(self, constraint: Constraint) -> Self { Self { filtered: self .filtered .iter() .copied() .filter(|idx| !constraint.satisfies(self.transactions[*idx])) .collect(), transactions: self.transactions, } } }