Skip to main content

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}