serde_influxlp/lib.rs
1//! # Serde InfluxDB V2 Line Protocol
2//!
3//! InfluxDB's line protocol is a text-based format used to represent data
4//! points. It includes the measurement, optional tag set, field set, and an
5//! optional timestamp.
6//!
7//! ```
8//! measurement tag set field set timestamp
9//! ----------- ------------------- ------------------------- -------------------
10//! measurement,tag1=val1,tag2=val2 field1="val1",field2=true 1729270461612452700
11//! ```
12//!
13//! ## Limitations
14//! Unfortunately due to the required format of the line protocol (as seen
15//! above) the struct, although created by the user, has a required format that
16//! must be followed closely. Some serde features are also currently
17//! unsupported, e.g., tagging. Below are different examples of how to setup and
18//! customize your struct.
19//!
20//! This crate does not support any type which is not [supported](https://docs.influxdata.com/influxdb/v2/reference/syntax/line-protocol/#data-types-and-format) by InfluxDB v2
21//! Line Protocol. These types are:
22//!
23//! 1. Any number (int, uint, float)
24//! 2. Strings
25//! 3. Booleans
26//!
27//! In the line protocol tag keys-/values and field keys-/values also has [restricted types](https://docs.influxdata.com/influxdb/v2/reference/syntax/line-protocol/#elements-of-line-protocol). This crate supports serializing and deserializing back-and-forth from types. Bare in mind however that InfluxDB will treat the element value as its expected type.
28//!
29//! ## Examples
30//!
31//! Below is the bare minimum required in a struct to be serialized and
32//! deserialized successfully. At most one entry is required in the fields map.
33//! `Value` is a custom enum for this crate.
34//!
35//! ```rust
36//! use serde_influxlp::Value;
37//!
38//! #[derive(Debug, Serialize, Deserialize)]
39//! pub struct Metric {
40//! pub measurement: String,
41//!
42//! pub fields: HashMap<String, Value>,
43//! }
44//! ```
45//!
46//! </br>
47//!
48//! Tags and a timestamp field can also be added to the struct. If in some cases
49//! its uncertain whether the fields are present they can be marked as an
50//! `Option`. Timestamp should always be an i64 as in the line protocol
51//! timestamp is a unix timestamp with the same range as an i64.
52//!
53//! </br>
54//!
55//! ```rust
56//! use serde_influxlp::Value;
57//!
58//! #[derive(Debug, Serialize, Deserialize)]
59//! pub struct Tags {
60//! pub tag1: i32,
61//!
62//! pub tag2: Option<String>,
63//! ...
64//! }
65//!
66//! #[derive(Debug, Serialize, Deserialize)]
67//! pub struct Metric {
68//! pub measurement: String,
69//!
70//! pub tags: Option<Tags>,
71//!
72//! pub fields: HashMap<String, Value>,
73//!
74//! pub timestamp: Option<i64>,
75//! }
76//! ```
77//!
78//! </br>
79//!
80//! Tags and fields can also be defined as structs of their own if the values
81//! are known beforehand, or if you only want to serialize/deserialize a few
82//! fields. As with the tags and timestamp these can be marked as an `Option`
83//!
84//! </br>
85//!
86//! ```rust
87//! use serde_influxlp::Value;
88//!
89//! #[derive(Debug, Serialize, Deserialize)]
90//! pub struct Tags {
91//! pub tag1: i32,
92//!
93//! pub tag2: Option<String>,
94//! ...
95//! }
96//!
97//! #[derive(Debug, Serialize, Deserialize)]
98//! pub struct Fields {
99//! pub field1: String,
100//!
101//! pub field2: Option<bool>,
102//! ...
103//! }
104//!
105//! #[derive(Debug, Serialize, Deserialize)]
106//! pub struct Metric {
107//! pub measurement: String,
108//!
109//! pub tags: Tags,
110//!
111//! pub fields: Fields,
112//!
113//! pub timestamp: i64,
114//! }
115//! ```
116//!
117//! </br>
118//!
119//! Enums are also supported
120//!
121//! </br>
122//!
123//! ```rust
124//! #[derive(Debug, Serialize, Deserialize)]
125//! #[serde(rename_all = "lowercase")]
126//! pub enum Measurement {
127//! Metric1,
128//! Metric2,
129//! }
130//!
131//! #[derive(Debug, Serialize, Deserialize)]
132//! pub struct Metric {
133//! pub measurement: Measurement,
134//!
135//! pub tags: Tags,
136//!
137//! pub fields: Fields,
138//!
139//! pub timestamp: i64,
140//! }
141//! ```
142//!
143//! </br>
144//!
145//! As said previously we require the field names to be as they are because they
146//! are used to ensure that the serialization and deserialization is done
147//! properly. If you want to rename the fields it can be done with serdes rename
148//! feature
149//!
150//! </br>
151//!
152//! ```rust
153//! #[derive(Debug, Serialize, Deserialize)]
154//! pub struct Metric {
155//! #[serde(rename = "measurement")]
156//! pub name: String,
157//!
158//! #[serde(rename = "tags")]
159//! pub tag_set: Tags,
160//!
161//! #[serde(rename = "fields")]
162//! pub field_set: Fields,
163//!
164//! #[serde(rename = "timestamp")]
165//! pub time: i64,
166//! }
167//! ```
168//!
169//! </br>
170//!
171//! ### Serialization and deserialization
172//! ```rust
173//! use serde_influxlp::Value;
174//!
175//! #[derive(Debug, Serialize, Deserialize)]
176//! #[serde(rename_all = "lowercase")]
177//! pub enum Measurement {
178//! Metric1,
179//! Metric2,
180//! }
181//!
182//! #[derive(Debug, Serialize, Deserialize)]
183//! pub struct Tags {
184//! pub tag1: i32,
185//! }
186//!
187//! #[derive(Debug, Serialize, Deserialize)]
188//! pub struct Fields {
189//! pub field1: String,
190//!
191//! pub field2: Option<bool>,
192//! }
193//!
194//! #[derive(Debug, Serialize, Deserialize)]
195//! pub struct Metric {
196//! pub measurement: Measurement,
197//!
198//! pub tags: HashMap<String, Value>,
199//!
200//! pub fields: Fields,
201//!
202//! pub timestamp: Option<i64>,
203//! }
204//!
205//! fn main() {
206//! let metric = Metric {
207//! measurement: Measurement::Metric1,
208//! tags: HashMap::from([
209//! ("tag1".to_string(), Value::from(12.5)),
210//! ("tag2".to_string(), Value::from(25)),
211//! ]),
212//! fields: Fields {
213//! field1: "{\"hello\": \"world\"}".to_string(),
214//! field2: None,
215//! },
216//! timestamp: Some(1577836800),
217//! };
218//!
219//! let string = serde_influxlp::to_string(&metric).unwrap();
220//!
221//! // Output:
222//! // metric1,tag1=10.5 field1="{\"hello\": \"world\"}" 1577836800
223//!
224//! let metric: Metric = serde_influxlp::from_str(&string).unwrap()
225//!
226//! // Output:
227//! // Metric {
228//! // measurement: Metric1,
229//! // tags: {
230//! // "tag1": Float(
231//! // 10.5,
232//! // ),
233//! // },
234//! // fields: Fields {
235//! // field1: "{\"hello\": \"world\"}",
236//! // field2: None,
237//! // },
238//! // timestamp: Some(1577836800),
239//! // }
240//!
241//! // A line protocol can also be made by hand
242//! let string = "metric2 field1=\"Hello, reader!\",field2=t";
243//! let metric: Metric = from_str(&string).unwrap();
244//!
245//! // Output:
246//! // Metric {
247//! // measurement: Metric2,
248//! // tags: None,
249//! // fields: Fields {
250//! // field1: "Hello, reader!",
251//! // field2: Some(
252//! // true,
253//! // ),
254//! // },
255//! // timestamp: None,
256//! // }
257//! }
258//! ```
259//!
260//! Tip: You can deserialize a line protocol string to a struct, then add,
261//! remove, or edit its values before serializing again to change the line
262//! protocol.
263
264pub(crate) mod builder;
265pub(crate) mod datatypes;
266pub(crate) mod de;
267pub(crate) mod error;
268pub(crate) mod reader;
269pub(crate) mod ser;
270pub(crate) mod value;
271
272pub use crate::{
273 de::{from_reader, from_slice, from_str},
274 error::{Error, ErrorCode},
275 ser::{to_string, to_vec, to_writer},
276 value::{
277 datatypes::{Number, Value},
278 de::from_value,
279 ser::to_value,
280 },
281};