diff --git a/Cargo.lock b/Cargo.lock index aa3154a8..173c2684 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -775,6 +775,7 @@ dependencies = [ "anyhow", "async-std", "brass-config", + "chrono", "clap", "sqlx", ] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 023b7259..6072a532 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -15,3 +15,4 @@ brass-config = { path = "../config" } async-std = { version = "1.13.0", features = ["attributes"] } sqlx = { version = "0.8.2", features = ["runtime-async-std", "postgres"] } anyhow = "1.0.94" +chrono = "0.4.41" diff --git a/cli/src/db.rs b/cli/src/db.rs index 2423baf6..0aebbacf 100644 --- a/cli/src/db.rs +++ b/cli/src/db.rs @@ -1,6 +1,10 @@ use anyhow::Context; +use chrono::{Local, NaiveDateTime, Utc}; use sqlx::migrate::Migrate; use sqlx::{migrate::Migrator, Executor}; +use std::fs::File; +use std::io::Write; +use std::time::SystemTime; use std::{ collections::HashMap, path::{Path, PathBuf}, @@ -28,6 +32,8 @@ enum Command { Reset, #[command(about = "Run all pending migrations on database")] Migrate, + #[command(about = "Create a new migration")] + NewMigration { title: String }, } #[async_std::main] @@ -59,12 +65,17 @@ async fn main() { migrate_db(&db_config) .await .expect("Failed migrating database."); - }, + } Command::Migrate => { migrate_db(&db_config) .await .expect("Failed migrating database."); } + Command::NewMigration { title } => { + create_new_migration(&title) + .await + .expect("Failed creating new migration."); + } } } @@ -111,13 +122,7 @@ async fn migrate_db(db_config: &PgConnectOptions) -> anyhow::Result<()> { .await .context("Connection to database failed!")?; - let migrations_path = PathBuf::from( - std::env::var("CARGO_MANIFEST_DIR").expect("This command needs to be invoked using cargo"), - ) - .join("..") - .join("migrations") - .canonicalize() - .unwrap(); + let migrations_path = db_package_root()?.join("migrations"); let migrator = Migrator::new(Path::new(&migrations_path)) .await @@ -148,3 +153,27 @@ async fn migrate_db(db_config: &PgConnectOptions) -> anyhow::Result<()> { Ok(()) } + +async fn create_new_migration(title: &str) -> anyhow::Result<()> { + let now = Local::now(); + let timestamp = now.format("%Y%m%d%H%M%S"); + let file_name = format!("{timestamp}_{title}.sql"); + let path = db_package_root()?.join("migrations").join(&file_name); + + let mut file = File::create(&path).context(format!(r#"Could not create file "{:?}""#, path))?; + file.write_all("".as_bytes()) + .context(format!(r#"Could not write file "{:?}""#, path))?; + + println!("Created migration {file_name}."); + + Ok(()) +} + +fn db_package_root() -> Result { + Ok(PathBuf::from( + std::env::var("CARGO_MANIFEST_DIR").expect("This command needs to be invoked using cargo"), + ) + .join("..") + .join("db") + .canonicalize()?) +} diff --git a/migrations/20230609121618_initial.sql b/db/migrations/20230609121618_initial.sql similarity index 100% rename from migrations/20230609121618_initial.sql rename to db/migrations/20230609121618_initial.sql diff --git a/migrations/20250503133011_availability_date_time_range.sql b/db/migrations/20250503133011_availability_date_time_range.sql similarity index 100% rename from migrations/20250503133011_availability_date_time_range.sql rename to db/migrations/20250503133011_availability_date_time_range.sql diff --git a/migrations/20250504124907_vehicle_assignment_time_range.sql b/db/migrations/20250504124907_vehicle_assignment_time_range.sql similarity index 100% rename from migrations/20250504124907_vehicle_assignment_time_range.sql rename to db/migrations/20250504124907_vehicle_assignment_time_range.sql diff --git a/migrations/20250512183312_fix_table_typos.sql b/db/migrations/20250512183312_fix_table_typos.sql similarity index 100% rename from migrations/20250512183312_fix_table_typos.sql rename to db/migrations/20250512183312_fix_table_typos.sql diff --git a/migrations/20250515174927_clothing_table.sql b/db/migrations/20250515174927_clothing_table.sql similarity index 100% rename from migrations/20250515174927_clothing_table.sql rename to db/migrations/20250515174927_clothing_table.sql diff --git a/migrations/20250604130602_export_event_assignment_type.sql b/db/migrations/20250604130602_export_event_assignment_type.sql similarity index 100% rename from migrations/20250604130602_export_event_assignment_type.sql rename to db/migrations/20250604130602_export_event_assignment_type.sql