Skip to main content

clickhouse_types/
lib.rs

1//! # clickhouse-types
2//!
3//! This crate is required for `RowBinaryWithNamesAndTypes` struct definition validation,
4//! as it contains ClickHouse data types AST, as well as functions and utilities
5//! to parse the types out of the ClickHouse server response.
6//!
7//! Note that this crate is not intended for public usage,
8//! as it might introduce internal breaking changes not following semver.
9
10pub use crate::data_types::{Column, DataTypeNode};
11use crate::decoders::read_string;
12use crate::error::TypesError;
13use bytes::{Buf, BufMut};
14
15/// Exported for internal usage only.
16/// Do not use it directly in your code.
17pub use crate::leb128::put_leb128;
18pub use crate::leb128::read_leb128;
19
20/// ClickHouse data types AST and utilities to parse it from strings.
21pub mod data_types;
22/// Required decoders to parse the columns definitions from the header of the response.
23pub mod decoders;
24/// Error types for this crate.
25pub mod error;
26/// Utils for working with LEB128 encoding and decoding.
27pub mod leb128;
28
29/// Parses the columns definitions from the response in `RowBinaryWithNamesAndTypes` format.
30/// This is a mandatory step for this format, as it enables client-side data types validation.
31#[doc(hidden)]
32pub fn parse_rbwnat_columns_header(mut buffer: impl Buf) -> Result<Vec<Column>, TypesError> {
33    let num_columns = read_leb128(&mut buffer)?;
34    if num_columns == 0 {
35        return Err(TypesError::EmptyColumns);
36    }
37    let mut columns_names: Vec<String> = Vec::with_capacity(num_columns as usize);
38    for _ in 0..num_columns {
39        let column_name = read_string(&mut buffer)?;
40        columns_names.push(column_name);
41    }
42    let mut column_data_types: Vec<DataTypeNode> = Vec::with_capacity(num_columns as usize);
43    for _ in 0..num_columns {
44        let column_type = read_string(&mut buffer)?;
45        let data_type = DataTypeNode::new(&column_type)?;
46        column_data_types.push(data_type);
47    }
48    let columns = columns_names
49        .into_iter()
50        .zip(column_data_types)
51        .map(|(name, data_type)| Column::new(name, data_type))
52        .collect();
53    Ok(columns)
54}
55
56/// Having a table definition as a slice of [`Column`],
57/// encodes it into the `RowBinary` format, and puts it into the provided buffer.
58/// This is required to insert the data in `RowBinaryWithNamesAndTypes` format.
59#[doc(hidden)]
60pub fn put_rbwnat_columns_header(
61    columns: &[Column],
62    mut buffer: impl BufMut,
63) -> Result<(), TypesError> {
64    if columns.is_empty() {
65        return Err(TypesError::EmptyColumns);
66    }
67    put_leb128(&mut buffer, columns.len() as u64);
68    for column in columns {
69        put_leb128(&mut buffer, column.name.len() as u64);
70        buffer.put_slice(column.name.as_bytes());
71    }
72    for column in columns.iter() {
73        let data_type = column.data_type.to_string();
74        put_leb128(&mut buffer, data_type.len() as u64);
75        buffer.put_slice(data_type.as_bytes());
76    }
77    Ok(())
78}
79
80#[cfg(test)]
81mod test {
82    use super::*;
83    use crate::data_types::DataTypeNode;
84    use bytes::BytesMut;
85
86    #[test]
87    fn test_rbwnat_header_round_trip() {
88        let mut buffer = BytesMut::new();
89        let columns = vec![
90            Column::new("id".to_string(), DataTypeNode::Int32),
91            Column::new("name".to_string(), DataTypeNode::String),
92        ];
93        put_rbwnat_columns_header(&columns, &mut buffer).unwrap();
94        let parsed_columns = parse_rbwnat_columns_header(&mut buffer).unwrap();
95        assert_eq!(parsed_columns, columns);
96    }
97}