zero_mysql/
opts.rs

1use std::sync::Arc;
2
3use crate::buffer_pool::{BufferPool, GLOBAL_BUFFER_POOL};
4use crate::constant::{CapabilityFlags, CAPABILITIES_ALWAYS_ENABLED};
5use crate::error::Error;
6
7/// A configuration for connection
8///
9/// ```rs
10/// let mut opts1 = Opts::default();
11/// opts1.port = 5000;
12///
13/// let mut opts2 = Opts::try_from("mysql://root:password@localhost:3306");
14/// opts2.compress = true;
15/// ```
16#[derive(Debug, Clone)]
17pub struct Opts {
18    /// Enable TCP_NODELAY socket option to disable Nagle's algorithm
19    /// Unix socket is not affected
20    pub tcp_nodelay: bool,
21
22    /// The client capabilities are `CAPABILITIES_ALWAYS_ENABLED | (opts.capabilities & CAPABILITIES_CONFIGURABLE)`.
23    /// The final negotiated capabilities are `SERVER_CAPABILITIES & CLIENT_CAPABILITIES`.
24    pub capabilities: CapabilityFlags,
25
26    /// Enable compression for the connection
27    pub compress: bool,
28
29    /// Database name to use
30    pub db: Option<String>,
31
32    /// Hostname or IP address
33    pub host: Option<String>,
34
35    /// Port number for the MySQL server
36    pub port: u16,
37
38    /// Unix socket path
39    pub socket: Option<String>,
40
41    /// Username for authentication (can be empty for anonymous connections)
42    pub user: String,
43
44    pub password: Option<String>,
45
46    pub tls: bool,
47
48    /// When connected via TCP, read `SELECT @@socket` and reconnect to the unix socket
49    pub upgrade_to_unix_socket: bool,
50
51    /// SQL command to execute after connection is established
52    pub init_command: Option<String>,
53
54    pub buffer_pool: Arc<BufferPool>,
55}
56
57impl Default for Opts {
58    fn default() -> Self {
59        Self {
60            tcp_nodelay: true,
61            capabilities: CAPABILITIES_ALWAYS_ENABLED,
62            compress: false,
63            db: None,
64            host: None,
65            port: 3306,
66            socket: None,
67            user: String::new(),
68            password: None,
69            tls: false,
70            upgrade_to_unix_socket: true,
71            init_command: None,
72            buffer_pool: Arc::clone(&GLOBAL_BUFFER_POOL),
73        }
74    }
75}
76
77impl TryFrom<&str> for Opts {
78    type Error = Error;
79
80    fn try_from(url: &str) -> Result<Self, Self::Error> {
81        // Parse URL
82        let parsed = url::Url::parse(url)
83            .map_err(|e| Error::BadConfigError(format!("Failed to parse MySQL URL: {}", e)))?;
84
85        // Verify scheme
86        if parsed.scheme() != "mysql" {
87            return Err(Error::BadConfigError(format!(
88                "Invalid URL scheme '{}', expected 'mysql'",
89                parsed.scheme()
90            )));
91        }
92
93        // Extract host (can be None for socket connections)
94        let host = parsed.host_str().map(ToString::to_string);
95        let port = parsed.port().unwrap_or(3306);
96
97        // Extract username (default empty)
98        let user = parsed.username().to_string();
99
100        // Extract password (default None)
101        let password = parsed.password().map(ToString::to_string);
102
103        // Extract database from path
104        let db = parsed
105            .path()
106            .strip_prefix('/')
107            .filter(|db| !db.is_empty())
108            .map(ToString::to_string);
109
110        Ok(Self {
111            host,
112            port,
113            user,
114            password,
115            db,
116            ..Default::default()
117        })
118    }
119}