Skip to main content

ngb_sqlbuilder/
lib.rs

1use tokio_postgres::types::ToSql;
2
3// type Parameter = (dyn ToSql + Sync);
4
5mod builder;
6mod clause;
7mod condition;
8mod delete;
9mod insert;
10#[allow(dead_code)]
11mod select;
12mod update;
13
14mod column;
15#[cfg(feature = "execution")]
16pub mod execution;
17
18// pub use builder::*;
19pub use clause::*;
20pub use condition::*;
21pub use delete::*;
22pub use insert::*;
23pub use select::*;
24pub use update::*;
25// pub use column::*;
26
27pub struct Raw;
28// #[derive(Debug)]
29pub struct Column;
30// #[derive(Debug)]
31pub struct Select;
32// #[derive(Debug)]
33pub struct From;
34// #[derive(Debug)]
35pub struct Table;
36// #[derive(Debug)]
37// pub struct Final;
38// #[derive(Debug)]
39pub struct Join;
40pub struct Condition;
41pub struct Paging;
42
43pub trait SqlClause<'q> {
44    fn unwrap(self) -> (String, Vec<&'q (dyn ToSql + Sync)>);
45    fn unwrap_ref(&self) -> (&str, &[&'q (dyn ToSql + Sync)]);
46}
47pub trait Build<'q> {
48    fn build(self) -> (String, Vec<&'q (dyn ToSql + Sync)>);
49    // fn build_ref(&self) -> (&str, &[&'q (dyn ToSql + Sync)]);
50    // fn inspect(&self);
51}
52
53fn format_col(name: &str) -> String {
54    let mut cast_split = name.split("::");
55    let name = cast_split.next().unwrap_or_default();
56    let mut result = match name.chars().position(|c| c == '.') {
57        Some(dot) => format!("{}.\"{}\"", &name[..dot], name[dot + 1..].trim()),
58        None => format!("\"{}\"", name),
59    };
60    if let Some(cast) = cast_split.next() {
61        result.push_str("::");
62        result.push_str(&cast);
63        // result.push_str(&format!("::{}", cast).as_str())
64    }
65    result
66}
67fn append_wrap(sql: &mut String, value: &str) {
68    sql.push('"');
69    sql.push_str(value);
70    sql.push('"');
71}
72fn append_col(sql: &mut String, expr: &str) {
73    let mut cast_split = expr.split("::");
74    let name = cast_split.next().unwrap_or_default();
75    match name.chars().position(|c| c == '.') {
76        Some(dot) => {
77            sql.push_str(&name[..dot]);
78            sql.push('.');
79            append_wrap(sql, &name[dot + 1..]);
80            // format!("{}.\"{}\"", &name[..dot], name[dot + 1..].trim())
81        }
82        None => {
83            append_wrap(sql, name);
84            // format!("\"{}\"", name)
85        }
86    };
87    if let Some(cast) = cast_split.next() {
88        sql.push_str("::");
89        sql.push_str(cast);
90        // result.push_str(&format!("::{}", cast).as_str())
91    }
92}
93fn split_alias(value: &str) -> (&str, Option<&str>) {
94    let mut split_as = value.split(" as ");
95    let col_name = split_as.next().unwrap_or_default();
96    let alias = split_as.next();
97    (col_name, alias)
98}
99fn format_prim(expr: &str) -> String {
100    // let name = name.trim();
101    // let (col, alias) = {
102    //     let mut split_as = name.split(" as ");
103    //     let col_name = split_as.next().unwrap_or_default();
104    //     let alias = split_as.next();
105    //     (col_name, alias)
106    // };
107    let (col, alias) = split_alias(expr.trim());
108
109    let mut col_name = format_col(col);
110
111    if let Some(a) = alias {
112        // col_name.push_str(" as ");
113        col_name.push(' ');
114        if a.chars().any(char::is_uppercase) {
115            col_name.push_str(&wrap(a));
116            // col_name.push_str(&format!(" as \"{}\"", a));
117        } else {
118            col_name.push_str(&a);
119            // col_name.push_str(&format!(" as {}", a));
120        }
121    }
122    col_name
123}
124fn append_prim(sql: &mut String, expr: &str) {
125    let (col, alias) = split_alias(expr.trim());
126
127    append_col(sql, col.trim());
128
129    if let Some(a) = alias {
130        // sql.push_str(" as ");
131        sql.push(' ');
132        if a.chars().any(char::is_uppercase) {
133            append_wrap(sql, a.trim());
134        } else {
135            sql.push_str(a.trim());
136        }
137    }
138}
139fn __cols(sql: &mut String, columns: &[&str]) {
140    let mut not_first = false;
141    for col in columns {
142        if not_first {
143            sql.push_str(", ");
144        }
145        not_first = true;
146        append_prim(sql, col);
147        // sql.push_str(&format_prim(col));
148    }
149}
150pub fn cols<'q>(columns: &[&str]) -> Clause<'q, Column> {
151    let mut sql = String::new();
152    __cols(&mut sql, columns);
153    Clause::new(sql, vec![])
154}
155pub fn func<'q, T, C>(name: &str, clause: Clause<'q, T>) -> Clause<'q, C> {
156    let mut sql = String::from(name);
157    let (cl_sql, cl_params) = clause.unwrap();
158    sql.push('(');
159    sql.push_str(&cl_sql);
160    sql.push(')');
161    Clause::new(sql, cl_params)
162}
163pub fn func_col<'q>(func_name: &str, column: &str) -> Clause<'q, Column> {
164    func(func_name, col(column))
165}
166/// Aggregate average `AVG(column)`. By default, this function returns `numeric` type.
167///
168/// # Arguments
169///
170/// * `column`:
171///
172/// returns: `Clause<Column>`
173///
174/// # Examples
175///
176/// ```
177/// use ngb_sqlbuilder::avg_col;
178///
179/// avg_col("t.ColName")
180/// // SQL: avg(t."ColName")
181/// ```
182pub fn avg_col(column: &str) -> Clause<'_, Column> {
183    func("avg", col(column))
184}
185/// Aggregate function average `AVG(column)` and cast it to double precision
186///
187/// # Arguments
188///
189/// * `column`:
190///
191/// returns: `Clause<Column>`
192///
193/// # Examples
194///
195/// ```
196/// use ngb_sqlbuilder::avg_col_f64;
197///
198/// avg_col_f64("t.ColName")
199/// // SQL: avg(t."ColName")::double precision
200/// ```
201pub fn avg_col_f64(column: &str) -> Clause<'_, Column> {
202    let mut sql = String::from("avg(");
203    append_col(&mut sql, column);
204    sql.push_str(")::double precision");
205    Clause::new(sql, vec![])
206}
207pub fn max_col(column: &str) -> Clause<'_, Column> {
208    func("max", col(column))
209}
210pub fn min_col(column: &str) -> Clause<'_, Column> {
211    func("min", col(column))
212}
213pub fn sum_col(column: &str) -> Clause<'_, Column> {
214    func("sum", col(column))
215}
216fn wrap(s: &str) -> String {
217    format!("\"{}\"", s)
218}
219pub fn extract_col<'q>(field: &str, from: &str) -> Clause<'q, Column> {
220    let mut sql = String::from("extract(");
221    sql.push_str(field);
222    sql.push_str(" from ");
223    sql.push_str(&format_col(from));
224    sql.push(')');
225    Clause::new(sql, vec![])
226}
227
228pub fn raw<'q, T>(sql: &str, values: &[&'q (dyn ToSql + Sync)]) -> Clause<'q, T> {
229    Clause::new(sql.to_string(), values.to_vec())
230}
231
232fn __and_col<'q, T>(
233    clause: Clause<'q, T>,
234    name: &str,
235    condition: Clause<'q, Condition>,
236) -> Clause<'q, T> {
237    let (mut sql, mut params) = clause.unwrap();
238    let (cond_sql, cond_params) = condition.unwrap();
239    sql.push_str(" AND ");
240    // sql.push_str(&format_col(name));
241    append_col(&mut sql, name);
242    sql.push_str(&cond_sql);
243    params.extend(cond_params);
244    Clause::new(sql, params)
245}
246fn __or_col<'q, T>(
247    clause: Clause<'q, T>,
248    name: &str,
249    condition: Clause<'q, Condition>,
250) -> Clause<'q, T> {
251    let (mut sql, mut params) = clause.unwrap();
252    let (cond_sql, cond_params) = condition.unwrap();
253    sql.push_str(" OR ");
254    // sql.push_str(&format_col(name));
255    append_col(&mut sql, name);
256    sql.push_str(&cond_sql);
257    params.extend(cond_params);
258    Clause::new(sql, params)
259}
260
261// fn __and_cond<'q, T>(clause: Clause<'q, T>, condition: Clause<'q, Condition>) -> Clause<'q, T> {
262//     let (mut sql, mut params) = clause.unwrap();
263//     let (cond_sql, cond_params) = condition.unwrap();
264//     sql.push_str(" AND ");
265//     sql.push_str(&cond_sql);
266//     params.extend(cond_params);
267//     Clause::new(sql, params)
268// }
269// fn __or_cond<'q, T>(clause: Clause<'q, T>, condition: Clause<'q, Condition>) -> Clause<'q, T> {
270//     let (mut sql, mut params) = clause.unwrap();
271//     let (cond_sql, cond_params) = condition.unwrap();
272//     sql.push_str(" OR ");
273//     sql.push_str(&cond_sql);
274//     params.extend(cond_params);
275//     Clause::new(sql, params)
276// }
277
278fn __and_nest<'q, T1, T2, R>(clause: Clause<'q, T1>, condition: Clause<'q, T2>) -> Clause<'q, R> {
279    let (mut sql, mut params) = clause.unwrap();
280    sql.push_str(" AND (");
281    sql.push_str(&condition.sql);
282    sql.push(')');
283    params.extend(condition.params);
284    Clause::new(sql, params)
285}
286fn __or_nest<'q, T1, T2, R>(clause: Clause<'q, T1>, condition: Clause<'q, T2>) -> Clause<'q, R> {
287    let (mut sql, mut params) = clause.unwrap();
288    sql.push_str(" OR (");
289    sql.push_str(&condition.sql);
290    sql.push(')');
291    params.extend(condition.params);
292    Clause::new(sql, params)
293}
294fn __condition<'q, T, C>(
295    connector: &str,
296    clause: Clause<'q, T>,
297    condition: Clause<'q, Condition>,
298) -> Clause<'q, C> {
299    let (mut sql, mut params) = clause.unwrap();
300    let (cond_sql, cond_params) = condition.unwrap();
301    sql.push_str(connector);
302    sql.push_str(&cond_sql);
303    params.extend_from_slice(&cond_params);
304    Clause::new(sql, params)
305}
306
307const LOGIC_CONN_NONE: &str = "";
308const LOGIC_CONN_AND: &str = " AND ";
309const LOGIC_CONN_OR: &str = " OR ";