Skip to content
Draft
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
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,15 @@ required-features = ["rustls-tls"]

[[example]]
name = "data_types_derive_simple"
required-features = ["time", "uuid", "chrono"]
required-features = ["time", "uuid", "chrono", "jiff"]

[[example]]
name = "data_types_variant"
required-features = ["time"]

[[example]]
name = "time_types_example"
required-features = ["time", "chrono"]
required-features = ["time", "chrono", "jiff"]

[profile.release]
debug = true
Expand All @@ -94,6 +94,7 @@ uuid = ["dep:uuid"]
time = ["dep:time"]
lz4 = ["dep:lz4_flex", "dep:cityhash-rs"]
chrono = ["dep:chrono"]
jiff = ["dep:jiff"]
futures03 = []

## TLS
Expand Down Expand Up @@ -148,6 +149,7 @@ cityhash-rs = { version = "=1.0.1", optional = true } # exact version for safety
uuid = { version = "1", optional = true }
time = { version = "0.3", optional = true }
chrono = { version = "0.4", optional = true, features = ["serde"] }
jiff = { version = "0.2", optional = true }
bstr = { version = "1.11.0", default-features = false }
quanta = { version = "0.12", optional = true }
replace_with = { version = "0.1.7" }
Expand Down
80 changes: 66 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ client.query("DROP TABLE IF EXISTS some").execute().await?;
* `uuid` — adds `serde::uuid` to work with [uuid](https://docs.rs/uuid) crate.
* `time` — adds `serde::time` to work with [time](https://docs.rs/time) crate.
* `chrono` — adds `serde::chrono` to work with [chrono](https://docs.rs/chrono) crate.
* `jiff` — adds `serde::jiff` to work with [jiff](https://docs.rs/jiff) crate.

### TLS
By default, TLS is disabled and one or more following features must be enabled to use HTTPS urls:
Expand Down Expand Up @@ -316,6 +317,7 @@ How to choose between all these features? Here are some considerations:
* `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.
* [`jiff::civil::Date`](https://docs.rs/jiff/latest/jiff/civil/struct.Date.html) is supported by using `serde::jiff::date`, requiring the `jiff` feature.
<details>
<summary>Example</summary>

Expand All @@ -324,17 +326,21 @@ How to choose between all these features? Here are some considerations:
struct MyRow {
days: u16,
#[serde(with = "clickhouse::serde::time::date")]
date: Date,
date: time::Date,
// if you prefer using chrono:
#[serde(with = "clickhouse::serde::chrono::date")]
date_chrono: NaiveDate,
// if you prefer using jiff:
#[serde(with = "clickhouse::serde::jiff::date")]
date_jiff: jiff::civil::Date,
}

```
</details>
* `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.
* [`jiff::civil::Date`](https://docs.rs/jiff/latest/jiff/civil/struct.Date.html) is supported by using `serde::jiff::date32`, requiring the `jiff` feature.
<details>
<summary>Example</summary>

Expand All @@ -343,18 +349,21 @@ How to choose between all these features? Here are some considerations:
struct MyRow {
days: i32,
#[serde(with = "clickhouse::serde::time::date32")]
date: Date,
date: time::Date,
// if you prefer using chrono:
#[serde(with = "clickhouse::serde::chrono::date32")]
date_chrono: NaiveDate,

// if you prefer using jiff:
#[serde(with = "clickhouse::serde::jiff::date32")]
date_jiff: jiff::civil::Date,
}

```
</details>
* `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.
* [`jiff::Timestamp`](https://docs.rs/jiff/latest/jiff/struct.Timestamp.html) is supported by using `serde::jiff::datetime`, requiring the `jiff` feature.
<details>
<summary>Example</summary>

Expand All @@ -366,13 +375,17 @@ How to choose between all these features? Here are some considerations:
dt: OffsetDateTime,
// if you prefer using chrono:
#[serde(with = "clickhouse::serde::chrono::datetime")]
dt_chrono: DateTime<Utc>,
dt_chrono: DateTime<Utc>,
// if you prefer using jiff:
#[serde(with = "clickhouse::serde::jiff::datetime")]
dt_jiff: Timestamp,
}
```
</details>
* `DateTime64(_)` maps to/from `i64` 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.
* [`jiff::Timestamp`](https://docs.rs/jiff/latest/jiff/struct.Timestamp.html) is supported by using `serde::jiff::datetime64::*`, requiring the `jiff` feature.
<details>
<summary>Example</summary>

Expand All @@ -397,39 +410,78 @@ How to choose between all these features? Here are some considerations:
dt64us_chrono: DateTime<Utc>, // `DateTime64(6)`
#[serde(with = "clickhouse::serde::chrono::datetime64::nanos")]
dt64ns_chrono: DateTime<Utc>, // `DateTime64(9)`
// if you prefer using jiff:
#[serde(with = "clickhouse::serde::jiff::datetime64::secs")]
dt64s_jiff: Timestamp, // `DateTime64(0)`
#[serde(with = "clickhouse::serde::jiff::datetime64::millis")]
dt64ms_jiff: Timestamp, // `DateTime64(3)`
#[serde(with = "clickhouse::serde::jiff::datetime64::micros")]
dt64us_jiff: Timestamp, // `DateTime64(6)`
#[serde(with = "clickhouse::serde::jiff::datetime64::nanos")]
dt64ns_jiff: Timestamp, // `DateTime64(9)`
}


```
</details>
* `Time` maps to/from i32 or a newtype around it. The Time data type is used to store a time value independent of any calendar date. It is ideal for representing daily schedules, event times, or any situation where only the time component (hours, minutes, seconds) is important.
* [`time:Duration`](https://docs.rs/time/latest/time/struct.Duration.html) is is supported by using `serde::time::*`, requiring the `time` feature.
* [`chrono::Duration`](https://docs.rs/chrono/latest/chrono/type.Duration.html) is supported by using `serde::chrono::*`, which is an alias to `TimeDelta`, requiring the `chrono` feature
* [`time::Duration`](https://docs.rs/time/latest/time/struct.Duration.html) is supported by using `serde::time::time`, requiring the `time` feature.
* [`chrono::Duration`](https://docs.rs/chrono/latest/chrono/type.Duration.html) is supported by using `serde::chrono::time`, which is an alias to `TimeDelta`, requiring the `chrono` feature
* [`jiff::SignedDuration`](https://docs.rs/jiff/latest/jiff/struct.SignedDuration.html) is supported by using `serde::jiff::time`, requiring the `jiff` feature.
<details>
<summary>Example</summary>

```rust,ignore
#[derive(Row, Serialize, Deserialize)]
struct MyRow {
#[serde(with = "clickhouse::serde::chrono::time64::secs")]
t0: chrono::Duration,
#[serde(with = "clickhouse::serde::chrono::time64::secs::option")]
t0_opt: Option<chrono::Duration>,
#[serde(with = "clickhouse::serde::time::time")]
t: time::Duration,
// if you prefer using chrono:
#[serde(with = "clickhouse::serde::chrono::time")]
t_chrono: chrono::Duration,
// if you prefer using jiff:
#[serde(with = "clickhouse::serde::jiff::time")]
t_jiff: jiff::SignedDuration,
}

```
</details>
* `Time64(_)` maps to/from i64 or a newtype around it. The Time data type is used to store a time value independent of any calendar date. It is ideal for representing daily schedules, event times, or any situation where only the time component (hours, minutes, seconds) is important.
* [`time:Duration`](https://docs.rs/time/latest/time/struct.Duration.html) is is supported by using `serde::time::*`, requiring the `time` feature.
* [`chrono::Duration`](https://docs.rs/chrono/latest/chrono/type.Duration.html) is supported by using `serde::chrono::*`, requiring the `chrono` feature
* [`time::Duration`](https://docs.rs/time/latest/time/struct.Duration.html) is supported by using `serde::time::time64::*`, requiring the `time` feature.
* [`chrono::Duration`](https://docs.rs/chrono/latest/chrono/type.Duration.html) is supported by using `serde::chrono::time64::*`, requiring the `chrono` feature
* [`jiff::SignedDuration`](https://docs.rs/jiff/latest/jiff/struct.SignedDuration.html) is supported by using `serde::jiff::time64::*`, requiring the `jiff` feature.
<details>
<summary>Example</summary>

```rust,ignore
#[derive(Row, Serialize, Deserialize)]
struct MyRow {
#[serde(with = "clickhouse::serde::time::time")]
t0: Time,
#[serde(with = "clickhouse::serde::time::time64::secs")]
t64s: time::Duration,
#[serde(with = "clickhouse::serde::time::time64::millis")]
t64ms: time::Duration,
#[serde(with = "clickhouse::serde::time::time64::micros")]
t64us: time::Duration,
#[serde(with = "clickhouse::serde::time::time64::nanos")]
t64ns: time::Duration,
// if you prefer using chrono:
#[serde(with = "clickhouse::serde::chrono::time64::secs")]
t64s_chrono: chrono::Duration,
#[serde(with = "clickhouse::serde::chrono::time64::millis")]
t64ms_chrono: chrono::Duration,
#[serde(with = "clickhouse::serde::chrono::time64::micros")]
t64us_chrono: chrono::Duration,
#[serde(with = "clickhouse::serde::chrono::time64::nanos")]
t64ns_chrono: chrono::Duration,
// if you prefer using jiff:
#[serde(with = "clickhouse::serde::jiff::time64::secs")]
t64s_jiff: jiff::SignedDuration,
#[serde(with = "clickhouse::serde::jiff::time64::millis")]
t64ms_jiff: jiff::SignedDuration,
#[serde(with = "clickhouse::serde::jiff::time64::micros")]
t64us_jiff: jiff::SignedDuration,
#[serde(with = "clickhouse::serde::jiff::time64::nanos")]
t64ns_jiff: jiff::SignedDuration,
}

```
Expand Down
40 changes: 40 additions & 0 deletions examples/data_types_derive_simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use fixnum::{
typenum::{U12, U4, U8},
FixedPoint,
};
use jiff::{civil::Date as JiffDate, Timestamp};
use rand::prelude::IndexedRandom;
use rand::{distr::Alphanumeric, Rng};
use std::str::FromStr;
Expand Down Expand Up @@ -73,6 +74,16 @@ async fn main() -> Result<()> {
chrono_datetime64_6 DateTime64(6),
chrono_datetime64_9 DateTime64(9),
chrono_datetime64_9_tz DateTime64(9, 'UTC'),

jiff_date Date,
jiff_date32 Date32,
jiff_datetime DateTime,
jiff_datetime_tz DateTime('UTC'),
jiff_datetime64_0 DateTime64(0),
jiff_datetime64_3 DateTime64(3),
jiff_datetime64_6 DateTime64(6),
jiff_datetime64_9 DateTime64(9),
jiff_datetime64_9_tz DateTime64(9, 'UTC'),
) ENGINE MergeTree ORDER BY ();
",
)
Expand Down Expand Up @@ -168,6 +179,25 @@ pub struct Row {
pub chrono_datetime64_9: DateTime<Utc>,
#[serde(with = "clickhouse::serde::chrono::datetime64::nanos")]
pub chrono_datetime64_9_tz: DateTime<Utc>,

#[serde(with = "clickhouse::serde::jiff::date")]
pub jiff_date: JiffDate,
#[serde(with = "clickhouse::serde::jiff::date32")]
pub jiff_date32: JiffDate,
#[serde(with = "clickhouse::serde::jiff::datetime")]
pub jiff_datetime: Timestamp,
#[serde(with = "clickhouse::serde::jiff::datetime")]
pub jiff_datetime_tz: Timestamp,
#[serde(with = "clickhouse::serde::jiff::datetime64::secs")]
pub jiff_datetime64_0: Timestamp,
#[serde(with = "clickhouse::serde::jiff::datetime64::millis")]
pub jiff_datetime64_3: Timestamp,
#[serde(with = "clickhouse::serde::jiff::datetime64::micros")]
pub jiff_datetime64_6: Timestamp,
#[serde(with = "clickhouse::serde::jiff::datetime64::nanos")]
pub jiff_datetime64_9: Timestamp,
#[serde(with = "clickhouse::serde::jiff::datetime64::nanos")]
pub jiff_datetime64_9_tz: Timestamp,
}

// See ClickHouse decimal sizes: https://clickhouse.com/docs/en/sql-reference/data-types/decimal
Expand Down Expand Up @@ -255,6 +285,16 @@ impl Row {
chrono_datetime64_6: Utc::now(),
chrono_datetime64_9: Utc::now(),
chrono_datetime64_9_tz: Utc::now(),

jiff_date: JiffDate::constant(2149, 6, 6),
jiff_date32: JiffDate::constant(2299, 12, 31),
jiff_datetime: Timestamp::now(),
jiff_datetime_tz: Timestamp::now(),
jiff_datetime64_0: Timestamp::now(),
jiff_datetime64_3: Timestamp::now(),
jiff_datetime64_6: Timestamp::now(),
jiff_datetime64_9: Timestamp::now(),
jiff_datetime64_9_tz: Timestamp::now(),
}
}
}
Expand Down
39 changes: 38 additions & 1 deletion examples/time_types_example.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use chrono::Duration;
use clickhouse::Client;
use jiff::SignedDuration;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize, clickhouse::Row)]
Expand Down Expand Up @@ -44,9 +45,30 @@ struct TimeExampleChrono {
time64_nanos: Duration,
}

#[derive(Debug, Serialize, Deserialize, clickhouse::Row)]
struct TimeExampleJiff {
#[serde(with = "clickhouse::serde::jiff::time")]
time_field: SignedDuration,

#[serde(with = "clickhouse::serde::jiff::time::option")]
time_optional: Option<SignedDuration>,

#[serde(with = "clickhouse::serde::jiff::time64::secs")]
time64_seconds: SignedDuration,

#[serde(with = "clickhouse::serde::jiff::time64::millis")]
time64_millis: SignedDuration,

#[serde(with = "clickhouse::serde::jiff::time64::micros")]
time64_micros: SignedDuration,

#[serde(with = "clickhouse::serde::jiff::time64::nanos")]
time64_nanos: SignedDuration,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::default();
let client = Client::default().with_url("http://localhost:8123");

let create_table_sql = r#"
CREATE TABLE IF NOT EXISTS time_example (
Expand All @@ -58,6 +80,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
time64_nanos Time64(9)
) ENGINE = MergeTree()
ORDER BY time_field
SETTINGS enable_time_time64_type = 1
"#;

client.query(create_table_sql).execute().await?;
Expand Down Expand Up @@ -116,6 +139,20 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Inserted edge case #{i}: {edge:?}");
}

// Insert data using jiff crate
let time_example = TimeExampleJiff {
time_field: SignedDuration::new(23 * 3600 + 56 * 60, 0),
time_optional: Some(SignedDuration::new(3600 + 2 * 60 + 2, 0)),
time64_seconds: SignedDuration::new(3 * 3600 + 4 * 60 + 5, 0),
time64_millis: SignedDuration::new(6 * 3600 + 7 * 60 + 8, 123_000_000),
time64_micros: SignedDuration::new(9 * 3600 + 10 * 60 + 11, 456_789_000),
time64_nanos: SignedDuration::new(12 * 3600 + 13 * 60 + 14, 123_456_789),
};

let mut insert = client.insert::<TimeExampleJiff>("time_example").await?;
insert.write(&time_example).await?;
insert.end().await?;

// Query the data
let rows: Vec<TimeExample> = client
.query("SELECT * FROM time_example ORDER BY time_field")
Expand Down
Loading