@@ -294,3 +294,202 @@ fn iterative_facet_string_ordered_iter<'t>(
294294
295295 Ok ( vec. into_iter ( ) )
296296}
297+
298+ #[ cfg( test) ]
299+ mod tests {
300+ use std:: str:: FromStr ;
301+
302+ use big_s:: S ;
303+ use maplit:: hashset;
304+
305+ use crate :: index:: tests:: TempIndex ;
306+ use crate :: { AscDesc , Filter , Search , SearchResult } ;
307+
308+ // Note that in this test, only the iterative sort algorithms are used. Set the CANDIDATES_THESHOLD
309+ // constant to 0 to ensure that the other sort algorithms are also correct.
310+ #[ test]
311+ fn sort_criterion_placeholder ( ) {
312+ let index = TempIndex :: new ( ) ;
313+
314+ index
315+ . update_settings ( |settings| {
316+ settings. set_primary_key ( "id" . to_owned ( ) ) ;
317+ settings
318+ . set_sortable_fields ( maplit:: hashset! { S ( "id" ) , S ( "mod_10" ) , S ( "mod_20" ) } ) ;
319+ settings. set_criteria ( vec ! [ "sort" . to_owned( ) ] ) ;
320+ } )
321+ . unwrap ( ) ;
322+
323+ let mut docs = vec ! [ ] ;
324+ for i in 0 ..100 {
325+ docs. push (
326+ serde_json:: json!( { "id" : i, "mod_10" : format!( "{}" , i % 10 ) , "mod_20" : i % 20 } ) ,
327+ ) ;
328+ }
329+
330+ index. add_documents ( documents ! ( docs) ) . unwrap ( ) ;
331+
332+ let all_ids = ( 0 ..100 ) . collect :: < Vec < _ > > ( ) ;
333+
334+ let rtxn = index. read_txn ( ) . unwrap ( ) ;
335+
336+ let mut search = Search :: new ( & rtxn, & index) ;
337+ search. sort_criteria ( vec ! [ AscDesc :: from_str( "mod_10:desc" ) . unwrap( ) ] ) ;
338+ search. limit ( 100 ) ;
339+
340+ let SearchResult { mut documents_ids, .. } = search. execute ( ) . unwrap ( ) ;
341+ insta:: assert_snapshot!( format!( "{documents_ids:?}" ) , @"[9, 19, 29, 39, 49, 59, 69, 79, 89, 99, 8, 18, 28, 38, 48, 58, 68, 78, 88, 98, 7, 17, 27, 37, 47, 57, 67, 77, 87, 97, 6, 16, 26, 36, 46, 56, 66, 76, 86, 96, 5, 15, 25, 35, 45, 55, 65, 75, 85, 95, 4, 14, 24, 34, 44, 54, 64, 74, 84, 94, 3, 13, 23, 33, 43, 53, 63, 73, 83, 93, 2, 12, 22, 32, 42, 52, 62, 72, 82, 92, 1, 11, 21, 31, 41, 51, 61, 71, 81, 91, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90]" ) ;
342+ documents_ids. sort ( ) ;
343+ assert_eq ! ( all_ids, documents_ids) ;
344+
345+ let mut search = Search :: new ( & rtxn, & index) ;
346+ search. sort_criteria ( vec ! [
347+ AscDesc :: from_str( "mod_10:desc" ) . unwrap( ) ,
348+ AscDesc :: from_str( "id:desc" ) . unwrap( ) ,
349+ ] ) ;
350+ search. limit ( 100 ) ;
351+
352+ let SearchResult { mut documents_ids, .. } = search. execute ( ) . unwrap ( ) ;
353+ insta:: assert_snapshot!( format!( "{documents_ids:?}" ) , @"[99, 89, 79, 69, 59, 49, 39, 29, 19, 9, 98, 88, 78, 68, 58, 48, 38, 28, 18, 8, 97, 87, 77, 67, 57, 47, 37, 27, 17, 7, 96, 86, 76, 66, 56, 46, 36, 26, 16, 6, 95, 85, 75, 65, 55, 45, 35, 25, 15, 5, 94, 84, 74, 64, 54, 44, 34, 24, 14, 4, 93, 83, 73, 63, 53, 43, 33, 23, 13, 3, 92, 82, 72, 62, 52, 42, 32, 22, 12, 2, 91, 81, 71, 61, 51, 41, 31, 21, 11, 1, 90, 80, 70, 60, 50, 40, 30, 20, 10, 0]" ) ;
354+ documents_ids. sort ( ) ;
355+ assert_eq ! ( all_ids, documents_ids) ;
356+
357+ let mut search = Search :: new ( & rtxn, & index) ;
358+ search. sort_criteria ( vec ! [
359+ AscDesc :: from_str( "mod_10:desc" ) . unwrap( ) ,
360+ AscDesc :: from_str( "mod_20:asc" ) . unwrap( ) ,
361+ ] ) ;
362+ search. limit ( 100 ) ;
363+
364+ let SearchResult { mut documents_ids, .. } = search. execute ( ) . unwrap ( ) ;
365+ insta:: assert_snapshot!( format!( "{documents_ids:?}" ) , @"[9, 29, 49, 69, 89, 19, 39, 59, 79, 99, 8, 28, 48, 68, 88, 18, 38, 58, 78, 98, 7, 27, 47, 67, 87, 17, 37, 57, 77, 97, 6, 26, 46, 66, 86, 16, 36, 56, 76, 96, 5, 25, 45, 65, 85, 15, 35, 55, 75, 95, 4, 24, 44, 64, 84, 14, 34, 54, 74, 94, 3, 23, 43, 63, 83, 13, 33, 53, 73, 93, 2, 22, 42, 62, 82, 12, 32, 52, 72, 92, 1, 21, 41, 61, 81, 11, 31, 51, 71, 91, 0, 20, 40, 60, 80, 10, 30, 50, 70, 90]" ) ;
366+ documents_ids. sort ( ) ;
367+ assert_eq ! ( all_ids, documents_ids) ;
368+
369+ let mut search = Search :: new ( & rtxn, & index) ;
370+ search. sort_criteria ( vec ! [
371+ AscDesc :: from_str( "mod_10:desc" ) . unwrap( ) ,
372+ AscDesc :: from_str( "mod_20:desc" ) . unwrap( ) ,
373+ ] ) ;
374+ search. limit ( 100 ) ;
375+
376+ let SearchResult { mut documents_ids, .. } = search. execute ( ) . unwrap ( ) ;
377+ insta:: assert_snapshot!( format!( "{documents_ids:?}" ) , @"[19, 39, 59, 79, 99, 9, 29, 49, 69, 89, 18, 38, 58, 78, 98, 8, 28, 48, 68, 88, 17, 37, 57, 77, 97, 7, 27, 47, 67, 87, 16, 36, 56, 76, 96, 6, 26, 46, 66, 86, 15, 35, 55, 75, 95, 5, 25, 45, 65, 85, 14, 34, 54, 74, 94, 4, 24, 44, 64, 84, 13, 33, 53, 73, 93, 3, 23, 43, 63, 83, 12, 32, 52, 72, 92, 2, 22, 42, 62, 82, 11, 31, 51, 71, 91, 1, 21, 41, 61, 81, 10, 30, 50, 70, 90, 0, 20, 40, 60, 80]" ) ;
378+ documents_ids. sort ( ) ;
379+ assert_eq ! ( all_ids, documents_ids) ;
380+
381+ let mut search = Search :: new ( & rtxn, & index) ;
382+ search. sort_criteria ( vec ! [
383+ AscDesc :: from_str( "mod_10:desc" ) . unwrap( ) ,
384+ AscDesc :: from_str( "mod_20:desc" ) . unwrap( ) ,
385+ AscDesc :: from_str( "id:desc" ) . unwrap( ) ,
386+ ] ) ;
387+ search. limit ( 100 ) ;
388+
389+ let SearchResult { mut documents_ids, .. } = search. execute ( ) . unwrap ( ) ;
390+ insta:: assert_snapshot!( format!( "{documents_ids:?}" ) , @"[99, 79, 59, 39, 19, 89, 69, 49, 29, 9, 98, 78, 58, 38, 18, 88, 68, 48, 28, 8, 97, 77, 57, 37, 17, 87, 67, 47, 27, 7, 96, 76, 56, 36, 16, 86, 66, 46, 26, 6, 95, 75, 55, 35, 15, 85, 65, 45, 25, 5, 94, 74, 54, 34, 14, 84, 64, 44, 24, 4, 93, 73, 53, 33, 13, 83, 63, 43, 23, 3, 92, 72, 52, 32, 12, 82, 62, 42, 22, 2, 91, 71, 51, 31, 11, 81, 61, 41, 21, 1, 90, 70, 50, 30, 10, 80, 60, 40, 20, 0]" ) ;
391+ documents_ids. sort ( ) ;
392+ assert_eq ! ( all_ids, documents_ids) ;
393+ }
394+
395+ // Note that in this test, only the iterative sort algorithms are used. Set the CANDIDATES_THESHOLD
396+ // constant to 0 to ensure that the other sort algorithms are also correct.
397+ #[ test]
398+ fn sort_criterion_non_placeholder ( ) {
399+ let index = TempIndex :: new ( ) ;
400+
401+ index
402+ . update_settings ( |settings| {
403+ settings. set_primary_key ( "id" . to_owned ( ) ) ;
404+ settings. set_filterable_fields ( hashset ! { S ( "id" ) , S ( "mod_10" ) , S ( "mod_20" ) } ) ;
405+ settings. set_sortable_fields ( hashset ! { S ( "id" ) , S ( "mod_10" ) , S ( "mod_20" ) } ) ;
406+ settings. set_criteria ( vec ! [ "sort" . to_owned( ) ] ) ;
407+ } )
408+ . unwrap ( ) ;
409+
410+ let mut docs = vec ! [ ] ;
411+ for i in 0 ..100 {
412+ docs. push (
413+ serde_json:: json!( { "id" : i, "mod_10" : format!( "{}" , i % 10 ) , "mod_20" : i % 20 } ) ,
414+ ) ;
415+ }
416+
417+ index. add_documents ( documents ! ( docs) ) . unwrap ( ) ;
418+
419+ let rtxn = index. read_txn ( ) . unwrap ( ) ;
420+
421+ let mut search = Search :: new ( & rtxn, & index) ;
422+ search. filter (
423+ Filter :: from_str ( "mod_10 IN [1, 0, 2] OR mod_20 IN [10, 13] OR id IN [5, 6]" )
424+ . unwrap ( )
425+ . unwrap ( ) ,
426+ ) ;
427+ search. sort_criteria ( vec ! [
428+ AscDesc :: from_str( "mod_10:desc" ) . unwrap( ) ,
429+ AscDesc :: from_str( "mod_20:asc" ) . unwrap( ) ,
430+ AscDesc :: from_str( "id:desc" ) . unwrap( ) ,
431+ ] ) ;
432+ search. limit ( 100 ) ;
433+
434+ let SearchResult { mut documents_ids, .. } = search. execute ( ) . unwrap ( ) ;
435+ // The order should be in increasing value of the id modulo 10, followed by increasing value of the id modulo 20, followed by decreasing value of the id
436+ insta:: assert_snapshot!( format!( "{documents_ids:?}" ) , @"[6, 5, 93, 73, 53, 33, 13, 82, 62, 42, 22, 2, 92, 72, 52, 32, 12, 81, 61, 41, 21, 1, 91, 71, 51, 31, 11, 80, 60, 40, 20, 0, 90, 70, 50, 30, 10]" ) ;
437+ let expected_ids = ( 0 ..100 )
438+ . filter ( |id| {
439+ [ 1 , 0 , 2 ] . contains ( & ( id % 10 ) )
440+ || [ 10 , 13 ] . contains ( & ( id % 20 ) )
441+ || [ 5 , 6 ] . contains ( id)
442+ } )
443+ . collect :: < Vec < _ > > ( ) ;
444+ documents_ids. sort ( ) ;
445+ assert_eq ! ( expected_ids, documents_ids) ;
446+
447+ let mut search = Search :: new ( & rtxn, & index) ;
448+ search. filter (
449+ Filter :: from_str ( "mod_10 IN [7, 8, 0] OR mod_20 IN [1, 15, 16] OR id IN [0, 4]" )
450+ . unwrap ( )
451+ . unwrap ( ) ,
452+ ) ;
453+ search. sort_criteria ( vec ! [
454+ AscDesc :: from_str( "mod_10:asc" ) . unwrap( ) ,
455+ AscDesc :: from_str( "mod_20:asc" ) . unwrap( ) ,
456+ AscDesc :: from_str( "id:desc" ) . unwrap( ) ,
457+ ] ) ;
458+ search. limit ( 100 ) ;
459+
460+ let SearchResult { mut documents_ids, .. } = search. execute ( ) . unwrap ( ) ;
461+ // The order should be in increasing value of the id modulo 10, followed by increasing value of the id modulo 20, followed by decreasing value of the id
462+ insta:: assert_snapshot!( format!( "{documents_ids:?}" ) , @"[80, 60, 40, 20, 0, 90, 70, 50, 30, 10, 81, 61, 41, 21, 1, 4, 95, 75, 55, 35, 15, 96, 76, 56, 36, 16, 87, 67, 47, 27, 7, 97, 77, 57, 37, 17, 88, 68, 48, 28, 8, 98, 78, 58, 38, 18]" ) ;
463+ let expected_ids = ( 0 ..100 )
464+ . filter ( |id| {
465+ [ 7 , 8 , 0 ] . contains ( & ( id % 10 ) )
466+ || [ 1 , 15 , 16 ] . contains ( & ( id % 20 ) )
467+ || [ 0 , 4 ] . contains ( id)
468+ } )
469+ . collect :: < Vec < _ > > ( ) ;
470+ documents_ids. sort ( ) ;
471+ assert_eq ! ( expected_ids, documents_ids) ;
472+
473+ let mut search = Search :: new ( & rtxn, & index) ;
474+ search. filter (
475+ Filter :: from_str ( "mod_10 IN [1, 0, 2] OR mod_20 IN [10, 13] OR id IN [5, 6]" )
476+ . unwrap ( )
477+ . unwrap ( ) ,
478+ ) ;
479+ search. sort_criteria ( vec ! [ AscDesc :: from_str( "id:desc" ) . unwrap( ) ] ) ;
480+ search. limit ( 100 ) ;
481+
482+ let SearchResult { documents_ids, .. } = search. execute ( ) . unwrap ( ) ;
483+ // The order should be in decreasing value of the id
484+ let mut expected_ids = ( 0 ..100 )
485+ . filter ( |id| {
486+ [ 1 , 0 , 2 ] . contains ( & ( id % 10 ) )
487+ || [ 10 , 13 ] . contains ( & ( id % 20 ) )
488+ || [ 5 , 6 ] . contains ( id)
489+ } )
490+ . collect :: < Vec < _ > > ( ) ;
491+ expected_ids. sort ( ) ;
492+ expected_ids. reverse ( ) ;
493+ assert_eq ! ( expected_ids, documents_ids) ;
494+ }
495+ }
0 commit comments