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 for (key, value) in data["connections"].entries() {
35 let connection = Connection::from(value.clone()).clone();
36 connections.insert(key.to_string(), connection.clone());
37 }
38 Self {
39 default,
40 connections,
41 }
42 }
43 pub fn create(config_file: PathBuf, pkg_name: bool) -> Config {
44 #[derive(Clone, Debug, Deserialize, Serialize)]
45 pub struct ConfigPkg {
46 pub br_db: Config,
47 }
48 impl ConfigPkg {
49 pub fn new() -> ConfigPkg {
50 let mut connections = BTreeMap::new();
51 connections.insert("sqlite".to_string(), Connection::new("sqlite"));
52 connections.insert("mysql".to_string(), Connection::new("mysql"));
53 connections.insert("pgsql".to_string(), Connection::new("pgsql"));
54 connections.insert("mssql".to_string(), Connection::new("mssql"));
55 Self {
56 br_db: Config {
57 default: "sqlite".to_string(),
58 connections,
59 }
60 }
61 }
62 }
63 match fs::read_to_string(config_file.clone()) {
64 Ok(e) => {
65 if pkg_name {
66 toml::from_str::<ConfigPkg>(&e).unwrap_or_else(|_| {
67 let data = ConfigPkg::new();
68 let toml = toml::to_string(&data).unwrap();
69 let toml = format!("{}\r\n{}", e, toml);
70 let _ = fs::write(config_file.to_str().unwrap(), toml);
71 data
72 }).br_db
73 } else {
74 toml::from_str::<Config>(&e).unwrap_or_else(|_| {
75 let data = Config::new();
76 let toml = toml::to_string(&data).unwrap();
77 let toml = format!("{}\r\n{}", e, toml);
78 let _ = fs::write(config_file.to_str().unwrap(), toml);
79 data
80 })
81 }
82 }
83 Err(_) => {
84 if pkg_name {
85 let data = ConfigPkg::new();
86 fs::create_dir_all(config_file.parent().unwrap()).unwrap();
87 let toml = toml::to_string(&data).unwrap();
88 let _ = fs::write(config_file.to_str().unwrap(), toml);
89 data.br_db
90 } else {
91 let data = Config::new();
92 fs::create_dir_all(config_file.parent().unwrap()).unwrap();
93 let toml = toml::to_string(&data).unwrap();
94 let _ = fs::write(config_file.to_str().unwrap(), toml);
95 data
96 }
97 }
98 }
99 }
100 pub fn set_connection(&mut self, name: &str, connection: JsonValue) {
102 let connection = Connection::from(connection);
103 self.connections.insert(name.to_string(), connection);
104 }
105 pub fn set_default(&mut self, name: &str) {
107 self.default = name.to_string();
108 }
109}
110#[derive(Clone, Debug, Deserialize, Serialize)]
112pub enum Mode {
113 Mysql,
114 Mssql,
115 Sqlite,
116 Pgsql,
117 None,
118}
119
120impl Mode {
121 pub fn str(&mut self) -> String {
122 match self {
123 Mode::Mysql => "mysql",
124 Mode::Sqlite => "sqlite",
125 Mode::Mssql => "mssql",
126 Mode::Pgsql => "pgsql",
127 Mode::None => "",
128 }.to_string()
129 }
130 pub fn from(name: &str) -> Self {
131 match name.to_lowercase().as_str() {
132 "mysql" => Mode::Mysql,
133 "sqlite" => Mode::Sqlite,
134 "mssql" => Mode::Mssql,
135 "pgsql" => Mode::Pgsql,
136 _ => Mode::None,
137 }
138 }
139}
140
141
142#[derive(Clone, Debug, Deserialize, Serialize)]
144pub struct Connection {
145 pub mode: Mode,
146 pub hostname: String,
148 pub hostport: String,
150 pub database: String,
152 pub username: String,
154 pub userpass: String,
156 pub params: Vec<String>,
157 pub charset: Charset,
159 pub prefix: String,
161 pub debug: bool,
163}
164
165impl Default for Connection {
166 fn default() -> Self {
167 Self::new("sqlite")
168 }
169}
170
171impl Connection {
172 pub fn new(mode: &str) -> Connection {
173 let mut that = Self {
174 mode: Mode::from(mode),
175 hostname: "".to_string(),
176 hostport: "".to_string(),
177 database: "".to_string(),
178 username: "".to_string(),
179 userpass: "".to_string(),
180 params: vec![],
181 charset: Charset::Utf8mb4,
182 prefix: "".to_string(),
183 debug: false,
184 };
185 match Mode::from(mode) {
186 Mode::Mysql => {
187 that.hostname = "127.0.0.1".to_string();
188 that.hostport = "3306".to_string();
189 that.database = "test".to_string();
190 that.username = "test".to_string();
191 that.userpass = "test".to_string();
192 }
193 Mode::Mssql => {}
194 Mode::Sqlite => {
195 that.database = "db/app.db".to_string();
196 }
197 Mode::Pgsql => {
198 that.hostname = "127.0.0.1".to_string();
199 that.hostport = "5432".to_string();
200 that.username = "test".to_string();
201 that.userpass = "test".to_string();
202 }
203 Mode::None => {}
204 }
205
206 that
207 }
208 pub fn json(&mut self) -> JsonValue {
209 object! {
210 mode: self.mode.str(),
211 hostname: self.hostname.clone(),
212 hostport: self.hostport.clone(),
213 database: self.database.clone(),
214 username: self.username.clone(),
215 userpass:self.userpass.clone(),
216 params: self.params.clone(),
217 charset: self.charset.str(),
218 prefix: self.prefix.clone(),
219 debug: self.debug
220 }
221 }
222 pub fn from(data: JsonValue) -> Connection {
223 Self {
224 mode: Mode::from(data["mode"].as_str().unwrap()),
225 hostname: data["hostname"].to_string(),
226 hostport: data["hostport"].to_string(),
227 database: data["database"].to_string(),
228 username: data["username"].to_string(),
229 userpass: data["userpass"].to_string(),
230 params: data["params"].members().map(|x| x.to_string()).collect(),
231 charset: Charset::from(data["charset"].as_str().unwrap_or("utf8mb4")),
232 prefix: data["prefix"].as_str().unwrap_or("").to_string(),
233 debug: data["debug"].to_string().parse::<bool>().unwrap_or(false),
234 }
235 }
236 pub fn get_dsn(self) -> String {
237 match self.mode {
238 Mode::Mysql => {
239 format!(
240 "mysql://{}:{}@{}:{}/{}",
241 self.username, self.userpass, self.hostname, self.hostport, self.database
242 )
243 }
244 Mode::Sqlite => {
245 let db_path = self.database.as_str();
246 let path_buf = PathBuf::from(db_path);
247 if !path_buf.is_file() && path_buf.file_name().is_some() {
248 fs::create_dir_all(
249 db_path.trim_end_matches(path_buf.file_name().unwrap().to_str().unwrap()),
250 ).unwrap();
251 }
252 path_buf.to_str().unwrap().to_string()
253 }
254 Mode::Mssql => format!(
255 "sqlsrv://{}:{}@{}:{}/{}",
256 self.username, self.userpass, self.hostname, self.hostport, self.database
257 ),
258 Mode::Pgsql => format!(
259 "host={} user={} password={} dbname={}",
260 self.hostname, self.username, self.userpass, self.database
261 ),
262 Mode::None => "".to_string(),
263 }
264 }
265}
266
267#[derive(Clone, Debug, Deserialize, Serialize)]
268pub enum Charset {
269 Utf8mb4,
270 Utf8,
271 None,
272}
273
274impl Charset {
275 pub fn from(str: &str) -> Charset {
276 match str {
277 "utf8" => Charset::Utf8,
278 "utf8mb4" => Charset::Utf8mb4,
279 _ => Charset::None,
280 }
281 }
282 pub fn str(&mut self) -> String {
283 match self {
284 Charset::Utf8 => "utf8",
285 Charset::Utf8mb4 => "utf8mb4",
286 Charset::None => "",
287 }.to_string()
288 }
289}