Skip to content

Commit 1be4960

Browse files
committed
Remove non-utc trait impls; start adjusting the derive macro
1 parent 9023443 commit 1be4960

File tree

8 files changed

+279
-101
lines changed

8 files changed

+279
-101
lines changed

influxdb/src/error.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,15 @@ pub enum Error {
3333
/// Error happens when HTTP request fails
3434
ConnectionError { error: String },
3535
}
36+
37+
#[cfg(feature = "chrono")]
38+
#[derive(Clone, Copy, Debug, Error)]
39+
#[error("The timestamp is too large to fit into an i64.")]
40+
pub struct TimestampTooLargeError(pub(crate) ());
41+
42+
#[cfg(any(feature = "chrono", feature = "time"))]
43+
#[derive(Clone, Copy, Debug, Error)]
44+
pub enum TimeTryFromError<T, I> {
45+
TimeError(#[source] T),
46+
IntError(#[source] I),
47+
}

influxdb/src/query/mod.rs

Lines changed: 61 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub mod consts;
2424
mod line_proto_term;
2525
pub mod read_query;
2626
pub mod write_query;
27-
use std::fmt;
27+
use std::{convert::Infallible, fmt};
2828

2929
use crate::{Error, WriteQuery};
3030
use consts::{
@@ -70,48 +70,55 @@ impl fmt::Display for Timestamp {
7070
}
7171

7272
#[cfg(feature = "chrono")]
73-
impl From<Timestamp> for chrono::DateTime<chrono::Utc> {
74-
fn from(ts: Timestamp) -> chrono::DateTime<chrono::Utc> {
73+
impl TryFrom<Timestamp> for chrono::DateTime<chrono::Utc> {
74+
type Error = <i64 as TryFrom<u128>>::Error;
75+
76+
fn try_from(ts: Timestamp) -> Result<Self, Self::Error> {
7577
use chrono::TimeZone as _;
76-
chrono::Utc.timestamp_nanos(ts.nanos() as i64)
78+
Ok(chrono::Utc.timestamp_nanos(ts.nanos().try_into()?))
7779
}
7880
}
7981

8082
#[cfg(feature = "chrono")]
81-
impl<T> From<chrono::DateTime<T>> for Timestamp
82-
where
83-
T: chrono::TimeZone,
84-
{
85-
fn from(date_time: chrono::DateTime<T>) -> Self {
86-
Timestamp::Nanoseconds(date_time.timestamp_nanos_opt().unwrap() as u128)
87-
}
88-
}
83+
impl TryFrom<chrono::DateTime<chrono::Utc>> for Timestamp {
84+
type Error = crate::error::TimeTryFromError<
85+
crate::error::TimestampTooLargeError,
86+
<u128 as TryFrom<i64>>::Error,
87+
>;
8988

90-
#[cfg(feature = "time")]
91-
impl From<Timestamp> for time::UtcDateTime {
92-
fn from(value: Timestamp) -> Self {
93-
time::UtcDateTime::from_unix_timestamp_nanos(value.nanos() as i128).unwrap()
89+
fn try_from(dt: chrono::DateTime<chrono::Utc>) -> Result<Self, Self::Error> {
90+
// unfortunately chrono doesn't give us the nanos as i128, so we have to error
91+
// if it doesn't fit and then cast the i64 to u128 anyways
92+
let nanos = dt
93+
.timestamp_nanos_opt()
94+
.ok_or(Self::Error::TimeError(
95+
crate::error::TimestampTooLargeError(()),
96+
))?
97+
.try_into()
98+
.map_err(Self::Error::IntError)?;
99+
Ok(Self::Nanoseconds(nanos))
94100
}
95101
}
96102

97103
#[cfg(feature = "time")]
98-
impl From<time::UtcDateTime> for Timestamp {
99-
fn from(value: time::UtcDateTime) -> Self {
100-
Timestamp::Nanoseconds(value.unix_timestamp_nanos() as u128)
101-
}
102-
}
104+
impl TryFrom<Timestamp> for time::UtcDateTime {
105+
type Error =
106+
crate::error::TimeTryFromError<time::error::ComponentRange, <i128 as TryFrom<u128>>::Error>;
103107

104-
#[cfg(feature = "time")]
105-
impl From<Timestamp> for time::OffsetDateTime {
106-
fn from(value: Timestamp) -> Self {
107-
time::OffsetDateTime::from_unix_timestamp_nanos(value.nanos() as i128).unwrap()
108+
fn try_from(value: Timestamp) -> Result<Self, Self::Error> {
109+
let nanos = value.nanos().try_into().map_err(Self::Error::IntError)?;
110+
time::UtcDateTime::from_unix_timestamp_nanos(nanos).map_err(Self::Error::TimeError)
108111
}
109112
}
110113

111114
#[cfg(feature = "time")]
112-
impl From<time::OffsetDateTime> for Timestamp {
113-
fn from(value: time::OffsetDateTime) -> Self {
114-
Timestamp::Nanoseconds(value.unix_timestamp_nanos() as u128)
115+
impl TryFrom<time::UtcDateTime> for Timestamp {
116+
type Error = <u128 as TryFrom<i128>>::Error;
117+
118+
fn try_from(value: time::UtcDateTime) -> Result<Self, Self::Error> {
119+
Ok(Timestamp::Nanoseconds(
120+
value.unix_timestamp_nanos().try_into()?,
121+
))
115122
}
116123
}
117124

@@ -186,12 +193,16 @@ impl<Q: Query> Query for Box<Q> {
186193
}
187194

188195
pub trait InfluxDbWriteable {
189-
fn into_query<I: Into<String>>(self, name: I) -> WriteQuery;
196+
type Error;
197+
198+
fn try_into_query<I: Into<String>>(self, name: I) -> Result<WriteQuery, Self::Error>;
190199
}
191200

192201
impl InfluxDbWriteable for Timestamp {
193-
fn into_query<I: Into<String>>(self, name: I) -> WriteQuery {
194-
WriteQuery::new(self, name.into())
202+
type Error = Infallible;
203+
204+
fn try_into_query<I: Into<String>>(self, name: I) -> Result<WriteQuery, Infallible> {
205+
Ok(WriteQuery::new(self, name.into()))
195206
}
196207
}
197208

@@ -232,30 +243,35 @@ pub enum QueryType {
232243

233244
#[cfg(test)]
234245
mod tests {
246+
#[cfg(feature = "chrono")]
235247
use super::consts::{
236248
MILLIS_PER_SECOND, MINUTES_PER_HOUR, NANOS_PER_MICRO, NANOS_PER_MILLI, SECONDS_PER_MINUTE,
237249
};
238250
use crate::query::{Timestamp, ValidQuery};
251+
239252
#[test]
240253
fn test_equality_str() {
241254
assert_eq!(ValidQuery::from("hello"), "hello");
242255
}
256+
243257
#[test]
244258
fn test_equality_string() {
245259
assert_eq!(
246260
ValidQuery::from(String::from("hello")),
247261
String::from("hello")
248262
);
249263
}
264+
250265
#[test]
251266
fn test_format_for_timestamp_else() {
252267
assert!(format!("{}", Timestamp::Nanoseconds(100)) == "100");
253268
}
269+
254270
#[cfg(feature = "chrono")]
255271
#[test]
256272
fn test_chrono_datetime_from_timestamp_hours() {
257273
use chrono::prelude::*;
258-
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Hours(2).into();
274+
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Hours(2).try_into().unwrap();
259275
assert_eq!(
260276
Utc.timestamp_nanos(
261277
(2 * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLIS_PER_SECOND * NANOS_PER_MILLI)
@@ -265,11 +281,12 @@ mod tests {
265281
datetime_from_timestamp
266282
)
267283
}
284+
268285
#[cfg(feature = "chrono")]
269286
#[test]
270287
fn test_chrono_datetime_from_timestamp_minutes() {
271288
use chrono::prelude::*;
272-
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Minutes(2).into();
289+
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Minutes(2).try_into().unwrap();
273290
assert_eq!(
274291
Utc.timestamp_nanos(
275292
(2 * SECONDS_PER_MINUTE * MILLIS_PER_SECOND * NANOS_PER_MILLI)
@@ -279,11 +296,12 @@ mod tests {
279296
datetime_from_timestamp
280297
)
281298
}
299+
282300
#[cfg(feature = "chrono")]
283301
#[test]
284302
fn test_chrono_datetime_from_timestamp_seconds() {
285303
use chrono::prelude::*;
286-
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Seconds(2).into();
304+
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Seconds(2).try_into().unwrap();
287305
assert_eq!(
288306
Utc.timestamp_nanos(
289307
(2 * MILLIS_PER_SECOND * NANOS_PER_MILLI)
@@ -293,33 +311,37 @@ mod tests {
293311
datetime_from_timestamp
294312
)
295313
}
314+
296315
#[cfg(feature = "chrono")]
297316
#[test]
298317
fn test_chrono_datetime_from_timestamp_millis() {
299318
use chrono::prelude::*;
300-
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Milliseconds(2).into();
319+
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Milliseconds(2).try_into().unwrap();
301320
assert_eq!(
302321
Utc.timestamp_nanos((2 * NANOS_PER_MILLI).try_into().unwrap()),
303322
datetime_from_timestamp
304323
)
305324
}
325+
306326
#[cfg(feature = "chrono")]
307327
#[test]
308328
fn test_chrono_datetime_from_timestamp_nanos() {
309329
use chrono::prelude::*;
310-
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Nanoseconds(1).into();
330+
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Nanoseconds(1).try_into().unwrap();
311331
assert_eq!(Utc.timestamp_nanos(1), datetime_from_timestamp)
312332
}
333+
313334
#[cfg(feature = "chrono")]
314335
#[test]
315336
fn test_chrono_datetime_from_timestamp_micros() {
316337
use chrono::prelude::*;
317-
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Microseconds(2).into();
338+
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Microseconds(2).try_into().unwrap();
318339
assert_eq!(
319340
Utc.timestamp_nanos((2 * NANOS_PER_MICRO).try_into().unwrap()),
320341
datetime_from_timestamp
321342
)
322343
}
344+
323345
#[cfg(feature = "chrono")]
324346
#[test]
325347
fn test_timestamp_from_chrono_date() {
@@ -328,7 +350,8 @@ mod tests {
328350
.with_ymd_and_hms(1970, 1, 1, 0, 0, 1)
329351
.single()
330352
.unwrap()
331-
.into();
353+
.try_into()
354+
.unwrap();
332355
assert_eq!(
333356
Timestamp::Nanoseconds(MILLIS_PER_SECOND * NANOS_PER_MILLI),
334357
timestamp_from_datetime

influxdb/src/query/write_query.rs

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -154,23 +154,24 @@ impl From<&str> for Type {
154154
}
155155

156156
#[cfg(feature = "chrono")]
157-
impl<Tz: chrono::TimeZone> From<chrono::DateTime<Tz>> for Type {
158-
fn from(dt: chrono::DateTime<Tz>) -> Self {
159-
match dt.timestamp_nanos_opt() {
160-
Some(nanos) => Type::SignedInteger(nanos),
161-
None => {
162-
// For dates before 1677-09-21, or after
163-
// 2262-04-11, we're just going to return 0.
164-
Type::SignedInteger(0)
165-
}
166-
}
157+
impl TryFrom<chrono::DateTime<chrono::Utc>> for Type {
158+
type Error = crate::error::TimestampTooLargeError;
159+
160+
fn try_from(dt: chrono::DateTime<chrono::Utc>) -> Result<Self, Self::Error> {
161+
let nanos = dt
162+
.timestamp_nanos_opt()
163+
.ok_or(crate::error::TimestampTooLargeError(()))?;
164+
Ok(Self::SignedInteger(nanos))
167165
}
168166
}
169167

170168
#[cfg(feature = "time")]
171-
impl From<time::UtcDateTime> for Type {
172-
fn from(dt: time::UtcDateTime) -> Self {
173-
Type::SignedInteger(dt.unix_timestamp_nanos().try_into().unwrap_or(0))
169+
impl TryFrom<time::UtcDateTime> for Type {
170+
type Error = <i64 as TryFrom<i128>>::Error;
171+
172+
fn try_from(dt: time::UtcDateTime) -> Result<Self, Self::Error> {
173+
let nanos = dt.unix_timestamp_nanos().try_into()?;
174+
Ok(Self::SignedInteger(nanos))
174175
}
175176
}
176177

@@ -296,7 +297,8 @@ mod tests {
296297
#[test]
297298
fn test_write_builder_empty_query() {
298299
let query = Timestamp::Hours(5)
299-
.into_query("marina_3".to_string())
300+
.try_into_query("marina_3".to_string())
301+
.unwrap()
300302
.build();
301303

302304
assert!(query.is_err(), "Query was not empty");
@@ -305,7 +307,8 @@ mod tests {
305307
#[test]
306308
fn test_write_builder_single_field() {
307309
let query = Timestamp::Hours(11)
308-
.into_query("weather".to_string())
310+
.try_into_query("weather".to_string())
311+
.unwrap()
309312
.add_field("temperature", 82)
310313
.build();
311314

@@ -316,7 +319,8 @@ mod tests {
316319
#[test]
317320
fn test_write_builder_multiple_fields() {
318321
let query = Timestamp::Hours(11)
319-
.into_query("weather".to_string())
322+
.try_into_query("weather".to_string())
323+
.unwrap()
320324
.add_field("temperature", 82)
321325
.add_field("wind_strength", 3.7)
322326
.add_field("temperature_unsigned", 82u64)
@@ -332,7 +336,8 @@ mod tests {
332336
#[test]
333337
fn test_write_builder_multiple_fields_with_v2() {
334338
let query = Timestamp::Hours(11)
335-
.into_query("weather".to_string())
339+
.try_into_query("weather".to_string())
340+
.unwrap()
336341
.add_field("temperature", 82)
337342
.add_field("wind_strength", 3.7)
338343
.add_field("temperature_unsigned", 82u64)
@@ -348,7 +353,8 @@ mod tests {
348353
#[test]
349354
fn test_write_builder_optional_fields() {
350355
let query = Timestamp::Hours(11)
351-
.into_query("weather".to_string())
356+
.try_into_query("weather".to_string())
357+
.unwrap()
352358
.add_field("temperature", 82u64)
353359
.add_tag("wind_strength", <Option<u64>>::None)
354360
.build();
@@ -360,7 +366,8 @@ mod tests {
360366
#[test]
361367
fn test_write_builder_optional_fields_with_v2() {
362368
let query = Timestamp::Hours(11)
363-
.into_query("weather".to_string())
369+
.try_into_query("weather".to_string())
370+
.unwrap()
364371
.add_field("temperature", 82u64)
365372
.add_tag("wind_strength", <Option<u64>>::None)
366373
.build_with_opts(true);
@@ -372,7 +379,8 @@ mod tests {
372379
#[test]
373380
fn test_write_builder_only_tags() {
374381
let query = Timestamp::Hours(11)
375-
.into_query("weather".to_string())
382+
.try_into_query("weather".to_string())
383+
.unwrap()
376384
.add_tag("season", "summer")
377385
.build();
378386

@@ -382,7 +390,8 @@ mod tests {
382390
#[test]
383391
fn test_write_builder_full_query() {
384392
let query = Timestamp::Hours(11)
385-
.into_query("weather".to_string())
393+
.try_into_query("weather".to_string())
394+
.unwrap()
386395
.add_field("temperature", 82)
387396
.add_tag("location", "us-midwest")
388397
.add_tag("season", "summer")
@@ -400,7 +409,8 @@ mod tests {
400409
use crate::query::QueryType;
401410

402411
let query = Timestamp::Hours(11)
403-
.into_query("weather".to_string())
412+
.try_into_query("weather".to_string())
413+
.unwrap()
404414
.add_field("temperature", 82)
405415
.add_tag("location", "us-midwest")
406416
.add_tag("season", "summer");
@@ -411,7 +421,8 @@ mod tests {
411421
#[test]
412422
fn test_escaping() {
413423
let query = Timestamp::Hours(11)
414-
.into_query("wea, ther=")
424+
.try_into_query("wea, ther=")
425+
.unwrap()
415426
.add_field("temperature", 82)
416427
.add_field("\"temp=era,t ure\"", r#"too"\\hot"#)
417428
.add_field("float", 82.0)
@@ -430,12 +441,14 @@ mod tests {
430441
#[test]
431442
fn test_batch() {
432443
let q0 = Timestamp::Hours(11)
433-
.into_query("weather")
444+
.try_into_query("weather")
445+
.unwrap()
434446
.add_field("temperature", 82)
435447
.add_tag("location", "us-midwest");
436448

437449
let q1 = Timestamp::Hours(12)
438-
.into_query("weather")
450+
.try_into_query("weather")
451+
.unwrap()
439452
.add_field("temperature", 65)
440453
.add_tag("location", "us-midwest");
441454

0 commit comments

Comments
 (0)