@@ -19,7 +19,9 @@ use axum::extract::{FromRequestParts, Query};
1919use axum_extra:: json;
2020use axum_extra:: response:: ErasedJson ;
2121use 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} ;
2325use 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 ) ]
230301struct ShowIncludeMode {
231302 versions : bool ,
0 commit comments