Skip to content

Commit e90a6be

Browse files
committed
Return downloads for the top 5 most downloaded versions
This changes the downloads endpoint to return the five most downloaded versions of a crate, instead of the five most recent versions. This should make the endpoint more useful for users who are interested in seeing the most popular versions of a crate. In particular it helps with the case where a crate has many pre-release versions, which are not as interesting to users as the stable versions.
1 parent 282c9d9 commit e90a6be

File tree

1 file changed

+13
-6
lines changed

1 file changed

+13
-6
lines changed

src/controllers/krate/downloads.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use axum::Json;
1414
use diesel::prelude::*;
1515
use diesel_async::RunQueryDsl;
1616
use serde_json::Value;
17-
use std::cmp;
1817

1918
/// Handles the `GET /crates/:crate_id/downloads` route.
2019
pub async fn downloads(state: AppState, Path(crate_name): Path<String>) -> AppResult<Json<Value>> {
@@ -30,15 +29,23 @@ pub async fn downloads(state: AppState, Path(crate_name): Path<String>) -> AppRe
3029
.optional()?
3130
.ok_or_else(|| crate_not_found(&crate_name))?;
3231

33-
let mut versions: Vec<Version> = versions::table
32+
let versions: Vec<Version> = versions::table
3433
.filter(versions::crate_id.eq(crate_id))
3534
.load(&mut conn)
3635
.await?;
3736

38-
versions.sort_by_cached_key(|version| cmp::Reverse(semver::Version::parse(&version.num).ok()));
39-
let (latest_five, rest) = versions.split_at(cmp::min(5, versions.len()));
37+
let top_downloaded_versions: Vec<(i32,)> = VersionDownload::belonging_to(&versions)
38+
.group_by(version_downloads::version_id)
39+
.select((version_downloads::version_id,))
40+
.order(sum(version_downloads::downloads).desc())
41+
.limit(5)
42+
.load(&mut conn)
43+
.await?;
44+
let (top_five, rest): (Vec<_>, Vec<_>) = versions
45+
.iter()
46+
.partition(|v| top_downloaded_versions.contains(&(v.id,)));
4047

41-
let downloads = VersionDownload::belonging_to(latest_five)
48+
let downloads = VersionDownload::belonging_to(&top_five)
4249
.filter(version_downloads::date.gt(date(now - 90.days())))
4350
.order((
4451
version_downloads::date.asc(),
@@ -51,7 +58,7 @@ pub async fn downloads(state: AppState, Path(crate_name): Path<String>) -> AppRe
5158
.collect::<Vec<EncodableVersionDownload>>();
5259

5360
let sum_downloads = sql::<BigInt>("SUM(version_downloads.downloads)");
54-
let extra: Vec<ExtraDownload> = VersionDownload::belonging_to(rest)
61+
let extra: Vec<ExtraDownload> = VersionDownload::belonging_to(&rest)
5562
.select((
5663
to_char(version_downloads::date, "YYYY-MM-DD"),
5764
sum_downloads,

0 commit comments

Comments
 (0)