@@ -401,20 +401,56 @@ impl<T, C> PaginatedQueryWithCountSubq<T, C> {
401
401
}
402
402
}
403
403
404
+ #[ allow( unused_macro_rules) ]
404
405
macro_rules! seek {
406
+ // Tuple struct
407
+ ( @variant_struct $vis: vis $variant: ident( $( $( #[ $field_meta: meta] ) ? $ty: ty) ,* ) ) => {
408
+ #[ derive( Debug , Default , Deserialize , Serialize , PartialEq ) ]
409
+ $vis struct $variant( $( $( #[ $field_meta] ) ? pub ( super ) $ty) ,* ) ;
410
+ } ;
411
+ // Field struct
412
+ ( @variant_struct $vis: vis $variant: ident {
413
+ $( $( #[ $field_meta: meta] ) ? $field: ident: $ty: ty) ,*
414
+ } ) => {
415
+ paste:: item! {
416
+ #[ derive( Debug , Default , Deserialize , PartialEq ) ]
417
+ #[ serde( from = $variant "Helper" ) ]
418
+ $vis struct $variant {
419
+ $( $( #[ $field_meta] ) ? pub ( super ) $field: $ty) ,*
420
+ }
421
+
422
+ #[ derive( Debug , Default , Deserialize , Serialize , PartialEq ) ]
423
+ struct [ <$variant Helper >] ( $( $( #[ $field_meta] ) ? pub ( super ) $ty) ,* ) ;
424
+
425
+ impl From <[ <$variant Helper >] > for $variant {
426
+ fn from( helper: [ <$variant Helper >] ) -> Self {
427
+ let [ <$variant Helper >] ( $( $field, ) * ) = helper;
428
+ Self { $( $field, ) * }
429
+ }
430
+ }
431
+
432
+ impl serde:: Serialize for $variant {
433
+ fn serialize<S >( & self , serializer: S ) -> Result <S :: Ok , S :: Error >
434
+ where
435
+ S : serde:: Serializer ,
436
+ {
437
+ let helper = [ <$variant Helper >] ( $( self . $field, ) * ) ;
438
+ serde:: Serialize :: serialize( & helper, serializer)
439
+ }
440
+ }
441
+ }
442
+ } ;
405
443
(
406
444
$vis: vis enum $name: ident {
407
445
$(
408
- $variant: ident( $ ( $ ( # [ $field_meta : meta ] ) ? $ty : ty ) , * )
446
+ $variant: ident $fields : tt
409
447
) *
410
448
}
411
449
) => {
450
+ $(
451
+ seek!( @variant_struct $vis $variant $fields) ;
452
+ ) *
412
453
paste:: item! {
413
- $(
414
- #[ derive( Debug , Default , Deserialize , Serialize , PartialEq ) ]
415
- $vis struct $variant( $( $( #[ $field_meta] ) ? pub ( super ) $ty) ,* ) ;
416
- ) *
417
-
418
454
#[ derive( Debug , Deserialize , Serialize , PartialEq ) ]
419
455
#[ serde( untagged) ]
420
456
$vis enum [ <$name Payload >] {
@@ -583,12 +619,16 @@ mod tests {
583
619
Id ( i32 )
584
620
New ( #[ serde( with="ts_microseconds" ) ] chrono:: NaiveDateTime , i32 )
585
621
RecentDownloads ( Option <i64 >, i32 )
622
+ NamedId { id: i32 }
623
+ NamedNew { #[ serde( with="ts_microseconds" ) ] dt: chrono:: NaiveDateTime , id: i32 }
624
+ NamedRecentDownloads { downloads: Option <i64 >, id: i32 }
586
625
}
587
626
}
588
627
}
589
628
590
629
#[ test]
591
630
fn test_seek_macro_encode_and_decode ( ) {
631
+ use chrono:: naive:: serde:: ts_microseconds;
592
632
use chrono:: { NaiveDate , NaiveDateTime } ;
593
633
use seek:: * ;
594
634
@@ -601,6 +641,7 @@ mod tests {
601
641
assert_eq ! ( decoded, expect) ;
602
642
} ;
603
643
644
+ // Tuple struct
604
645
let seek = Seek :: Id ;
605
646
let payload = SeekPayload :: Id ( Id ( 1234 ) ) ;
606
647
let query = format ! ( "seek={}" , encode_seek( & payload) . unwrap( ) ) ;
@@ -634,13 +675,62 @@ mod tests {
634
675
assert_eq ! ( error. to_string( ) , "invalid seek parameter" ) ;
635
676
let response = error. response ( ) ;
636
677
assert_eq ! ( response. status( ) , StatusCode :: BAD_REQUEST ) ;
678
+
679
+ // Field struct
680
+ let id = 1234 ;
681
+ let seek = Seek :: NamedId ;
682
+ let payload = SeekPayload :: NamedId ( NamedId { id } ) ;
683
+ let query = format ! ( "seek={}" , encode_seek( & payload) . unwrap( ) ) ;
684
+ assert_decode_after ( seek, & query, Some ( payload) ) ;
685
+
686
+ let dt: NaiveDateTime = NaiveDate :: from_ymd_opt ( 2016 , 7 , 8 )
687
+ . unwrap ( )
688
+ . and_hms_opt ( 9 , 10 , 11 )
689
+ . unwrap ( ) ;
690
+ let seek = Seek :: NamedNew ;
691
+ let payload = SeekPayload :: NamedNew ( NamedNew { dt, id } ) ;
692
+ let query = format ! ( "seek={}" , encode_seek( & payload) . unwrap( ) ) ;
693
+ assert_decode_after ( seek, & query, Some ( payload) ) ;
694
+
695
+ let downloads = Some ( 5678 ) ;
696
+ let seek = Seek :: NamedRecentDownloads ;
697
+ let payload = SeekPayload :: NamedRecentDownloads ( NamedRecentDownloads { downloads, id } ) ;
698
+ let query = format ! ( "seek={}" , encode_seek( & payload) . unwrap( ) ) ;
699
+ assert_decode_after ( seek, & query, Some ( payload) ) ;
700
+
701
+ let seek = Seek :: Id ;
702
+ assert_decode_after ( seek, "" , None ) ;
703
+
704
+ let seek = Seek :: Id ;
705
+ let payload = SeekPayload :: NamedRecentDownloads ( NamedRecentDownloads { downloads, id } ) ;
706
+ let query = format ! ( "seek={}" , encode_seek( payload) . unwrap( ) ) ;
707
+ let pagination = PaginationOptions :: builder ( )
708
+ . enable_seek ( true )
709
+ . gather ( & mock ( & query) )
710
+ . unwrap ( ) ;
711
+ let error = seek. after ( & pagination. page ) . unwrap_err ( ) ;
712
+ assert_eq ! ( error. to_string( ) , "invalid seek parameter" ) ;
713
+ let response = error. response ( ) ;
714
+ assert_eq ! ( response. status( ) , StatusCode :: BAD_REQUEST ) ;
715
+
716
+ // Ensures it still encodes compactly with a field struct
717
+ #[ derive( Debug , Default , Serialize , PartialEq ) ]
718
+ struct NewTuple (
719
+ #[ serde( with = "ts_microseconds" ) ] chrono:: NaiveDateTime ,
720
+ i32 ,
721
+ ) ;
722
+ assert_eq ! (
723
+ encode_seek( NewTuple ( dt, id) ) . unwrap( ) ,
724
+ encode_seek( SeekPayload :: NamedNew ( NamedNew { dt, id } ) ) . unwrap( )
725
+ ) ;
637
726
}
638
727
639
728
#[ test]
640
729
fn test_seek_macro_conv ( ) {
641
730
use chrono:: { NaiveDate , NaiveDateTime } ;
642
731
use seek:: * ;
643
732
733
+ // Tuple struct
644
734
assert_eq ! ( Seek :: from( SeekPayload :: Id ( Id ( 1234 ) ) ) , Seek :: Id ) ;
645
735
646
736
let dt: NaiveDateTime = NaiveDate :: from_ymd_opt ( 2016 , 7 , 8 )
@@ -653,6 +743,31 @@ mod tests {
653
743
Seek :: from( SeekPayload :: RecentDownloads ( RecentDownloads ( None , 1234 ) ) ) ,
654
744
Seek :: RecentDownloads
655
745
) ;
746
+
747
+ // Field struct
748
+ let id = 1234 ;
749
+ assert_eq ! (
750
+ Seek :: from( SeekPayload :: NamedId ( NamedId { id } ) ) ,
751
+ Seek :: NamedId
752
+ ) ;
753
+
754
+ let dt: NaiveDateTime = NaiveDate :: from_ymd_opt ( 2016 , 7 , 8 )
755
+ . unwrap ( )
756
+ . and_hms_opt ( 9 , 10 , 11 )
757
+ . unwrap ( ) ;
758
+ assert_eq ! (
759
+ Seek :: from( SeekPayload :: NamedNew ( NamedNew { dt, id } ) ) ,
760
+ Seek :: NamedNew
761
+ ) ;
762
+
763
+ let downloads = None ;
764
+ assert_eq ! (
765
+ Seek :: from( SeekPayload :: NamedRecentDownloads ( NamedRecentDownloads {
766
+ downloads,
767
+ id
768
+ } ) ) ,
769
+ Seek :: NamedRecentDownloads
770
+ ) ;
656
771
}
657
772
658
773
fn mock ( query : & str ) -> Request < ( ) > {
0 commit comments