Skip to content

URLEncode Query & Improve Test Coverage #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ matrix:
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make &&
sudo make install && cd ../.. &&
kcov --coveralls-id=$TRAVIS_JOB_ID --exclude-pattern=/.cargo target/kcov target/debug/influxdb-*
kcov --coveralls-id=$TRAVIS_JOB_ID --exclude-pattern=/.cargo --exclude-path=./tests target/kcov target/debug/influxdb-*
addons:
apt:
packages:
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description = "InfluxDB Driver for Rust"
keywords = ["influxdb", "database", "influx"]
license-file = "LICENSE.md"
readme = "README.md"
include = ["src/**/*", "tests/**/*", "Cargo.toml", "LICENSE"]
include = ["src/**/*", "tests/**/*", "Cargo.toml", "LICENSE.md"]
repository = "https://github.com/Empty2k12/influxdb-rust"

[badges]
Expand All @@ -20,6 +20,7 @@ futures = "0.1.27"
tokio = "0.1.20"
itertools = "0.8"
failure = "0.1.5"
url = "1.7.2"
serde = { version = "1.0.92", optional = true }
serde_json = { version = "1.0", optional = true }

Expand Down
11 changes: 8 additions & 3 deletions src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ use std::mem;
use crate::error::InfluxDbError;
use crate::query::{InfluxDbQuery, QueryType};

use url::form_urlencoded;

/// Internal Representation of a Client
pub struct InfluxDbClient {
url: String,
Expand Down Expand Up @@ -134,11 +136,14 @@ impl InfluxDbClient {
let client = match q_type {
QueryType::ReadQuery => {
let read_query = query.get();
let encoded: String = form_urlencoded::Serializer::new(String::new())
.append_pair("db", self.database_name())
.append_pair("q", &read_query)
.finish();
let http_query_string = format!(
"{url}/query?db={db}&q={read_query}",
"{url}/query?{encoded}",
url = self.database_url(),
db = self.database_name(),
read_query = read_query,
encoded = encoded
);

if read_query.contains("SELECT") || read_query.contains("SHOW") {
Expand Down
67 changes: 29 additions & 38 deletions src/integrations/serde_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
//! let mut rt = tokio::runtime::current_thread::Runtime::new().unwrap();
//! let client = InfluxDbClient::new("http://localhost:8086", "test");
//! let query = InfluxDbQuery::raw_read_query("SELECT temperature FROM /weather_[a-z]*$/ WHERE time > now() - 1m ORDER BY DESC");
//! let _result = rt.block_on(client.json_query::<WeatherWithoutCityName, _>(query))
//! let _result = rt.block_on(client.json_query::<WeatherWithoutCityName>(query))
//! .map(|it| {
//! it.map(|series_vec| {
//! series_vec
Expand All @@ -36,6 +36,7 @@
//! }).collect::<Vec<Weather>>()
//! })
//! });
//! ```

use crate::client::InfluxDbClient;

Expand All @@ -49,7 +50,11 @@ use serde::Deserialize;
use serde_json;

use crate::error::InfluxDbError;
use crate::query::{InfluxDbQuery, QueryType};

use crate::query::read_query::InfluxDbReadQuery;
use crate::query::InfluxDbQuery;

use url::form_urlencoded;

#[derive(Deserialize)]
#[doc(hidden)]
Expand Down Expand Up @@ -77,55 +82,41 @@ pub struct InfluxDbSeries<T> {
}

impl InfluxDbClient {
pub fn json_query<T: 'static, Q>(
pub fn json_query<T: 'static>(
&self,
q: Q,
q: InfluxDbReadQuery,
) -> Box<dyn Future<Item = Option<Vec<InfluxDbSeries<T>>>, Error = InfluxDbError>>
where
Q: InfluxDbQuery,
T: DeserializeOwned,
{
use futures::future;

let q_type = q.get_type();
let query = match q.build() {
Err(err) => {
let query = q.build().unwrap();

let client = {
let read_query = query.get();
let encoded: String = form_urlencoded::Serializer::new(String::new())
.append_pair("db", self.database_name())
.append_pair("q", &read_query)
.finish();
let http_query_string = format!(
"{url}/query?{encoded}",
url = self.database_url(),
encoded = encoded
);

if read_query.contains("SELECT") || read_query.contains("SHOW") {
Client::new().get(http_query_string.as_str())
} else {
let error = InfluxDbError::InvalidQueryError {
error: format!("{}", err),
error: String::from(
"Only SELECT and SHOW queries supported with JSON deserialization",
),
};
return Box::new(
future::err::<Option<Vec<InfluxDbSeries<T>>>, InfluxDbError>(error),
);
}
Ok(query) => query,
};

let client = match q_type {
QueryType::ReadQuery => {
let read_query = query.get();
let http_query_string = format!(
"{url}/query?db={db}&q={read_query}",
url = self.database_url(),
db = self.database_name(),
read_query = read_query,
);

if read_query.contains("SELECT") || read_query.contains("SHOW") {
Client::new().get(http_query_string.as_str())
} else {
Client::new().post(http_query_string.as_str())
}
}
QueryType::WriteQuery => Client::new()
.post(
format!(
"{url}/write?db={db}",
url = self.database_url(),
db = self.database_name(),
)
.as_str(),
)
.body(query.get()),
};

Box::new(
Expand Down
26 changes: 26 additions & 0 deletions src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ impl ValidQuery {
self.0
}
}
impl<T> From<T> for ValidQuery
where
T: ToString,
{
fn from(string: T) -> Self {
Self(string.to_string())
}
}
impl PartialEq<String> for ValidQuery {
fn eq(&self, other: &String) -> bool {
&self.0 == other
Expand All @@ -105,3 +113,21 @@ pub enum QueryType {
ReadQuery,
WriteQuery,
}

#[cfg(test)]
mod tests {
use super::ValidQuery;

#[test]
fn test_equality_str() {
assert_eq!(ValidQuery::from("hello"), "hello");
}

#[test]
fn test_equality_string() {
assert_eq!(
ValidQuery::from(String::from("hello")),
String::from("hello")
);
}
}
48 changes: 47 additions & 1 deletion tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,56 @@ fn test_json_query() {

let client = create_client();
let query = InfluxDbQuery::raw_read_query("SELECT * FROM weather");
let result = get_runtime().block_on(client.json_query::<Weather, _>(query));
let result = get_runtime().block_on(client.json_query::<Weather>(query));

assert!(
result.is_ok(),
format!("We couldn't read from the DB: {}", result.unwrap_err())
);
}

#[test]
#[cfg(feature = "use-serde")]
/// INTEGRATION TEST
///
/// This integration test tests whether using the wrong query method fails building the query
fn test_serde_query_build_error() {
use serde::Deserialize;

#[derive(Deserialize, Debug)]
struct Weather {
time: String,
temperature: i32,
}

let client = create_client();
let query = InfluxDbQuery::raw_read_query("CREATE database should_fail");
let result = get_runtime().block_on(client.json_query::<Weather>(query));

assert!(
result.is_err(),
format!(
"Should not be able to build JSON query that is not SELECT or SELECT .. INTO: {}",
result.unwrap_err()
)
);
}

#[test]
#[cfg(feature = "use-serde")]
/// INTEGRATION TEST
///
/// This test case tests whether JSON can be decoded from a InfluxDB response
fn test_raw_query_build_error() {
let client = create_client();
let query = InfluxDbQuery::write_query("weather").add_tag("season", "summer");
let result = get_runtime().block_on(client.query(query));

assert!(
result.is_err(),
format!(
"Should not be able to build JSON query that is not SELECT or SELECT .. INTO: {}",
result.unwrap_err()
)
);
}