Skip to content

Commit 6168130

Browse files
authored
Merge pull request #10697 from eth3lbert/pipeline-krate-read
controllers/krate/metadata: Pipeline SQL queries
2 parents c109d06 + 9611c72 commit 6168130

File tree

1 file changed

+130
-59
lines changed

1 file changed

+130
-59
lines changed

src/controllers/krate/metadata.rs

Lines changed: 130 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ use axum::extract::{FromRequestParts, Query};
1919
use axum_extra::json;
2020
use axum_extra::response::ErasedJson;
2121
use diesel::prelude::*;
22-
use diesel_async::RunQueryDsl;
22+
use diesel_async::{AsyncPgConnection, RunQueryDsl};
23+
use futures_util::FutureExt;
24+
use futures_util::future::{BoxFuture, always_ready};
2325
use std::str::FromStr;
2426

2527
#[derive(Debug, Deserialize, FromRequestParts, utoipa::IntoParams)]
@@ -97,14 +99,31 @@ pub async fn find_crate(
9799
.optional()?
98100
.ok_or_else(|| crate_not_found(&path.name))?;
99101

100-
let mut versions_publishers_and_audit_actions = if include.versions {
101-
let versions_and_publishers: Vec<(Version, Option<User>)> = Version::belonging_to(&krate)
102-
.left_outer_join(users::table)
103-
.select(<(Version, Option<User>)>::as_select())
104-
.order_by(versions::id.desc())
105-
.load(&mut conn)
106-
.await?;
102+
// Since `versions` and `default_version` share the same key (versions), we should only settle
103+
// the `include.default_version` when `include.versions` is not included, and ignore when no
104+
// `default_version` available.
105+
let include_default_version =
106+
include.default_version && !include.versions && default_version.is_some();
107+
let (versions_and_publishers, default_versions_and_publishers, kws, cats, recent_downloads) = tokio::try_join!(
108+
load_versions_and_publishers(&mut conn, &krate, include.versions),
109+
load_default_versions_and_publishers(
110+
&mut conn,
111+
&krate,
112+
default_version.as_deref(),
113+
include_default_version,
114+
),
115+
load_keywords(&mut conn, &krate, include.keywords),
116+
load_categories(&mut conn, &krate, include.categories),
117+
load_recent_downloads(&mut conn, &krate, include.downloads),
118+
)?;
119+
120+
let ids = versions_and_publishers
121+
.as_ref()
122+
.map(|vps| vps.iter().map(|v| v.0.id).collect());
107123

124+
let versions_publishers_and_audit_actions = if let Some(versions_and_publishers) =
125+
versions_and_publishers.or(default_versions_and_publishers)
126+
{
108127
let versions = versions_and_publishers
109128
.iter()
110129
.map(|(v, _)| v)
@@ -120,57 +139,6 @@ pub async fn find_crate(
120139
} else {
121140
None
122141
};
123-
let ids = versions_publishers_and_audit_actions
124-
.as_ref()
125-
.map(|vps| vps.iter().map(|v| v.0.id).collect());
126-
127-
// Since `versions` and `default_version` share the same key (versions), we should only settle
128-
// the `default_version` when `versions` is not included.
129-
if let Some(default_version) = default_version
130-
.as_ref()
131-
.filter(|_| include.default_version && !include.versions)
132-
{
133-
let version = krate.find_version(&mut conn, default_version).await?;
134-
let version = version.ok_or_else(|| version_not_found(&krate.name, default_version))?;
135-
136-
let (actions, published_by) = tokio::try_join!(
137-
VersionOwnerAction::by_version(&mut conn, &version),
138-
version.published_by(&mut conn),
139-
)?;
140-
versions_publishers_and_audit_actions = Some(vec![(version, published_by, actions)]);
141-
};
142-
143-
let kws = if include.keywords {
144-
Some(
145-
CrateKeyword::belonging_to(&krate)
146-
.inner_join(keywords::table)
147-
.select(Keyword::as_select())
148-
.load(&mut conn)
149-
.await?,
150-
)
151-
} else {
152-
None
153-
};
154-
let cats = if include.categories {
155-
Some(
156-
CrateCategory::belonging_to(&krate)
157-
.inner_join(categories::table)
158-
.select(Category::as_select())
159-
.load(&mut conn)
160-
.await?,
161-
)
162-
} else {
163-
None
164-
};
165-
let recent_downloads = if include.downloads {
166-
RecentCrateDownloads::belonging_to(&krate)
167-
.select(recent_crate_downloads::downloads)
168-
.get_result(&mut conn)
169-
.await
170-
.optional()?
171-
} else {
172-
None
173-
};
174142

175143
let top_versions = if let Some(versions) = versions_publishers_and_audit_actions
176144
.as_ref()
@@ -226,6 +194,109 @@ pub async fn find_crate(
226194
}))
227195
}
228196

197+
type VersionsAndPublishers = (Version, Option<User>);
198+
199+
fn load_versions_and_publishers<'a>(
200+
conn: &mut AsyncPgConnection,
201+
krate: &'a Crate,
202+
includes: bool,
203+
) -> BoxFuture<'a, AppResult<Option<Vec<VersionsAndPublishers>>>> {
204+
if !includes {
205+
return always_ready(|| Ok(None)).boxed();
206+
}
207+
208+
_load_versions_and_publishers(conn, krate, None)
209+
}
210+
211+
fn load_default_versions_and_publishers<'a>(
212+
conn: &mut AsyncPgConnection,
213+
krate: &'a Crate,
214+
version_num: Option<&'a str>,
215+
includes: bool,
216+
) -> BoxFuture<'a, AppResult<Option<Vec<VersionsAndPublishers>>>> {
217+
if !includes || version_num.is_none() {
218+
return always_ready(|| Ok(None)).boxed();
219+
}
220+
221+
let fut = _load_versions_and_publishers(conn, krate, version_num);
222+
async move {
223+
let records = fut.await?.ok_or_else(|| {
224+
version_not_found(
225+
&krate.name,
226+
version_num.expect("default_version should not be None"),
227+
)
228+
})?;
229+
Ok(Some(records))
230+
}
231+
.boxed()
232+
}
233+
234+
fn load_keywords<'a>(
235+
conn: &mut AsyncPgConnection,
236+
krate: &'a Crate,
237+
includes: bool,
238+
) -> BoxFuture<'a, AppResult<Option<Vec<Keyword>>>> {
239+
if !includes {
240+
return always_ready(|| Ok(None)).boxed();
241+
}
242+
243+
let fut = CrateKeyword::belonging_to(&krate)
244+
.inner_join(keywords::table)
245+
.select(Keyword::as_select())
246+
.load(conn);
247+
async move { Ok(Some(fut.await?)) }.boxed()
248+
}
249+
250+
fn load_categories<'a>(
251+
conn: &mut AsyncPgConnection,
252+
krate: &'a Crate,
253+
includes: bool,
254+
) -> BoxFuture<'a, AppResult<Option<Vec<Category>>>> {
255+
if !includes {
256+
return always_ready(|| Ok(None)).boxed();
257+
}
258+
259+
let fut = CrateCategory::belonging_to(&krate)
260+
.inner_join(categories::table)
261+
.select(Category::as_select())
262+
.load(conn);
263+
async move { Ok(Some(fut.await?)) }.boxed()
264+
}
265+
266+
fn load_recent_downloads<'a>(
267+
conn: &mut AsyncPgConnection,
268+
krate: &'a Crate,
269+
includes: bool,
270+
) -> BoxFuture<'a, AppResult<Option<i64>>> {
271+
if !includes {
272+
return always_ready(|| Ok(None)).boxed();
273+
}
274+
275+
let fut = RecentCrateDownloads::belonging_to(&krate)
276+
.select(recent_crate_downloads::downloads)
277+
.get_result(conn);
278+
async move { Ok(fut.await.optional()?) }.boxed()
279+
}
280+
281+
fn _load_versions_and_publishers<'a>(
282+
conn: &mut AsyncPgConnection,
283+
krate: &'a Crate,
284+
version_num: Option<&'a str>,
285+
) -> BoxFuture<'a, AppResult<Option<Vec<VersionsAndPublishers>>>> {
286+
let mut query = Version::belonging_to(&krate)
287+
.left_outer_join(users::table)
288+
.select(<(Version, Option<User>)>::as_select())
289+
.order_by(versions::id.desc())
290+
.into_boxed();
291+
292+
if let Some(num) = version_num {
293+
query = query.filter(versions::num.eq(num));
294+
}
295+
296+
let fut = query.load(conn);
297+
async move { Ok(Some(fut.await?)) }.boxed()
298+
}
299+
229300
#[derive(Debug)]
230301
struct ShowIncludeMode {
231302
versions: bool,

0 commit comments

Comments
 (0)