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