diff --git a/README.md b/README.md index 452997a..0e3f033 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ async fn main() { struct WeatherReading { time: DateTime, humidity: i32, - #[tag] wind_direction: String, + #[influxdb(tag)] wind_direction: String, } // Let's write some data into a measurement called `weather` diff --git a/benches/client.rs b/benches/client.rs index a94c987..2b8ca5d 100644 --- a/benches/client.rs +++ b/benches/client.rs @@ -11,7 +11,7 @@ use tokio::sync::Semaphore; struct WeatherReading { time: DateTime, humidity: i32, - #[tag] + #[influxdb(tag)] wind_direction: String, } diff --git a/influxdb/src/lib.rs b/influxdb/src/lib.rs index 2e5eebb..5aec3a4 100644 --- a/influxdb/src/lib.rs +++ b/influxdb/src/lib.rs @@ -39,7 +39,7 @@ //! struct WeatherReading { //! time: DateTime, //! humidity: i32, -//! #[tag] wind_direction: String, +//! #[influxdb(tag)] wind_direction: String, //! } //! //! // Let's write some data into a measurement called `weather` diff --git a/influxdb/tests/derive_integration_tests.rs b/influxdb/tests/derive_integration_tests.rs index 4e507c5..463fed9 100644 --- a/influxdb/tests/derive_integration_tests.rs +++ b/influxdb/tests/derive_integration_tests.rs @@ -14,11 +14,20 @@ use utilities::{assert_result_ok, create_client, create_db, delete_db, run_test} #[derive(Debug, PartialEq)] #[cfg_attr(feature = "derive", derive(InfluxDbWriteable))] -#[cfg_attr(feature = "use-serde", derive(Deserialize))] struct WeatherReading { time: DateTime, + #[influxdb(ignore)] humidity: i32, - #[tag] + pressure: i32, + #[influxdb(tag)] + wind_strength: Option, +} + +#[derive(Debug)] +#[cfg_attr(feature = "use-serde", derive(Deserialize))] +struct WeatherReadingWithoutIgnored { + time: DateTime, + pressure: i32, wind_strength: Option, } @@ -27,15 +36,14 @@ fn test_build_query() { let weather_reading = WeatherReading { time: Timestamp::Hours(1).into(), humidity: 30, + pressure: 100, wind_strength: Some(5), }; - let query = weather_reading - .into_query("weather_reading") - .build() - .unwrap(); + let query = weather_reading.into_query("weather_reading"); + let query = query.build().unwrap(); assert_eq!( query.get(), - "weather_reading,wind_strength=5 humidity=30i 3600000000000" + "weather_reading,wind_strength=5 pressure=100i 3600000000000" ); } @@ -56,6 +64,7 @@ async fn test_derive_simple_write() { time: Timestamp::Nanoseconds(0).into(), humidity: 30, wind_strength: Some(5), + pressure: 100, }; let query = weather_reading.into_query("weather_reading"); let result = client.query(&query).await; @@ -86,20 +95,21 @@ async fn test_write_and_read_option() { time: Timestamp::Hours(11).into(), humidity: 30, wind_strength: None, + pressure: 100, }; let write_result = client .query(&weather_reading.into_query("weather_reading".to_string())) .await; assert_result_ok(&write_result); let query = - Query::raw_read_query("SELECT time, humidity, wind_strength FROM weather_reading"); + Query::raw_read_query("SELECT time, pressure, wind_strength FROM weather_reading"); let result = client.json_query(query).await.and_then(|mut db_result| { println!("{:?}", db_result); - db_result.deserialize_next::() + db_result.deserialize_next::() }); assert_result_ok(&result); let result = result.unwrap(); - assert_eq!(result.series[0].values[0].humidity, 30); + assert_eq!(result.series[0].values[0].pressure, 100); assert_eq!(result.series[0].values[0].wind_strength, None); }, || async move { diff --git a/influxdb_derive/src/lib.rs b/influxdb_derive/src/lib.rs index 6c4b02d..a6bbba8 100644 --- a/influxdb_derive/src/lib.rs +++ b/influxdb_derive/src/lib.rs @@ -9,7 +9,7 @@ fn krate() -> TokenStream2 { quote!(::influxdb) } -#[proc_macro_derive(InfluxDbWriteable, attributes(tag))] +#[proc_macro_derive(InfluxDbWriteable, attributes(influxdb))] pub fn derive_writeable(tokens: TokenStream) -> TokenStream { expand_writeable(tokens) } diff --git a/influxdb_derive/src/writeable.rs b/influxdb_derive/src/writeable.rs index f42c333..04a7bb0 100644 --- a/influxdb_derive/src/writeable.rs +++ b/influxdb_derive/src/writeable.rs @@ -1,32 +1,79 @@ use proc_macro::TokenStream; -use proc_macro2::TokenStream as TokenStream2; +use proc_macro2::{TokenStream as TokenStream2, TokenTree}; use quote::{format_ident, quote}; use syn::{parse_macro_input, Field, Fields, Ident, ItemStruct}; +#[derive(Debug)] struct WriteableField { ident: Ident, is_tag: bool, + is_ignore: bool, } impl From for WriteableField { fn from(field: Field) -> WriteableField { let ident = field.ident.expect("fields without ident are not supported"); - let is_tag = field.attrs.iter().any(|attr| { + + let check_influx_aware = |attr: &syn::Attribute| -> bool { attr.path .segments .iter() .last() .map(|seg| seg.ident.to_string()) .unwrap_or_default() - == "tag" + == "influxdb" + }; + + let check_for_attr = |token_tree, ident_cmp: &str| -> bool { + match token_tree { + TokenTree::Group(group) => group + .stream() + .into_iter() + .next() + .map(|token_tree| match token_tree { + TokenTree::Ident(ident) => ident == ident_cmp, + _ => false, + }) + .unwrap(), + _ => false, + } + }; + + let is_ignore = field.attrs.iter().any(|attr| { + if !check_influx_aware(attr) { + return false; + } + + attr.tokens + .clone() + .into_iter() + .next() + .map(|token_tree| check_for_attr(token_tree, "ignore")) + .unwrap() }); - WriteableField { ident, is_tag } + + let is_tag = field.attrs.iter().any(|attr| { + if !check_influx_aware(attr) { + return false; + } + attr.tokens + .clone() + .into_iter() + .next() + .map(|token_tree| check_for_attr(token_tree, "tag")) + .unwrap() + }); + + WriteableField { + ident, + is_tag, + is_ignore, + } } } pub fn expand_writeable(tokens: TokenStream) -> TokenStream { let krate = super::krate(); - let input = parse_macro_input!(tokens as ItemStruct); let ident = input.ident; let generics = input.generics; @@ -38,6 +85,7 @@ pub fn expand_writeable(tokens: TokenStream) -> TokenStream { .named .into_iter() .map(WriteableField::from) + .filter(|field| !field.is_ignore) .filter(|field| field.ident.to_string() != time_field.to_string()) .map(|field| { let ident = field.ident;