From 0544304e8c1ceadd3aafc7b339b8f97f22cb6502 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Mon, 5 Aug 2024 15:50:24 +0200 Subject: [PATCH] Embed database migrations in the binary --- Cargo.lock | 85 ++++++++++++++++++++++++++++++++++ Cargo.toml | 7 ++- src/database/schema.rs | 47 +++++++++++++++++++ src/instance/config.rs | 11 +++++ src/instance/mod.rs | 29 +++++++++++- src/interfaces/database/mod.rs | 11 +++++ 6 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 src/database/schema.rs diff --git a/Cargo.lock b/Cargo.lock index 36aed37a..ea39c080 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -305,6 +305,17 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "diesel_migrations" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a73ce704bad4231f001bff3314d91dce4aba0770cee8b233991859abc15c1f6" +dependencies = [ + "diesel", + "migrations_internals", + "migrations_macros", +] + [[package]] name = "diesel_table_macro_syntax" version = "0.2.0" @@ -977,6 +988,27 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "migrations_internals" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd01039851e82f8799046eabbb354056283fb265c8ec0996af940f4e85a380ff" +dependencies = [ + "serde", + "toml", +] + +[[package]] +name = "migrations_macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb161cc72176cb37aa47f1fc520d3ef02263d67d661f44f05d05a079e1237fd" +dependencies = [ + "migrations_internals", + "proc-macro2", + "quote", +] + [[package]] name = "mime" version = "0.3.17" @@ -1428,6 +1460,7 @@ dependencies = [ "anyhow", "chrono", "diesel", + "diesel_migrations", "graphql_client", "log", "micronfig", @@ -1601,6 +1634,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1939,6 +1981,40 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower" version = "0.4.13" @@ -2336,6 +2412,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" diff --git a/Cargo.toml b/Cargo.toml index f6ac21cc..ad27ea87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,10 @@ version = "2.2.1" features = ["postgres"] optional = true +[dependencies.diesel_migrations] +version = "2.2.0" +optional = true + [dependencies.teloxide] version = "0.12.2" default-features = false @@ -102,7 +106,8 @@ default = [ "service_telegram", ] interface_database = [ - "diesel" + "diesel", + "diesel_migrations", ] interface_stratz = [ "graphql_client" diff --git a/src/database/schema.rs b/src/database/schema.rs new file mode 100644 index 00000000..1e38eec4 --- /dev/null +++ b/src/database/schema.rs @@ -0,0 +1,47 @@ +// @generated automatically by Diesel CLI. + +diesel::table! { + brooch_match (id) { + id -> Int8, + } +} + +diesel::table! { + discord (discord_id) { + user_id -> Int4, + discord_id -> Int8, + } +} + +diesel::table! { + steam (steam_id) { + user_id -> Int4, + steam_id -> Int8, + } +} + +diesel::table! { + telegram (telegram_id) { + user_id -> Int4, + telegram_id -> Int8, + } +} + +diesel::table! { + users (id) { + id -> Int4, + username -> Varchar, + } +} + +diesel::joinable!(discord -> users (user_id)); +diesel::joinable!(steam -> users (user_id)); +diesel::joinable!(telegram -> users (user_id)); + +diesel::allow_tables_to_appear_in_same_query!( + brooch_match, + discord, + steam, + telegram, + users, +); diff --git a/src/instance/config.rs b/src/instance/config.rs index a41d71eb..7aed840c 100644 --- a/src/instance/config.rs +++ b/src/instance/config.rs @@ -1,6 +1,17 @@ #![allow(unused_attributes, unused_qualifications, clippy::needless_pub_self)] +#[cfg(feature = "interface_database")] +pub mod interface_database { + use micronfig::config; + + config! { + DATABASE_AUTOMIGRATE: String > bool, + DATABASE_URL: String, + } +} + + #[cfg(feature = "service_telegram")] pub mod service_telegram { use micronfig::config; diff --git a/src/instance/mod.rs b/src/instance/mod.rs index 9bd69394..038b519d 100644 --- a/src/instance/mod.rs +++ b/src/instance/mod.rs @@ -23,6 +23,8 @@ impl RoyalnetInstance { } pub async fn run(mut self) { + Self::run_pending_migrations(); + let future_telegram = async move { Self::get_telegram_future(&mut self.service_telegram).await; }; @@ -39,6 +41,29 @@ impl RoyalnetInstance { ); } + #[cfg(feature = "interface_database")] + fn run_pending_migrations() { + if !config::interface_database::DATABASE_AUTOMIGRATE() { + log::warn!("Database automigration is disabled."); + return + } + + log::debug!("Automatically applying database migrations..."); + + let mut db = crate::interfaces::database::connect( + config::interface_database::DATABASE_URL() + ).expect("Unable to connect to the database to apply migrations."); + + crate::interfaces::database::migrate(&mut db) + .expect("Failed to automatically apply migrations to the database."); + } + + #[cfg(not(feature = "interface_database"))] + fn run_pending_migrations() { + log::warn!("Database automigration is not compiled in."); + return + } + #[cfg(feature = "service_telegram")] async fn setup_telegram_service() -> crate::services::telegram::TelegramService { log::debug!("Setting up Telegram service..."); @@ -52,7 +77,7 @@ impl RoyalnetInstance { #[cfg(not(feature = "service_telegram"))] async fn setup_telegram_service() -> () { - log::warn!("Telegram service is disabled."); + log::warn!("Telegram service is not compiled in."); () } @@ -85,7 +110,7 @@ impl RoyalnetInstance { #[cfg(not(feature = "service_brooch"))] fn setup_brooch_service() -> () { - log::warn!("Brooch service is disabled."); + log::warn!("Brooch service is not compiled in."); () } diff --git a/src/interfaces/database/mod.rs b/src/interfaces/database/mod.rs index 213108a6..4e392fe3 100644 --- a/src/interfaces/database/mod.rs +++ b/src/interfaces/database/mod.rs @@ -1,4 +1,8 @@ +use anyhow::anyhow; use diesel::{Connection, ConnectionResult, PgConnection}; +use diesel::migration::MigrationVersion; +use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; +use crate::utils::result::AnyResult; pub mod schema; pub mod models; @@ -6,3 +10,10 @@ pub mod models; pub fn connect(database_url: &str) -> ConnectionResult { PgConnection::establish(database_url) } + +const MIGRATIONS: EmbeddedMigrations = embed_migrations!(); + +pub fn migrate(database: &mut PgConnection) -> AnyResult> { + database.run_pending_migrations(MIGRATIONS) + .map_err(|e| anyhow!("Failed to run pending migrations: {e:?}")) +} \ No newline at end of file