Skip to content

Commit

Permalink
Merge pull request #15 from davidkurilla/14-feature-implement-citrus-…
Browse files Browse the repository at this point in the history
…migrations-library

14 feature implement citrus migrations library
  • Loading branch information
davidkurilla authored Jun 2, 2024
2 parents e2f54b5 + c41128e commit 3b617bd
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 10 deletions.
8 changes: 6 additions & 2 deletions crates/citrus-migrations/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ version = "0.1.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
description = "A library of database migration functions for citrus."
repository = "https://github.com/davidkurilla/citrus"
readme = "../../docs/README.md"

[dependencies]
diesel = { version = "2.1.6", features = ["postgres"] }
diesel_migrations = "2.1.0"
toml = "0.5"
123 changes: 115 additions & 8 deletions crates/citrus-migrations/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,121 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
use std::string::String;
use toml::Value;
use diesel::{pg::PgConnection, Connection};
use diesel_migrations::{FileBasedMigrations, HarnessWithOutput, MigrationHarness};

pub struct InputData {
username: String,
password: String,
dbname: String,
host: String,
port: u16
}

fn get_str_or_default(toml: &Value, key: &str) -> String {
let value = toml.get(key);

let str =
if value.is_none() {
eprintln!("Could not read toml field: \"{}\"", key);
""
} else {
value.unwrap().as_str().unwrap_or_default()
};

String::from(str)
}
fn get_int_or_default(toml: &Value, key: &str) -> i64 {
let value = toml.get(key);

if value.is_none() {
eprintln!("Could not read toml field: \"{}\"", key);
0
} else {
value.unwrap().as_integer().unwrap_or_default()
}
}

impl InputData {
pub fn read(toml: &Value) -> InputData {
InputData {
username: get_str_or_default(toml, "username"),
password: get_str_or_default(toml, "password"),
dbname: get_str_or_default(toml, "dbname"),
host: get_str_or_default(toml, "host"),
port: get_int_or_default(toml, "port") as u16
}
}

pub fn postgres_url(&self) -> String {
format!(
"postgres://{}:{}@{}:{}/{}",
self.username,
self.password,
self.host,
self.port,
self.dbname
)
}
}

pub fn run_migration(toml_file_path: std::path::PathBuf, toml_table: String) {

let toml_file = toml_file_path;
let table_name = toml_table;

let toml_contents = match std::fs::read_to_string(toml_file) {
Ok(contents) => contents,
Err(e) => {
eprintln!("Error reading TOML file: {}", e);
return;
}
};

let toml_data: Value = match toml_contents.parse() {
Ok(data) => data,
Err(e) => {
eprintln!("Error parsing TOML file: {}", e);
return;
}
};

let table = get_toml_table(&table_name, &toml_data);

let input = InputData::read(table);

let db_url = input.postgres_url();

println!("Attempting to connect to {}", db_url);

let mut conn = PgConnection::establish(&db_url)
.expect("Unable to connect");

let migrations = FileBasedMigrations::find_migrations_directory()
.expect("Could not read migrations directory");

let mut harness = HarnessWithOutput::write_to_stdout(&mut conn);

harness.run_pending_migrations(migrations).expect("Couldn't run migrations");

println!("Successfully ran migrations")
}


pub fn get_toml_table<'a>(table_name: &'a str, toml_data: &'a Value) -> &'a Value{
if !table_name.is_empty() {
let table = toml_data.get(&table_name);
if table.is_none() {
eprintln!("Unable to find toml table: \"{}\"", &table_name);
std::process::abort()
}

table.unwrap()
} else {
&toml_data
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}

0 comments on commit 3b617bd

Please sign in to comment.