1- use crate :: controllers:: helpers:: pagination:: decode_seek;
21use crate :: models:: Category ;
32use crate :: schema:: { crates, users} ;
43use crate :: tests:: builders:: { CrateBuilder , VersionBuilder } ;
@@ -412,8 +411,6 @@ async fn index_sorting() -> anyhow::Result<()> {
412411 assert_eq ! ( resp[ 3 ] . meta. total, 4 ) ;
413412 assert_eq ! ( calls, 5 ) ;
414413
415- use std:: cmp:: Reverse ;
416-
417414 // Sort by alpha with query
418415 // ordering (exact match desc, name asc)
419416 let query = "sort=alpha&q=bar_sort" ;
@@ -438,39 +435,51 @@ async fn index_sorting() -> anyhow::Result<()> {
438435 assert_eq ! ( calls, 5 ) ;
439436
440437 // 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+
441452 // 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" ) ;
473476 }
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+ ) ;
474483
475484 // Test for bug with showing null results first when sorting
476485 // by descending downloads
@@ -1275,3 +1284,28 @@ fn default_versions_iter(
12751284fn yanked_iter ( crates : & [ crate :: tests:: EncodableCrate ] ) -> impl Iterator < Item = & bool > {
12761285 crates. iter ( ) . map ( |c| & c. yanked )
12771286}
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