@@ -228,7 +228,7 @@ pub async fn list_crates(
228
228
let seek = seek. unwrap ( ) ;
229
229
if let Some ( condition) = seek
230
230
. decode ( & pagination. page ) ?
231
- . map ( |s| filter_params. seek_after ( & s) )
231
+ . map ( |s| filter_params. seek ( & s, is_forward ) )
232
232
{
233
233
query = query. filter ( condition) ;
234
234
}
@@ -506,7 +506,7 @@ impl FilterParams {
506
506
query
507
507
}
508
508
509
- fn seek_after ( & self , seek_payload : & seek:: SeekPayload ) -> BoxedCondition < ' _ > {
509
+ fn seek ( & self , seek_payload : & seek:: SeekPayload , is_forward : bool ) -> BoxedCondition < ' _ > {
510
510
use seek:: * ;
511
511
512
512
let crates_aliased = alias ! ( crates as crates_aliased) ;
@@ -518,63 +518,85 @@ impl FilterParams {
518
518
} ;
519
519
let conditions: Vec < BoxedCondition < ' _ > > = match * seek_payload {
520
520
SeekPayload :: Name ( Name { id } ) => {
521
- // Equivalent of:
522
- // ```
523
- // WHERE name > name'
524
- // ORDER BY name ASC
525
- // ```
526
- vec ! [ Box :: new( crates:: name. nullable( ) . gt( crate_name_by_id( id) ) ) ]
521
+ if is_forward {
522
+ // Equivalent of:
523
+ // ```
524
+ // WHERE name > name'
525
+ // ORDER BY name ASC
526
+ // ```
527
+ vec ! [ Box :: new( crates:: name. nullable( ) . gt( crate_name_by_id( id) ) ) ]
528
+ } else {
529
+ vec ! [ Box :: new( crates:: name. nullable( ) . lt( crate_name_by_id( id) ) ) ]
530
+ }
527
531
}
528
532
SeekPayload :: New ( New { created_at, id } ) => {
529
- // Equivalent of:
530
- // ```
531
- // WHERE (created_at = created_at' AND id < id') OR created_at < created_at'
532
- // ORDER BY created_at DESC, id DESC
533
- // ```
534
- vec ! [
535
- Box :: new(
536
- crates:: created_at
537
- . eq( created_at)
538
- . and( crates:: id. lt( id) )
539
- . nullable( ) ,
540
- ) ,
541
- Box :: new( crates:: created_at. lt( created_at) . nullable( ) ) ,
542
- ]
533
+ if is_forward {
534
+ // Equivalent of:
535
+ // ```
536
+ // WHERE (created_at = created_at' AND id < id') OR created_at < created_at'
537
+ // ORDER BY created_at DESC, id DESC
538
+ // ```
539
+ vec ! [
540
+ Box :: new(
541
+ crates:: created_at
542
+ . eq( created_at)
543
+ . and( crates:: id. lt( id) )
544
+ . nullable( ) ,
545
+ ) ,
546
+ Box :: new( crates:: created_at. lt( created_at) . nullable( ) ) ,
547
+ ]
548
+ } else {
549
+ vec ! [
550
+ Box :: new(
551
+ crates:: created_at
552
+ . eq( created_at)
553
+ . and( crates:: id. gt( id) )
554
+ . nullable( ) ,
555
+ ) ,
556
+ Box :: new( crates:: created_at. gt( created_at) . nullable( ) ) ,
557
+ ]
558
+ }
543
559
}
544
560
SeekPayload :: RecentUpdates ( RecentUpdates { updated_at, id } ) => {
545
- // Equivalent of:
546
- // ```
547
- // WHERE (updated_at = updated_at' AND id < id') OR updated_at < updated_at'
548
- // ORDER BY updated_at DESC, id DESC
549
- // ```
550
- vec ! [
551
- Box :: new(
552
- crates:: updated_at
553
- . eq( updated_at)
554
- . and( crates:: id. lt( id) )
555
- . nullable( ) ,
556
- ) ,
557
- Box :: new( crates:: updated_at. lt( updated_at) . nullable( ) ) ,
558
- ]
561
+ if is_forward {
562
+ // Equivalent of:
563
+ // ```
564
+ // WHERE (updated_at = updated_at' AND id < id') OR updated_at < updated_at'
565
+ // ORDER BY updated_at DESC, id DESC
566
+ // ```
567
+ vec ! [
568
+ Box :: new(
569
+ crates:: updated_at
570
+ . eq( updated_at)
571
+ . and( crates:: id. lt( id) )
572
+ . nullable( ) ,
573
+ ) ,
574
+ Box :: new( crates:: updated_at. lt( updated_at) . nullable( ) ) ,
575
+ ]
576
+ } else {
577
+ vec ! [
578
+ Box :: new(
579
+ crates:: updated_at
580
+ . eq( updated_at)
581
+ . and( crates:: id. gt( id) )
582
+ . nullable( ) ,
583
+ ) ,
584
+ Box :: new( crates:: updated_at. gt( updated_at) . nullable( ) ) ,
585
+ ]
586
+ }
559
587
}
560
588
SeekPayload :: RecentDownloads ( RecentDownloads {
561
589
recent_downloads,
562
590
id,
563
591
} ) => {
564
- // Equivalent of:
565
- // for recent_downloads is not None:
566
- // ```
567
- // WHERE (recent_downloads = recent_downloads' AND id < id')
568
- // OR (recent_downloads < recent_downloads' OR recent_downloads IS NULL)
569
- // ORDER BY recent_downloads DESC NULLS LAST, id DESC
570
- // ```
571
- // for recent_downloads is None:
572
- // ```
573
- // WHERE (recent_downloads IS NULL AND id < id')
574
- // ORDER BY recent_downloads DESC NULLS LAST, id DESC
575
- // ```
576
- match recent_downloads {
577
- Some ( dl) => {
592
+ match ( recent_downloads, is_forward) {
593
+ ( Some ( dl) , true ) => {
594
+ // Equivalent of:
595
+ // ```
596
+ // WHERE (recent_downloads = recent_downloads' AND id < id')
597
+ // OR (recent_downloads < recent_downloads' OR recent_downloads IS NULL)
598
+ // ORDER BY recent_downloads DESC NULLS LAST, id DESC
599
+ // ```
578
600
vec ! [
579
601
Box :: new(
580
602
recent_crate_downloads:: downloads
@@ -590,80 +612,157 @@ impl FilterParams {
590
612
) ,
591
613
]
592
614
}
593
- None => {
615
+ ( None , true ) => {
616
+ // Equivalent of:
617
+ // ```
618
+ // WHERE (recent_downloads IS NULL AND id < id')
619
+ // ORDER BY recent_downloads DESC NULLS LAST, id DESC
620
+ // ```
594
621
vec ! [ Box :: new(
595
622
recent_crate_downloads:: downloads
596
623
. is_null( )
597
624
. and( crates:: id. lt( id) )
598
625
. nullable( ) ,
599
626
) ]
600
627
}
628
+ ( Some ( dl) , false ) => {
629
+ // Equivalent of:
630
+ // ```
631
+ // WHERE (recent_downloads = recent_downloads' AND id > id')
632
+ // OR (recent_downloads > recent_downloads')
633
+ // ORDER BY recent_downloads ASC NULLS FIRST, id ASC
634
+ // ```
635
+ vec ! [
636
+ Box :: new(
637
+ recent_crate_downloads:: downloads
638
+ . eq( dl)
639
+ . and( crates:: id. gt( id) )
640
+ . nullable( ) ,
641
+ ) ,
642
+ Box :: new( recent_crate_downloads:: downloads. gt( dl) . nullable( ) ) ,
643
+ ]
644
+ }
645
+ ( None , false ) => {
646
+ // Equivalent of:
647
+ // ```
648
+ // WHERE (recent_downloads IS NULL AND id > id')
649
+ // OR (recent_downloads IS NOT NULL)
650
+ // ORDER BY recent_downloads ASC NULLS FIRST, id ASC
651
+ // ```
652
+ vec ! [
653
+ Box :: new(
654
+ recent_crate_downloads:: downloads
655
+ . is_null( )
656
+ . and( crates:: id. gt( id) )
657
+ . nullable( ) ,
658
+ ) ,
659
+ Box :: new( recent_crate_downloads:: downloads. is_not_null( ) . nullable( ) ) ,
660
+ ]
661
+ }
601
662
}
602
663
}
603
664
SeekPayload :: Downloads ( Downloads { downloads, id } ) => {
604
- // Equivalent of:
605
- // ```
606
- // WHERE (downloads = downloads' AND id < id') OR downloads < downloads'
607
- // ORDER BY downloads DESC, id DESC
608
- // ```
609
- vec ! [
610
- Box :: new(
611
- crate_downloads:: downloads
612
- . eq( downloads)
613
- . and( crates:: id. lt( id) )
614
- . nullable( ) ,
615
- ) ,
616
- Box :: new( crate_downloads:: downloads. lt( downloads) . nullable( ) ) ,
617
- ]
665
+ if is_forward {
666
+ // Equivalent of:
667
+ // ```
668
+ // WHERE (downloads = downloads' AND id < id') OR downloads < downloads'
669
+ // ORDER BY downloads DESC, id DESC
670
+ // ```
671
+ vec ! [
672
+ Box :: new(
673
+ crate_downloads:: downloads
674
+ . eq( downloads)
675
+ . and( crates:: id. lt( id) )
676
+ . nullable( ) ,
677
+ ) ,
678
+ Box :: new( crate_downloads:: downloads. lt( downloads) . nullable( ) ) ,
679
+ ]
680
+ } else {
681
+ vec ! [
682
+ Box :: new(
683
+ crate_downloads:: downloads
684
+ . eq( downloads)
685
+ . and( crates:: id. gt( id) )
686
+ . nullable( ) ,
687
+ ) ,
688
+ Box :: new( crate_downloads:: downloads. gt( downloads) . nullable( ) ) ,
689
+ ]
690
+ }
618
691
}
619
692
SeekPayload :: Query ( Query { exact_match, id } ) => {
620
- // Equivalent of:
621
- // ```
622
- // WHERE (exact_match = exact_match' AND name > name') OR exact_match < exact_match'
623
- // ORDER BY exact_match DESC, NAME ASC
624
- // ```
625
693
let q_string = self . q_string . as_ref ( ) . expect ( "q_string should not be None" ) ;
626
694
let name_exact_match = Crate :: with_name ( q_string) ;
627
- vec ! [
628
- Box :: new(
629
- name_exact_match
630
- . eq( exact_match)
631
- . and( crates:: name. nullable( ) . gt( crate_name_by_id( id) ) )
632
- . nullable( ) ,
633
- ) ,
634
- Box :: new( name_exact_match. lt( exact_match) . nullable( ) ) ,
635
- ]
695
+ if is_forward {
696
+ // Equivalent of:
697
+ // ```
698
+ // WHERE (exact_match = exact_match' AND name > name') OR exact_match < exact_match'
699
+ // ORDER BY exact_match DESC, NAME ASC
700
+ // ```
701
+ vec ! [
702
+ Box :: new(
703
+ name_exact_match
704
+ . eq( exact_match)
705
+ . and( crates:: name. nullable( ) . gt( crate_name_by_id( id) ) )
706
+ . nullable( ) ,
707
+ ) ,
708
+ Box :: new( name_exact_match. lt( exact_match) . nullable( ) ) ,
709
+ ]
710
+ } else {
711
+ vec ! [
712
+ Box :: new(
713
+ name_exact_match
714
+ . eq( exact_match)
715
+ . and( crates:: name. nullable( ) . lt( crate_name_by_id( id) ) )
716
+ . nullable( ) ,
717
+ ) ,
718
+ Box :: new( name_exact_match. gt( exact_match) . nullable( ) ) ,
719
+ ]
720
+ }
636
721
}
637
722
SeekPayload :: Relevance ( Relevance {
638
723
exact_match : exact,
639
724
rank : rank_in,
640
725
id,
641
726
} ) => {
642
- // Equivalent of:
643
- // ```
644
- // WHERE (exact_match = exact_match' AND rank = rank' AND name > name')
645
- // OR (exact_match = exact_match' AND rank < rank')
646
- // OR exact_match < exact_match'
647
- // ORDER BY exact_match DESC, rank DESC, name ASC
648
- // ```
649
727
let q_string = self . q_string . as_ref ( ) . expect ( "q_string should not be None" ) ;
650
728
let q = plainto_tsquery_with_search_config (
651
729
TsConfigurationByName ( "english" ) ,
652
730
q_string. as_str ( ) ,
653
731
) ;
654
732
let rank = ts_rank_cd ( crates:: textsearchable_index_col, q) ;
655
733
let name_exact_match = Crate :: with_name ( q_string. as_str ( ) ) ;
656
- vec ! [
657
- Box :: new(
658
- name_exact_match
659
- . eq( exact)
660
- . and( rank. eq( rank_in) )
661
- . and( crates:: name. nullable( ) . gt( crate_name_by_id( id) ) )
662
- . nullable( ) ,
663
- ) ,
664
- Box :: new( name_exact_match. eq( exact) . and( rank. lt( rank_in) ) . nullable( ) ) ,
665
- Box :: new( name_exact_match. lt( exact) . nullable( ) ) ,
666
- ]
734
+ if is_forward {
735
+ // Equivalent of:
736
+ // ```
737
+ // WHERE (exact_match = exact_match' AND rank = rank' AND name > name')
738
+ // OR (exact_match = exact_match' AND rank < rank')
739
+ // OR exact_match < exact_match'
740
+ // ORDER BY exact_match DESC, rank DESC, name ASC
741
+ // ```
742
+ vec ! [
743
+ Box :: new(
744
+ name_exact_match
745
+ . eq( exact)
746
+ . and( rank. eq( rank_in) )
747
+ . and( crates:: name. nullable( ) . gt( crate_name_by_id( id) ) )
748
+ . nullable( ) ,
749
+ ) ,
750
+ Box :: new( name_exact_match. eq( exact) . and( rank. lt( rank_in) ) . nullable( ) ) ,
751
+ Box :: new( name_exact_match. lt( exact) . nullable( ) ) ,
752
+ ]
753
+ } else {
754
+ vec ! [
755
+ Box :: new(
756
+ name_exact_match
757
+ . eq( exact)
758
+ . and( rank. eq( rank_in) )
759
+ . and( crates:: name. nullable( ) . lt( crate_name_by_id( id) ) )
760
+ . nullable( ) ,
761
+ ) ,
762
+ Box :: new( name_exact_match. eq( exact) . and( rank. gt( rank_in) ) . nullable( ) ) ,
763
+ Box :: new( name_exact_match. gt( exact) . nullable( ) ) ,
764
+ ]
765
+ }
667
766
}
668
767
} ;
669
768
0 commit comments