Skip to main content

rsiot/components_config/influxdb3/
line_protocol_item.rs

1use std::collections::HashMap;
2
3use crate::message::*;
4
5use super::FieldValue;
6
7// ANCHOR: LineProtocolItem
8/// Строка записи в данных в базу через HTTP API
9#[derive(Debug)]
10pub struct LineProtocolItem {
11    /// Table
12    pub table: String,
13
14    /// Словать Тег = Значение тега
15    pub tags: HashMap<String, String>,
16
17    /// Словать Поле = Значение поля
18    pub fields: HashMap<String, FieldValue>,
19
20    /// Метка времени
21    pub ts: Option<Timestamp>,
22}
23// ANCHOR: LineProtocolItem
24
25impl LineProtocolItem {
26    /// Новая строка записи
27    pub fn new_simple(table: &str, value: impl Into<FieldValue>) -> Self {
28        Self {
29            table: table.into(),
30            tags: HashMap::new(),
31            fields: HashMap::from([("value".to_string(), value.into())]),
32            ts: Some(Timestamp::default()),
33        }
34    }
35
36    /// Преобразование в строку, для отправки в базу данных
37    pub fn to_string(&self) -> Result<String, super::Error> {
38        let mut line = String::from("");
39
40        let table = &self.table;
41        line.push_str(table);
42
43        let tags = self
44            .tags
45            .iter()
46            .map(|(k, v)| format!("{k}={v}"))
47            .collect::<Vec<String>>()
48            .join(",");
49        if !tags.is_empty() {
50            line.push(',');
51            line.push_str(&tags);
52        }
53
54        let fields = self
55            .fields
56            .iter()
57            .map(|(k, v)| format!("{k}={v}"))
58            .collect::<Vec<String>>()
59            .join(",");
60        line.push(' ');
61        line.push_str(&fields);
62
63        if let Some(ts) = &self.ts {
64            let ts = ts.unix_timestamp_nanos();
65            line.push(' ');
66            line.push_str(&ts.to_string());
67        }
68
69        Ok(line)
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use itertools::Itertools;
76
77    use super::*;
78
79    /// cargo test --features cmp_influxdb -- components_config::influxdb3::line_protocol_item::tests::test1 --exact --show-output
80    #[test]
81    fn test1() -> anyhow::Result<()> {
82        let lpi = LineProtocolItem {
83            table: "cpu".to_string(),
84            tags: HashMap::from([
85                ("host".to_string(), "Alpha".to_string()),
86                ("region".to_string(), "us-west".to_string()),
87                ("application".to_string(), "webserver".to_string()),
88            ]),
89            fields: HashMap::from([
90                ("val".to_string(), FieldValue::from(1)),
91                ("usage_percent".to_string(), FieldValue::from(20.5)),
92                ("status".to_string(), FieldValue::from("OK".to_string())),
93            ]),
94            ts: None,
95        };
96
97        let lpi: String = lpi.to_string()?;
98
99        println!("line protocol: {}", lpi);
100
101        let from_manual = r#"cpu,host=Alpha,region=us-west,application=webserver val=1i,usage_percent=20.5,status="OK""#;
102        println!("from manual:   {}", from_manual);
103
104        assert_eq!(
105            lpi.chars().sorted().rev().collect::<String>(),
106            from_manual.chars().sorted().rev().collect::<String>()
107        );
108
109        Ok(())
110    }
111}