1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
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<Self::Item> {
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<String>,
reference_filter : Vec<String>
}
/*
* 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<crate::banking::account::Transaction>) -> 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<crate::banking::account::Transaction>, date_start : chrono::NaiveDate, date_end : chrono::NaiveDate) -> Vec<crate::banking::account::Transaction> {
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
}
|