@@ -14,7 +14,7 @@ use iron::{
14
14
modifiers:: Redirect ,
15
15
status, IronResult , Request , Response , Url ,
16
16
} ;
17
- use log:: debug;
17
+ use log:: { debug, trace } ;
18
18
use postgres:: Client ;
19
19
use router:: Router ;
20
20
use serde:: { Deserialize , Serialize } ;
@@ -232,8 +232,6 @@ fn get_search_results(
232
232
struct CratesIoRelease {
233
233
name : String ,
234
234
max_version : String ,
235
- description : Option < String > ,
236
- updated_at : DateTime < Utc > ,
237
235
}
238
236
#[ derive( Deserialize ) ]
239
237
struct CratesIoMeta {
@@ -255,47 +253,57 @@ fn get_search_results(
255
253
. unwrap ( )
256
254
} ) ;
257
255
258
- let page: & str = & page. to_string ( ) ;
259
256
let url = url:: Url :: parse_with_params (
260
257
"https://crates.io/api/v1/crates" ,
261
258
& [
262
- ( "page" , page) ,
263
- ( "per_page" , & limit. to_string ( ) ) ,
264
259
( "q" , query) ,
260
+ ( "page" , & page. to_string ( ) ) ,
261
+ ( "per_page" , & limit. to_string ( ) ) ,
265
262
] ,
266
263
) ?;
267
264
debug ! ( "fetching search results from {}" , url) ;
268
265
let releases: CratesIoReleases = HTTP_CLIENT . get ( url) . send ( ) ?. json ( ) ?;
269
- let query = conn. prepare (
270
- "SELECT github_repos.stars, releases.target_name, releases.rustdoc_status
266
+ let ( names_and_versions, names) : ( Vec < _ > , Vec < _ > ) = releases
267
+ . crates
268
+ . into_iter ( )
269
+ // The `postgres` crate doesn't support anonymous records.
270
+ // Use strings instead.
271
+ // Additionally, looking at both the name and version doesn't allow using the index;
272
+ // first filter by crate name so the query is more efficient.
273
+ . map ( |krate| ( format ! ( "{}:{}" , krate. name, krate. max_version) , krate. name ) )
274
+ . unzip ( ) ;
275
+ trace ! ( "crates.io search results {:#?}" , names_and_versions) ;
276
+ let crates = conn
277
+ . query (
278
+ "
279
+ SELECT
280
+ crates.name,
281
+ releases.version,
282
+ releases.description,
283
+ releases.release_time,
284
+ releases.target_name,
285
+ releases.rustdoc_status,
286
+ github_repos.stars
271
287
FROM crates INNER JOIN releases ON crates.id = releases.crate_id
272
288
LEFT JOIN github_repos ON releases.github_repo = github_repos.id
273
- WHERE crates.name = $1 AND releases.version = $2" ,
274
- ) ? ;
275
- let crates = releases
276
- . crates
289
+ WHERE crates.name = ANY($1) AND crates.name || ':' || releases.version = ANY($2)
290
+ " ,
291
+ & [ & names , & names_and_versions ] ,
292
+ ) ?
277
293
. into_iter ( )
278
- . flat_map ( |krate| {
279
- let rows = match conn. query ( & query, & [ & krate. name , & krate. max_version ] ) {
280
- Err ( e) => return Some ( Err ( e) ) ,
281
- Ok ( rows) => rows,
282
- } ;
283
- debug ! ( "looking up results for {:?}" , krate) ;
284
- // crates.io could have a release that hasn't yet been added to the database.
285
- // If so, just skip it.
286
- let row = rows. get ( 0 ) ?;
294
+ . map ( |row| {
287
295
let stars: Option < _ > = row. get ( "stars" ) ;
288
- Some ( Result :: < _ , postgres :: Error > :: Ok ( Release {
289
- name : krate . name ,
290
- version : krate . max_version ,
291
- description : krate . description ,
292
- release_time : krate . updated_at ,
296
+ Release {
297
+ name : row . get ( " name" ) ,
298
+ version : row . get ( "version" ) ,
299
+ description : row . get ( " description" ) ,
300
+ release_time : row . get ( "release_time" ) ,
293
301
target_name : row. get ( "target_name" ) ,
294
302
rustdoc_status : row. get ( "rustdoc_status" ) ,
295
303
stars : stars. unwrap_or ( 0 ) ,
296
- } ) )
304
+ }
297
305
} )
298
- . collect :: < Result < _ , _ > > ( ) ? ;
306
+ . collect ( ) ;
299
307
Ok ( ( releases. meta . total , crates) )
300
308
}
301
309
0 commit comments