br_db/
config.rs

1use json::{object, JsonValue};
2use serde::{Deserialize, Serialize};
3use std::collections::BTreeMap;
4use std::fs;
5use std::path::PathBuf;
6
7#[derive(Clone, Debug, Deserialize, Serialize)]
8pub struct Config {
9    pub default: String,
10    pub connections: BTreeMap<String, Connection>,
11}
12
13impl Default for Config {
14    fn default() -> Self {
15        Self::new()
16    }
17}
18
19impl Config {
20    pub fn new() -> Config {
21        let mut connections = BTreeMap::new();
22        connections.insert("sqlite".to_string(), Connection::new("sqlite"));
23        connections.insert("mysql".to_string(), Connection::new("mysql"));
24        connections.insert("pgsql".to_string(), Connection::new("pgsql"));
25        connections.insert("mssql".to_string(), Connection::new("mssql"));
26        Self {
27            default: "sqlite".to_string(),
28            connections,
29        }
30    }
31    pub fn from(data: JsonValue) -> Config {
32        let default = data["default"].to_string();
33        let mut connections = BTreeMap::new();
34        // 避免不必要的克隆
35        for (key, value) in data["connections"].entries() {
36            let connection = Connection::from(value.clone());
37            connections.insert(key.to_string(), connection);
38        }
39
40        Self {
41            default,
42            connections,
43        }
44    }
45    pub fn create(config_file: PathBuf, pkg_name: bool) -> Config {
46        #[derive(Clone, Debug, Deserialize, Serialize)]
47        pub struct ConfigPkg {
48            pub br_db: Config,
49        }
50        impl ConfigPkg {
51            pub fn new() -> ConfigPkg {
52                let mut connections = BTreeMap::new();
53                connections.insert("sqlite".to_string(), Connection::new("sqlite"));
54                connections.insert("mysql".to_string(), Connection::new("mysql"));
55                connections.insert("pgsql".to_string(), Connection::new("pgsql"));
56                connections.insert("mssql".to_string(), Connection::new("mssql"));
57                Self {
58                    br_db: Config {
59                        default: "sqlite".to_string(),
60                        connections,
61                    }
62                }
63            }
64        }
65        match fs::read_to_string(config_file.clone()) {
66            Ok(e) => {
67                if pkg_name {
68                    toml::from_str::<ConfigPkg>(&e).unwrap().br_db
69                } else {
70                    toml::from_str::<Config>(&e).unwrap()
71                }
72            }
73            Err(_) => {
74                if pkg_name {
75                    let data = ConfigPkg::new();
76                    fs::create_dir_all(config_file.parent().unwrap()).unwrap();
77                    let toml = toml::to_string(&data).unwrap();
78                    let _ = fs::write(config_file.to_str().unwrap(), toml);
79                    data.br_db
80                } else {
81                    let data = Config::new();
82                    fs::create_dir_all(config_file.parent().unwrap()).unwrap();
83                    let toml = toml::to_string(&data).unwrap();
84                    let _ = fs::write(config_file.to_str().unwrap(), toml);
85                    data
86                }
87            }
88        }
89    }
90    /// 设置新地连接配置
91    pub fn set_connection(&mut self, name: &str, connection: JsonValue) {
92        let connection = Connection::from(connection);
93        self.connections.insert(name.to_string(), connection);
94    }
95    /// 设置当前运行配置
96    pub fn set_default(&mut self, name: &str) {
97        self.default = name.to_string();
98    }
99}
100/// 数据库模式
101#[derive(Clone, Debug, Deserialize, Serialize)]
102pub enum Mode {
103    Mysql,
104    Mssql,
105    Sqlite,
106    Pgsql,
107    None,
108}
109
110impl Mode {
111    pub fn str(&mut self) -> String {
112        match self {
113            Mode::Mysql => "mysql",
114            Mode::Sqlite => "sqlite",
115            Mode::Mssql => "mssql",
116            Mode::Pgsql => "pgsql",
117            Mode::None => "",
118        }.to_string()
119    }
120    pub fn from(name: &str) -> Self {
121        match name.to_lowercase().as_str() {
122            "mysql" => Mode::Mysql,
123            "sqlite" => Mode::Sqlite,
124            "mssql" => Mode::Mssql,
125            "pgsql" => Mode::Pgsql,
126            _ => Mode::None,
127        }
128    }
129}
130
131
132/// 数据库连接
133#[derive(Clone, Debug, Deserialize, Serialize)]
134pub struct Connection {
135    pub mode: Mode,
136    /// 连接地址
137    pub hostname: String,
138    /// 连接端口
139    pub hostport: String,
140    /// 数据库名称
141    pub database: String,
142    /// 账号
143    pub username: String,
144    /// 密码
145    pub userpass: String,
146    pub params: Vec<String>,
147    /// 数据库语言
148    pub charset: Charset,
149    /// 表前缀
150    pub prefix: String,
151    /// 调试开关
152    pub debug: bool,
153}
154
155impl Default for Connection {
156    fn default() -> Self {
157        Self::new("sqlite")
158    }
159}
160
161impl Connection {
162    pub fn new(mode: &str) -> Connection {
163        let mut that = Self {
164            mode: Mode::from(mode),
165            hostname: "".to_string(),
166            hostport: "".to_string(),
167            database: "".to_string(),
168            username: "".to_string(),
169            userpass: "".to_string(),
170            params: vec![],
171            charset: Charset::Utf8mb4,
172            prefix: "".to_string(),
173            debug: false,
174        };
175        match Mode::from(mode) {
176            Mode::Mysql => {
177                that.hostname = "127.0.0.1".to_string();
178                that.hostport = "3306".to_string();
179                that.database = "test".to_string();
180                that.username = "test".to_string();
181                that.userpass = "test".to_string();
182            }
183            Mode::Mssql => {}
184            Mode::Sqlite => {
185                that.database = "db/app.db".to_string();
186            }
187            Mode::Pgsql => {
188                that.hostname = "127.0.0.1".to_string();
189                that.hostport = "5432".to_string();
190                that.username = "test".to_string();
191                that.userpass = "test".to_string();
192            }
193            Mode::None => {}
194        }
195
196        that
197    }
198    pub fn json(&mut self) -> JsonValue {
199        object! {
200            mode: self.mode.str(),
201            hostname: self.hostname.clone(),
202            hostport: self.hostport.clone(),
203            database: self.database.clone(),
204            username: self.username.clone(),
205            userpass: self.userpass.clone(),
206            params: self.params.clone(),
207            charset: self.charset.str(),
208            prefix: self.prefix.clone(),
209            debug: self.debug
210        }
211    }
212    pub fn from(data: JsonValue) -> Connection {
213        // 优化字符串转换,避免不必要的 to_string() 调用
214        Self {
215            mode: Mode::from(data["mode"].as_str().unwrap_or("")),
216            hostname: data["hostname"].as_str().unwrap_or("").to_string(),
217            hostport: data["hostport"].as_str().unwrap_or("").to_string(),
218            database: data["database"].as_str().unwrap_or("").to_string(),
219            username: data["username"].as_str().unwrap_or("").to_string(),
220            userpass: data["userpass"].as_str().unwrap_or("").to_string(),
221            params: data["params"].members().map(|x| x.as_str().unwrap_or("").to_string()).collect(),
222            charset: Charset::from(data["charset"].as_str().unwrap_or("utf8mb4")),
223            prefix: data["prefix"].as_str().unwrap_or("").to_string(),
224            debug: data["debug"].as_bool().unwrap_or(false),
225        }
226    }
227    pub fn get_dsn(self) -> String {
228        match self.mode {
229            Mode::Mysql => {
230                format!(
231                    "mysql://{}:{}@{}:{}/{}",
232                    self.username, self.userpass, self.hostname, self.hostport, self.database
233                )
234            }
235            Mode::Sqlite => {
236                let db_path = self.database.as_str();
237                let path_buf = PathBuf::from(db_path);
238                if !path_buf.is_file() && path_buf.file_name().is_some() {
239                    fs::create_dir_all(
240                        db_path.trim_end_matches(path_buf.file_name().unwrap().to_str().unwrap()),
241                    ).unwrap();
242                }
243                path_buf.to_str().unwrap().to_string()
244            }
245            Mode::Mssql => format!(
246                "sqlsrv://{}:{}@{}:{}/{}",
247                self.username, self.userpass, self.hostname, self.hostport, self.database
248            ),
249            Mode::Pgsql => format!(
250                "host={} user={} password={} dbname={}",
251                self.hostname, self.username, self.userpass, self.database
252            ),
253            Mode::None => "".to_string(),
254        }
255    }
256}
257
258#[derive(Clone, Debug, Deserialize, Serialize)]
259pub enum Charset {
260    Utf8mb4,
261    Utf8,
262    None,
263}
264
265impl Charset {
266    pub fn from(str: &str) -> Charset {
267        match str.to_lowercase().as_str() {
268            "utf8" => Charset::Utf8,
269            "utf8mb4" => Charset::Utf8mb4,
270            _ => Charset::None,
271        }
272    }
273    pub fn str(&self) -> String {
274        match self {
275            Charset::Utf8 => "utf8",
276            Charset::Utf8mb4 => "utf8mb4",
277            Charset::None => "",
278        }.to_string()
279    }
280}