use chrono::{NaiveDate, Utc}; use chrono::Datelike; use regex::{Regex, RegexBuilder}; #[derive(Debug)] pub struct DateRange { start_year : i32, start_month : u32, end_year : i32, end_month : u32, last : bool, } impl DateRange { pub fn new(start : chrono::NaiveDate, end : chrono::NaiveDate) -> DateRange { DateRange { start_year : start.year(), start_month : start.month(), end_year : end.year(), end_month : end.month(), last : false, } } } impl Iterator for DateRange { type Item = chrono::NaiveDate; fn next(&mut self) -> Option { if self.last { return None } if self.start_year == self.end_year && self.start_month == self.end_month { self.last = true; } let mut tmp = self.start_year.to_string(); if self.start_month < 10 { tmp.push_str("-0"); } else { tmp.push_str("-"); } tmp.push_str(&self.start_month.to_string()); tmp.push_str("-01"); if self.start_month < 12 { self.start_month = self.start_month + 1; } else { self.start_month = 1; self.start_year = self.start_year + 1; } return Some(chrono::NaiveDate::parse_from_str(&tmp, "%Y-%m-%d").unwrap()) } } /* This files contains the code to handle the /transactions requests */ struct TransactionFilter { sender_name_filter : Vec, reference_filter : Vec } /* * files syntax: . seperates different search critereas * a search crietera is a key value pair, with key as fiter type, e.g. * sender name of transation. The value is what is should be and can be a regex * key value pair is split by - */ pub fn apply_transaction_filter<'t>(filter : &str , transactions : &'t Vec) -> Vec<&'t crate::banking::account::Transaction> { let mut tmp; // special case if for general search if !filter.to_string().contains(";") { let re = Regex::new(&filter).unwrap(); tmp = transactions.iter().filter(|transaction| re.is_match(&transaction.sender_name) || re.is_match(&transaction.reference) ).collect(); return tmp; } // parse filter string and construct TransactionFilter struct let mut sender_name_vec = Vec::new(); let mut reference_vec = Vec::new(); for entry in filter.to_string().split(";") { let v : Vec<_> = entry.split("-").collect(); if v.len() > 1 { if v[0] == "sender" { let re_sender = RegexBuilder::new(v[1]) .case_insensitive(true) .build() .expect("invalid regex"); sender_name_vec.push(re_sender); } else if v[0] == "reference" { let re_reference = RegexBuilder::new(v[1]) .case_insensitive(true) .build() .expect("invalid regex"); reference_vec.push(re_reference); } } } // prebuild regexes ... println!("sender name len {}, reference name length {}", sender_name_vec.len(), reference_vec.len()); tmp = transactions.iter().filter(|transaction| { for sender in &sender_name_vec { if sender.is_match(&transaction.sender_name) { return true; } } for reference in &reference_vec { if reference.is_match(&transaction.reference) { return true; } } return false; }).collect(); println!("end filtering {}", filter); tmp } pub fn apply_date_filter(transactions : Vec, date_start : chrono::NaiveDate, date_end : chrono::NaiveDate) -> Vec { let date_range = DateRange::new(date_start, date_end); let mut t_filtered = Vec::new(); for date in date_range { let tc = transactions.clone(); let mut tmp : Vec<_> = tc.into_iter().filter(|x| x.date.month() == date.month() && x.date.year() == date.year()).collect(); t_filtered.append(&mut tmp); } t_filtered }