From 3fe5966f4cd59767e057ef3521bbc181496db70a Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 26 Nov 2024 17:42:51 +0100 Subject: [PATCH 1/4] controllers/summary: Move `encode_crates()` fn to top-level --- src/controllers/summary.rs | 70 +++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/controllers/summary.rs b/src/controllers/summary.rs index bd7829f294e..e15217dee8b 100644 --- a/src/controllers/summary.rs +++ b/src/controllers/summary.rs @@ -30,41 +30,6 @@ pub async fn summary(state: AppState) -> AppResult { .get_result(&mut conn) .await?; - async fn encode_crates( - conn: &mut AsyncPgConnection, - data: Vec, - ) -> AppResult> { - use diesel::GroupedBy; - use diesel_async::RunQueryDsl; - - let krates = data.iter().map(|(c, ..)| c).collect::>(); - let versions: Vec = Version::belonging_to(&krates) - .filter(versions::yanked.eq(false)) - .select(Version::as_select()) - .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() - } - let config = &state.config; let selection = ( @@ -143,3 +108,38 @@ pub async fn summary(state: AppState) -> AppResult { } type Record = (Crate, i64, Option, Option, Option); + +async fn encode_crates( + conn: &mut AsyncPgConnection, + data: Vec, +) -> AppResult> { + use diesel::GroupedBy; + use diesel_async::RunQueryDsl; + + let krates = data.iter().map(|(c, ..)| c).collect::>(); + let versions: Vec = Version::belonging_to(&krates) + .filter(versions::yanked.eq(false)) + .select(Version::as_select()) + .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() +} From 39b44414bb08dd10f63191c9cff46b0bc4a7cefd Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 26 Nov 2024 17:46:18 +0100 Subject: [PATCH 2/4] controllers/summary: Simplify imports --- src/controllers/summary.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/controllers/summary.rs b/src/controllers/summary.rs index e15217dee8b..616dec3e43e 100644 --- a/src/controllers/summary.rs +++ b/src/controllers/summary.rs @@ -7,12 +7,8 @@ use crate::util::errors::AppResult; use crate::views::{EncodableCategory, EncodableCrate, EncodableKeyword}; use axum_extra::json; use axum_extra::response::ErasedJson; -use diesel::{ - BelongingToDsl, ExpressionMethods, JoinOnDsl, NullableExpressionMethods, QueryDsl, - SelectableHelper, -}; -use diesel_async::AsyncPgConnection; -use diesel_async::RunQueryDsl; +use diesel::prelude::*; +use diesel_async::{AsyncPgConnection, RunQueryDsl}; /// Handles the `GET /summary` route. pub async fn summary(state: AppState) -> AppResult { @@ -113,9 +109,6 @@ async fn encode_crates( conn: &mut AsyncPgConnection, data: Vec, ) -> AppResult> { - use diesel::GroupedBy; - use diesel_async::RunQueryDsl; - let krates = data.iter().map(|(c, ..)| c).collect::>(); let versions: Vec = Version::belonging_to(&krates) .filter(versions::yanked.eq(false)) From f3edbcdb1ac977f12f39906c10c5edc459611c52 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 26 Nov 2024 17:47:32 +0100 Subject: [PATCH 3/4] controllers/summary: Extracted intermediate variables --- src/controllers/summary.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/controllers/summary.rs b/src/controllers/summary.rs index 616dec3e43e..441ede2f9fa 100644 --- a/src/controllers/summary.rs +++ b/src/controllers/summary.rs @@ -91,13 +91,18 @@ pub async fn summary(state: AppState) -> AppResult { .map(Keyword::into) .collect::>(); + let new_crates = encode_crates(&mut conn, new_crates).await?; + let most_downloaded = encode_crates(&mut conn, most_downloaded).await?; + let most_recently_downloaded = encode_crates(&mut conn, most_recently_downloaded).await?; + let just_updated = encode_crates(&mut conn, just_updated).await?; + Ok(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?, + "new_crates": new_crates, + "most_downloaded": most_downloaded, + "most_recently_downloaded": most_recently_downloaded, + "just_updated": just_updated, "popular_keywords": popular_keywords, "popular_categories": popular_categories, })) From c068816f97808272af9674140065803bcc122608 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 26 Nov 2024 18:02:45 +0100 Subject: [PATCH 4/4] controllers/summary: Convert `Record` to named struct --- src/controllers/summary.rs | 57 ++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/controllers/summary.rs b/src/controllers/summary.rs index 441ede2f9fa..9ab7e99ccc1 100644 --- a/src/controllers/summary.rs +++ b/src/controllers/summary.rs @@ -28,21 +28,13 @@ pub async fn summary(state: AppState) -> AppResult { let config = &state.config; - 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) + .select(Record::as_select()) .limit(10) .load(&mut conn) .await?; @@ -53,7 +45,7 @@ pub async fn summary(state: AppState) -> AppResult { .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) + .select(Record::as_select()) .limit(10) .load(&mut conn) .await?; @@ -65,7 +57,7 @@ pub async fn summary(state: AppState) -> AppResult { .left_join(versions::table.on(default_versions::version_id.eq(versions::id))) .filter(crates::name.ne_all(&config.excluded_crate_names)) .then_order_by(crate_downloads::downloads.desc()) - .select(selection) + .select(Record::as_select()) .limit(10) .load(&mut conn) .await?; @@ -77,7 +69,7 @@ pub async fn summary(state: AppState) -> AppResult { .left_join(versions::table.on(default_versions::version_id.eq(versions::id))) .filter(crates::name.ne_all(&config.excluded_crate_names)) .then_order_by(recent_crate_downloads::downloads.desc()) - .select(selection) + .select(Record::as_select()) .limit(10) .load(&mut conn) .await?; @@ -108,13 +100,26 @@ pub async fn summary(state: AppState) -> AppResult { })) } -type Record = (Crate, i64, Option, Option, Option); +#[derive(Debug, Queryable, Selectable)] +#[diesel(check_for_backend(diesel::pg::Pg))] +struct Record { + #[diesel(embed)] + krate: Crate, + #[diesel(select_expression = crate_downloads::columns::downloads)] + total_downloads: i64, + #[diesel(select_expression = recent_crate_downloads::columns::downloads.nullable())] + recent_downloads: Option, + #[diesel(select_expression = versions::columns::num.nullable())] + default_version: Option, + #[diesel(select_expression = versions::columns::yanked.nullable())] + yanked: Option, +} async fn encode_crates( conn: &mut AsyncPgConnection, data: Vec, ) -> AppResult> { - let krates = data.iter().map(|(c, ..)| c).collect::>(); + let krates = data.iter().map(|record| &record.krate).collect::>(); let versions: Vec = Version::belonging_to(&krates) .filter(versions::yanked.eq(false)) .select(Version::as_select()) @@ -126,18 +131,16 @@ async fn encode_crates( .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, - )) - }, - ) + .map(|(top_versions, record)| { + Ok(EncodableCrate::from_minimal( + record.krate, + record.default_version.as_deref(), + record.yanked, + Some(&top_versions), + false, + record.total_downloads, + record.recent_downloads, + )) + }) .collect() }