Skip to main content

chain_builder/
sqlx_mysql.rs

1use crate::builder::ChainBuilder;
2use serde_json::Value;
3use sqlx::{self, mysql::MySqlArguments, Arguments, Row};
4
5impl ChainBuilder {
6    #[cfg(all(feature = "mysql", feature = "sqlx_mysql"))]
7    fn value_to_arguments(&self, binds: &Vec<Value>) -> MySqlArguments {
8        let mut arguments: MySqlArguments = MySqlArguments::default();
9        for bind in binds {
10            match bind {
11                Value::Null => {
12                    // bind NULL อย่างชัดเจน
13                    let _ = arguments.add(Option::<String>::None);
14                }
15                Value::Bool(b) => {
16                    let _ = arguments.add(b);
17                }
18                Value::Number(n) => {
19                    if let Some(i) = n.as_i64() {
20                        let _ = arguments.add(i);
21                    } else if let Some(u) = n.as_u64() {
22                        if u <= i64::MAX as u64 {
23                            let _ = arguments.add(u as i64);
24                        } else {
25                            // ถ้าใหญ่เกิน เก็บเป็น string ปลอดภัยสุด
26                            let _ = arguments.add(u.to_string());
27                        }
28                    } else if let Some(f) = n.as_f64() {
29                        let _ = arguments.add(f);
30                    } else {
31                        let _ = arguments.add(n.to_string());
32                    }
33                }
34                Value::String(s) => {
35                    let _ = arguments.add(s);
36                }
37                Value::Array(arr) => {
38                    // SQLite ไม่มี array type → เก็บเป็น JSON text
39                    let _ = arguments.add(serde_json::to_string(&arr).unwrap_or_default());
40                }
41                Value::Object(obj) => {
42                    // เก็บเป็น JSON text
43                    let _ = arguments.add(serde_json::to_string(&obj).unwrap_or_default());
44                }
45            }
46        }
47        arguments
48    }
49
50    #[cfg(all(feature = "mysql", feature = "sqlx_mysql"))]
51    pub fn to_sqlx_query(
52        &mut self,
53    ) -> sqlx::query::Query<'_, sqlx::MySql, sqlx::mysql::MySqlArguments> {
54        let (_, binds) = self.to_sql();
55        // sqlx 0.9 requires `SqlSafeStr`; the SQL is builder-generated with bound
56        // parameters, so assert safety explicitly (also satisfies the 'static bound).
57        sqlx::query_with(
58            sqlx::AssertSqlSafe(self.sql_str.clone()),
59            self.value_to_arguments(&binds),
60        )
61    }
62
63    #[cfg(all(feature = "mysql", feature = "sqlx_mysql"))]
64    pub fn to_sqlx_query_as<T>(
65        &mut self,
66    ) -> sqlx::query::QueryAs<'_, sqlx::MySql, T, sqlx::mysql::MySqlArguments>
67    where
68        T: for<'r> sqlx::FromRow<'r, sqlx::mysql::MySqlRow>,
69    {
70        let (_, binds) = self.to_sql();
71        sqlx::query_as_with(
72            sqlx::AssertSqlSafe(self.sql_str.clone()),
73            self.value_to_arguments(&binds),
74        )
75    }
76
77    #[cfg(all(feature = "mysql", feature = "sqlx_mysql"))]
78    pub async fn count(
79        &mut self,
80        column: &str,
81        pool: &sqlx::Pool<sqlx::MySql>,
82    ) -> Result<i64, sqlx::Error> {
83        let (_, binds) = self.to_sql();
84        let sql = self.sql_str.as_str();
85        let sql = format!("SELECT COUNT({}) FROM ({}) as count", column, sql);
86        let qb = sqlx::query_with(sqlx::AssertSqlSafe(sql), self.value_to_arguments(&binds));
87        let query_count = qb.fetch_one(pool).await?;
88        let count: i64 = query_count.try_get(0)?;
89        Ok(count)
90    }
91}