clickhouse/row.rs
1use crate::sql;
2use serde::{Deserialize, Serialize};
3
4#[doc(hidden)]
5#[derive(Debug, Clone, PartialEq)]
6pub enum RowKind {
7 Primitive,
8 Struct,
9 Tuple,
10 Vec,
11}
12
13/// Represents a row that can be used in queries.
14///
15/// Implemented for:
16/// * All [`#[derive(Row)]`][row-derive] items
17/// * `(P1, P2, ...)` where P* is a primitive type or string
18///
19/// Do not implement this trait directly, use [`#[derive(Row)]`][row-derive] instead.
20///
21/// In order to write a generic code over rows, check
22/// * [`RowRead`] for reading queries.
23/// * [`RowWrite`] for writing queries.
24/// * [`RowOwned`] for rows that do not hold any references.
25///
26/// [row-derive]: derive@crate::Row
27pub trait Row {
28 // NOTE: all properties are unstable and, hence, not following semver.
29
30 #[doc(hidden)]
31 const NAME: &'static str;
32 // TODO: different list for SELECT/INSERT (de/ser)
33 #[doc(hidden)]
34 const COLUMN_NAMES: &'static [&'static str];
35 #[doc(hidden)]
36 const COLUMN_COUNT: usize;
37 #[doc(hidden)]
38 const KIND: RowKind;
39 #[doc(hidden)]
40 type Value<'a>: Row;
41}
42
43/// Represents a row that can be read from the database.
44///
45/// This trait is implemented automatically for all `Row + Deserialize` types.
46///
47/// The main purpose of this trait is to simplify writing generic code.
48///
49/// # Examples
50/// Let's say we want to iterate over rows of a provided table in a generic way
51/// and apply a function to each row:
52/// ```
53/// use clickhouse::{Client, RowOwned, RowRead, sql::Identifier, error::Result};
54///
55/// async fn iterate<R: RowOwned + RowRead>(
56/// table: &str,
57/// client: Client,
58/// f: impl Fn(R),
59/// ) -> Result<()> {
60/// let mut cursor = client
61/// .query("SELECT ?fields FROM ?")
62/// .bind(Identifier(table))
63/// .fetch::<R>()?;
64///
65/// while let Some(row) = cursor.next().await? {
66/// f(row);
67/// }
68///
69/// Ok(())
70/// }
71///
72/// // Usage
73///
74/// #[derive(clickhouse::Row, serde::Deserialize)]
75/// struct SomeRow { a: u32, b: String }
76/// fn callback(row: SomeRow) {}
77///
78/// # async fn usage(client: Client) -> Result<()> {
79/// iterate::<SomeRow>("table", client, callback).await?;
80/// # Ok(())
81/// # }
82/// ```
83///
84/// However, this code works only for rows that do not hold any references.
85/// To support also rows that borrows data from cursor (avoiding extra allocations),
86/// the signature should be changed to less intuitive one:
87/// ```
88/// # use clickhouse::{Client, Row, RowRead, sql::Identifier, error::Result};
89/// async fn iterate<R: Row + RowRead>( //<<< Row instead of RowOwned
90/// table: &str,
91/// client: Client,
92/// f: impl Fn(R::Value<'_>), //<<< R::Value instead of R
93/// ) -> Result<()> {
94/// /* same code */
95/// # let mut cursor = client.query("SELECT ?fields FROM ?").bind(Identifier(table)).fetch::<R>()?;
96/// # while let Some(row) = cursor.next().await? { f(row); }
97/// # Ok(())
98/// }
99///
100/// // Usage
101///
102/// #[derive(Row, serde::Deserialize)]
103/// struct SomeRow<'a> { a: u32, b: &'a str }
104/// fn callback(row: SomeRow<'_>) {}
105///
106/// # async fn usage(client: Client) -> Result<()> {
107/// iterate::<SomeRow<'_>>("table", client, callback).await?;
108/// # Ok(())
109/// # }
110/// ```
111///
112/// We use [`Row`] instead of [`RowOwned`] and `R::Value<'_>` instead of `R` here.
113/// The last one is actually the same `R` but with a changed lifetime restricted
114/// to the cursor.
115pub trait RowRead: for<'a> Row<Value<'a>: Deserialize<'a>> {}
116impl<R> RowRead for R where R: for<'a> Row<Value<'a>: Deserialize<'a>> {}
117
118/// Represents a row that can be written into the database.
119///
120/// This trait is implemented automatically for all `Row + Serialize` types.
121///
122/// The main purpose of this trait is to simplify writing generic code.
123///
124/// # Examples
125/// Let's say we want to write a function that insert the provided batch of rows:
126/// ```
127/// use clickhouse::{Client, RowOwned, RowWrite, error::Result};
128///
129/// async fn write_batch<R: RowOwned + RowWrite>(
130/// table: &str,
131/// client: Client,
132/// data: &[R],
133/// ) -> Result<()> {
134/// let mut insert = client.insert::<R>(table).await?;
135/// for row in data {
136/// insert.write(row).await?;
137/// }
138/// insert.end().await
139/// }
140///
141/// // Usage
142///
143/// #[derive(clickhouse::Row, serde::Serialize)]
144/// struct SomeRow { a: u32, b: String }
145///
146/// # async fn usage(client: Client) -> Result<()> {
147/// write_batch::<SomeRow>("table", client, &[/* ... */]).await?;
148/// # Ok(())
149/// # }
150/// ```
151///
152/// However, this code works only for rows that do not hold any references.
153/// To support also rows that borrows data avoiding extra allocations,
154/// the signature should be changed to less intuitive one:
155/// ```
156/// # use clickhouse::{Client, Row, RowWrite, error::Result};
157/// async fn write_batch<R: Row + RowWrite>( //<<< Row instead of RowOwned
158/// table: &str,
159/// client: Client,
160/// data: &[R::Value<'_>], //<<< R::Value instead of R
161/// ) -> Result<()> {
162/// /* same code */
163/// # let mut insert = client.insert::<R>(table).await?;
164/// # for row in data { insert.write(row).await?; }
165/// # insert.end().await
166/// }
167///
168/// // Usage
169///
170/// #[derive(Row, serde::Serialize)]
171/// struct SomeRow<'a> { a: u32, b: &'a str }
172///
173/// # async fn usage(client: Client) -> Result<()> {
174/// let (first_b, second_b) = ("first", "second");
175/// let rows = [SomeRow { a: 0, b: first_b }, SomeRow { a: 1, b: second_b }];
176/// write_batch::<SomeRow>("table", client, &rows).await?;
177/// # Ok(())
178/// # }
179/// ```
180///
181/// We use [`Row`] instead of [`RowOwned`] and `R::Value<'_>` instead of `R` here.
182/// The last one is actually the same `R` but with a changed lifetime restricted to data.
183pub trait RowWrite: for<'a> Row<Value<'a>: Serialize> {}
184impl<R> RowWrite for R where R: for<'a> Row<Value<'a>: Serialize> {}
185
186/// Represents a row not holding any references.
187///
188/// This trait is implemented automatically and useful for writing generic code.
189/// Usually used with [`RowRead`] and [`RowWrite`].
190pub trait RowOwned: 'static + for<'a> Row<Value<'a> = Self> {}
191impl<R> RowOwned for R where R: 'static + for<'a> Row<Value<'a> = R> {}
192
193// Actually, it's not public now.
194#[doc(hidden)]
195pub trait Primitive {}
196
197impl<T: Primitive> Primitive for Option<T> {}
198
199macro_rules! impl_primitive_for {
200 ($t:ty, $($other:tt)*) => {
201 impl Primitive for $t {}
202 impl_primitive_for!($($other)*);
203 };
204 () => {};
205}
206
207// TODO: char? &str? SocketAddr? Path? Duration? NonZero*?
208impl_primitive_for![
209 bool,
210 String,
211 u8,
212 u16,
213 u32,
214 u64,
215 u128,
216 usize,
217 i8,
218 i16,
219 i32,
220 i64,
221 i128,
222 isize,
223 f32,
224 f64,
225 bytes::Bytes,
226 bytes::BytesMut,
227];
228
229macro_rules! count_tokens {
230 () => { 0 };
231 ($head:tt $($tail:tt)*) => { 1 + count_tokens!($($tail)*) };
232}
233
234/// Two forms are supported:
235/// * (P1, P2, ...)
236/// * (SomeRow, P1, P2, ...)
237///
238/// The second one is useful for queries like
239/// `SELECT ?fields, count() FROM ... GROUP BY ?fields`.
240macro_rules! impl_row_for_tuple {
241 ($i:ident $($other:ident)+) => {
242 impl<$i: Row, $($other: Primitive),+> Row for ($i, $($other),+) {
243 const NAME: &'static str = $i::NAME;
244 const COLUMN_NAMES: &'static [&'static str] = $i::COLUMN_NAMES;
245 const COLUMN_COUNT: usize = $i::COLUMN_COUNT + count_tokens!($($other)*);
246 const KIND: RowKind = RowKind::Tuple;
247
248 type Value<'a> = Self;
249 }
250
251 impl_row_for_tuple!($($other)+);
252 };
253 ($i:ident) => {};
254}
255
256// TODO: revise this?
257impl Primitive for () {}
258
259impl<P: Primitive> Row for P {
260 const NAME: &'static str = stringify!(P);
261 const COLUMN_NAMES: &'static [&'static str] = &[];
262 const COLUMN_COUNT: usize = 1;
263 const KIND: RowKind = RowKind::Primitive;
264
265 type Value<'a> = Self;
266}
267
268impl_row_for_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8);
269
270impl<T> Row for Vec<T> {
271 const NAME: &'static str = "Vec";
272 const COLUMN_NAMES: &'static [&'static str] = &[];
273 const COLUMN_COUNT: usize = 1;
274 const KIND: RowKind = RowKind::Vec;
275
276 type Value<'a> = Self;
277}
278
279/// Collects all field names in depth and joins them with comma.
280pub(crate) fn join_column_names<R: Row>() -> Option<String> {
281 if R::COLUMN_NAMES.is_empty() {
282 return None;
283 }
284
285 let out = R::COLUMN_NAMES
286 .iter()
287 .enumerate()
288 .fold(String::new(), |mut res, (idx, name)| {
289 if idx > 0 {
290 res.push(',');
291 }
292 sql::escape::identifier(name, &mut res).expect("impossible");
293 res
294 });
295
296 Some(out)
297}
298
299#[cfg(test)]
300mod tests {
301 use crate::Row;
302
303 use super::*;
304
305 #[test]
306 fn it_grabs_simple_struct() {
307 #[derive(Row)]
308 #[clickhouse(crate = "crate")]
309 #[allow(dead_code)]
310 struct Simple1 {
311 one: u32,
312 }
313
314 #[derive(Row)]
315 #[clickhouse(crate = "crate")]
316 #[allow(dead_code)]
317 struct Simple2 {
318 one: u32,
319 two: u32,
320 }
321
322 assert_eq!(join_column_names::<Simple1>().unwrap(), "`one`");
323 assert_eq!(join_column_names::<Simple2>().unwrap(), "`one`,`two`");
324 }
325
326 #[test]
327 fn it_grabs_mix() {
328 #[derive(Row)]
329 #[clickhouse(crate = "crate")]
330 struct SomeRow {
331 _a: u32,
332 }
333
334 assert_eq!(join_column_names::<(SomeRow, u32)>().unwrap(), "`_a`");
335 }
336
337 #[test]
338 fn it_supports_renaming() {
339 use serde::Serialize;
340
341 #[derive(Row, Serialize)]
342 #[clickhouse(crate = "crate")]
343 #[allow(dead_code)]
344 struct TopLevel {
345 #[serde(rename = "two")]
346 one: u32,
347 }
348
349 assert_eq!(join_column_names::<TopLevel>().unwrap(), "`two`");
350 }
351
352 #[test]
353 fn it_skips_serializing() {
354 use serde::Serialize;
355
356 #[derive(Row, Serialize)]
357 #[clickhouse(crate = "crate")]
358 #[allow(dead_code)]
359 struct TopLevel {
360 one: u32,
361 #[serde(skip_serializing)]
362 two: u32,
363 }
364
365 assert_eq!(join_column_names::<TopLevel>().unwrap(), "`one`");
366 }
367
368 #[test]
369 fn it_skips_deserializing() {
370 use serde::Deserialize;
371
372 #[derive(Row, Deserialize)]
373 #[clickhouse(crate = "crate")]
374 #[allow(dead_code)]
375 struct TopLevel {
376 one: u32,
377 #[serde(skip_deserializing)]
378 two: u32,
379 }
380
381 assert_eq!(join_column_names::<TopLevel>().unwrap(), "`one`");
382 }
383
384 #[test]
385 fn it_rejects_other() {
386 #[allow(dead_code)]
387 #[derive(Row)]
388 #[clickhouse(crate = "crate")]
389 struct NamedTuple(u32, u32);
390
391 assert_eq!(join_column_names::<u32>(), None);
392 assert_eq!(join_column_names::<(u32, u64)>(), None);
393 assert_eq!(join_column_names::<NamedTuple>(), None);
394 }
395
396 #[test]
397 fn it_handles_raw_identifiers() {
398 use serde::Serialize;
399
400 #[derive(Row, Serialize)]
401 #[clickhouse(crate = "crate")]
402 #[allow(dead_code)]
403 struct MyRow {
404 r#type: u32,
405 #[serde(rename = "if")]
406 r#match: u32,
407 }
408
409 assert_eq!(join_column_names::<MyRow>().unwrap(), "`type`,`if`");
410 }
411}