rust_ef_mysql/
provider.rs1use crate::sql_generator::MySqlSqlGenerator;
2use crate::tls::MySqlTlsMode;
3use async_trait::async_trait;
4use rust_ef::error::{EFError, EFResult};
5#[cfg(feature = "tracing")]
6use rust_ef::provider::IAsyncConnection;
7use rust_ef::provider::{IDatabaseProvider, ISqlGenerator};
8
9pub struct MySqlProvider {
10 pool: sqlx::MySqlPool,
11 #[cfg(feature = "tracing")]
12 slow_query_threshold_ms: std::sync::atomic::AtomicU64,
13}
14
15impl MySqlProvider {
16 pub async fn new(connection_string: &str) -> EFResult<Self> {
21 Self::new_with_tls(connection_string, MySqlTlsMode::Required).await
22 }
23
24 pub async fn new_insecure(connection_string: &str) -> EFResult<Self> {
26 Self::new_with_tls(connection_string, MySqlTlsMode::Disabled).await
27 }
28
29 pub fn from_pool(pool: sqlx::MySqlPool) -> Self {
30 Self {
31 pool,
32 #[cfg(feature = "tracing")]
33 slow_query_threshold_ms: std::sync::atomic::AtomicU64::new(0),
34 }
35 }
36
37 pub fn new_lazy(connection_string: &str) -> EFResult<Self> {
39 Self::new_lazy_with_tls(connection_string, MySqlTlsMode::Required)
40 }
41
42 pub fn new_lazy_insecure(connection_string: &str) -> EFResult<Self> {
44 Self::new_lazy_with_tls(connection_string, MySqlTlsMode::Disabled)
45 }
46
47 pub async fn new_with_tls(connection_string: &str, tls: MySqlTlsMode) -> EFResult<Self> {
58 let mut options: sqlx::mysql::MySqlConnectOptions = connection_string
59 .parse()
60 .map_err(|e| EFError::connection(format!("MySQL URL parse: {}", e)))?;
61 options = options.ssl_mode(tls.into());
62 let pool = sqlx::MySqlPool::connect_with(options)
63 .await
64 .map_err(|e| EFError::connection(format!("MySQL connection failed: {}", e)))?;
65 Ok(Self {
66 pool,
67 #[cfg(feature = "tracing")]
68 slow_query_threshold_ms: std::sync::atomic::AtomicU64::new(0),
69 })
70 }
71
72 pub fn new_lazy_with_tls(connection_string: &str, tls: MySqlTlsMode) -> EFResult<Self> {
76 let mut options: sqlx::mysql::MySqlConnectOptions = connection_string
77 .parse()
78 .map_err(|e| EFError::connection(format!("MySQL URL parse: {}", e)))?;
79 options = options.ssl_mode(tls.into());
80 let pool = sqlx::MySqlPool::connect_lazy_with(options);
81 Ok(Self {
82 pool,
83 #[cfg(feature = "tracing")]
84 slow_query_threshold_ms: std::sync::atomic::AtomicU64::new(0),
85 })
86 }
87}
88
89#[async_trait]
90impl IDatabaseProvider for MySqlProvider {
91 fn sql_generator(&self) -> &'static dyn ISqlGenerator {
92 &MySqlSqlGenerator
93 }
94
95 async fn get_connection(&self) -> EFResult<Box<dyn rust_ef::provider::IAsyncConnection>> {
96 let _guard = rust_ef::observability::PoolAcquireGuard::new("MySQL");
97 let conn = self
98 .pool
99 .acquire()
100 .await
101 .map_err(|e| EFError::connection(format!("Pool acquire failed: {}", e)))?;
102 #[cfg_attr(not(feature = "tracing"), allow(unused_mut))]
103 let mut conn = Box::new(crate::connection::MySqlConnection::new(conn));
104 #[cfg(feature = "tracing")]
105 {
106 let ms = self
107 .slow_query_threshold_ms
108 .load(std::sync::atomic::Ordering::Relaxed);
109 if ms > 0 {
110 conn.set_slow_query_threshold(std::time::Duration::from_millis(ms));
111 }
112 }
113 Ok(conn)
114 }
115
116 async fn execute_migration_command(&self, sql: &str) -> EFResult<()> {
117 sqlx::query(sql)
118 .execute(&self.pool)
119 .await
120 .map_err(|e| EFError::migration(format!("Migration execution failed: {}", e)))?;
121 Ok(())
122 }
123
124 fn name(&self) -> &str {
125 "MySQL"
126 }
127
128 fn migration_dialect(&self) -> rust_ef::migration::MigrationDialect {
129 rust_ef::migration::MigrationDialect::MySql
130 }
131
132 #[cfg(feature = "tracing")]
133 fn set_slow_query_threshold(&self, threshold: std::time::Duration) {
134 self.slow_query_threshold_ms.store(
135 threshold.as_millis() as u64,
136 std::sync::atomic::Ordering::Relaxed,
137 );
138 }
139}
140
141impl std::fmt::Debug for MySqlProvider {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 f.debug_struct("MySqlProvider")
144 .field("name", &self.name())
145 .finish()
146 }
147}