sql_composer_mysql/
lib.rs1#[cfg(feature = "async")]
53pub use mysql_async;
54
55#[cfg(feature = "sync")]
56pub use mysql;
57
58use std::collections::BTreeMap;
59use std::ops::{Deref, DerefMut};
60
61use sql_composer::composer::Composer;
62use sql_composer::driver;
63use sql_composer::types::Template;
64
65#[cfg(feature = "async")]
71#[derive(Debug, thiserror::Error)]
72pub enum AsyncError {
73 #[error(transparent)]
75 Composer(#[from] sql_composer::Error),
76
77 #[error(transparent)]
79 Mysql(#[from] mysql_async::Error),
80}
81
82#[cfg(feature = "async")]
87pub struct MysqlConn(pub mysql_async::Conn);
88
89#[cfg(feature = "async")]
90impl MysqlConn {
91 pub fn from_conn(conn: mysql_async::Conn) -> Self {
93 Self(conn)
94 }
95}
96
97#[cfg(feature = "async")]
98impl Deref for MysqlConn {
99 type Target = mysql_async::Conn;
100
101 fn deref(&self) -> &Self::Target {
102 &self.0
103 }
104}
105
106#[cfg(feature = "async")]
107impl DerefMut for MysqlConn {
108 fn deref_mut(&mut self) -> &mut Self::Target {
109 &mut self.0
110 }
111}
112
113#[cfg(feature = "async")]
114impl driver::ComposerConnectionAsync for MysqlConn {
115 type Value = mysql_async::Value;
116 type Statement = String;
117 type Error = AsyncError;
118
119 async fn compose(
120 &self,
121 composer: &Composer,
122 template: &Template,
123 mut values: BTreeMap<String, Vec<Self::Value>>,
124 ) -> Result<(String, Vec<Self::Value>), AsyncError> {
125 let composed = composer.compose_with_values(template, &values)?;
126 let ordered = driver::resolve_values(&composed, &mut values)?;
127 Ok((composed.sql, ordered))
128 }
129}
130
131#[cfg(feature = "sync")]
137#[derive(Debug, thiserror::Error)]
138pub enum SyncError {
139 #[error(transparent)]
141 Composer(#[from] sql_composer::Error),
142
143 #[error(transparent)]
145 Mysql(#[from] mysql::Error),
146}
147
148#[cfg(feature = "sync")]
153pub struct MysqlConnection(pub mysql::Conn);
154
155#[cfg(feature = "sync")]
156impl MysqlConnection {
157 pub fn from_conn(conn: mysql::Conn) -> Self {
159 Self(conn)
160 }
161}
162
163#[cfg(feature = "sync")]
164impl Deref for MysqlConnection {
165 type Target = mysql::Conn;
166
167 fn deref(&self) -> &Self::Target {
168 &self.0
169 }
170}
171
172#[cfg(feature = "sync")]
173impl DerefMut for MysqlConnection {
174 fn deref_mut(&mut self) -> &mut Self::Target {
175 &mut self.0
176 }
177}
178
179#[cfg(feature = "sync")]
180impl driver::ComposerConnection for MysqlConnection {
181 type Value = mysql::Value;
182 type Statement = String;
183 type Error = SyncError;
184
185 fn compose(
186 &self,
187 composer: &Composer,
188 template: &Template,
189 mut values: BTreeMap<String, Vec<Self::Value>>,
190 ) -> Result<(String, Vec<Self::Value>), SyncError> {
191 let composed = composer.compose_with_values(template, &values)?;
192 let ordered = driver::resolve_values(&composed, &mut values)?;
193 Ok((composed.sql, ordered))
194 }
195}
196
197#[cfg(feature = "async")]
200pub type Error = AsyncError;
201
202#[cfg(test)]
203mod tests {
204 use sql_composer::composer::Composer;
205 use sql_composer::parser::parse_template;
206 use sql_composer::types::{Dialect, TemplateSource};
207
208 #[test]
209 fn test_compose_single_bind_mysql() {
210 let input = "SELECT * FROM users WHERE id = :bind(user_id)";
211 let template = parse_template(input, TemplateSource::Literal("test".into())).unwrap();
212 let composer = Composer::new(Dialect::Mysql);
213 let result = composer.compose(&template).unwrap();
214 assert_eq!(result.sql, "SELECT * FROM users WHERE id = ?");
215 assert_eq!(result.bind_params, vec!["user_id"]);
216 }
217
218 #[test]
219 fn test_compose_multiple_binds_mysql() {
220 let input = "SELECT * FROM users WHERE name = :bind(name) AND active = :bind(active)";
221 let template = parse_template(input, TemplateSource::Literal("test".into())).unwrap();
222 let composer = Composer::new(Dialect::Mysql);
223 let result = composer.compose(&template).unwrap();
224 assert_eq!(
226 result.sql,
227 "SELECT * FROM users WHERE name = ? AND active = ?"
228 );
229 assert_eq!(result.bind_params, vec!["name", "active"]);
230 }
231
232 #[test]
233 fn test_compose_with_values_multi_bind_mysql() {
234 let input = "SELECT * FROM users WHERE id IN (:bind(ids))";
235 let template = parse_template(input, TemplateSource::Literal("test".into())).unwrap();
236 let composer = Composer::new(Dialect::Mysql);
237 let values = sql_composer::bind_values!("ids" => [10, 20, 30]);
238 let result = composer.compose_with_values(&template, &values).unwrap();
239 assert_eq!(result.sql, "SELECT * FROM users WHERE id IN (?, ?, ?)");
240 assert_eq!(result.bind_params, vec!["ids", "ids", "ids"]);
241 }
242}