From d649248b17cd3ac20a499464b559c7d83e9236fb Mon Sep 17 00:00:00 2001 From: Nathan Perry Date: Mon, 28 Nov 2022 10:59:46 -0500 Subject: db: run migrations in db connect, upgrade diesel --- src/db/mod.rs | 59 ++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 21 deletions(-) (limited to 'src/db/mod.rs') diff --git a/src/db/mod.rs b/src/db/mod.rs index 180012d..483665e 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -26,6 +26,7 @@ use r2d2_postgres::{ use anyhow::anyhow; use lazy_static::lazy_static; +use diesel_migrations::MigrationHarness; use crate::{Error, Result}; @@ -35,6 +36,9 @@ use self::schema::*; mod schema; mod models; +const MIGRATIONS: diesel_migrations::EmbeddedMigrations = diesel_migrations::embed_migrations!(); +static MIGRATE: std::sync::Once = std::sync::Once::new(); + lazy_static! { static ref DB_URL: String = env::var("DATABASE_URL").expect("no database url in environment").into(); static ref DB_CONFIG: Config = Config::from_str(&DB_URL).expect("parsing db url as config"); @@ -42,20 +46,33 @@ lazy_static! { static ref RAW_CONN_MGR: RawPgConnMgr = RawPgConnMgr::new(DB_CONFIG.clone(), NoTls); } + #[inline] pub fn connection() -> Result { - CONN_MGR.connect().map_err(Error::from) + CONN_MGR.connect() + .map(|mut conn| { + MIGRATE.call_once(|| { + log::info!("running migrations"); + conn.run_pending_migrations(MIGRATIONS).expect("failed running migrations"); + }); + + conn + }) + .map_err(Error::from) } #[inline] fn raw_connection() -> Result { - RAW_CONN_MGR.connect().map_err(Error::from) -} + // HACK + if !MIGRATE.is_completed() { + connection()?; + } -pub fn find_meme>(conn: &PgConnection, search: T) -> Result { - use diesel::dsl::sql; - use diesel::sql_types::Text; + RAW_CONN_MGR.connect() + .map_err(Error::from) +} +pub fn find_meme>(conn: &mut PgConnection, search: T) -> Result { let search = search.as_ref(); let mut meme = memes::table @@ -67,7 +84,7 @@ pub fn find_meme>(conn: &PgConnection, search: T) -> Result let format_search = format!("%{}%", search); meme = memes::table - .filter(memes::title.ilike(&format_search).or(sql("content ILIKE ").bind::(&format_search))) + .filter(memes::title.ilike(&format_search).or(memes::content.ilike(&format_search))) .limit(1) .first::(conn); } @@ -121,26 +138,26 @@ pub fn query_meme>(search: T, user_id: Option, age_desc: bool Ok(result) } -pub fn delete_meme>(conn: &PgConnection, search: T, deleted_by: u64) -> Result<()> { - conn.transaction::<(), Error, _>(|| { +pub fn delete_meme>(conn: &mut PgConnection, search: T, deleted_by: u64) -> Result<()> { + conn.transaction::<(), Error, _>(|tx| { let deleted = memes::table .filter(memes::title.eq(search.as_ref())) - .first::(conn)?; + .first::(tx)?; ::diesel::delete(memes::table) .filter(memes::id.eq(deleted.id)) - .execute(conn)?; + .execute(tx)?; if let Some(image_id) = deleted.image_id { let count = memes::table .filter(memes::image_id.eq(image_id)) .count() - .execute(conn)?; + .execute(tx)?; if count == 0 { ::diesel::delete(images::table) .filter(images::id.eq(image_id)) - .execute(conn)?; + .execute(tx)?; } } @@ -148,12 +165,12 @@ pub fn delete_meme>(conn: &PgConnection, search: T, deleted_by: u6 let count = memes::table .select(::diesel::dsl::count_star()) .filter(memes::audio_id.eq(audio_id)) - .execute(conn)?; + .execute(tx)?; if count == 0 { ::diesel::delete(audio::table) .filter(audio::id.eq(audio_id)) - .execute(conn)?; + .execute(tx)?; } } @@ -165,13 +182,13 @@ pub fn delete_meme>(conn: &PgConnection, search: T, deleted_by: u6 let _ = ::diesel::insert_into(tombstones::table) .values(&tombstone) - .execute(conn)?; + .execute(tx)?; Ok(()) }) } -pub fn rare_meme(conn: &PgConnection, audio: bool) -> Result { +pub fn rare_meme(conn: &mut PgConnection, audio: bool) -> Result { use rand::prelude::*; let mut raw_conn = raw_connection()?; @@ -227,7 +244,7 @@ pub fn rare_meme(conn: &PgConnection, audio: bool) -> Result { Meme::find(conn, meme_id) } -pub fn rand_meme(conn: &PgConnection, audio: bool) -> Result { +pub fn rand_meme(conn: &mut PgConnection, audio: bool) -> Result { use rand::{thread_rng, seq::SliceRandom}; let ids: Vec = if audio { @@ -256,7 +273,7 @@ pub fn rand_meme(conn: &PgConnection, audio: bool) -> Result { .map_err(Error::from) } -pub fn rand_audio_meme(conn: &PgConnection) -> Result { +pub fn rand_audio_meme(conn: &mut PgConnection) -> Result { use rand::{thread_rng, seq::SliceRandom}; let ids: Vec = memes::table @@ -274,7 +291,7 @@ pub fn rand_audio_meme(conn: &PgConnection) -> Result { .map_err(Error::from) } -pub fn rand_silent_meme(conn: &PgConnection) -> Result { +pub fn rand_silent_meme(conn: &mut PgConnection) -> Result { use rand::{thread_rng, seq::SliceRandom}; let ids: Vec = memes::table @@ -323,7 +340,7 @@ pub struct Stats { pub most_popular_meme_overall_count: usize, } -pub fn stats(conn: &PgConnection) -> Result { +pub fn stats(conn: &mut PgConnection) -> Result { use diesel::dsl::{count_star, count}; use chrono::{ NaiveDateTime, -- cgit v1.3.1