Skip to content

Commit a488180

Browse files
authored
Merge pull request #10004 from Turbo87/async-crate-metadata
controllers/krate/metadata: Remove `spawn_blocking()` usage
2 parents a7d1ef4 + dc883e1 commit a488180

File tree

2 files changed

+136
-119
lines changed

2 files changed

+136
-119
lines changed

src/controllers/krate/metadata.rs

Lines changed: 118 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use crate::models::{
1111
Version, VersionOwnerAction,
1212
};
1313
use crate::schema::*;
14-
use crate::tasks::spawn_blocking;
1514
use crate::util::diesel::prelude::*;
1615
use crate::util::errors::{bad_request, crate_not_found, AppResult, BoxedAppError};
1716
use crate::util::{redirect, RequestUtils};
@@ -22,7 +21,6 @@ use axum::extract::Path;
2221
use axum::response::{IntoResponse, Response};
2322
use axum_extra::json;
2423
use axum_extra::response::ErasedJson;
25-
use diesel_async::async_connection_wrapper::AsyncConnectionWrapper;
2624
use http::request::Parts;
2725
use std::cmp::Reverse;
2826
use std::str::FromStr;
@@ -34,25 +32,19 @@ pub async fn show_new(app: AppState, req: Parts) -> AppResult<ErasedJson> {
3432

3533
/// Handles the `GET /crates/:crate_id` route.
3634
pub async fn show(app: AppState, Path(name): Path<String>, req: Parts) -> AppResult<ErasedJson> {
37-
let conn = app.db_read().await?;
38-
spawn_blocking(move || {
39-
use diesel::RunQueryDsl;
40-
41-
let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into();
42-
43-
let include = req
44-
.query()
45-
.get("include")
46-
.map(|mode| ShowIncludeMode::from_str(mode))
47-
.transpose()?
48-
.unwrap_or_default();
49-
50-
let (krate, downloads, default_version, yanked): (
51-
Crate,
52-
i64,
53-
Option<String>,
54-
Option<bool>,
55-
) = Crate::by_name(&name)
35+
use diesel_async::RunQueryDsl;
36+
37+
let mut conn = app.db_read().await?;
38+
39+
let include = req
40+
.query()
41+
.get("include")
42+
.map(|mode| ShowIncludeMode::from_str(mode))
43+
.transpose()?
44+
.unwrap_or_default();
45+
46+
let (krate, downloads, default_version, yanked): (Crate, i64, Option<String>, Option<bool>) =
47+
Crate::by_name(&name)
5648
.inner_join(crate_downloads::table)
5749
.left_join(default_versions::table)
5850
.left_join(versions::table.on(default_versions::version_id.eq(versions::id)))
@@ -62,109 +54,116 @@ pub async fn show(app: AppState, Path(name): Path<String>, req: Parts) -> AppRes
6254
versions::num.nullable(),
6355
versions::yanked.nullable(),
6456
))
65-
.first(conn)
57+
.first(&mut conn)
58+
.await
6659
.optional()?
6760
.ok_or_else(|| crate_not_found(&name))?;
6861

69-
let versions_publishers_and_audit_actions = if include.versions {
70-
let mut versions_and_publishers: Vec<(Version, Option<User>)> =
71-
Version::belonging_to(&krate)
72-
.left_outer_join(users::table)
73-
.select(<(Version, Option<User>)>::as_select())
74-
.load(conn)?;
75-
versions_and_publishers.sort_by_cached_key(|(version, _)| {
76-
Reverse(semver::Version::parse(&version.num).ok())
77-
});
78-
79-
let versions = versions_and_publishers
80-
.iter()
81-
.map(|(v, _)| v)
82-
.collect::<Vec<_>>();
83-
let actions = VersionOwnerAction::for_versions(conn, &versions)?;
84-
Some(
85-
versions_and_publishers
86-
.into_iter()
87-
.zip(actions)
88-
.map(|((v, pb), aas)| (v, pb, aas))
89-
.collect::<Vec<_>>(),
90-
)
91-
} else {
92-
None
93-
};
94-
let ids = versions_publishers_and_audit_actions
95-
.as_ref()
96-
.map(|vps| vps.iter().map(|v| v.0.id).collect());
97-
98-
let kws = if include.keywords {
99-
Some(
100-
CrateKeyword::belonging_to(&krate)
101-
.inner_join(keywords::table)
102-
.select(Keyword::as_select())
103-
.load(conn)?,
104-
)
105-
} else {
106-
None
107-
};
108-
let cats = if include.categories {
109-
Some(
110-
CrateCategory::belonging_to(&krate)
111-
.inner_join(categories::table)
112-
.select(Category::as_select())
113-
.load(conn)?,
114-
)
115-
} else {
116-
None
117-
};
118-
let recent_downloads = if include.downloads {
119-
RecentCrateDownloads::belonging_to(&krate)
120-
.select(recent_crate_downloads::downloads)
121-
.get_result(conn)
122-
.optional()?
123-
} else {
124-
None
125-
};
62+
let versions_publishers_and_audit_actions = if include.versions {
63+
let mut versions_and_publishers: Vec<(Version, Option<User>)> =
64+
Version::belonging_to(&krate)
65+
.left_outer_join(users::table)
66+
.select(<(Version, Option<User>)>::as_select())
67+
.load(&mut conn)
68+
.await?;
12669

127-
let top_versions = if include.versions {
128-
Some(krate.top_versions(conn)?)
129-
} else {
130-
None
131-
};
70+
versions_and_publishers
71+
.sort_by_cached_key(|(version, _)| Reverse(semver::Version::parse(&version.num).ok()));
13272

133-
let encodable_crate = EncodableCrate::from(
134-
krate.clone(),
135-
default_version.as_deref(),
136-
yanked,
137-
top_versions.as_ref(),
138-
ids,
139-
kws.as_deref(),
140-
cats.as_deref(),
141-
false,
142-
downloads,
143-
recent_downloads,
144-
);
145-
let encodable_versions = versions_publishers_and_audit_actions.map(|vpa| {
146-
vpa.into_iter()
147-
.map(|(v, pb, aas)| EncodableVersion::from(v, &krate.name, pb, aas))
148-
.collect::<Vec<_>>()
149-
});
150-
let encodable_keywords = kws.map(|kws| {
151-
kws.into_iter()
152-
.map(Keyword::into)
153-
.collect::<Vec<EncodableKeyword>>()
154-
});
155-
let encodable_cats = cats.map(|cats| {
156-
cats.into_iter()
157-
.map(Category::into)
158-
.collect::<Vec<EncodableCategory>>()
159-
});
160-
Ok(json!({
161-
"crate": encodable_crate,
162-
"versions": encodable_versions,
163-
"keywords": encodable_keywords,
164-
"categories": encodable_cats,
165-
}))
166-
})
167-
.await?
73+
let versions = versions_and_publishers
74+
.iter()
75+
.map(|(v, _)| v)
76+
.collect::<Vec<_>>();
77+
let actions = VersionOwnerAction::async_for_versions(&mut conn, &versions).await?;
78+
Some(
79+
versions_and_publishers
80+
.into_iter()
81+
.zip(actions)
82+
.map(|((v, pb), aas)| (v, pb, aas))
83+
.collect::<Vec<_>>(),
84+
)
85+
} else {
86+
None
87+
};
88+
let ids = versions_publishers_and_audit_actions
89+
.as_ref()
90+
.map(|vps| vps.iter().map(|v| v.0.id).collect());
91+
92+
let kws = if include.keywords {
93+
Some(
94+
CrateKeyword::belonging_to(&krate)
95+
.inner_join(keywords::table)
96+
.select(Keyword::as_select())
97+
.load(&mut conn)
98+
.await?,
99+
)
100+
} else {
101+
None
102+
};
103+
let cats = if include.categories {
104+
Some(
105+
CrateCategory::belonging_to(&krate)
106+
.inner_join(categories::table)
107+
.select(Category::as_select())
108+
.load(&mut conn)
109+
.await?,
110+
)
111+
} else {
112+
None
113+
};
114+
let recent_downloads = if include.downloads {
115+
RecentCrateDownloads::belonging_to(&krate)
116+
.select(recent_crate_downloads::downloads)
117+
.get_result(&mut conn)
118+
.await
119+
.optional()?
120+
} else {
121+
None
122+
};
123+
124+
let top_versions = if include.versions {
125+
Some(krate.async_top_versions(&mut conn).await?)
126+
} else {
127+
None
128+
};
129+
130+
let encodable_crate = EncodableCrate::from(
131+
krate.clone(),
132+
default_version.as_deref(),
133+
yanked,
134+
top_versions.as_ref(),
135+
ids,
136+
kws.as_deref(),
137+
cats.as_deref(),
138+
false,
139+
downloads,
140+
recent_downloads,
141+
);
142+
143+
let encodable_versions = versions_publishers_and_audit_actions.map(|vpa| {
144+
vpa.into_iter()
145+
.map(|(v, pb, aas)| EncodableVersion::from(v, &krate.name, pb, aas))
146+
.collect::<Vec<_>>()
147+
});
148+
149+
let encodable_keywords = kws.map(|kws| {
150+
kws.into_iter()
151+
.map(Keyword::into)
152+
.collect::<Vec<EncodableKeyword>>()
153+
});
154+
155+
let encodable_cats = cats.map(|cats| {
156+
cats.into_iter()
157+
.map(Category::into)
158+
.collect::<Vec<EncodableCategory>>()
159+
});
160+
161+
Ok(json!({
162+
"crate": encodable_crate,
163+
"versions": encodable_versions,
164+
"keywords": encodable_keywords,
165+
"categories": encodable_cats,
166+
}))
168167
}
169168

170169
#[derive(Debug)]

src/models/krate.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,24 @@ impl Crate {
341341
}
342342
}
343343

344+
/// Return both the newest (most recently updated) and
345+
/// highest version (in semver order) for the current crate,
346+
/// where all top versions are not yanked.
347+
pub async fn async_top_versions(
348+
&self,
349+
conn: &mut AsyncPgConnection,
350+
) -> QueryResult<TopVersions> {
351+
use diesel_async::RunQueryDsl;
352+
353+
Ok(TopVersions::from_date_version_pairs(
354+
Version::belonging_to(self)
355+
.filter(versions::yanked.eq(false))
356+
.select((versions::created_at, versions::num))
357+
.load(conn)
358+
.await?,
359+
))
360+
}
361+
344362
/// Return both the newest (most recently updated) and
345363
/// highest version (in semver order) for the current crate,
346364
/// where all top versions are not yanked.

0 commit comments

Comments
 (0)