@@ -8,7 +8,8 @@ use std::cmp::Reverse;
8
8
use std:: str:: FromStr ;
9
9
10
10
use crate :: controllers:: frontend_prelude:: * ;
11
- use crate :: controllers:: helpers:: pagination:: PaginationOptions ;
11
+ use crate :: controllers:: helpers:: Paginate ;
12
+ use crate :: controllers:: helpers:: pagination:: { PaginationOptions , Paginated } ;
12
13
13
14
use crate :: models:: {
14
15
Category , Crate , CrateCategory , CrateKeyword , CrateVersions , Keyword , RecentCrateDownloads ,
@@ -320,15 +321,34 @@ pub async fn readme(
320
321
/// Handles the `GET /crates/:crate_id/versions` route.
321
322
// FIXME: Not sure why this is necessary since /crates/:crate_id returns
322
323
// this information already, but ember is definitely requesting it
323
- pub async fn versions ( state : AppState , Path ( crate_name) : Path < String > ) -> AppResult < Json < Value > > {
324
+ pub async fn versions ( state : AppState , Path ( crate_name) : Path < String > , req : Parts ) -> AppResult < Json < Value > > {
324
325
conduit_compat ( move || {
325
326
let conn = state. db_read ( ) ?;
326
327
let krate: Crate = Crate :: by_name ( & crate_name) . first ( & * conn) ?;
327
- let mut versions_and_publishers: Vec < ( Version , Option < User > ) > = krate
328
- . all_versions ( )
329
- . left_outer_join ( users:: table)
330
- . select ( ( versions:: all_columns, users:: all_columns. nullable ( ) ) )
331
- . load ( & * conn) ?;
328
+ // to keep retrocompatibility, we paginate only if per_page parameter is present
329
+ let ( mut versions_and_publishers, meta) = if req. query ( ) . get ( "per_page" ) . is_some ( ) {
330
+ let pagination_options = PaginationOptions :: builder ( ) . gather ( & req) ?;
331
+ let data: Paginated < ( Version , Option < User > ) > = krate
332
+ . all_versions ( )
333
+ . left_outer_join ( users:: table)
334
+ . select ( ( versions:: all_columns, users:: all_columns. nullable ( ) ) )
335
+ . order ( versions:: created_at. desc ( ) )
336
+ . pages_pagination ( pagination_options)
337
+ . load ( & conn) ?;
338
+ let more = data. next_page_params ( ) . is_some ( ) ;
339
+
340
+ (
341
+ data. into_iter ( ) . collect :: < Vec < _ > > ( ) ,
342
+ Some ( json ! ( { "more" : more } ) ) ,
343
+ )
344
+ } else {
345
+ let data: Vec < ( Version , Option < User > ) > = krate
346
+ . all_versions ( )
347
+ . left_outer_join ( users:: table)
348
+ . select ( ( versions:: all_columns, users:: all_columns. nullable ( ) ) )
349
+ . load ( & * conn) ?;
350
+ ( data, None )
351
+ } ;
332
352
333
353
versions_and_publishers
334
354
. sort_by_cached_key ( |( version, _) | Reverse ( semver:: Version :: parse ( & version. num ) . ok ( ) ) ) ;
@@ -344,7 +364,18 @@ pub async fn versions(state: AppState, Path(crate_name): Path<String>) -> AppRes
344
364
. map ( |( ( v, pb) , aas) | EncodableVersion :: from ( v, & crate_name, pb, aas) )
345
365
. collect :: < Vec < _ > > ( ) ;
346
366
347
- Ok ( Json ( json ! ( { "versions" : versions } ) ) )
367
+ // probably here would be simplier with a concrete response type
368
+ let response = if let Some ( meta) = meta {
369
+ json ! ( {
370
+ "versions" : versions,
371
+ "meta" : meta,
372
+ } )
373
+ } else {
374
+ json ! ( {
375
+ "versions" : versions,
376
+ } )
377
+ } ;
378
+ Ok ( Json ( response) )
348
379
} )
349
380
. await
350
381
}
0 commit comments