diff --git a/src/controllers/summary.rs b/src/controllers/summary.rs index 0881f37a7f8..c38b65c44b8 100644 --- a/src/controllers/summary.rs +++ b/src/controllers/summary.rs @@ -3,13 +3,12 @@ use crate::models::{Category, Crate, CrateVersions, Keyword, TopVersions, Versio use crate::schema::{ crate_downloads, crates, default_versions, keywords, metadata, recent_crate_downloads, versions, }; -use crate::tasks::spawn_blocking; -use crate::util::diesel::Conn; use crate::util::errors::AppResult; use crate::views::{EncodableCategory, EncodableCrate, EncodableKeyword}; use axum::Json; -use diesel::prelude::*; -use diesel_async::async_connection_wrapper::AsyncConnectionWrapper; +use diesel::{ExpressionMethods, JoinOnDsl, NullableExpressionMethods, QueryDsl, SelectableHelper}; +use diesel_async::AsyncPgConnection; +use diesel_async::RunQueryDsl; use serde_json::Value; /// Handles the `GET /summary` route. @@ -22,123 +21,127 @@ pub async fn summary(state: AppState) -> AppResult> { .map(Category::into) .collect::>(); - spawn_blocking(move || { - let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into(); + let num_crates: i64 = crates::table.count().get_result(&mut conn).await?; + let num_downloads: i64 = metadata::table + .select(metadata::total_downloads) + .get_result(&mut conn) + .await?; - let config = &state.config; + async fn encode_crates( + conn: &mut AsyncPgConnection, + data: Vec, + ) -> AppResult> { + use diesel::GroupedBy; + use diesel_async::RunQueryDsl; - let num_crates: i64 = crates::table.count().get_result(conn)?; - let num_downloads: i64 = metadata::table - .select(metadata::total_downloads) - .get_result(conn)?; + let krates = data.iter().map(|(c, ..)| c).collect::>(); + let versions: Vec = krates.versions().load(conn).await?; + versions + .grouped_by(&krates) + .into_iter() + .map(TopVersions::from_versions) + .zip(data) + .map( + |(top_versions, (krate, total, recent, default_version, yanked))| { + Ok(EncodableCrate::from_minimal( + krate, + default_version.as_deref(), + yanked, + Some(&top_versions), + false, + total, + recent, + )) + }, + ) + .collect() + } - fn encode_crates( - conn: &mut impl Conn, - data: Vec, - ) -> AppResult> { - let krates = data.iter().map(|(c, ..)| c).collect::>(); - let versions: Vec = krates.versions().load(conn)?; - versions - .grouped_by(&krates) - .into_iter() - .map(TopVersions::from_versions) - .zip(data) - .map( - |(top_versions, (krate, total, recent, default_version, yanked))| { - Ok(EncodableCrate::from_minimal( - krate, - default_version.as_deref(), - yanked, - Some(&top_versions), - false, - total, - recent, - )) - }, - ) - .collect() - } + let config = &state.config; - let selection = ( - Crate::as_select(), - crate_downloads::downloads, - recent_crate_downloads::downloads.nullable(), - versions::num.nullable(), - versions::yanked.nullable(), - ); + let selection = ( + Crate::as_select(), + crate_downloads::downloads, + recent_crate_downloads::downloads.nullable(), + versions::num.nullable(), + versions::yanked.nullable(), + ); - let new_crates = crates::table - .inner_join(crate_downloads::table) - .left_join(recent_crate_downloads::table) - .left_join(default_versions::table) - .left_join(versions::table.on(default_versions::version_id.eq(versions::id))) - .order(crates::created_at.desc()) - .select(selection) - .limit(10) - .load(conn)?; - let just_updated = crates::table - .inner_join(crate_downloads::table) - .left_join(recent_crate_downloads::table) - .left_join(default_versions::table) - .left_join(versions::table.on(default_versions::version_id.eq(versions::id))) - .filter(crates::updated_at.ne(crates::created_at)) - .order(crates::updated_at.desc()) - .select(selection) - .limit(10) - .load(conn)?; + let new_crates = crates::table + .inner_join(crate_downloads::table) + .left_join(recent_crate_downloads::table) + .left_join(default_versions::table) + .left_join(versions::table.on(default_versions::version_id.eq(versions::id))) + .order(crates::created_at.desc()) + .select(selection) + .limit(10) + .load(&mut conn) + .await?; + let just_updated = crates::table + .inner_join(crate_downloads::table) + .left_join(recent_crate_downloads::table) + .left_join(default_versions::table) + .left_join(versions::table.on(default_versions::version_id.eq(versions::id))) + .filter(crates::updated_at.ne(crates::created_at)) + .order(crates::updated_at.desc()) + .select(selection) + .limit(10) + .load(&mut conn) + .await?; - let mut most_downloaded_query = crates::table - .inner_join(crate_downloads::table) - .left_join(recent_crate_downloads::table) - .left_join(default_versions::table) - .left_join(versions::table.on(default_versions::version_id.eq(versions::id))) - .into_boxed(); - if !config.excluded_crate_names.is_empty() { - most_downloaded_query = - most_downloaded_query.filter(crates::name.ne_all(&config.excluded_crate_names)); - } - let most_downloaded = most_downloaded_query - .then_order_by(crate_downloads::downloads.desc()) - .select(selection) - .limit(10) - .load(conn)?; + let mut most_downloaded_query = crates::table + .inner_join(crate_downloads::table) + .left_join(recent_crate_downloads::table) + .left_join(default_versions::table) + .left_join(versions::table.on(default_versions::version_id.eq(versions::id))) + .into_boxed(); + if !config.excluded_crate_names.is_empty() { + most_downloaded_query = + most_downloaded_query.filter(crates::name.ne_all(&config.excluded_crate_names)); + } + let most_downloaded = most_downloaded_query + .then_order_by(crate_downloads::downloads.desc()) + .select(selection) + .limit(10) + .load(&mut conn) + .await?; - let mut most_recently_downloaded_query = crates::table - .inner_join(crate_downloads::table) - .inner_join(recent_crate_downloads::table) - .left_join(default_versions::table) - .left_join(versions::table.on(default_versions::version_id.eq(versions::id))) - .into_boxed(); - if !config.excluded_crate_names.is_empty() { - most_recently_downloaded_query = most_recently_downloaded_query - .filter(crates::name.ne_all(&config.excluded_crate_names)); - } - let most_recently_downloaded = most_recently_downloaded_query - .then_order_by(recent_crate_downloads::downloads.desc()) - .select(selection) - .limit(10) - .load(conn)?; + let mut most_recently_downloaded_query = crates::table + .inner_join(crate_downloads::table) + .inner_join(recent_crate_downloads::table) + .left_join(default_versions::table) + .left_join(versions::table.on(default_versions::version_id.eq(versions::id))) + .into_boxed(); + if !config.excluded_crate_names.is_empty() { + most_recently_downloaded_query = most_recently_downloaded_query + .filter(crates::name.ne_all(&config.excluded_crate_names)); + } + let most_recently_downloaded = most_recently_downloaded_query + .then_order_by(recent_crate_downloads::downloads.desc()) + .select(selection) + .limit(10) + .load(&mut conn) + .await?; - let popular_keywords = keywords::table - .order(keywords::crates_cnt.desc()) - .limit(10) - .load(conn)? - .into_iter() - .map(Keyword::into) - .collect::>(); + let popular_keywords = keywords::table + .order(keywords::crates_cnt.desc()) + .limit(10) + .load(&mut conn) + .await? + .into_iter() + .map(Keyword::into) + .collect::>(); - Ok(Json(json!({ - "num_downloads": num_downloads, - "num_crates": num_crates, - "new_crates": encode_crates(conn, new_crates)?, - "most_downloaded": encode_crates(conn, most_downloaded)?, - "most_recently_downloaded": encode_crates(conn, most_recently_downloaded)?, - "just_updated": encode_crates(conn, just_updated)?, - "popular_keywords": popular_keywords, - "popular_categories": popular_categories, - }))) - }) - .await + Ok(Json(json!({ + "num_downloads": num_downloads, + "num_crates": num_crates, + "new_crates": encode_crates(&mut conn, new_crates).await?, + "most_downloaded": encode_crates(&mut conn, most_downloaded).await?, + "most_recently_downloaded": encode_crates(&mut conn, most_recently_downloaded).await?, + "just_updated": encode_crates(&mut conn, just_updated).await?, + "popular_keywords": popular_keywords, + "popular_categories": popular_categories, + }))) } type Record = (Crate, i64, Option, Option, Option);