diff --git a/src/bin/crates-admin/migrate.rs b/src/bin/crates-admin/migrate.rs index 94b3929d106..79950c1ae0b 100644 --- a/src/bin/crates-admin/migrate.rs +++ b/src/bin/crates-admin/migrate.rs @@ -45,17 +45,19 @@ pub async fn run(_opts: Opts) -> Result<(), Error> { let mut conn = AsyncConnectionWrapper::::from(conn); - spawn_blocking(move || { - info!("Migrating the database"); + info!("Migrating the database"); + let mut conn = spawn_blocking(move || { HarnessWithOutput::write_to_stdout(&mut conn) .run_pending_migrations(MIGRATIONS) .map_err(|e| anyhow!(e)) .context("Failed to run migrations")?; - info!("Synchronizing crate categories"); - crates_io::boot::categories::sync_with_connection(CATEGORIES_TOML, &mut conn)?; - - Ok(()) + Ok::<_, Error>(conn) }) - .await + .await?; + + info!("Synchronizing crate categories"); + crates_io::boot::categories::sync_with_connection(CATEGORIES_TOML, &mut conn).await?; + + Ok(()) } diff --git a/src/boot/categories.rs b/src/boot/categories.rs index cb42d1b5bc3..1aed741e75e 100644 --- a/src/boot/categories.rs +++ b/src/boot/categories.rs @@ -1,9 +1,12 @@ // Sync available crate categories from `src/categories.toml`. // Runs when the server is started. -use crate::util::diesel::prelude::*; -use crate::util::diesel::Conn; use anyhow::{Context, Result}; +use crates_io_database::schema::categories; +use diesel::pg::upsert::excluded; +use diesel::prelude::*; +use diesel_async::scoped_futures::ScopedFutureExt; +use diesel_async::{AsyncConnection, AsyncPgConnection, RunQueryDsl}; #[derive(Debug)] struct Category { @@ -76,11 +79,7 @@ fn categories_from_toml( Ok(result) } -pub fn sync_with_connection(toml_str: &str, conn: &mut impl Conn) -> Result<()> { - use crate::schema::categories; - use diesel::pg::upsert::excluded; - use diesel::RunQueryDsl; - +pub async fn sync_with_connection(toml_str: &str, conn: &mut AsyncPgConnection) -> Result<()> { let toml: toml::value::Table = toml::from_str(toml_str).context("Could not parse categories toml")?; @@ -97,20 +96,27 @@ pub fn sync_with_connection(toml_str: &str, conn: &mut impl Conn) -> Result<()> .collect::>(); conn.transaction(|conn| { - let slugs: Vec = diesel::insert_into(categories::table) - .values(&to_insert) - .on_conflict(categories::slug) - .do_update() - .set(( - categories::category.eq(excluded(categories::category)), - categories::description.eq(excluded(categories::description)), - )) - .returning(categories::slug) - .get_results(conn)?; - - diesel::delete(categories::table) - .filter(categories::slug.ne_all(slugs)) - .execute(conn)?; - Ok(()) + async move { + let slugs: Vec = diesel::insert_into(categories::table) + .values(&to_insert) + .on_conflict(categories::slug) + .do_update() + .set(( + categories::category.eq(excluded(categories::category)), + categories::description.eq(excluded(categories::description)), + )) + .returning(categories::slug) + .get_results(conn) + .await?; + + diesel::delete(categories::table) + .filter(categories::slug.ne_all(slugs)) + .execute(conn) + .await?; + + Ok(()) + } + .scope_boxed() }) + .await } diff --git a/src/tests/categories.rs b/src/tests/categories.rs index 990cc02cf0c..b03befccdfa 100644 --- a/src/tests/categories.rs +++ b/src/tests/categories.rs @@ -1,6 +1,7 @@ use crate::schema::categories; use crates_io_test_db::TestDatabase; use diesel::*; +use diesel_async::{AsyncConnection, AsyncPgConnection, RunQueryDsl}; const ALGORITHMS: &str = r#" [algorithms] @@ -37,56 +38,65 @@ name = "Another" description = "Another category ho hum" "#; -fn select_slugs(conn: &mut PgConnection) -> Vec { +async fn select_slugs(conn: &mut AsyncPgConnection) -> Vec { categories::table .select(categories::slug) .order(categories::slug) .load(conn) + .await .unwrap() } -#[test] -fn sync_adds_new_categories() { +#[tokio::test] +async fn sync_adds_new_categories() { let test_db = TestDatabase::new(); - let mut conn = test_db.connect(); + let mut conn = AsyncPgConnection::establish(test_db.url()).await.unwrap(); - crate::boot::categories::sync_with_connection(ALGORITHMS_AND_SUCH, &mut conn).unwrap(); + crate::boot::categories::sync_with_connection(ALGORITHMS_AND_SUCH, &mut conn) + .await + .unwrap(); - let categories = select_slugs(&mut conn); + let categories = select_slugs(&mut conn).await; assert_eq!(categories, vec!["algorithms", "algorithms::such"]); } -#[test] -fn sync_removes_missing_categories() { +#[tokio::test] +async fn sync_removes_missing_categories() { let test_db = TestDatabase::new(); - let mut conn = test_db.connect(); + let mut conn = AsyncPgConnection::establish(test_db.url()).await.unwrap(); - crate::boot::categories::sync_with_connection(ALGORITHMS_AND_SUCH, &mut conn).unwrap(); - crate::boot::categories::sync_with_connection(ALGORITHMS, &mut conn).unwrap(); + crate::boot::categories::sync_with_connection(ALGORITHMS_AND_SUCH, &mut conn) + .await + .unwrap(); + crate::boot::categories::sync_with_connection(ALGORITHMS, &mut conn) + .await + .unwrap(); - let categories = select_slugs(&mut conn); + let categories = select_slugs(&mut conn).await; assert_eq!(categories, vec!["algorithms"]); } -#[test] -fn sync_adds_and_removes() { +#[tokio::test] +async fn sync_adds_and_removes() { let test_db = TestDatabase::new(); - let mut conn = test_db.connect(); + let mut conn = AsyncPgConnection::establish(test_db.url()).await.unwrap(); - crate::boot::categories::sync_with_connection(ALGORITHMS_AND_SUCH, &mut conn).unwrap(); - crate::boot::categories::sync_with_connection(ALGORITHMS_AND_ANOTHER, &mut conn).unwrap(); + crate::boot::categories::sync_with_connection(ALGORITHMS_AND_SUCH, &mut conn) + .await + .unwrap(); + crate::boot::categories::sync_with_connection(ALGORITHMS_AND_ANOTHER, &mut conn) + .await + .unwrap(); - let categories = select_slugs(&mut conn); + let categories = select_slugs(&mut conn).await; assert_eq!(categories, vec!["algorithms", "another"]); } -#[test] -fn test_real_categories() { +#[tokio::test] +async fn test_real_categories() { let test_db = TestDatabase::new(); - let mut conn = test_db.connect(); + let mut conn = AsyncPgConnection::establish(test_db.url()).await.unwrap(); const TOML: &str = include_str!("../boot/categories.toml"); - assert_ok!(crate::boot::categories::sync_with_connection( - TOML, &mut conn - )); + assert_ok!(crate::boot::categories::sync_with_connection(TOML, &mut conn).await); }