@@ -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 } ;
@@ -182,8 +182,6 @@ fn get_search_results(
182
182
struct CratesIoRelease {
183
183
name : String ,
184
184
max_version : String ,
185
- description : Option < String > ,
186
- updated_at : DateTime < Utc > ,
187
185
}
188
186
#[ derive( Deserialize ) ]
189
187
struct CratesIoMeta {
@@ -205,47 +203,57 @@ fn get_search_results(
205
203
. unwrap ( )
206
204
} ) ;
207
205
208
- let page: & str = & page. to_string ( ) ;
209
206
let url = url:: Url :: parse_with_params (
210
207
"https://crates.io/api/v1/crates" ,
211
208
& [
212
- ( "page" , page) ,
213
- ( "per_page" , & limit. to_string ( ) ) ,
214
209
( "q" , query) ,
210
+ ( "page" , & page. to_string ( ) ) ,
211
+ ( "per_page" , & limit. to_string ( ) ) ,
215
212
] ,
216
213
) ?;
217
214
debug ! ( "fetching search results from {}" , url) ;
218
215
let releases: CratesIoReleases = HTTP_CLIENT . get ( url) . send ( ) ?. json ( ) ?;
219
- let query = conn. prepare (
220
- "SELECT github_repos.stars, releases.target_name, releases.rustdoc_status
216
+ let ( names_and_versions, names) : ( Vec < _ > , Vec < _ > ) = releases
217
+ . crates
218
+ . into_iter ( )
219
+ // The `postgres` crate doesn't support anonymous records.
220
+ // Use strings instead.
221
+ // Additionally, looking at both the name and version doesn't allow using the index;
222
+ // first filter by crate name so the query is more efficient.
223
+ . map ( |krate| ( format ! ( "{}:{}" , krate. name, krate. max_version) , krate. name ) )
224
+ . unzip ( ) ;
225
+ trace ! ( "crates.io search results {:#?}" , names_and_versions) ;
226
+ let crates = conn
227
+ . query (
228
+ "
229
+ SELECT
230
+ crates.name,
231
+ releases.version,
232
+ releases.description,
233
+ releases.release_time,
234
+ releases.target_name,
235
+ releases.rustdoc_status,
236
+ github_repos.stars
221
237
FROM crates INNER JOIN releases ON crates.id = releases.crate_id
222
238
LEFT JOIN github_repos ON releases.github_repo = github_repos.id
223
- WHERE crates.name = $1 AND releases.version = $2" ,
224
- ) ? ;
225
- let crates = releases
226
- . crates
239
+ WHERE crates.name = ANY($1) AND crates.name || ':' || releases.version = ANY($2)
240
+ " ,
241
+ & [ & names , & names_and_versions ] ,
242
+ ) ?
227
243
. into_iter ( )
228
- . flat_map ( |krate| {
229
- let rows = match conn. query ( & query, & [ & krate. name , & krate. max_version ] ) {
230
- Err ( e) => return Some ( Err ( e) ) ,
231
- Ok ( rows) => rows,
232
- } ;
233
- debug ! ( "looking up results for {:?}" , krate) ;
234
- // crates.io could have a release that hasn't yet been added to the database.
235
- // If so, just skip it.
236
- let row = rows. get ( 0 ) ?;
244
+ . map ( |row| {
237
245
let stars: Option < _ > = row. get ( "stars" ) ;
238
- Some ( Result :: < _ , postgres :: Error > :: Ok ( Release {
239
- name : krate . name ,
240
- version : krate . max_version ,
241
- description : krate . description ,
242
- release_time : krate . updated_at ,
246
+ Release {
247
+ name : row . get ( " name" ) ,
248
+ version : row . get ( "version" ) ,
249
+ description : row . get ( " description" ) ,
250
+ release_time : row . get ( "release_time" ) ,
243
251
target_name : row. get ( "target_name" ) ,
244
252
rustdoc_status : row. get ( "rustdoc_status" ) ,
245
253
stars : stars. unwrap_or ( 0 ) ,
246
- } ) )
254
+ }
247
255
} )
248
- . collect :: < Result < _ , _ > > ( ) ? ;
256
+ . collect ( ) ;
249
257
Ok ( ( releases. meta . total , crates) )
250
258
}
251
259
0 commit comments