Skip to main content

rust_ef_mysql/
sql_generator.rs

1use rust_ef::provider::ISqlGenerator;
2
3#[derive(Debug, Clone)]
4pub struct MySqlSqlGenerator;
5
6impl MySqlSqlGenerator {
7    #[allow(clippy::new_without_default)]
8    pub fn new() -> Self {
9        Self
10    }
11}
12
13impl ISqlGenerator for MySqlSqlGenerator {
14    fn select(&self, table: &str, columns: &[&str]) -> String {
15        let cols = if columns.is_empty() {
16            "*".to_string()
17        } else {
18            columns
19                .iter()
20                .map(|c| self.quote_identifier(c))
21                .collect::<Vec<_>>()
22                .join(", ")
23        };
24        format!("SELECT {} FROM {}", cols, self.quote_identifier(table))
25    }
26
27    fn insert(&self, table: &str, columns: &[&str], _returning: bool) -> String {
28        let cols = columns
29            .iter()
30            .map(|c| self.quote_identifier(c))
31            .collect::<Vec<_>>()
32            .join(", ");
33        let placeholders = vec!["?"; columns.len()].join(", ");
34        format!(
35            "INSERT INTO {} ({}) VALUES ({})",
36            self.quote_identifier(table),
37            cols,
38            placeholders
39        )
40    }
41
42    fn insert_batch(&self, table: &str, columns: &[&str], row_count: usize) -> String {
43        let cols = columns
44            .iter()
45            .map(|c| self.quote_identifier(c))
46            .collect::<Vec<_>>()
47            .join(", ");
48        let row = format!("({})", vec!["?"; columns.len()].join(", "));
49        let all_rows = vec![row; row_count].join(", ");
50        format!(
51            "INSERT INTO {} ({}) VALUES {}",
52            self.quote_identifier(table),
53            cols,
54            all_rows,
55        )
56    }
57
58    fn upsert_batch(
59        &self,
60        table: &str,
61        columns: &[&str],
62        conflict_cols: &[&str],
63        row_count: usize,
64    ) -> String {
65        let cols = columns
66            .iter()
67            .map(|c| self.quote_identifier(c))
68            .collect::<Vec<_>>()
69            .join(", ");
70        let row = format!("({})", vec!["?"; columns.len()].join(", "));
71        let all_rows = vec![row; row_count].join(", ");
72        let update_cols: Vec<&str> = columns
73            .iter()
74            .filter(|c| !conflict_cols.contains(c))
75            .copied()
76            .collect();
77        let sets = update_cols
78            .iter()
79            .map(|c| {
80                format!(
81                    "{} = VALUES({})",
82                    self.quote_identifier(c),
83                    self.quote_identifier(c)
84                )
85            })
86            .collect::<Vec<_>>()
87            .join(", ");
88        format!(
89            "INSERT INTO {} ({}) VALUES {} ON DUPLICATE KEY UPDATE {}",
90            self.quote_identifier(table),
91            cols,
92            all_rows,
93            sets,
94        )
95    }
96
97    fn update(&self, table: &str, set_columns: &[&str], where_clause: &str) -> String {
98        let sets: Vec<String> = set_columns
99            .iter()
100            .map(|c| format!("{} = ?", self.quote_identifier(c)))
101            .collect();
102        format!(
103            "UPDATE {} SET {} WHERE {}",
104            self.quote_identifier(table),
105            sets.join(", "),
106            where_clause
107        )
108    }
109
110    fn delete(&self, table: &str, where_clause: &str) -> String {
111        format!(
112            "DELETE FROM {} WHERE {}",
113            self.quote_identifier(table),
114            where_clause
115        )
116    }
117
118    fn create_table(&self, table: &str, columns: &[(String, String)]) -> String {
119        let col_defs: Vec<String> = columns
120            .iter()
121            .map(|(name, type_def)| format!("{} {}", self.quote_identifier(name), type_def))
122            .collect();
123        format!(
124            "CREATE TABLE {} (\n    {}\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4",
125            self.quote_identifier(table),
126            col_defs.join(",\n    ")
127        )
128    }
129
130    fn drop_table(&self, table: &str) -> String {
131        format!("DROP TABLE IF EXISTS {}", self.quote_identifier(table))
132    }
133
134    fn pagination(&self, skip: Option<usize>, take: Option<usize>) -> String {
135        match (skip, take) {
136            (Some(s), Some(t)) => format!("LIMIT {} OFFSET {}", t, s),
137            (None, Some(t)) => format!("LIMIT {}", t),
138            (Some(s), None) => format!("LIMIT 18446744073709551615 OFFSET {}", s),
139            (None, None) => String::new(),
140        }
141    }
142
143    fn parameter_placeholder(&self, _index: usize) -> String {
144        "?".to_string()
145    }
146
147    fn quote_identifier(&self, identifier: &str) -> String {
148        format!("`{}`", identifier)
149    }
150
151    fn auto_increment_syntax(&self) -> &'static str {
152        "AUTO_INCREMENT"
153    }
154
155    fn supports_returning(&self) -> bool {
156        false
157    }
158
159    fn last_insert_id_sql(&self) -> Option<&'static str> {
160        Some("SELECT LAST_INSERT_ID()")
161    }
162
163    fn last_insert_id_returns_first(&self) -> bool {
164        true
165    }
166}