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
|
use chrono::{naive::NaiveDate, Duration};
use crate::transaction::{Category, Transaction};
pub struct Search<'t> {
filtered: Vec<usize>,
transactions: Vec<&'t Transaction>,
}
pub enum DateFilter {
Absolute {
start: Option<NaiveDate>,
end: Option<NaiveDate>,
},
Relative {
start: Option<Duration>,
end: Option<Duration>,
}
}
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,
}
}
}
|