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() {
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 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 pub fn set_default(&mut self, name: &str) {
97 self.default = name.to_string();
98 }
99}
100#[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#[derive(Clone, Debug, Deserialize, Serialize)]
134pub struct Connection {
135 pub mode: Mode,
136 pub hostname: String,
138 pub hostport: String,
140 pub database: String,
142 pub username: String,
144 pub userpass: String,
146 pub params: Vec<String>,
147 pub charset: Charset,
149 pub prefix: String,
151 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 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}