Skip to main content

ngb_sqlbuilder/
clause.rs

1use crate::{Build, SqlClause};
2use std::fmt::{Debug, Display, Formatter};
3use std::marker::PhantomData;
4use tokio_postgres::types::ToSql;
5
6// #[derive(Debug)]
7pub struct Clause<'q, T> {
8    pub(crate) sql: String,
9    pub(crate) params: Vec<&'q (dyn ToSql + Sync)>,
10    _ph: PhantomData<T>,
11}
12
13pub trait ToClause<'q> {
14    fn to_clause<C>(self) -> Clause<'q, C>;
15}
16impl<'q> ToClause<'q> for &str {
17    fn to_clause<C>(self) -> Clause<'q, C> {
18        Clause::new(String::from(self), vec![])
19    }
20}
21impl<T> Clone for Clause<'_, T> {
22    fn clone(&self) -> Self {
23        Self {
24            sql: self.sql.clone(),
25            params: self.params.clone(),
26            _ph: PhantomData,
27        }
28    }
29}
30impl<'q, T> Clause<'q, T> {
31    pub(crate) fn new(sql: String, params: Vec<&'q (dyn ToSql + Sync)>) -> Self {
32        Self {
33            sql,
34            params,
35            _ph: PhantomData,
36        }
37    }
38    // pub fn alias(mut self, name: &str) -> Self {
39    //     self.sql.push_str(format!(" as \"{}\"", name).as_str());
40    //     self
41    // }
42
43    pub fn this(self) -> Self {
44        self
45    }
46
47    /// Force convert clause type
48    pub fn into<C>(self) -> Clause<'q, C> {
49        Clause::new(self.sql, self.params)
50    }
51    pub fn combine_raw(self, raw_sql: &str, params: &[&'q (dyn ToSql + Sync)]) -> Self {
52        let (mut s, mut p) = self.unwrap();
53        s.push(' ');
54        s.push_str(&raw_sql.trim());
55        p.extend_from_slice(params);
56        Self::new(s, p)
57    }
58
59    pub fn union<C>(self, clause: Clause<'q, C>) -> Clause<'q, C> {
60        let (mut sql, mut params) = self.unwrap();
61        let (cl_sql, cl_params) = clause.unwrap();
62        sql.push_str(" UNION ");
63        sql.push_str(&cl_sql);
64        params.extend_from_slice(&cl_params);
65        Clause::new(sql, params)
66    }
67
68    /// This method will call `println!("{:?}", &self)` to show temporary SQL result
69    pub fn debug(self) -> Self {
70        println!("{:?}", &self);
71        self
72    }
73}
74
75// impl<T1, T2> Into<Clause<'_, T2>> for Clause<'_, T1>  {
76//     fn into(self) -> Clause<'_, T2> {
77//         todo!()
78//     }
79// }
80
81impl<'q, T> Build<'q> for Clause<'q, T> {
82    /// Build and compile query into SQL syntax with numbered parameters
83    fn build(self) -> (String, Vec<&'q (dyn ToSql + Sync)>) {
84        // let init_capacity = self.sql.len() + self.params.len();
85        // let mut result = String::with_capacity(init_capacity);
86        // let mut start = 0;
87        // let mut count = 1;
88        // for (i, _) in self.sql.match_indices("$") {
89        //     result.push_str(&self.sql[start..i]);
90        //     result.push_str(&format!("${count}"));
91        //     count += 1;
92        //     start = i + 1;
93        // }
94        // result.push_str(&self.sql[start..]);
95        (__build_sql(&self.sql, self.params.len()), self.params)
96    }
97    // fn build_ref(&self) -> (&str, &[&'q (dyn ToSql + Sync)]) {
98    //     (&self.sql, &self.params)
99    // }
100    // fn inspect(&self){
101    //     let q = __build_sql(&self.sql, 0);
102    //     println!("{}", q);
103    // }
104}
105impl<'q, T> Display for Clause<'q, T> {
106    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
107        let sql = __build_sql(&self.sql, self.params.len());
108        write!(f, "{}", &sql)
109    }
110}
111impl<'q, T> Debug for Clause<'q, T> {
112    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
113        write!(f, "{}", self)
114    }
115}
116fn __build_sql(sql: &str, params_len: usize) -> String {
117    // let init_capacity = self.sql.len() + self.params.len();
118    let mut result = String::with_capacity(sql.len() + params_len);
119    let mut start = 0;
120    let mut count = 1;
121    for (i, _) in sql.match_indices("$") {
122        result.push_str(&sql[start..i]);
123        result.push_str(&format!("${count}"));
124        count += 1;
125        start = i + 1;
126    }
127    result.push_str(&sql[start..]);
128    result
129}