1
- use crate :: controllers:: helpers:: pagination:: decode_seek;
2
1
use crate :: models:: Category ;
3
2
use crate :: schema:: { crates, users} ;
4
3
use crate :: tests:: builders:: { CrateBuilder , VersionBuilder } ;
@@ -412,8 +411,6 @@ async fn index_sorting() -> anyhow::Result<()> {
412
411
assert_eq ! ( resp[ 3 ] . meta. total, 4 ) ;
413
412
assert_eq ! ( calls, 5 ) ;
414
413
415
- use std:: cmp:: Reverse ;
416
-
417
414
// Sort by alpha with query
418
415
// ordering (exact match desc, name asc)
419
416
let query = "sort=alpha&q=bar_sort" ;
@@ -438,39 +435,51 @@ async fn index_sorting() -> anyhow::Result<()> {
438
435
assert_eq ! ( calls, 5 ) ;
439
436
440
437
// Sort by relevance
438
+ // ordering (exact match desc, rank desc, name asc)
439
+ let query = "q=foo_sort" ;
440
+ let ( resp, calls) = page_with_seek ( & anon, query) . await ;
441
+ for json in search_both ( & anon, query) . await {
442
+ assert_eq ! ( json. meta. total, 3 ) ;
443
+ assert_eq ! ( resp[ 0 ] . crates[ 0 ] . name, "foo_sort" ) ;
444
+ // same rank, by name asc
445
+ assert_eq ! ( resp[ 1 ] . crates[ 0 ] . name, "bar_sort" ) ;
446
+ assert_eq ! ( resp[ 2 ] . crates[ 0 ] . name, "baz_sort" ) ;
447
+ }
448
+ assert_eq ! ( calls, 4 ) ;
449
+ let ranks = querystring_rank ( & mut conn, "foo_sort" ) . await ;
450
+ assert_eq ! ( ranks. get( "bar_sort" ) , ranks. get( "baz_sort" ) ) ;
451
+
441
452
// Add query containing a space to ensure tsquery works
442
- for query in [ "q=foo_sort" , "q=sort" , "q=foo%20sort" ] {
443
- let ( resp, calls) = page_with_seek ( & anon, query) . await ;
444
- assert_eq ! ( calls, resp[ 0 ] . meta. total + 1 ) ;
445
- let decoded_seeks = resp
446
- . iter ( )
447
- . filter_map ( |cl| {
448
- cl. meta
449
- . next_page
450
- . as_ref ( )
451
- . map ( |next_page| ( next_page, cl. crates [ 0 ] . name . to_owned ( ) ) )
452
- } )
453
- . filter_map ( |( q, name) | {
454
- let query = url:: form_urlencoded:: parse ( q. trim_start_matches ( '?' ) . as_bytes ( ) )
455
- . into_owned ( )
456
- . collect :: < indexmap:: IndexMap < String , String > > ( ) ;
457
- query. get ( "seek" ) . map ( |s| {
458
- let d = decode_seek :: < ( bool , f32 , i32 ) > ( s) . unwrap ( ) ;
459
- ( d. 0 , ( d. 1 * 1e12 ) as i64 , name)
460
- } )
461
- } )
462
- . collect :: < Vec < _ > > ( ) ;
463
- // ordering (exact match desc, rank desc, name asc)
464
- let mut sorted = decoded_seeks. clone ( ) ;
465
- sorted. sort_by_key ( |k| ( Reverse ( k. 0 ) , Reverse ( k. 1 ) , k. 2 . to_owned ( ) ) ) ;
466
- assert_eq ! ( sorted, decoded_seeks) ;
467
- for json in search_both ( & anon, query) . await {
468
- assert_eq ! ( json. meta. total, resp[ 0 ] . meta. total) ;
469
- for ( c, r) in json. crates . iter ( ) . zip ( & resp) {
470
- assert_eq ! ( c. name, r. crates[ 0 ] . name) ;
471
- }
472
- }
453
+ // "foo_sort" and "foo sort" would generate same tsquery
454
+ let query = "q=foo%20sort" ;
455
+ let ( resp, calls) = page_with_seek ( & anon, query) . await ;
456
+ for json in search_both ( & anon, query) . await {
457
+ assert_eq ! ( json. meta. total, 3 ) ;
458
+ assert_eq ! ( resp[ 0 ] . crates[ 0 ] . name, "foo_sort" ) ;
459
+ // same rank, by name asc
460
+ assert_eq ! ( resp[ 1 ] . crates[ 0 ] . name, "bar_sort" ) ;
461
+ assert_eq ! ( resp[ 2 ] . crates[ 0 ] . name, "baz_sort" ) ;
462
+ }
463
+ assert_eq ! ( calls, 4 ) ;
464
+ let ranks = querystring_rank ( & mut conn, "foo%20sort" ) . await ;
465
+ assert_eq ! ( ranks. get( "bar_sort" ) , ranks. get( "baz_sort" ) ) ;
466
+
467
+ let query = "q=sort" ;
468
+ let ( resp, calls) = page_with_seek ( & anon, query) . await ;
469
+ for json in search_both ( & anon, query) . await {
470
+ assert_eq ! ( json. meta. total, 4 ) ;
471
+ // by rank desc (items with more "sort" should have a hider rank value)
472
+ assert_eq ! ( resp[ 0 ] . crates[ 0 ] . name, "baz_sort" ) ;
473
+ assert_eq ! ( resp[ 1 ] . crates[ 0 ] . name, "bar_sort" ) ;
474
+ assert_eq ! ( resp[ 2 ] . crates[ 0 ] . name, "foo_sort" ) ;
475
+ assert_eq ! ( resp[ 3 ] . crates[ 0 ] . name, "other_sort" ) ;
473
476
}
477
+ assert_eq ! ( calls, 5 ) ;
478
+ let ranks = querystring_rank ( & mut conn, "sort" ) . await ;
479
+ assert_eq ! (
480
+ ranks. keys( ) . collect:: <Vec <_>>( ) ,
481
+ [ "baz_sort" , "bar_sort" , "foo_sort" , "other_sort" ]
482
+ ) ;
474
483
475
484
// Test for bug with showing null results first when sorting
476
485
// by descending downloads
@@ -1275,3 +1284,28 @@ fn default_versions_iter(
1275
1284
fn yanked_iter ( crates : & [ crate :: tests:: EncodableCrate ] ) -> impl Iterator < Item = & bool > {
1276
1285
crates. iter ( ) . map ( |c| & c. yanked )
1277
1286
}
1287
+
1288
+ async fn querystring_rank (
1289
+ conn : & mut diesel_async:: AsyncPgConnection ,
1290
+ q : & str ,
1291
+ ) -> indexmap:: IndexMap < String , f32 > {
1292
+ use diesel_full_text_search:: configuration:: TsConfigurationByName ;
1293
+ use diesel_full_text_search:: { plainto_tsquery_with_search_config, ts_rank_cd} ;
1294
+ use futures_util:: future:: ready;
1295
+ use futures_util:: TryStreamExt ;
1296
+
1297
+ let tsquery = plainto_tsquery_with_search_config ( TsConfigurationByName ( "english" ) , q) ;
1298
+ let rank = ts_rank_cd ( crates:: textsearchable_index_col, tsquery) ;
1299
+ crates:: table
1300
+ . select ( ( crates:: name, rank) )
1301
+ . order_by ( rank. desc ( ) )
1302
+ . load_stream :: < ( String , f32 ) > ( conn)
1303
+ . await
1304
+ . unwrap ( )
1305
+ . try_fold ( indexmap:: IndexMap :: new ( ) , |mut map, ( name, id) | {
1306
+ map. insert ( name, id) ;
1307
+ ready ( Ok ( map) )
1308
+ } )
1309
+ . await
1310
+ . unwrap ( )
1311
+ }
0 commit comments