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()));
}