clickhouse_arrow/
query.rs

1use std::fmt;
2
3use uuid::Uuid;
4
5use crate::io::ClickHouseWrite;
6use crate::prelude::SettingValue;
7use crate::{Result, Settings};
8
9/// An internal representation of a query id, meant to reduce costs when tracing, passing around,
10/// and converting to strings.
11#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
12pub struct Qid(Uuid);
13
14impl Default for Qid {
15    fn default() -> Self { Self::new() }
16}
17
18impl Qid {
19    /// Generate a new `v4` [`Uuid`]
20    pub fn new() -> Self { Self(Uuid::new_v4()) }
21
22    /// Take the inner [`Uuid`]
23    pub fn into_inner(self) -> Uuid { self.0 }
24
25    // Convert to 32-char hex string, no heap allocation
26    pub(crate) async fn write_id<W: ClickHouseWrite>(&self, writer: &mut W) -> Result<()> {
27        let mut buffer = [0u8; 32];
28        let hex = self.0.as_simple().encode_lower(&mut buffer);
29        writer.write_string(hex).await
30    }
31
32    // Helper to calculate a determinstic hash from a qid
33    #[cfg_attr(not(feature = "inner_pool"), expect(unused))]
34    pub(crate) fn key(self) -> usize {
35        self.into_inner().as_bytes().iter().copied().map(usize::from).sum::<usize>()
36    }
37}
38
39impl<T: Into<Qid>> From<Option<T>> for Qid {
40    fn from(value: Option<T>) -> Self {
41        match value {
42            Some(v) => v.into(),
43            None => Qid::default(),
44        }
45    }
46}
47
48impl From<Uuid> for Qid {
49    fn from(id: Uuid) -> Self { Self(id) }
50}
51
52impl fmt::Display for Qid {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        // Use as_simple() for 32-char hex, no heap allocation
55        write!(f, "{}", self.0.as_simple())
56    }
57}
58
59/// Type alias to help distinguish settings from params
60pub type ParamValue = SettingValue;
61
62/// Represent parameters that can be passed to bind values during queries.
63///
64/// `ClickHouse` has very specific syntax for how it manages query parameters. Refer to their docs
65/// for more information.
66///
67/// See:
68/// [Queries with parameters](https://clickhouse.com/docs/interfaces/cli#cli-queries-with-parameters)
69#[derive(Debug, Clone, Default, PartialEq)]
70pub struct QueryParams(pub Vec<(String, ParamValue)>);
71
72impl<T, K, S> From<T> for QueryParams
73where
74    T: IntoIterator<Item = (K, S)>,
75    K: Into<String>,
76    ParamValue: From<S>,
77{
78    fn from(value: T) -> Self {
79        Self(value.into_iter().map(|(k, v)| (k.into(), v.into())).collect())
80    }
81}
82
83impl<K, S> FromIterator<(K, S)> for QueryParams
84where
85    K: Into<String>,
86    ParamValue: From<S>,
87{
88    fn from_iter<T>(iter: T) -> Self
89    where
90        T: IntoIterator<Item = (K, S)>,
91    {
92        iter.into_iter().collect()
93    }
94}
95
96impl From<QueryParams> for Settings {
97    /// Helpful to serialize params when dispatching a query
98    fn from(value: QueryParams) -> Settings { value.0.into_iter().collect() }
99}
100
101/// Represents a parsed query.
102///
103/// In the future this will enable better validation of queries, possibly
104/// saving a roundtrip to the database.
105#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
106#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
107pub struct ParsedQuery(pub(crate) String);
108
109impl std::ops::Deref for ParsedQuery {
110    type Target = String;
111
112    fn deref(&self) -> &Self::Target { &self.0 }
113}
114
115impl fmt::Display for ParsedQuery {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) }
117}
118
119impl From<String> for ParsedQuery {
120    fn from(q: String) -> ParsedQuery { ParsedQuery(q.trim().to_string()) }
121}
122
123impl From<&str> for ParsedQuery {
124    fn from(q: &str) -> ParsedQuery { ParsedQuery(q.trim().to_string()) }
125}
126
127impl From<&String> for ParsedQuery {
128    fn from(q: &String) -> ParsedQuery { ParsedQuery(q.trim().to_string()) }
129}