clickhouse_client/query/
stmt.rs

1//! Query statement
2
3use crate::value::{ChValue, Value};
4
5/// SQQL query placeholder
6const QUERY_PARAM_PLACEHOLDER: &str = "[??]";
7
8/// Extension trait for SQL statements
9pub(crate) trait SqlStatement: Sized {
10    /// Binds the statement to a string
11    fn bind_str(self, value: &str) -> Self;
12
13    /// Binds the statement to a value
14    fn bind_val(self, value: impl ChValue) -> Self {
15        self.bind_str(&value.into_ch_value().to_sql_string())
16    }
17
18    /// Binds the statement to a list of strings
19    fn bind_str_list(self, values: Vec<&str>) -> Self {
20        self.bind_str(values.join(", ").as_str())
21    }
22
23    /// Binds the statement to a list of [Value]s
24    fn bind_val_list(self, values: Vec<Value>) -> Self {
25        self.bind_str(
26            values
27                .into_iter()
28                .map(|v| v.to_sql_string())
29                .collect::<Vec<_>>()
30                .join(", ")
31                .as_str(),
32        )
33    }
34}
35
36impl SqlStatement for String {
37    fn bind_str(self, value: &str) -> String {
38        self.replacen(QUERY_PARAM_PLACEHOLDER, value, 1)
39    }
40}
41
42/// SQL WHERE condition
43#[derive(Debug, Clone, Default)]
44pub struct Where {
45    clause: String,
46}
47
48impl Where {
49    /// Creates a new WHERE condition
50    pub fn new(col: &str, operator: &str, value: &str) -> Self {
51        let mut w = Self::default();
52        w.add_condition("AND", col, operator, value);
53        w
54    }
55
56    /// Creates a new WHERE condition with a [Value]
57    pub fn with_val(col: &str, operator: &str, value: impl ChValue) -> Self {
58        Self::new(
59            col,
60            operator,
61            value.into_ch_value().to_sql_string().as_str(),
62        )
63    }
64
65    /// Adds an AND condition
66    pub fn and(mut self, col: &str, operator: &str, value: &str) -> Self {
67        self.add_condition("AND", col, operator, value);
68        self
69    }
70
71    /// Adds an OR condition
72    pub fn or(mut self, col: &str, operator: &str, value: &str) -> Self {
73        self.add_condition("OR", col, operator, value);
74        self
75    }
76
77    /// Adds an AND condition
78    pub fn and_val(mut self, col: &str, operator: &str, value: impl ChValue) -> Self {
79        self.add_condition_val("AND", col, operator, value);
80        self
81    }
82
83    /// Adds an OR condition
84    pub fn or_val(mut self, col: &str, operator: &str, value: impl ChValue) -> Self {
85        self.add_condition_val("OR", col, operator, value);
86        self
87    }
88
89    /// Adds a condition
90    fn add_condition(&mut self, prefix: &str, col: &str, operator: &str, value: &str) {
91        let value = if self.clause.is_empty() {
92            format!("{} {} {}", col, operator, value)
93        } else {
94            format!("{} {} {} {} {}", self.clause, prefix, col, operator, value)
95        };
96        self.clause = value;
97    }
98
99    /// Adds a condition with a [Value]
100    fn add_condition_val(&mut self, prefix: &str, col: &str, operator: &str, value: impl ChValue) {
101        self.add_condition(
102            prefix,
103            col,
104            operator,
105            value.into_ch_value().to_sql_string().as_str(),
106        );
107    }
108}
109
110impl std::fmt::Display for Where {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        if self.clause.is_empty() {
113            write!(f, "")
114        } else {
115            write!(f, " WHERE {}", self.clause)
116        }
117    }
118}