Skip to content

Commit 7ea7ebe

Browse files
authored
Merge branch 'main' into 0.14.0-changelog
2 parents 387ab21 + 2e57c26 commit 7ea7ebe

File tree

28 files changed

+627
-65
lines changed

28 files changed

+627
-65
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ jobs:
4141
- run: cargo update -p zerofrom --precise 0.1.5 # 0.1.6 requires rustc 1.81
4242
- run: cargo update -p lz4_flex --precise 0.11.3 # 0.11.4 requires rustc 1.81
4343
- run: cargo update -p url --precise 2.5.0 # 2.5.4 requires rustc 1.82
44+
- run: cargo update -p time --precise 0.3.41 # 0.3.43 requires rustc 1.81
45+
- run: cargo update -p time-core --precise 0.1.4 # 0.1.6 requires rustc 1.81
46+
- run: cargo update -p deranged --precise 0.4.0 # 0.5.x requires rustc 1.81
4447
- run: cargo build
4548
- run: cargo build --no-default-features
4649
- run: cargo build --features uuid,time,chrono

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4545
`RowBinaryWithNamesAndTypes` struct definition validation, as it contains ClickHouse data types AST, as well as
4646
functions and utilities to parse the types out of the ClickHouse server response. ([#221]).
4747
- query: support serializing `serde_bytes::Bytes` as hex string literals in query parameters ([#250]).
48+
- derive: added `#[clickhouse(crate = "...")]` attribute for `#[derive(Row)]` ([#189]/[#292])
4849

4950
### Fixed
5051

5152
- client: extract the exception code from `X-ClickHouse-Exception-Code` in case of incorrect 200 OK response
5253
that could occur with ClickHouse server up to versions 24.x ([#256]).
5354

55+
[#189]: https://github.com/ClickHouse/clickhouse-rs/pull/189
5456
[#221]: https://github.com/ClickHouse/clickhouse-rs/pull/221
5557
[#229]: https://github.com/ClickHouse/clickhouse-rs/pull/229
5658
[#232]: https://github.com/ClickHouse/clickhouse-rs/pull/232
@@ -61,6 +63,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6163
[#250]: https://github.com/ClickHouse/clickhouse-rs/pull/250
6264
[#256]: https://github.com/ClickHouse/clickhouse-rs/pull/256
6365
[#258]: https://github.com/ClickHouse/clickhouse-rs/pull/258
66+
[#292]: https://github.com/ClickHouse/clickhouse-rs/pull/292
6467

6568
## [0.13.3] - 2025-05-29
6669
### Added

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ hyper-rustls = { version = "0.27.3", default-features = false, features = [
137137
"tls12",
138138
], optional = true }
139139
url = "2.1.1"
140-
futures = "0.3.5"
141-
futures-channel = "0.3.30"
140+
futures-util = { version = "0.3.5", default-features = false, features = ["sink", "io"] }
141+
futures-channel = { version = "0.3.30", features = ["sink"] }
142142
static_assertions = "1.1"
143143
sealed = "0.6"
144144
lz4_flex = { version = "0.11.3", default-features = false, features = [

benches/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::{
1212

1313
use bytes::Bytes;
1414
use clickhouse::error::Result;
15-
use futures::stream::StreamExt;
15+
use futures_util::stream::StreamExt;
1616
use http_body_util::BodyExt;
1717
use hyper::{
1818
body::{Body, Incoming},

benches/mocked_select.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use clickhouse::{
55
};
66
use clickhouse_types::{Column, DataTypeNode};
77
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
8-
use futures::stream::{self, StreamExt as _};
8+
use futures_util::stream::{self, StreamExt as _};
99
use http_body_util::StreamBody;
1010
use hyper::{
1111
body::{Body, Frame, Incoming},

benches/select_nyc_taxi_data.rs

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::common_select::{
44
do_select_bench, print_header, print_results, BenchmarkRow, WithAccessType, WithId,
55
};
6-
use clickhouse::{Compression, Row};
6+
use clickhouse::{Client, Compression, Row};
77
use serde::Deserialize;
88
use serde_repr::Deserialize_repr;
99
use time::OffsetDateTime;
@@ -74,6 +74,86 @@ struct TripSmallMapAccess {
7474
impl_benchmark_row!(TripSmallSeqAccess, trip_id, "seq");
7575
impl_benchmark_row!(TripSmallMapAccess, trip_id, "map");
7676

77+
// See https://clickhouse.com/docs/getting-started/example-datasets/nyc-taxi
78+
async fn prepare_data() {
79+
let client = Client::default().with_url("http://localhost:8123");
80+
81+
client
82+
.query("CREATE DATABASE IF NOT EXISTS nyc_taxi")
83+
.execute()
84+
.await
85+
.unwrap();
86+
client
87+
.query(
88+
r#"
89+
CREATE TABLE IF NOT EXISTS nyc_taxi.trips_small (
90+
trip_id UInt32,
91+
pickup_datetime DateTime,
92+
dropoff_datetime DateTime,
93+
pickup_longitude Nullable(Float64),
94+
pickup_latitude Nullable(Float64),
95+
dropoff_longitude Nullable(Float64),
96+
dropoff_latitude Nullable(Float64),
97+
passenger_count UInt8,
98+
trip_distance Float32,
99+
fare_amount Float32,
100+
extra Float32,
101+
tip_amount Float32,
102+
tolls_amount Float32,
103+
total_amount Float32,
104+
payment_type Enum('CSH' = 1, 'CRE' = 2, 'NOC' = 3, 'DIS' = 4, 'UNK' = 5),
105+
pickup_ntaname LowCardinality(String),
106+
dropoff_ntaname LowCardinality(String)
107+
)
108+
ENGINE = MergeTree
109+
PRIMARY KEY (pickup_datetime, dropoff_datetime)
110+
"#,
111+
)
112+
.execute()
113+
.await
114+
.unwrap();
115+
116+
let len = client
117+
.query("SELECT count() FROM nyc_taxi.trips_small")
118+
.fetch_one::<usize>()
119+
.await
120+
.unwrap();
121+
122+
if len == 0 {
123+
client
124+
.query(
125+
"
126+
INSERT INTO nyc_taxi.trips_small
127+
SELECT
128+
trip_id,
129+
pickup_datetime,
130+
dropoff_datetime,
131+
pickup_longitude,
132+
pickup_latitude,
133+
dropoff_longitude,
134+
dropoff_latitude,
135+
passenger_count,
136+
trip_distance,
137+
fare_amount,
138+
extra,
139+
tip_amount,
140+
tolls_amount,
141+
total_amount,
142+
payment_type,
143+
pickup_ntaname,
144+
dropoff_ntaname
145+
FROM gcs(
146+
'https://storage.googleapis.com/clickhouse-public-datasets/nyc-taxi/trips_{0..2}.gz',
147+
'TabSeparatedWithNames'
148+
);
149+
",
150+
)
151+
.execute()
152+
.await
153+
.unwrap();
154+
}
155+
}
156+
77157
async fn bench<T: BenchmarkRow>(compression: Compression, validation: bool) {
78158
let stats = do_select_bench::<T>(
79159
"SELECT * FROM nyc_taxi.trips_small ORDER BY trip_id DESC",
@@ -87,6 +167,7 @@ async fn bench<T: BenchmarkRow>(compression: Compression, validation: bool) {
87167

88168
#[tokio::main]
89169
async fn main() {
170+
prepare_data().await;
90171
print_header(Some(" access"));
91172
bench::<TripSmallSeqAccess>(Compression::None, false).await;
92173
bench::<TripSmallSeqAccess>(Compression::None, true).await;

derive/src/attributes.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use syn::meta::ParseNestedMeta;
2+
3+
pub struct Attributes {
4+
pub crate_path: syn::Path,
5+
}
6+
7+
impl Default for Attributes {
8+
fn default() -> Self {
9+
Attributes {
10+
// Note: changing this to `::clickhouse` is likely a breaking change;
11+
// it's possible that the user has renamed the `clickhouse` package,
12+
// but then aliased it back to `clickhouse` to fix the derive.
13+
crate_path: syn::parse_str("clickhouse").expect("BUG: crate_path should parse"),
14+
}
15+
}
16+
}
17+
18+
impl TryFrom<&[syn::Attribute]> for Attributes {
19+
type Error = syn::Error;
20+
21+
fn try_from(attrs: &[syn::Attribute]) -> syn::Result<Self> {
22+
for attr in attrs {
23+
if attr.path().is_ident("clickhouse") {
24+
let mut out = Attributes::default();
25+
26+
attr.parse_nested_meta(|meta| parse_nested_meta(meta, &mut out))?;
27+
28+
return Ok(out);
29+
}
30+
}
31+
32+
Ok(Self::default())
33+
}
34+
}
35+
36+
/// Called for each meta-item inside the `#[clickhouse(...)]` attribute.
37+
fn parse_nested_meta(meta: ParseNestedMeta<'_>, out: &mut Attributes) -> syn::Result<()> {
38+
// #[clickhouse(crate = "<path>")]
39+
if meta.path.is_ident("crate") {
40+
out.crate_path = meta
41+
// Expect and eat the `=` token
42+
.value()?
43+
// Expect a string literal like Serde: https://serde.rs/container-attrs.html#crate
44+
.parse::<syn::LitStr>()?
45+
// Parse the literal content as `Path`
46+
.parse()?;
47+
} else {
48+
return Err(meta.error("unexpected `#[clickhouse(...)]` argument"));
49+
}
50+
51+
Ok(())
52+
}

derive/src/lib.rs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::attributes::Attributes;
12
use proc_macro2::{Span, TokenStream};
23
use quote::quote;
34
use serde_derive_internals::{
@@ -6,9 +7,21 @@ use serde_derive_internals::{
67
};
78
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Error, Fields, Lifetime, Result};
89

10+
mod attributes;
11+
912
#[cfg(test)]
1013
mod tests;
1114

15+
// TODO: support wrappers `Wrapper(Inner)` and `Wrapper<T>(T)`.
16+
// TODO: support the `nested` attribute.
17+
#[proc_macro_derive(Row, attributes(clickhouse))]
18+
pub fn row(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
19+
let input = parse_macro_input!(input as DeriveInput);
20+
row_impl(input)
21+
.unwrap_or_else(Error::into_compile_error)
22+
.into()
23+
}
24+
1225
fn column_names(data: &DataStruct, cx: &Ctxt, container: &Container) -> Result<TokenStream> {
1326
Ok(match &data.fields {
1427
Fields::Named(fields) => {
@@ -36,19 +49,11 @@ fn column_names(data: &DataStruct, cx: &Ctxt, container: &Container) -> Result<T
3649
})
3750
}
3851

39-
// TODO: support wrappers `Wrapper(Inner)` and `Wrapper<T>(T)`.
40-
// TODO: support the `nested` attribute.
41-
// TODO: support the `crate` attribute.
42-
#[proc_macro_derive(Row)]
43-
pub fn row(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
44-
let input = parse_macro_input!(input as DeriveInput);
45-
row_impl(input)
46-
.unwrap_or_else(Error::into_compile_error)
47-
.into()
48-
}
49-
5052
fn row_impl(input: DeriveInput) -> Result<TokenStream> {
5153
let cx = Ctxt::new();
54+
55+
let Attributes { crate_path } = input.attrs[..].try_into()?;
56+
5257
let container = Container::from_ast(&cx, &input);
5358
let name = input.ident;
5459

@@ -89,14 +94,13 @@ fn row_impl(input: DeriveInput) -> Result<TokenStream> {
8994

9095
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
9196

92-
// TODO: replace `clickhouse` with `::clickhouse` here.
9397
Ok(quote! {
9498
#[automatically_derived]
95-
impl #impl_generics clickhouse::Row for #name #ty_generics #where_clause {
99+
impl #impl_generics #crate_path::Row for #name #ty_generics #where_clause {
96100
const NAME: &'static str = stringify!(#name);
97101
const COLUMN_NAMES: &'static [&'static str] = #column_names;
98-
const COLUMN_COUNT: usize = <Self as clickhouse::Row>::COLUMN_NAMES.len();
99-
const KIND: clickhouse::_priv::RowKind = clickhouse::_priv::RowKind::Struct;
102+
const COLUMN_COUNT: usize = <Self as #crate_path::Row>::COLUMN_NAMES.len();
103+
const KIND: #crate_path::_priv::RowKind = #crate_path::_priv::RowKind::Struct;
100104

101105
type Value<'__v> = #value;
102106
}

derive/src/tests/cases.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ fn simple_owned_row() {
1414
a: i32,
1515
b: String,
1616
}
17-
};
17+
}
1818
}
1919

2020
#[test]
@@ -25,23 +25,23 @@ fn generic_owned_row() {
2525
a: i32,
2626
b: T,
2727
}
28-
};
28+
}
2929

3030
render! {
3131
#[derive(Row)]
3232
struct Sample<A, B> {
3333
a: A,
3434
b: B,
3535
}
36-
};
36+
}
3737

3838
render! {
3939
#[derive(Row)]
4040
struct Sample<T> where T: Clone {
4141
a: i32,
4242
b: T,
4343
}
44-
};
44+
}
4545
}
4646

4747
#[test]
@@ -52,7 +52,7 @@ fn simple_borrowed_row() {
5252
a: i32,
5353
b: &'a str,
5454
}
55-
};
55+
}
5656
}
5757

5858
#[test]
@@ -63,23 +63,23 @@ fn generic_borrowed_row() {
6363
a: i32,
6464
b: &'a T,
6565
}
66-
};
66+
}
6767

6868
render! {
6969
#[derive(Row)]
7070
struct Sample<'a, A, B> {
7171
a: A,
7272
b: &'a B,
7373
}
74-
};
74+
}
7575

7676
render! {
7777
#[derive(Row)]
7878
struct Sample<'a, T> where T: Clone {
7979
a: i32,
8080
b: &'a T,
8181
}
82-
};
82+
}
8383
}
8484

8585
#[test]
@@ -93,7 +93,7 @@ fn serde_rename() {
9393
#[serde(rename = "items.b")]
9494
items_b: Vec<u32>,
9595
}
96-
};
96+
}
9797
}
9898

9999
#[test]
@@ -105,7 +105,7 @@ fn serde_skip_serializing() {
105105
#[serde(skip_serializing)]
106106
b: u32,
107107
}
108-
};
108+
}
109109
}
110110

111111
#[test]
@@ -117,5 +117,17 @@ fn serde_skip_deserializing() {
117117
#[serde(skip_deserializing)]
118118
b: u32,
119119
}
120-
};
120+
}
121+
}
122+
123+
#[test]
124+
fn crate_attribute() {
125+
render! {
126+
#[derive(Row)]
127+
#[clickhouse(crate = "foo")]
128+
struct Foo {
129+
a: u32,
130+
b: u32,
131+
}
132+
}
121133
}

0 commit comments

Comments
 (0)