ainoio_agent/
transaction.rs

1use crate::status::Status;
2use serde_json;
3use std::fmt;
4
5/// A log entry for a single `Transaction` between two applications.
6#[derive(Serialize, Clone, Debug)]
7#[serde(rename_all = "camelCase")]
8pub struct Transaction {
9    /// The name of originating application
10    pub from: String,
11
12    /// The name of the target application
13    pub to: String,
14
15    /// A [`Status`](enum.Status.html) flag indicating the whether the `Transaction` was successful or not.
16    pub status: Status,
17
18    /// The timestamp when the `Transaction` took place, in milliseconds.
19    pub timestamp: u128,
20
21    /// The operation of the `Transaction`.
22    pub operation: String,
23
24    /// The ID for the whole logical flow if `Transaction`s.
25    pub flow_id: String,
26
27    /// The type of payload in the `Transaction` (optional)
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub payload_type: Option<String>,
30
31    /// A possible log message (optional)
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub message: Option<String>,
34
35    /// All IDs related to this `Transaction` (optional)
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub ids: Option<Vec<TransactionId>>,
38
39    /// All metadata related to this `Transaction` (optional)
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub metadata: Option<Vec<TransactionMetadata>>,
42}
43
44/// Container for IDs of a single type.
45#[derive(Serialize, Clone, PartialEq, Debug)]
46#[serde(rename_all = "camelCase")]
47pub struct TransactionId {
48    /// The type of the ID.
49    pub id_type: String,
50
51    /// The actual ID values for this type.
52    pub values: Vec<String>,
53}
54
55/// A name/value pair for generic metadata.
56#[derive(Serialize, Clone, Debug)]
57#[serde(rename_all = "camelCase")]
58pub struct TransactionMetadata {
59    /// The name of the metadata.
60    pub name: String,
61
62    /// The value of the metadata.
63    pub value: String,
64}
65
66impl Transaction {
67    /// Constructs a single `Transaction` with the mandatory values.
68    pub fn new(
69        from: String,
70        to: String,
71        operation: String,
72        status: Status,
73        timestamp: u128,
74        flow_id: String,
75    ) -> Self {
76        Transaction {
77            from,
78            to,
79            status,
80            timestamp,
81            operation,
82            flow_id,
83            payload_type: None,
84            message: None,
85            ids: None,
86            metadata: None,
87        }
88    }
89
90    /// Adds a metadata to the `Transaction`
91    pub fn add_metadata(&mut self, metadata: TransactionMetadata) -> &mut Self {
92        match &mut self.metadata {
93            Some(m) => m.push(metadata),
94            None => self.metadata = Some(vec![metadata]),
95        };
96
97        self
98    }
99
100    /// Add an ID to the `Transaction`
101    pub fn add_id(&mut self, id: TransactionId) -> &mut Self {
102        match &mut self.ids {
103            Some(ids) => ids.push(id),
104            None => self.ids = Some(vec![id]),
105        };
106
107        self
108    }
109}
110
111impl TransactionMetadata {
112    /// Constructs a new [`TransactionMetadata`](struct.TransactionMetadata.html).
113    pub fn new(name: String, value: String) -> Self {
114        TransactionMetadata { name, value }
115    }
116}
117
118impl<'a> TransactionId {
119    /// Constructs a new [`TransactionId`](struct.TransactionId.html).
120    pub fn new(id_type: String, values: Vec<String>) -> Self {
121        TransactionId { id_type, values }
122    }
123}
124
125impl fmt::Display for Transaction {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        match serde_json::to_string_pretty(self) {
128            Ok(text) => write!(f, "{}", text),
129            Err(_) => Err(fmt::Error {}),
130        }
131    }
132}
133
134impl fmt::Display for TransactionId {
135    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136        match serde_json::to_string_pretty(self) {
137            Ok(text) => write!(f, "{}", text),
138            Err(_) => Err(fmt::Error {}),
139        }
140    }
141}
142
143impl fmt::Display for TransactionMetadata {
144    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        match serde_json::to_string_pretty(self) {
146            Ok(text) => write!(f, "{}", text),
147            Err(_) => Err(fmt::Error {}),
148        }
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use super::*;
155    use std::time::SystemTime;
156
157    #[test]
158    fn test_add_metadata() {
159        let timestamp = SystemTime::now()
160            .duration_since(SystemTime::UNIX_EPOCH)
161            .unwrap();
162        let mut trx = Transaction::new(
163            "from".to_string(),
164            "to".to_string(),
165            "operation".to_string(),
166            Status::Success,
167            timestamp.as_millis(),
168            "flow_id".to_string(),
169        );
170        assert_eq!(trx.metadata.is_none(), true);
171
172        let metadata = TransactionMetadata::new("name".to_string(), "value".to_string());
173        trx.add_metadata(metadata);
174        assert_eq!(trx.metadata.is_some(), true);
175    }
176
177    #[test]
178    fn test_add_id() {
179        let timestamp = SystemTime::now()
180            .duration_since(SystemTime::UNIX_EPOCH)
181            .unwrap();
182        let mut trx = Transaction::new(
183            "from".to_string(),
184            "to".to_string(),
185            "operation".to_string(),
186            Status::Success,
187            timestamp.as_millis(),
188            "flow_id".to_string(),
189        );
190        assert_eq!(trx.ids.is_none(), true);
191
192        let id = TransactionId::new("id_type".to_string(), vec!["value".to_string()]);
193        trx.add_id(id);
194        assert_eq!(trx.ids.is_some(), true);
195        if let Some(ids) = &trx.ids {
196            assert_eq!(ids[0].id_type, "id_type".to_string());
197            assert_eq!(ids[0].values[0], "value".to_string());
198        }
199    }
200}