forked from rust-lang/crates.io
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrev_deps.rs
More file actions
96 lines (81 loc) · 3.06 KB
/
Copy pathrev_deps.rs
File metadata and controls
96 lines (81 loc) · 3.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use crate::app::AppState;
use crate::controllers::helpers::pagination::{PaginationOptions, PaginationQueryParams};
use crate::controllers::krate::CratePath;
use crate::models::{CrateName, ReverseDependency, User, Version, VersionOwnerAction};
use crate::util::errors::AppResult;
use crate::views::{EncodableDependency, EncodableVersion};
use axum::Json;
use crates_io_database::schema::{crates, oauth_github, users, versions};
use diesel::prelude::*;
use diesel_async::RunQueryDsl;
use http::request::Parts;
use serde::Serialize;
#[derive(Debug, Serialize, utoipa::ToSchema)]
pub struct RevDepsResponse {
/// The list of reverse dependencies of the crate.
dependencies: Vec<EncodableDependency>,
/// The versions referenced in the `dependencies` field.
versions: Vec<EncodableVersion>,
#[schema(inline)]
meta: RevDepsMeta,
}
#[derive(Debug, Serialize, utoipa::ToSchema)]
pub struct RevDepsMeta {
#[schema(example = 32)]
total: i64,
}
/// Lists reverse dependencies of a crate.
#[utoipa::path(
get,
path = "/api/v1/crates/{name}/reverse_dependencies",
params(CratePath, PaginationQueryParams),
tag = "crates",
responses((status = 200, description = "Successful Response", body = inline(RevDepsResponse))),
)]
pub async fn list_reverse_dependencies(
app: AppState,
path: CratePath,
req: Parts,
) -> AppResult<Json<RevDepsResponse>> {
let mut conn = app.db_read().await?;
let pagination_options = PaginationOptions::builder()
.limit_page_numbers()
.gather(&req)?;
let krate = path.load_crate(&conn).await?;
let offset = pagination_options.offset().unwrap_or_default();
let limit = pagination_options.per_page;
let (rev_deps, total) = tokio::try_join!(
ReverseDependency::page_for_crate(krate.id, &conn, offset, limit),
ReverseDependency::count_for_crate(krate.id, &conn),
)?;
let rev_deps: Vec<_> = rev_deps
.into_iter()
.map(|dep| EncodableDependency::from_reverse_dep(dep, &krate.name))
.collect();
let version_ids: Vec<i32> = rev_deps.iter().map(|dep| dep.version_id).collect();
let versions_and_publishers: Vec<(Version, CrateName, Option<User>)> = versions::table
.filter(versions::id.eq_any(version_ids))
.inner_join(crates::table)
.left_outer_join(users::table.left_join(oauth_github::table))
.select(<(Version, CrateName, Option<User>)>::as_select())
.order(versions::id)
.load(&mut conn)
.await?;
let versions = versions_and_publishers
.iter()
.map(|(v, ..)| v)
.collect::<Vec<_>>();
let actions = VersionOwnerAction::for_versions(&conn, &versions).await?;
let versions = versions_and_publishers
.into_iter()
.zip(actions)
.map(|((version, krate_name, published_by), actions)| {
EncodableVersion::from(version, &krate_name.name, published_by, actions)
})
.collect::<Vec<_>>();
Ok(Json(RevDepsResponse {
dependencies: rev_deps,
versions,
meta: RevDepsMeta { total },
}))
}