1use std::string::String;
2use toml::Value;
3use diesel::{pg::PgConnection, Connection};
4use diesel_migrations::{FileBasedMigrations, HarnessWithOutput, MigrationHarness};
5
6pub struct InputData {
7 username: String,
8 password: String,
9 dbname: String,
10 host: String,
11 port: u16
12}
13
14fn get_str_or_default(toml: &Value, key: &str) -> String {
15 let value = toml.get(key);
16
17 let str =
18 if value.is_none() {
19 eprintln!("Could not read toml field: \"{}\"", key);
20 ""
21 } else {
22 value.unwrap().as_str().unwrap_or_default()
23 };
24
25 String::from(str)
26}
27fn get_int_or_default(toml: &Value, key: &str) -> i64 {
28 let value = toml.get(key);
29
30 if value.is_none() {
31 eprintln!("Could not read toml field: \"{}\"", key);
32 0
33 } else {
34 value.unwrap().as_integer().unwrap_or_default()
35 }
36}
37
38impl InputData {
39 pub fn read(toml: &Value) -> InputData {
40 InputData {
41 username: get_str_or_default(toml, "username"),
42 password: get_str_or_default(toml, "password"),
43 dbname: get_str_or_default(toml, "dbname"),
44 host: get_str_or_default(toml, "host"),
45 port: get_int_or_default(toml, "port") as u16
46 }
47 }
48
49 pub fn postgres_url(&self) -> String {
50 format!(
51 "postgres://{}:{}@{}:{}/{}",
52 self.username,
53 self.password,
54 self.host,
55 self.port,
56 self.dbname
57 )
58 }
59}
60
61pub fn run_migration(toml_file_path: std::path::PathBuf, toml_table: String) {
62
63 let toml_file = toml_file_path;
64 let table_name = if !toml_table.is_empty() {
65 toml_table
66 } else {
67 String::from("database")
68 };
69
70 let toml_contents = match std::fs::read_to_string(toml_file) {
71 Ok(contents) => contents,
72 Err(e) => {
73 eprintln!("Error reading TOML file: {}", e);
74 return;
75 }
76 };
77
78 let toml_data: Value = match toml_contents.parse() {
79 Ok(data) => data,
80 Err(e) => {
81 eprintln!("Error parsing TOML file: {}", e);
82 return;
83 }
84 };
85
86 let table = get_toml_table(&table_name, &toml_data);
87
88 let input = InputData::read(table);
89
90 let db_url = input.postgres_url();
91
92 println!("Attempting to connect to {}", db_url);
93
94 let mut conn = PgConnection::establish(&db_url)
95 .expect("Unable to connect");
96
97 let migrations = FileBasedMigrations::find_migrations_directory()
98 .expect("Could not read migrations directory");
99
100 let mut harness = HarnessWithOutput::write_to_stdout(&mut conn);
101
102 harness.run_pending_migrations(migrations).expect("Couldn't run migrations");
103
104 println!("Successfully ran migrations")
105}
106
107
108pub fn get_toml_table<'a>(table_name: &'a str, toml_data: &'a Value) -> &'a Value{
109 if !table_name.is_empty() {
110 let table = toml_data.get(&table_name);
111 if table.is_none() {
112 eprintln!("Unable to find toml table: \"{}\"", &table_name);
113 std::process::abort()
114 }
115
116 table.unwrap()
117 } else {
118 &toml_data
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125}