1mod filter_definition;
12pub mod logic;
13pub mod posting;
14pub mod txn;
15
16pub use crate::filters::filter_definition::FilterDefZoned;
17pub use crate::filters::filter_definition::FilterDefinition;
18use jiff::tz::TimeZone;
19use rust_decimal::Decimal;
20use serde::{Deserialize, Serialize};
21use std::fmt::{Error, Formatter};
22
23use logic::TxnFilterAND;
24use logic::TxnFilterNOT;
25use logic::TxnFilterOR;
26
27use txn::TxnFilterBBoxLatLon;
28use txn::TxnFilterBBoxLatLonAlt;
29use txn::TxnFilterTxnCode;
30use txn::TxnFilterTxnComments;
31use txn::TxnFilterTxnDescription;
32use txn::TxnFilterTxnExtId;
33use txn::TxnFilterTxnTSBegin;
34use txn::TxnFilterTxnTSEnd;
35use txn::TxnFilterTxnTags;
36use txn::TxnFilterTxnUUID;
37
38use posting::TxnFilterPostingAccount;
39use posting::TxnFilterPostingAmountEqual;
40use posting::TxnFilterPostingAmountGreater;
41use posting::TxnFilterPostingAmountLess;
42use posting::TxnFilterPostingComment;
43use posting::TxnFilterPostingCommodity;
44
45pub trait IndentDisplay {
48 fn i_fmt(&self, indent: &str, _tz: TimeZone, f: &mut Formatter<'_>) -> std::fmt::Result;
54}
55
56#[derive(Serialize, Deserialize, Clone, Debug)]
61pub enum TxnFilter {
62 #[doc(hidden)]
64 NullaryTRUE(NullaryTRUE),
65 #[doc(hidden)]
66 NullaryFALSE(NullaryFALSE),
67
68 #[doc(hidden)]
70 TxnFilterAND(TxnFilterAND),
71 #[doc(hidden)]
72 TxnFilterOR(TxnFilterOR),
73 #[doc(hidden)]
74 TxnFilterNOT(TxnFilterNOT),
75
76 #[doc(hidden)]
78 TxnFilterTxnTSBegin(TxnFilterTxnTSBegin),
79 #[doc(hidden)]
80 TxnFilterTxnTSEnd(TxnFilterTxnTSEnd),
81 #[doc(hidden)]
82 TxnFilterTxnCode(TxnFilterTxnCode),
83 #[doc(hidden)]
84 TxnFilterTxnDescription(TxnFilterTxnDescription),
85 #[doc(hidden)]
86 TxnFilterTxnUUID(TxnFilterTxnUUID),
87 #[doc(hidden)]
88 TxnFilterTxnExtId(TxnFilterTxnExtId),
89 #[doc(hidden)]
90 TxnFilterBBoxLatLon(TxnFilterBBoxLatLon),
91 #[doc(hidden)]
92 TxnFilterBBoxLatLonAlt(TxnFilterBBoxLatLonAlt),
93 #[doc(hidden)]
94 TxnFilterTxnTags(TxnFilterTxnTags),
95 #[doc(hidden)]
96 TxnFilterTxnComments(TxnFilterTxnComments),
97
98 #[doc(hidden)]
100 TxnFilterPostingAccount(TxnFilterPostingAccount),
101 #[doc(hidden)]
102 TxnFilterPostingComment(TxnFilterPostingComment),
103 #[doc(hidden)]
104 TxnFilterPostingAmountEqual(TxnFilterPostingAmountEqual),
105 #[doc(hidden)]
106 TxnFilterPostingAmountLess(TxnFilterPostingAmountLess),
107 #[doc(hidden)]
108 TxnFilterPostingAmountGreater(TxnFilterPostingAmountGreater),
109 #[doc(hidden)]
110 TxnFilterPostingCommodity(TxnFilterPostingCommodity),
111}
112
113impl IndentDisplay for TxnFilter {
121 fn i_fmt(&self, indent: &str, tz: TimeZone, f: &mut Formatter<'_>) -> std::fmt::Result {
122 match self {
123 TxnFilter::NullaryTRUE(tf) => tf.i_fmt(indent, tz, f),
125 TxnFilter::NullaryFALSE(tf) => tf.i_fmt(indent, tz, f),
126
127 TxnFilter::TxnFilterAND(tf) => tf.i_fmt(indent, tz, f),
129 TxnFilter::TxnFilterOR(tf) => tf.i_fmt(indent, tz, f),
130 TxnFilter::TxnFilterNOT(tf) => tf.i_fmt(indent, tz, f),
131
132 TxnFilter::TxnFilterTxnTSBegin(tf) => tf.i_fmt(indent, tz, f),
134 TxnFilter::TxnFilterTxnTSEnd(tf) => tf.i_fmt(indent, tz, f),
135 TxnFilter::TxnFilterTxnCode(tf) => tf.i_fmt(indent, tz, f),
136 TxnFilter::TxnFilterTxnDescription(tf) => tf.i_fmt(indent, tz, f),
137 TxnFilter::TxnFilterTxnUUID(tf) => tf.i_fmt(indent, tz, f),
138 TxnFilter::TxnFilterTxnExtId(tf) => tf.i_fmt(indent, tz, f),
139 TxnFilter::TxnFilterBBoxLatLon(tf) => tf.i_fmt(indent, tz, f),
140 TxnFilter::TxnFilterBBoxLatLonAlt(tf) => tf.i_fmt(indent, tz, f),
141 TxnFilter::TxnFilterTxnTags(tf) => tf.i_fmt(indent, tz, f),
142 TxnFilter::TxnFilterTxnComments(tf) => tf.i_fmt(indent, tz, f),
143
144 TxnFilter::TxnFilterPostingAccount(tf) => tf.i_fmt(indent, tz, f),
146 TxnFilter::TxnFilterPostingComment(tf) => tf.i_fmt(indent, tz, f),
147 TxnFilter::TxnFilterPostingAmountEqual(tf) => tf.i_fmt(indent, tz, f),
148 TxnFilter::TxnFilterPostingAmountLess(tf) => tf.i_fmt(indent, tz, f),
149 TxnFilter::TxnFilterPostingAmountGreater(tf) => tf.i_fmt(indent, tz, f),
150 TxnFilter::TxnFilterPostingCommodity(tf) => tf.i_fmt(indent, tz, f),
151 }
152 }
153}
154
155#[derive(Serialize, Deserialize, Clone, Debug)]
157pub struct NullaryTRUE {}
158
159impl IndentDisplay for NullaryTRUE {
160 fn i_fmt(&self, indent: &str, _tz: TimeZone, f: &mut Formatter<'_>) -> std::fmt::Result {
161 writeln!(f, "{indent}All pass")
162 }
163}
164
165#[derive(Serialize, Deserialize, Clone, Debug)]
167pub struct NullaryFALSE {}
168
169impl IndentDisplay for NullaryFALSE {
170 fn i_fmt(&self, indent: &str, _tz: TimeZone, f: &mut Formatter<'_>) -> std::fmt::Result {
171 writeln!(f, "{indent}None pass")
172 }
173}
174
175#[allow(clippy::needless_pass_by_value)]
176fn logic_filter_indent_fmt(
177 op: &str,
178 indent: &str,
179 tz: TimeZone,
180 filters: &[TxnFilter],
181 f: &mut Formatter<'_>,
182) -> std::fmt::Result {
183 let new_ident = format!("{indent} ");
184
185 writeln!(f, "{indent}{op}")?;
186 let result: Result<Vec<()>, Error> = filters
187 .iter()
188 .map(|tf| tf.i_fmt(&new_ident, tz.clone(), f))
189 .collect();
190
191 match result {
192 Ok(_) => Ok(()),
193 Err(err) => Err(err),
194 }
195}
196
197fn posting_filter_indent_fmt(
198 indent: &str,
199 target: &str,
200 regex: &str,
201 op: &str,
202 amount: &Decimal,
203 f: &mut Formatter<'_>,
204) -> std::fmt::Result {
205 let my_indent = format!("{indent} ");
206 writeln!(f, "{indent}{target}")?;
207 writeln!(f, "{my_indent}account: \"{regex}\"")?;
208 writeln!(f, "{my_indent}amount {op} {amount}")
209}