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