Function rinfluxdb_influxql::from_str [−][src]
pub fn from_str<DF, E>(input: &str) -> ResponseResult<DF> where
DF: TryFrom<(String, Vec<DateTime<Utc>>, HashMap<String, Vec<Value>>), Error = E>,
E: Into<ResponseError>,
Expand description
Parse a JSON response returned from InfluxDB to a list of tagged dataframes.
An example of such JSON response is the following.
{
"results": [
{
"statement_id": 0,
"series": [
{
"name": "environment",
"columns": ["time","temperature","humidity"],
"values":[
["2021-03-04T17:00:00Z",28.4,41.0],
["2021-03-04T18:00:00Z",29.2,37.0]
],
"tags": {
"room": "bedroom",
"building": "b1"
}
}
]
}
]
}
More specifically, a single query to InfluxDB can consist of multiple semicolon-separated statements, and for each of them a result is returned. The result can contain a list of timeseries and a list of tags, or also nothing if the statement did not generate any data.
For instance, consider the following query.
CREATE DATABASE other;
SELECT temperature, humidity FROM outdoor;
SELECT temperature FROM indoor GROUP BY room
This would return three results:
- An empty one, corresponding to the first statement
CREATE DATABASE other
. - A single dataframe for outdoor temperature and humidity, without tags.
- Multiple dataframes for indoor temperature, one for each room.
Return type
This function is agnostics on the actual return type. The only constraint is that it can be constructed from a string, a list of instants, namely the index, and a map of lists of values, namely the columns.
I.e. the return type must implement trait
TryFrom<(String, Vec<DateTime<Utc>>, HashMap<String, Vec<Value>>), Error = E>
,
where E
must implement trait Into<ResponseError>
.
Example
use std::convert::{TryFrom, TryInto};
struct DummyDataFrame {
name: String,
index: Vec<DateTime<Utc>>,
columns: HashMap<String, Vec<Value>>
}
impl TryFrom<(String, Vec<DateTime<Utc>>, HashMap<String, Vec<Value>>)> for DummyDataFrame {
type Error = ResponseError;
fn try_from(
(name, index, columns): (String, Vec<DateTime<Utc>>, HashMap<String, Vec<Value>>),
) -> Result<Self, Self::Error> {
if columns.len() > 0 {
Ok(Self { name, index, columns })
} else {
Err(ResponseError::ValueError("columns list is empty".into()))
}
}
}
let input = r#"{
"results": [
{
"statement_id": 0,
"series": [
{
"name": "environment",
"columns": ["time","temperature","humidity"],
"values":[
["2021-03-04T17:00:00Z",28.4,41.0],
["2021-03-04T18:00:00Z",29.2,37.0]
],
"tags": {
"room": "bedroom",
"building": "b1"
}
}
]
}
]
}"#;
let statements: Vec<Result<Vec<(DummyDataFrame, Option<HashMap<String, String>>)>, ResponseError>>;
statements = from_str(input)?;
assert_eq!(statements.len(), 1);
for statement in statements {
let dataframes_and_tags: Vec<(DummyDataFrame, Option<HashMap<String, String>>)>;
dataframes_and_tags = statement?;
assert_eq!(dataframes_and_tags.len(), 1);
let (dataframe, tags) = dataframes_and_tags.first().unwrap();
assert_eq!(dataframe.index.len(), 2);
assert_eq!(dataframe.columns.len(), 2);
assert!(dataframe.columns.contains_key("temperature"));
assert!(dataframe.columns.contains_key("humidity"));
assert!(tags.is_some());
assert_eq!(tags.as_ref().unwrap().get("room"), Some(&"bedroom".to_string()));
assert_eq!(tags.as_ref().unwrap().get("building"), Some(&"b1".to_string()));
}