tackler_api/metadata/
items.rs

1/*
2 * Tackler-NG 2022-2025
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! This module contains various Metadata items
7//!
8
9use crate::filters::{FilterDefZoned, FilterDefinition};
10use crate::metadata::Checksum;
11use crate::txn_ts;
12use jiff::Zoned;
13use jiff::tz::TimeZone;
14
15#[doc(hidden)]
16pub type MetadataItems = Vec<MetadataItem>;
17
18#[doc(hidden)]
19pub trait Text: std::fmt::Debug {
20    /// Get metadata item as text
21    #[must_use]
22    fn text(&self, tz: TimeZone) -> Vec<String>;
23}
24
25#[doc(hidden)]
26#[derive(Debug, Clone)]
27pub enum MetadataItem {
28    #[doc(hidden)]
29    TxnSetChecksum(TxnSetChecksum),
30    #[doc(hidden)]
31    AccountSelectorChecksum(AccountSelectorChecksum),
32    #[doc(hidden)]
33    GitInputReference(GitInputReference),
34    #[doc(hidden)]
35    TxnFilterDescription(TxnFilterDescription),
36}
37
38impl MetadataItem {
39    pub const ITEM_PAD: usize = 15;
40}
41
42impl Text for MetadataItem {
43    fn text(&self, tz: TimeZone) -> Vec<String> {
44        match self {
45            Self::GitInputReference(gif) => gif.text(tz),
46            Self::TxnSetChecksum(tscs) => tscs.text(tz),
47            Self::AccountSelectorChecksum(asc) => asc.text(tz),
48            Self::TxnFilterDescription(tfd) => tfd.text(tz),
49        }
50    }
51}
52
53/// Txn Set Checksum metadata item
54#[derive(Debug, Clone)]
55pub struct TxnSetChecksum {
56    /// size of transaction set
57    pub size: usize,
58    /// hash of Txn Set Checksum
59    pub hash: Checksum,
60}
61impl Text for TxnSetChecksum {
62    fn text(&self, _tz: TimeZone) -> Vec<String> {
63        // echo -n "SHA-512/256" | wc -c => 11
64        let pad = MetadataItem::ITEM_PAD;
65        vec![
66            format!("Txn Set Checksum"),
67            format!("{:>pad$} : {}", self.hash.algorithm, &self.hash.value),
68            format!("{:>pad$} : {}", "Set size", self.size),
69        ]
70    }
71}
72
73/// Account Selector Checksum item
74#[derive(Debug, Clone)]
75pub struct AccountSelectorChecksum {
76    /// Hash of selector Checksum
77    pub hash: Checksum,
78}
79impl Text for AccountSelectorChecksum {
80    fn text(&self, _tz: TimeZone) -> Vec<String> {
81        // echo -n "SHA-512/256" | wc -c => 11
82        let pad = MetadataItem::ITEM_PAD;
83        vec![
84            format!("Account Selector Checksum"),
85            format!("{:>pad$} : {}", self.hash.algorithm, &self.hash.value),
86        ]
87    }
88}
89
90/// Report timezone item
91#[derive(Debug, Clone)]
92pub struct ReportTimezone {
93    /// Timezone name
94    pub timezone: String,
95}
96impl Text for ReportTimezone {
97    fn text(&self, _tz: TimeZone) -> Vec<String> {
98        let pad = MetadataItem::ITEM_PAD;
99        vec![
100            "Report Time Zone".to_string(),
101            format!("{:>pad$} : {}", "TZ name", &self.timezone),
102        ]
103    }
104}
105/// Metadata information about active Txn Filters
106///
107#[derive(Debug, Clone)]
108pub struct TxnFilterDescription {
109    #[doc(hidden)]
110    txn_filter_def: FilterDefinition,
111}
112
113impl TxnFilterDescription {
114    /// Make Txn filter Description from Filter Definition
115    ///
116    #[must_use]
117    pub fn from(tf: FilterDefinition) -> TxnFilterDescription {
118        TxnFilterDescription { txn_filter_def: tf }
119    }
120}
121impl Text for TxnFilterDescription {
122    fn text(&self, tz: TimeZone) -> Vec<String> {
123        // todo: TxnFilterDescription needs proper implementation for Text
124        //       See equity_exporter::write_export
125        format!(
126            "{}",
127            FilterDefZoned {
128                filt_def: &self.txn_filter_def,
129                tz
130            }
131        )
132        .trim_end()
133        .split("\n")
134        .map(String::from)
135        .collect::<Vec<String>>()
136    }
137}
138
139/// Metadata information about Git Txn input
140///
141#[derive(Debug, Clone)]
142pub struct GitInputReference {
143    /// commit id
144    pub commit: String,
145    /// git symbolic reference `main`, `Y2023`, etc.
146    pub reference: Option<String>,
147    /// Git directory inside repository
148    pub dir: String,
149    /// filename suffix of journal files
150    pub suffix: String,
151    /// Git commit message of selected commit
152    pub message: String,
153}
154
155impl Text for GitInputReference {
156    fn text(&self, _tz: TimeZone) -> Vec<String> {
157        let pad = MetadataItem::ITEM_PAD;
158        vec![
159            format!("Git Storage"),
160            format!("{:>pad$} : {}", "commit", self.commit),
161            format!(
162                "{:>pad$} : {}",
163                "reference",
164                self.reference
165                    .as_ref()
166                    .unwrap_or(&"FIXED by commit".to_string())
167            ),
168            format!("{:>pad$} : {}", "directory", self.dir),
169            format!("{:>pad$} : .{}", "suffix", self.suffix),
170            format!("{:>pad$} : {}", "message", self.message.trim()),
171        ]
172    }
173}
174
175/// Metadata item for one commodity conversion
176#[derive(Debug, Clone)]
177pub struct PriceRecord {
178    /// Time of price record
179    pub ts: Option<Zoned>,
180    /// Source (from) commodity
181    pub source: String,
182    /// Conversion rate (value in target commodity)
183    pub rate: Option<String>,
184    /// Target (to) commodity
185    pub target: String,
186}
187impl Text for PriceRecord {
188    fn text(&self, tz: TimeZone) -> Vec<String> {
189        let pad = MetadataItem::ITEM_PAD;
190        vec![
191            format!(
192                "{:>pad$} : {}",
193                "Time",
194                self.ts.as_ref().map_or("At txn time".to_string(), |ts| {
195                    txn_ts::as_tz_full(ts, tz)
196                })
197            ),
198            format!("{:>pad$} : {}", "Commodity", self.source),
199            format!(
200                "{:>pad$} : {} {}",
201                "Value",
202                self.rate.clone().map_or("-".to_string(), |v| v),
203                self.target
204            ),
205        ]
206    }
207}
208/// Metadata information of used commodity conversions
209#[derive(Debug, Clone)]
210pub struct PriceRecords {
211    /// Collection of used commodity conversions prices / rates
212    pub rates: Vec<PriceRecord>,
213}
214impl Text for PriceRecords {
215    fn text(&self, tz: TimeZone) -> Vec<String> {
216        let pad = MetadataItem::ITEM_PAD;
217
218        let mut txt = Vec::new();
219
220        if let Some(pr) = self.rates.first() {
221            txt.push("Commodity Prices".to_string());
222            txt.extend(pr.text(tz.clone()));
223
224            if self.rates.len() > 1 {
225                for pr in &self.rates[1..] {
226                    txt.push(format!("{:>pad$} -", ""));
227                    txt.extend(pr.text(tz.clone()));
228                }
229            }
230        }
231        txt
232    }
233}