diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 1865d31f..8abcd50c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,8 +5,8 @@ ### Checklist - [ ] Formatted code using `cargo fmt --all` - [ ] Linted code using clippy - - [ ] with reqwest feature: `cargo clippy --manifest-path influxdb/Cargo.toml --all-targets --no-default-features --features serde,derive,reqwest-client-rustls -- -D warnings` - - [ ] with surf feature: `cargo clippy --manifest-path influxdb/Cargo.toml --all-targets --no-default-features --features serde,derive,hyper-client -- -D warnings` + - [ ] with reqwest feature: `cargo clippy --manifest-path influxdb/Cargo.toml --all-targets --no-default-features --features chrono,time,serde,derive,reqwest-client-rustls -- -D warnings` + - [ ] with surf feature: `cargo clippy --manifest-path influxdb/Cargo.toml --all-targets --no-default-features --features chrono,time,serde,derive,hyper-client -- -D warnings` - [ ] Updated README.md using `cargo doc2readme -p influxdb --expand-macros` - [ ] Reviewed the diff. Did you leave any print statements or unnecessary comments? - [ ] Any unfinished work that warrants a separate issue captured in an issue with a TODO code comment diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b07f4a4f..21c560ce 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -30,9 +30,9 @@ jobs: - name: Update Cargo.lock run: cargo --config 'resolver.incompatible-rust-versions="fallback"' update - name: Check Clippy lints (reqwest) - run: cargo clippy --manifest-path influxdb/Cargo.toml --locked --all-targets --no-default-features --features serde,derive,reqwest-client-rustls -- -D warnings + run: cargo clippy --manifest-path influxdb/Cargo.toml --locked --all-targets --no-default-features --features chrono,time,serde,derive,reqwest-client-rustls -- -D warnings - name: Check Clippy lints (surf) - run: cargo clippy --manifest-path influxdb/Cargo.toml --locked --all-targets --no-default-features --features serde,derive,hyper-client -- -D warnings + run: cargo clippy --manifest-path influxdb/Cargo.toml --locked --all-targets --no-default-features --features chrono,time,serde,derive,hyper-client -- -D warnings # this checks that the code is formatted with rustfmt rustfmt: @@ -108,8 +108,8 @@ jobs: key: "${{runner.os}} Rust ${{steps.msrv-toolchain.outputs.cachekey}}" if: matrix.rust.name == 'MSRV' # finally we can run tests - - run: cargo test --lib --locked - - run: cargo test --doc --locked + - run: cargo test --lib --locked --features 'chrono time serde derive' + - run: cargo test --doc --locked --features 'chrono time serde derive' # this tests that all integration tests are successful integration_tests: @@ -124,10 +124,6 @@ jobs: toolchain: stable nightly: false http-backend: - - curl-client - - h1-client - - h1-client-rustls - - hyper-client - reqwest-client-rustls - reqwest-client-native-tls - reqwest-client-native-tls-vendored @@ -172,10 +168,12 @@ jobs: key: "${{runner.os}} Rust ${{steps.rust-toolchain.outputs.cachekey}}" - name: Run tests run: | - for test in integration_tests{,_v2} - do - cargo test -p influxdb --no-default-features --features 'serde derive ${{matrix.http-backend}}' --no-fail-fast --test $test - done + cargo test -p influxdb \ + --no-default-features \ + --features "serde derive chrono time ${{matrix.http-backend}}" \ + --no-fail-fast \ + --test integration_tests \ + --test integration_tests_v2 # this uses cargo-tarpaulin to inspect the code coverage coverage: @@ -221,7 +219,7 @@ jobs: cargo tarpaulin -v \ --target-dir target/tarpaulin \ --workspace \ - --features serde,derive \ + --features chrono,time,serde,derive \ --exclude-files 'derive/*' \ --exclude-files 'target/*' \ --ignore-panics --ignore-tests \ diff --git a/Cargo.toml b/Cargo.toml index 37508cab..1b3a9f76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ resolver = "2" [workspace.package] authors = ["Gero Gerke ", "Dominic "] edition = "2018" -rust-version = "1.65" +rust-version = "1.67.1" license = "MIT" repository = "https://github.com/influxdb-rs/influxdb-rust" diff --git a/README.md b/README.md index 289ed652..bb33e0ea 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ Build with Rust - - Minimum Rust Version: 1.65.0 + + Minimum Rust Version: 1.67.1

@@ -155,7 +155,7 @@ To communicate with InfluxDB, you can choose the HTTP backend to be used configu @ 2020-2024 Gero Gerke, msrd0 and [contributors]. [contributors]: https://github.com/influxdb-rs/influxdb-rust/graphs/contributors - [__cargo_doc2readme_dependencies_info]: ggGkYW0BYXSEGzJ_QpW55zB1G0S-TER-rIfLG2gXv8EYBG3jG1nuXXn-kdx-YXKEG1LaAVLASZMqG5J2qfpyCvbMG_Rohh5BobOmG0DqLv5454SZYWSBgmhpbmZsdXhkYmUwLjcuMg + [__cargo_doc2readme_dependencies_info]: ggGkYW0CYXSEGzJ_QpW55zB1G0S-TER-rIfLG2gXv8EYBG3jG1nuXXn-kdx-YXKEG1LaAVLASZMqG5J2qfpyCvbMG_Rohh5BobOmG0DqLv5454SZYWSBgmhpbmZsdXhkYmUwLjcuMg [__link0]: https://github.com/influxdb-rs/influxdb-rust/blob/main/CONTRIBUTING.md [__link1]: https://github.com/influxdb-rs/influxdb-rust/blob/main/CODE_OF_CONDUCT.md [__link10]: https://github.com/alexcrichton/curl-rust diff --git a/influxdb/Cargo.toml b/influxdb/Cargo.toml index b0ca36e4..77a9aee8 100644 --- a/influxdb/Cargo.toml +++ b/influxdb/Cargo.toml @@ -17,17 +17,18 @@ repository.workspace = true workspace = true [dependencies] -chrono = { version = "0.4.23", features = ["serde"], default-features = false } +chrono = { version = "0.4.23", features = ["serde"], default-features = false, optional = true } futures-util = "0.3.17" http = "0.2.4" influxdb_derive = { version = "0.5.1", optional = true } lazy-regex = "3.1" reqwest = { version = "0.11.4", default-features = false, optional = true } -surf = { version = "2.2.0", default-features = false, optional = true } serde = { version = "1.0.186", optional = true } serde_derive = { version = "1.0.186", optional = true } serde_json = { version = "1.0.48", optional = true } +surf = { version = "2.2.0", default-features = false, optional = true } thiserror = "1.0" +time = { version = "0.3.39", optional = true } [features] default = ["serde", "reqwest-client-rustls"] @@ -44,6 +45,10 @@ reqwest-client-native-tls = ["reqwest", "reqwest/native-tls-alpn"] reqwest-client-native-tls-vendored = ["reqwest", "reqwest/native-tls-vendored"] wasm-client = ["surf", "surf/wasm-client"] +# etc +time = ["dep:time"] +chrono = ["dep:chrono"] + [dev-dependencies] async-std = { version = "1.6.5", features = ["attributes", "tokio02", "tokio1"] } indoc = "1.0" diff --git a/influxdb/src/query/mod.rs b/influxdb/src/query/mod.rs index e83c2241..6268d3ef 100644 --- a/influxdb/src/query/mod.rs +++ b/influxdb/src/query/mod.rs @@ -20,9 +20,6 @@ //! assert!(read_query.is_ok()); //! ``` -use chrono::prelude::{DateTime, TimeZone, Utc}; -use std::convert::TryInto; - pub mod consts; mod line_proto_term; pub mod read_query; @@ -47,6 +44,21 @@ pub enum Timestamp { Hours(u128), } +impl Timestamp { + pub fn nanos(&self) -> u128 { + match self { + Timestamp::Hours(h) => { + h * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLIS_PER_SECOND * NANOS_PER_MILLI + } + Timestamp::Minutes(m) => m * SECONDS_PER_MINUTE * MILLIS_PER_SECOND * NANOS_PER_MILLI, + Timestamp::Seconds(s) => s * MILLIS_PER_SECOND * NANOS_PER_MILLI, + Timestamp::Milliseconds(millis) => millis * NANOS_PER_MILLI, + Timestamp::Microseconds(micros) => micros * NANOS_PER_MICRO, + Timestamp::Nanoseconds(nanos) => *nanos, + } + } +} + impl fmt::Display for Timestamp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use Timestamp::*; @@ -57,44 +69,52 @@ impl fmt::Display for Timestamp { } } -impl From for DateTime { - fn from(ts: Timestamp) -> DateTime { - match ts { - Timestamp::Hours(h) => { - let nanos = - h * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLIS_PER_SECOND * NANOS_PER_MILLI; - Utc.timestamp_nanos(nanos.try_into().unwrap()) - } - Timestamp::Minutes(m) => { - let nanos = m * SECONDS_PER_MINUTE * MILLIS_PER_SECOND * NANOS_PER_MILLI; - Utc.timestamp_nanos(nanos.try_into().unwrap()) - } - Timestamp::Seconds(s) => { - let nanos = s * MILLIS_PER_SECOND * NANOS_PER_MILLI; - Utc.timestamp_nanos(nanos.try_into().unwrap()) - } - Timestamp::Milliseconds(millis) => { - let nanos = millis * NANOS_PER_MILLI; - Utc.timestamp_nanos(nanos.try_into().unwrap()) - } - Timestamp::Nanoseconds(nanos) => Utc.timestamp_nanos(nanos.try_into().unwrap()), - Timestamp::Microseconds(micros) => { - let nanos = micros * NANOS_PER_MICRO; - Utc.timestamp_nanos(nanos.try_into().unwrap()) - } - } +#[cfg(feature = "chrono")] +impl From for chrono::DateTime { + fn from(ts: Timestamp) -> chrono::DateTime { + use chrono::TimeZone as _; + chrono::Utc.timestamp_nanos(ts.nanos() as i64) } } -impl From> for Timestamp +#[cfg(feature = "chrono")] +impl From> for Timestamp where - T: TimeZone, + T: chrono::TimeZone, { - fn from(date_time: DateTime) -> Self { + fn from(date_time: chrono::DateTime) -> Self { Timestamp::Nanoseconds(date_time.timestamp_nanos_opt().unwrap() as u128) } } +#[cfg(feature = "time")] +impl From for time::UtcDateTime { + fn from(value: Timestamp) -> Self { + time::UtcDateTime::from_unix_timestamp_nanos(value.nanos() as i128).unwrap() + } +} + +#[cfg(feature = "time")] +impl From for Timestamp { + fn from(value: time::UtcDateTime) -> Self { + Timestamp::Nanoseconds(value.unix_timestamp_nanos() as u128) + } +} + +#[cfg(feature = "time")] +impl From for time::OffsetDateTime { + fn from(value: Timestamp) -> Self { + time::OffsetDateTime::from_unix_timestamp_nanos(value.nanos() as i128).unwrap() + } +} + +#[cfg(feature = "time")] +impl From for Timestamp { + fn from(value: time::OffsetDateTime) -> Self { + Timestamp::Nanoseconds(value.unix_timestamp_nanos() as u128) + } +} + pub trait Query { /// Builds valid InfluxSQL which can be run against the Database. /// In case no fields have been specified, it will return an error, @@ -235,7 +255,6 @@ mod tests { MILLIS_PER_SECOND, MINUTES_PER_HOUR, NANOS_PER_MICRO, NANOS_PER_MILLI, SECONDS_PER_MINUTE, }; use crate::query::{Timestamp, ValidQuery}; - use chrono::prelude::{DateTime, TimeZone, Utc}; use std::convert::TryInto; #[test] fn test_equality_str() { @@ -252,8 +271,10 @@ mod tests { fn test_format_for_timestamp_else() { assert!(format!("{}", Timestamp::Nanoseconds(100)) == "100"); } + #[cfg(feature = "chrono")] #[test] fn test_chrono_datetime_from_timestamp_hours() { + use chrono::prelude::*; let datetime_from_timestamp: DateTime = Timestamp::Hours(2).into(); assert_eq!( Utc.timestamp_nanos( @@ -264,8 +285,10 @@ mod tests { datetime_from_timestamp ) } + #[cfg(feature = "chrono")] #[test] fn test_chrono_datetime_from_timestamp_minutes() { + use chrono::prelude::*; let datetime_from_timestamp: DateTime = Timestamp::Minutes(2).into(); assert_eq!( Utc.timestamp_nanos( @@ -276,8 +299,10 @@ mod tests { datetime_from_timestamp ) } + #[cfg(feature = "chrono")] #[test] fn test_chrono_datetime_from_timestamp_seconds() { + use chrono::prelude::*; let datetime_from_timestamp: DateTime = Timestamp::Seconds(2).into(); assert_eq!( Utc.timestamp_nanos( @@ -288,29 +313,37 @@ mod tests { datetime_from_timestamp ) } + #[cfg(feature = "chrono")] #[test] fn test_chrono_datetime_from_timestamp_millis() { + use chrono::prelude::*; let datetime_from_timestamp: DateTime = Timestamp::Milliseconds(2).into(); assert_eq!( Utc.timestamp_nanos((2 * NANOS_PER_MILLI).try_into().unwrap()), datetime_from_timestamp ) } + #[cfg(feature = "chrono")] #[test] fn test_chrono_datetime_from_timestamp_nanos() { + use chrono::prelude::*; let datetime_from_timestamp: DateTime = Timestamp::Nanoseconds(1).into(); assert_eq!(Utc.timestamp_nanos(1), datetime_from_timestamp) } + #[cfg(feature = "chrono")] #[test] fn test_chrono_datetime_from_timestamp_micros() { + use chrono::prelude::*; let datetime_from_timestamp: DateTime = Timestamp::Microseconds(2).into(); assert_eq!( Utc.timestamp_nanos((2 * NANOS_PER_MICRO).try_into().unwrap()), datetime_from_timestamp ) } + #[cfg(feature = "chrono")] #[test] fn test_timestamp_from_chrono_date() { + use chrono::prelude::*; let timestamp_from_datetime: Timestamp = Utc .with_ymd_and_hms(1970, 1, 1, 0, 0, 1) .single()