Skip to main content

chain_builder/mysql/
mod.rs

1use serde_json::Value;
2
3// inner
4use crate::{
5    builder::ChainBuilder,
6    common::{
7        join_compiler::join_compiler,
8        method_compiler::{method_compiler_with_provider, ToSqlProvider},
9        statement_compiler::statement_compiler,
10    },
11};
12
13struct MySqlToSqlProvider;
14
15impl ToSqlProvider for MySqlToSqlProvider {
16    fn to_sql(&self, chain_builder: &ChainBuilder) -> (String, Vec<Value>) {
17        merge_to_sql(to_sql(chain_builder))
18    }
19}
20
21#[derive(Debug, Clone, Default)]
22pub struct ToSql {
23    pub statement: (String, Vec<Value>),
24    pub method: (String, Vec<Value>),
25    pub join: (String, Vec<Value>),
26    pub raw: (String, Vec<Value>),
27    pub sql_with: (String, Vec<Value>),
28    pub sql_union: (String, Vec<Value>),
29    pub limit: Option<usize>,
30    pub offset: Option<usize>,
31    pub group_by: Vec<String>,
32    pub group_by_raw: (String, Vec<Value>),
33    pub having: (String, Vec<Value>),
34    pub order_by: Vec<String>,
35    pub order_by_raw: (String, Vec<Value>),
36}
37
38pub fn to_sql(chain_builder: &ChainBuilder) -> ToSql {
39    // statement compiler
40    let mut statement = statement_compiler(chain_builder);
41    if !statement.0.is_empty() {
42        statement.0 = format!("WHERE {}", statement.0);
43    }
44    // compiler method
45    let method = method_compiler_with_provider(chain_builder, &MySqlToSqlProvider);
46    // join compiler
47    let join = join_compiler(chain_builder, true);
48
49    // QueryCommon
50    // - with
51    let mut with = String::new();
52    let mut with_binds: Vec<serde_json::Value> = vec![];
53    let mut is_first_with = true;
54    //  - union
55    let mut sql_union = String::new();
56    let mut sql_union_binds: Vec<serde_json::Value> = vec![];
57    let mut is_first_union = true;
58    // - limit
59    let mut limit = None;
60    // - offset
61    let mut offset = None;
62    // - group by
63    let mut group_by: Vec<String> = vec![];
64    // - group by raw
65    let mut group_by_raw = String::new();
66    let mut group_by_raw_binds: Vec<serde_json::Value> = vec![];
67    // - having
68    let mut having = String::new();
69    let mut having_binds: Vec<serde_json::Value> = vec![];
70    // - order by
71    let mut order_by: Vec<String> = vec![];
72    // - order by raw
73    let mut order_by_raw = String::new();
74    let mut order_by_raw_binds: Vec<serde_json::Value> = vec![];
75
76    // Capture the dialect before the loop: the `With` arm shadows `chain_builder`.
77    let client = chain_builder.query.client.clone();
78
79    for common in chain_builder.query.query_common.iter() {
80        match common {
81            crate::types::Common::With(alias, recursive, chain_builder) => {
82                with.push_str("WITH");
83                with.push(' ');
84                if !is_first_with {
85                    with.push_str(", ");
86                }
87                is_first_with = false;
88                if *recursive {
89                    with.push_str("RECURSIVE");
90                    with.push(' ');
91                }
92                with.push_str(&crate::dialect::escape_identifier(alias, &client));
93                with.push_str(" AS (");
94                let sql = merge_to_sql(to_sql(chain_builder));
95                with.push_str(sql.0.as_str());
96                with.push(')');
97                with_binds.extend(sql.1);
98                with.push(' ');
99            }
100            crate::types::Common::Union(is_all, chain_builder) => {
101                if !is_first_union {
102                    sql_union.push(' ');
103                }
104                is_first_union = false;
105                if *is_all {
106                    sql_union.push_str("UNION ALL");
107                } else {
108                    sql_union.push_str("UNION");
109                }
110                sql_union.push(' ');
111                let sql = merge_to_sql(to_sql(chain_builder));
112                sql_union.push_str(sql.0.as_str());
113                sql_union_binds.extend(sql.1);
114            }
115            crate::types::Common::Limit(l) => {
116                limit = Some(*l);
117            }
118            crate::types::Common::Offset(o) => {
119                offset = Some(*o);
120            }
121            crate::types::Common::GroupBy(g) => {
122                group_by.extend(
123                    g.iter()
124                        .map(|col| crate::dialect::escape_identifier(col, &client)),
125                );
126            }
127            crate::types::Common::GroupByRaw(g, b) => {
128                group_by_raw.push_str(g.as_str());
129                if let Some(b) = b {
130                    group_by_raw_binds.extend(b.clone());
131                }
132            }
133            crate::types::Common::OrderBy(column, order) => {
134                order_by.push(format!(
135                    "{} {}",
136                    crate::dialect::escape_identifier(column, &client),
137                    order
138                ));
139            }
140            crate::types::Common::OrderByRaw(sql, val) => {
141                order_by_raw.push_str(sql.as_str());
142                if let Some(val) = val {
143                    order_by_raw_binds.extend(val.clone());
144                }
145            }
146            crate::types::Common::Having(sql, val) => {
147                if !having.is_empty() {
148                    having.push_str(" AND ");
149                }
150                having.push_str(sql);
151                if let Some(val) = val {
152                    having_binds.extend(val.clone());
153                }
154            }
155        }
156    }
157
158    // raw compiler
159    let mut raw_sql = String::new();
160    let mut raw_binds: Vec<serde_json::Value> = vec![];
161    if !chain_builder.query.raw.is_empty() {
162        for (i, raw) in chain_builder.query.raw.iter().enumerate() {
163            if i > 0 {
164                raw_sql.push(' ');
165            }
166            raw_sql.push_str(&raw.0);
167            if let Some(binds) = &raw.1 {
168                raw_binds.extend(binds.clone());
169            }
170        }
171    }
172
173    ToSql {
174        statement,
175        method,
176        join,
177        raw: (raw_sql, raw_binds),
178        sql_with: (with, with_binds),
179        sql_union: (sql_union, sql_union_binds),
180        limit,
181        offset,
182        group_by,
183        group_by_raw: (group_by_raw, group_by_raw_binds),
184        having: (having, having_binds),
185        order_by,
186        order_by_raw: (order_by_raw, order_by_raw_binds),
187    }
188}
189
190pub fn merge_to_sql(to_sql: ToSql) -> (String, Vec<Value>) {
191    let mut select_sql = String::new();
192    let mut select_binds: Vec<serde_json::Value> = vec![];
193
194    // Add all order by
195    // - with,
196    // - method
197    // - join
198    // - statement
199    // - limit
200    // - group by
201    // - group by raw
202    // - order by
203    // - order by raw
204    // - offset
205    // - union
206    // - raw
207
208    if !to_sql.sql_with.0.is_empty() {
209        select_sql.push_str(to_sql.sql_with.0.as_str());
210        select_binds.extend(to_sql.sql_with.1);
211    }
212    if !to_sql.method.0.is_empty() {
213        select_sql.push_str(to_sql.method.0.as_str());
214        select_binds.extend(to_sql.method.1);
215    }
216    if !to_sql.join.0.is_empty() {
217        select_sql.push(' ');
218        select_sql.push_str(to_sql.join.0.as_str());
219        select_binds.extend(to_sql.join.1);
220    }
221    if !to_sql.statement.0.is_empty() {
222        select_sql.push(' ');
223        select_sql.push_str(to_sql.statement.0.as_str());
224        select_binds.extend(to_sql.statement.1);
225    }
226    if !to_sql.group_by.is_empty() {
227        select_sql.push_str(" GROUP BY ");
228        select_sql.push_str(to_sql.group_by.join(", ").as_str());
229    }
230    if !to_sql.group_by_raw.0.is_empty() {
231        select_sql.push_str(" GROUP BY ");
232        select_sql.push_str(to_sql.group_by_raw.0.as_str());
233        select_binds.extend(to_sql.group_by_raw.1);
234    }
235    if !to_sql.having.0.is_empty() {
236        select_sql.push_str(" HAVING ");
237        select_sql.push_str(to_sql.having.0.as_str());
238        select_binds.extend(to_sql.having.1);
239    }
240    if !to_sql.order_by.is_empty() {
241        select_sql.push_str(" ORDER BY ");
242        select_sql.push_str(to_sql.order_by.join(", ").as_str());
243    }
244    if !to_sql.order_by_raw.0.is_empty() {
245        select_sql.push_str(" ORDER BY ");
246        select_sql.push_str(to_sql.order_by_raw.0.as_str());
247        select_binds.extend(to_sql.order_by_raw.1);
248    }
249    if let Some(limit) = to_sql.limit {
250        select_sql.push(' ');
251        select_sql.push_str("LIMIT ?");
252        select_binds.push(serde_json::Value::Number(serde_json::Number::from(limit)));
253    }
254    if let Some(offset) = to_sql.offset {
255        select_sql.push(' ');
256        select_sql.push_str("OFFSET ?");
257        select_binds.push(serde_json::Value::Number(serde_json::Number::from(offset)));
258    }
259    if !to_sql.sql_union.0.is_empty() {
260        select_sql.push(' ');
261        select_sql.push_str(to_sql.sql_union.0.as_str());
262        select_binds.extend(to_sql.sql_union.1);
263    }
264    if !to_sql.raw.0.is_empty() {
265        select_sql.push(' ');
266        select_sql.push_str(to_sql.raw.0.as_str());
267        select_binds.extend(to_sql.raw.1);
268    }
269
270    (select_sql, select_binds)
271}