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    /// This method will call `println!("{:?}", &self)` to show temporary SQL result
60    pub fn debug(self) -> Self {
61        println!("{:?}", &self);
62        self
63    }
64}
65
66// impl<T1, T2> Into<Clause<'_, T2>> for Clause<'_, T1>  {
67//     fn into(self) -> Clause<'_, T2> {
68//         todo!()
69//     }
70// }
71
72impl<'q, T> Build<'q> for Clause<'q, T> {
73    /// Build and compile query into SQL syntax with numbered parameters
74    fn build(self) -> (String, Vec<&'q (dyn ToSql + Sync)>) {
75        // let init_capacity = self.sql.len() + self.params.len();
76        // let mut result = String::with_capacity(init_capacity);
77        // let mut start = 0;
78        // let mut count = 1;
79        // for (i, _) in self.sql.match_indices("$") {
80        //     result.push_str(&self.sql[start..i]);
81        //     result.push_str(&format!("${count}"));
82        //     count += 1;
83        //     start = i + 1;
84        // }
85        // result.push_str(&self.sql[start..]);
86        (__build_sql(&self.sql, self.params.len()), self.params)
87    }
88    // fn build_ref(&self) -> (&str, &[&'q (dyn ToSql + Sync)]) {
89    //     (&self.sql, &self.params)
90    // }
91    // fn inspect(&self){
92    //     let q = __build_sql(&self.sql, 0);
93    //     println!("{}", q);
94    // }
95}
96impl<'q, T> Display for Clause<'q, T> {
97    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
98        let sql = __build_sql(&self.sql, self.params.len());
99        write!(f, "{}", &sql)
100    }
101}
102impl<'q, T> Debug for Clause<'q, T> {
103    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
104        write!(f, "{}", self)
105    }
106}
107fn __build_sql(sql: &str, params_len: usize) -> String {
108    // let init_capacity = self.sql.len() + self.params.len();
109    let mut result = String::with_capacity(sql.len() + params_len);
110    let mut start = 0;
111    let mut count = 1;
112    for (i, _) in sql.match_indices("$") {
113        result.push_str(&sql[start..i]);
114        result.push_str(&format!("${count}"));
115        count += 1;
116        start = i + 1;
117    }
118    result.push_str(&sql[start..]);
119    result
120}