1use std::collections::HashMap;
2use std::path::Path;
3
4#[derive(Debug, Clone)]
6pub struct MysqlConfig {
7 pub host: String,
8 pub port: u16,
9 pub user: String,
10 pub password: Option<String>,
11 pub database: Option<String>,
12 pub socket: Option<String>,
13}
14
15impl Default for MysqlConfig {
16 fn default() -> Self {
17 MysqlConfig {
18 host: "localhost".to_string(),
19 port: 3306,
20 user: "root".to_string(),
21 password: None,
22 database: None,
23 socket: None,
24 }
25 }
26}
27
28impl MysqlConfig {
29 pub fn connection_url(&self) -> String {
31 let mut url = format!("mysql://{}@{}:{}", self.user, self.host, self.port);
32 if let Some(ref db) = self.database {
33 url.push('/');
34 url.push_str(db);
35 }
36 url
37 }
38
39 pub fn to_opts(&self) -> mysql_async::OptsBuilder {
41 let mut builder = mysql_async::OptsBuilder::default()
42 .ip_or_hostname(&self.host)
43 .tcp_port(self.port)
44 .user(Some(&self.user));
45
46 if let Some(ref pw) = self.password {
47 builder = builder.pass(Some(pw));
48 }
49 if let Some(ref db) = self.database {
50 builder = builder.db_name(Some(db));
51 }
52 if let Some(ref sock) = self.socket {
53 builder = builder.socket(Some(sock));
54 }
55
56 builder
57 }
58}
59
60pub fn parse_defaults_file(path: &Path) -> Option<MysqlConfig> {
62 let content = std::fs::read_to_string(path).ok()?;
63 let mut config = MysqlConfig::default();
64 let mut in_client = false;
65
66 for line in content.lines() {
67 let line = line.trim();
68 if line.starts_with('[') {
69 in_client = line.eq_ignore_ascii_case("[client]");
70 continue;
71 }
72 if !in_client || line.is_empty() || line.starts_with('#') {
73 continue;
74 }
75
76 if let Some((key, value)) = line.split_once('=') {
77 let key = key.trim().to_lowercase();
78 let value = value.trim().trim_matches('"').trim_matches('\'');
79 match key.as_str() {
80 "host" => config.host = value.to_string(),
81 "port" => {
82 if let Ok(p) = value.parse() {
83 config.port = p;
84 }
85 }
86 "user" => config.user = value.to_string(),
87 "password" => config.password = Some(value.to_string()),
88 "socket" => config.socket = Some(value.to_string()),
89 "database" => config.database = Some(value.to_string()),
90 _ => {}
91 }
92 }
93 }
94
95 Some(config)
96}
97
98pub fn find_defaults_file() -> Option<std::path::PathBuf> {
100 if let Some(home) = std::env::var_os("HOME") {
102 let path = Path::new(&home).join(".my.cnf");
103 if path.exists() {
104 return Some(path);
105 }
106 }
107 let etc = Path::new("/etc/my.cnf");
109 if etc.exists() {
110 return Some(etc.to_path_buf());
111 }
112 None
113}
114
115pub type Row = HashMap<String, String>;