@@ -50,6 +50,7 @@ pub struct Release {
50
50
pub ( crate ) build_time : Option < DateTime < Utc > > ,
51
51
pub ( crate ) stars : i32 ,
52
52
pub ( crate ) has_unyanked_releases : Option < bool > ,
53
+ pub ( crate ) href : Option < & ' static str > ,
53
54
}
54
55
55
56
#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
@@ -124,6 +125,7 @@ pub(crate) async fn get_releases(
124
125
build_time : row. get ( 5 ) ,
125
126
stars : row. get :: < Option < i32 > , _ > ( 6 ) . unwrap_or ( 0 ) ,
126
127
has_unyanked_releases : None ,
128
+ href : None ,
127
129
} )
128
130
. try_collect ( )
129
131
. await ?)
@@ -142,13 +144,28 @@ struct SearchResult {
142
144
pub next_page : Option < String > ,
143
145
}
144
146
147
+ fn rust_lib_release ( name : & str , description : & str , href : & ' static str ) -> ReleaseStatus {
148
+ ReleaseStatus :: Available ( Release {
149
+ name : name. to_string ( ) ,
150
+ version : String :: new ( ) ,
151
+ description : Some ( description. to_string ( ) ) ,
152
+ build_time : None ,
153
+ target_name : None ,
154
+ rustdoc_status : false ,
155
+ stars : 0 ,
156
+ has_unyanked_releases : None ,
157
+ href : Some ( href) ,
158
+ } )
159
+ }
160
+
145
161
/// Get the search results for a crate search query
146
162
///
147
163
/// This delegates to the crates.io search API.
148
164
async fn get_search_results (
149
165
conn : & mut sqlx:: PgConnection ,
150
166
registry : & RegistryApi ,
151
167
query_params : & str ,
168
+ query : & str ,
152
169
) -> Result < SearchResult , anyhow:: Error > {
153
170
let crate :: registry_api:: Search { crates, meta } = registry. search ( query_params) . await ?;
154
171
@@ -206,28 +223,38 @@ async fn get_search_results(
206
223
rustdoc_status : row. rustdoc_status . unwrap_or ( false ) ,
207
224
stars : row. stars . unwrap_or ( 0 ) ,
208
225
has_unyanked_releases : row. has_unyanked_releases ,
226
+ href : None ,
209
227
} ,
210
228
)
211
229
} )
212
230
. try_collect ( )
213
231
. await ?;
214
232
233
+ // start with the original names from crates.io to keep the original ranking,
234
+ // extend with the release/build information from docs.rs
235
+ // Crates that are not on docs.rs yet will not be returned.
236
+ let mut results = Vec :: new ( ) ;
237
+ if let Some ( super :: rustdoc:: OfficialCrateDescription {
238
+ name,
239
+ href,
240
+ description,
241
+ } ) = super :: rustdoc:: DOC_RUST_LANG_ORG_REDIRECTS . get ( query)
242
+ {
243
+ results. push ( rust_lib_release ( name, description, href) )
244
+ }
245
+
215
246
let names: Vec < String > =
216
247
Arc :: into_inner ( names) . expect ( "Arc still borrowed in `get_search_results`" ) ;
248
+ results. extend ( names. into_iter ( ) . map ( |name| {
249
+ if let Some ( release) = crates. remove ( & name) {
250
+ ReleaseStatus :: Available ( release)
251
+ } else {
252
+ ReleaseStatus :: NotAvailable ( name)
253
+ }
254
+ } ) ) ;
255
+
217
256
Ok ( SearchResult {
218
- // start with the original names from crates.io to keep the original ranking,
219
- // extend with the release/build information from docs.rs
220
- // Crates that are not on docs.rs yet will not be returned.
221
- results : names
222
- . into_iter ( )
223
- . map ( |name| {
224
- if let Some ( release) = crates. remove ( & name) {
225
- ReleaseStatus :: Available ( release)
226
- } else {
227
- ReleaseStatus :: NotAvailable ( name)
228
- }
229
- } )
230
- . collect ( ) ,
257
+ results,
231
258
prev_page : meta. prev_page ,
232
259
next_page : meta. next_page ,
233
260
} )
@@ -589,15 +616,15 @@ pub(crate) async fn search_handler(
589
616
}
590
617
}
591
618
592
- get_search_results ( & mut conn, & registry, query_params) . await ?
619
+ get_search_results ( & mut conn, & registry, query_params, "" ) . await ?
593
620
} else if !query. is_empty ( ) {
594
621
let query_params: String = form_urlencoded:: Serializer :: new ( String :: new ( ) )
595
622
. append_pair ( "q" , & query)
596
623
. append_pair ( "sort" , & sort_by)
597
624
. append_pair ( "per_page" , & RELEASES_IN_RELEASES . to_string ( ) )
598
625
. finish ( ) ;
599
626
600
- get_search_results ( & mut conn, & registry, & query_params) . await ?
627
+ get_search_results ( & mut conn, & registry, & query_params, & query ) . await ?
601
628
} else {
602
629
return Err ( AxumNope :: NoResults ) ;
603
630
} ;
@@ -2231,4 +2258,55 @@ mod tests {
2231
2258
Ok ( ( ) )
2232
2259
} ) ;
2233
2260
}
2261
+
2262
+ #[ test]
2263
+ fn test_search_std ( ) {
2264
+ async_wrapper ( |env| async move {
2265
+ let web = env. web_app ( ) . await ;
2266
+
2267
+ async fn inner ( web : & axum:: Router , krate : & str ) -> Result < ( ) , anyhow:: Error > {
2268
+ let full = kuchikiki:: parse_html ( ) . one (
2269
+ web. get ( & format ! ( "/releases/search?query={krate}" ) )
2270
+ . await ?
2271
+ . text ( )
2272
+ . await ?,
2273
+ ) ;
2274
+ let items = full
2275
+ . select ( "ul a.release" )
2276
+ . expect ( "missing list items" )
2277
+ . collect :: < Vec < _ > > ( ) ;
2278
+
2279
+ // empty because expand_rebuild_queue is not set
2280
+ let item_element = items. first ( ) . unwrap ( ) ;
2281
+ let item = item_element. as_node ( ) ;
2282
+ assert_eq ! (
2283
+ item. select( ".name" )
2284
+ . unwrap( )
2285
+ . next( )
2286
+ . unwrap( )
2287
+ . text_contents( ) ,
2288
+ "std"
2289
+ ) ;
2290
+ assert_eq ! (
2291
+ item. select( ".description" )
2292
+ . unwrap( )
2293
+ . next( )
2294
+ . unwrap( )
2295
+ . text_contents( ) ,
2296
+ "Rust standard library" ,
2297
+ ) ;
2298
+ assert_eq ! (
2299
+ item_element. attributes. borrow( ) . get( "href" ) . unwrap( ) ,
2300
+ "https://doc.rust-lang.org/stable/std/"
2301
+ ) ;
2302
+
2303
+ Ok ( ( ) )
2304
+ }
2305
+
2306
+ inner ( & web, "std" ) . await ?;
2307
+ inner ( & web, "libstd" ) . await ?;
2308
+
2309
+ Ok ( ( ) )
2310
+ } ) ;
2311
+ }
2234
2312
}
0 commit comments