Skip to content

Commit

Permalink
fix issues highlighted in PR
Browse files Browse the repository at this point in the history
  • Loading branch information
dean-shaff committed Jan 6, 2025
1 parent bbfeb39 commit bfe8179
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 149 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ watch = ["dep:sha-1", "dep:serde_json", "serde/derive"]
uuid = ["dep:uuid"]
time = ["dep:time"]
lz4 = ["dep:lz4_flex", "dep:cityhash-rs"]
chrono = ["dep:chrono", "dep:serde_json"]
chrono = ["dep:chrono"]
## TLS
native-tls = ["dep:hyper-tls"]
# ext: native-tls-alpn
Expand Down
39 changes: 19 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,9 @@ How to choose between all these features? Here are some considerations:
}
```
</details>
* `Date` maps to/from `u16` or a newtype around it and represents a number of days elapsed since `1970-01-01`. Also, [`time::Date`](https://docs.rs/time/latest/time/struct.Date.html) is supported by using `serde::time::date`, that requires the `time` feature. `chrono::NaiveDate` is supported by using `serde::chrono::date`, requiring the `chrono` feature.
* `Date` maps to/from `u16` or a newtype around it and represents a number of days elapsed since `1970-01-01`. The following external types are supported:
* [`time::Date`](https://docs.rs/time/latest/time/struct.Date.html) is supported by using `serde::time::date`, requiring the `time` feature.
* [`chrono::NaiveDate`](https://docs.rs/chrono/latest/chrono/struct.NaiveDate.html) is supported by using `serde::chrono::date`, requiring the `chrono` feature.
<details>
<summary>Example</summary>
Expand All @@ -350,7 +352,9 @@ How to choose between all these features? Here are some considerations:
}
```
</details>
* `Date32` maps to/from `i32` or a newtype around it and represents a number of days elapsed since `1970-01-01`. Also, [`time::Date`](https://docs.rs/time/latest/time/struct.Date.html) is supported by using `serde::time::date32`, that requires the `time` feature. `chrono::NaiveDate` is supported by using `serde::chrono::date`, requiring the `chrono` feature.
* `Date32` maps to/from `i32` or a newtype around it and represents a number of days elapsed since `1970-01-01`. The following external types are supported:
* [`time::Date`](https://docs.rs/time/latest/time/struct.Date.html) is supported by using `serde::time::date32`, requiring the `time` feature.
* [`chrono::NaiveDate`](https://docs.rs/chrono/latest/chrono/struct.NaiveDate.html) is supported by using `serde::chrono::date32`, requiring the `chrono` feature.
<details>
<summary>Example</summary>
Expand All @@ -372,7 +376,9 @@ How to choose between all these features? Here are some considerations:
```
</details>
* `DateTime` maps to/from `u32` or a newtype around it and represents a number of seconds elapsed since UNIX epoch. Also, [`time::OffsetDateTime`](https://docs.rs/time/latest/time/struct.OffsetDateTime.html) is supported by using `serde::time::datetime`, that requires the `time` feature. `chrono::DateTime<Utc>` is supported by using `serde::chrono::datetime`, which requires the `chrono` feature.
* `DateTime` maps to/from `u32` or a newtype around it and represents a number of seconds elapsed since UNIX epoch. The following external types are supported:
* [`time::OffsetDateTime`](https://docs.rs/time/latest/time/struct.OffsetDateTime.html) is supported by using `serde::time::datetime`, requiring the `time` feature.
* [`chrono::DateTime<Utc>`](https://docs.rs/chrono/latest/chrono/struct.DateTime.html) is supported by using `serde::chrono::datetime`, requiring the `chrono` feature.
<details>
<summary>Example</summary>
Expand All @@ -382,17 +388,14 @@ How to choose between all these features? Here are some considerations:
ts: u32,
#[serde(with = "clickhouse::serde::time::datetime")]
dt: OffsetDateTime,
}
// or if you prefer chrono:
#[derive(Row, Serialize, Deserialize)]
struct MyRow {
ts: u32,
#[serde(with = "clickhouse::serde::chrono::datetime")]
dt: DateTime<Utc>,
dt_chrono: DateTime<Utc>,
}
```
</details>
* `DateTime64(_)` maps to/from `i32` or a newtype around it and represents a time elapsed since UNIX epoch. Also, [`time::OffsetDateTime`](https://docs.rs/time/latest/time/struct.OffsetDateTime.html) is supported by using `serde::time::datetime64::*`, that requires the `time` feature. `chrono::DateTime<Utc>` is supported by using `serde::chrono::datetime`, which requires the `chrono` feature.
* `DateTime64(_)` maps to/from `i32` or a newtype around it and represents a time elapsed since UNIX epoch. The following external types are supported:
* [`time::OffsetDateTime`](https://docs.rs/time/latest/time/struct.OffsetDateTime.html) is supported by using `serde::time::datetime64::*`, requiring the `time` feature.
* [`chrono::DateTime<Utc>`](https://docs.rs/chrono/latest/chrono/struct.DateTime.html) is supported by using `serde::chrono::datetime64::*`, requiring the `chrono` feature.
<details>
<summary>Example</summary>
Expand All @@ -408,22 +411,18 @@ How to choose between all these features? Here are some considerations:
dt64us: OffsetDateTime, // `DateTime64(6)`
#[serde(with = "clickhouse::serde::time::datetime64::nanos")]
dt64ns: OffsetDateTime, // `DateTime64(9)`
}
// or if you prefer chrono:
#[derive(Row, Serialize, Deserialize)]
struct MyRow {
ts: u32,
// if you prefer using chrono:
#[serde(with = "clickhouse::serde::chrono::datetime64::secs")]
dt64s: DateTime<Utc>, // `DateTime64(0)`
dt64s_chrono: DateTime<Utc>, // `DateTime64(0)`
#[serde(with = "clickhouse::serde::chrono::datetime64::millis")]
dt64ms: DateTime<Utc>, // `DateTime64(3)`
dt64ms_chrono: DateTime<Utc>, // `DateTime64(3)`
#[serde(with = "clickhouse::serde::chrono::datetime64::micros")]
dt64us: DateTime<Utc>, // `DateTime64(6)`
dt64us_chrono: DateTime<Utc>, // `DateTime64(6)`
#[serde(with = "clickhouse::serde::chrono::datetime64::nanos")]
dt64ns: DateTime<Utc>, // `DateTime64(9)`
dt64ns_chrono: DateTime<Utc>, // `DateTime64(9)`
}
```
</details>
* `Tuple(A, B, ...)` maps to/from `(A, B, ...)` or a newtype around it.
Expand Down
36 changes: 18 additions & 18 deletions examples/data_types_derive_simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,23 +121,23 @@ pub struct Row {
pub decimal64_18_8: Decimal64,
pub decimal128_38_12: Decimal128,
#[serde(with = "clickhouse::serde::time::date")]
pub date: Date,
pub time_date: Date,
#[serde(with = "clickhouse::serde::time::date32")]
pub date32: Date,
pub time_date32: Date,
#[serde(with = "clickhouse::serde::time::datetime")]
pub datetime: OffsetDateTime,
pub time_datetime: OffsetDateTime,
#[serde(with = "clickhouse::serde::time::datetime")]
pub datetime_tz: OffsetDateTime,
pub time_datetime_tz: OffsetDateTime,
#[serde(with = "clickhouse::serde::time::datetime64::secs")]
pub datetime64_0: OffsetDateTime,
pub time_datetime64_0: OffsetDateTime,
#[serde(with = "clickhouse::serde::time::datetime64::millis")]
pub datetime64_3: OffsetDateTime,
pub time_datetime64_3: OffsetDateTime,
#[serde(with = "clickhouse::serde::time::datetime64::micros")]
pub datetime64_6: OffsetDateTime,
pub time_datetime64_6: OffsetDateTime,
#[serde(with = "clickhouse::serde::time::datetime64::nanos")]
pub datetime64_9: OffsetDateTime,
pub time_datetime64_9: OffsetDateTime,
#[serde(with = "clickhouse::serde::time::datetime64::nanos")]
pub datetime64_9_tz: OffsetDateTime,
pub time_datetime64_9_tz: OffsetDateTime,

#[serde(with = "clickhouse::serde::chrono::date")]
pub chrono_date: NaiveDate,
Expand Down Expand Up @@ -225,15 +225,15 @@ impl Row {
// See
// - https://clickhouse.com/docs/en/sql-reference/data-types/date
// - https://clickhouse.com/docs/en/sql-reference/data-types/date32
date: Date::from_calendar_date(2149, Month::June, 6).unwrap(),
date32: Date::from_calendar_date(2299, Month::December, 31).unwrap(),
datetime: max_datetime(),
datetime_tz: max_datetime(),
datetime64_0: max_datetime64(),
datetime64_3: max_datetime64(),
datetime64_6: max_datetime64(),
datetime64_9: max_datetime64_nanos(),
datetime64_9_tz: max_datetime64_nanos(),
time_date: Date::from_calendar_date(2149, Month::June, 6).unwrap(),
time_date32: Date::from_calendar_date(2299, Month::December, 31).unwrap(),
time_datetime: max_datetime(),
time_datetime_tz: max_datetime(),
time_datetime64_0: max_datetime64(),
time_datetime64_3: max_datetime64(),
time_datetime64_6: max_datetime64(),
time_datetime64_9: max_datetime64_nanos(),
time_datetime64_9_tz: max_datetime64_nanos(),

chrono_date: NaiveDate::from_ymd_opt(2149, 6, 6).unwrap(),
chrono_date32: NaiveDate::from_ymd_opt(2299, 12, 31).unwrap(),
Expand Down
113 changes: 3 additions & 110 deletions src/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,28 +142,6 @@ pub mod chrono {
D::Error::custom(format!("{ts} cannot be converted to DateTime<Utc>"))
})
}

#[cfg(test)]
mod tests {
use ::chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct WithDateTime {
#[serde(with = "super::datetime")]
dt: DateTime<Utc>,
}

#[test]
fn test_serde() {
let dt = WithDateTime { dt: Utc::now() };
let serde_dt: WithDateTime =
serde_json::from_str(&serde_json::to_string(&dt).unwrap()).unwrap();
// we have to compare `timestamp` because we lose information when serializing
// and deserializing using clickhouse `DateTime` format
assert!(dt.dt.timestamp() == serde_dt.dt.timestamp());
}
}
}

/// Contains modules to ser/de `DateTime<Utc>` to/from `DateTime64(_)`.
Expand Down Expand Up @@ -269,7 +247,7 @@ pub mod chrono {
S: Serializer,
{
let ts = dt.timestamp_nanos_opt().ok_or_else(|| {
S::Error::custom(format!("Can't create a timestamp from {dt}"))
S::Error::custom(format!("{dt} cannot be represented as DateTime64"))
})?;
ts.serialize(serializer)
}
Expand All @@ -282,41 +260,6 @@ pub mod chrono {
Ok(DateTime::<Utc>::from_timestamp_nanos(ts))
}
}

#[cfg(test)]
mod tests {
use ::chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct WithDateTime {
#[serde(with = "super::datetime64::nanos")]
dt_nanos: DateTime<Utc>,
#[serde(with = "super::datetime64::micros")]
dt_micros: DateTime<Utc>,
#[serde(with = "super::datetime64::millis")]
dt_millis: DateTime<Utc>,
#[serde(with = "super::datetime64::secs")]
dt_secs: DateTime<Utc>,
}

#[test]
fn test_serde() {
let now = Utc::now();
let dt = WithDateTime {
dt_nanos: now,
dt_micros: now,
dt_millis: now,
dt_secs: now,
};
let serde_dt: WithDateTime =
serde_json::from_str(&serde_json::to_string(&dt).unwrap()).unwrap();
assert!(dt.dt_nanos == serde_dt.dt_nanos);
assert!(dt.dt_micros == serde_dt.dt_micros);
assert!(dt.dt_millis.timestamp_millis() == serde_dt.dt_millis.timestamp_millis());
assert!(dt.dt_secs.timestamp() == serde_dt.dt_secs.timestamp());
}
}
}

/// Ser/de `time::Date` to/from `Date`.
Expand All @@ -326,7 +269,7 @@ pub mod chrono {

option!(
NaiveDate,
"Ser/de `Option<time::Date>` to/from `Nullable(Date)`."
"Ser/de `Option<NaiveDate>` to/from `Nullable(Date)`."
);

const ORIGIN: Option<NaiveDate> = NaiveDate::from_yo_opt(1970, 1);
Expand Down Expand Up @@ -356,27 +299,6 @@ pub mod chrono {
let days: u16 = Deserialize::deserialize(deserializer)?;
Ok(ORIGIN.unwrap() + Duration::days(i64::from(days))) // cannot overflow: always < `Date::MAX`
}

#[cfg(test)]
mod tests {
use ::chrono::{NaiveDate, Utc};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct WithDate {
#[serde(with = "super::date")]
d: NaiveDate,
}

#[test]
fn test_serde() {
let now = Utc::now().date_naive();
let dt = WithDate { d: now };
let serde_dt: WithDate =
serde_json::from_str(&serde_json::to_string(&dt).unwrap()).unwrap();
assert!(dt.d == serde_dt.d);
}
}
}

/// Ser/de `time::Date` to/from `Date32`.
Expand All @@ -387,7 +309,7 @@ pub mod chrono {

option!(
NaiveDate,
"Ser/de `Option<time::Date>` to/from `Nullable(Date32)`."
"Ser/de `Option<NaiveDate>` to/from `Nullable(Date32)`."
);

const ORIGIN: Option<NaiveDate> = NaiveDate::from_yo_opt(1970, 1);
Expand Down Expand Up @@ -423,35 +345,6 @@ pub mod chrono {
// TODO: ensure CH clamps when an invalid value is inserted in binary format.
Ok(ORIGIN.unwrap() + Duration::days(i64::from(days)))
}
#[cfg(test)]
mod tests {
use ::chrono::{NaiveDate, Utc};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct WithDate {
#[serde(with = "super::date32")]
d_32: NaiveDate,
}

#[test]
fn test_serde() {
let now = Utc::now().date_naive();
let dt = WithDate { d_32: now };
let serde_dt: WithDate =
serde_json::from_str(&serde_json::to_string(&dt).unwrap()).unwrap();
assert!(dt.d_32 == serde_dt.d_32);
}

#[test]
fn test_serde_invalid() {
let french_revolution = NaiveDate::from_ymd_opt(1789, 7, 14).unwrap();
let dt = WithDate {
d_32: french_revolution,
};
assert!(serde_json::to_string(&dt).is_err());
}
}
}
}

Expand Down
Loading

0 comments on commit bfe8179

Please sign in to comment.