Skip to content

Commit 0433043

Browse files
committed
controllers/helpers/pagination: Add named fields struct support for seek!
1 parent 74892ed commit 0433043

File tree

1 file changed

+120
-6
lines changed

1 file changed

+120
-6
lines changed

src/controllers/helpers/pagination.rs

Lines changed: 120 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -402,19 +402,54 @@ impl<T, C> PaginatedQueryWithCountSubq<T, C> {
402402
}
403403

404404
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+
};
405442
(
406443
$vis:vis enum $name:ident {
407444
$(
408-
$variant:ident($($(#[$field_meta:meta])? $ty:ty),*)
445+
$variant:ident $fields:tt
409446
)*
410447
}
411448
) => {
449+
$(
450+
seek!(@variant_struct $vis $variant $fields);
451+
)*
412452
paste::item! {
413-
$(
414-
#[derive(Debug, Default, Deserialize, Serialize, PartialEq)]
415-
$vis struct $variant($($(#[$field_meta])? pub(super) $ty),*);
416-
)*
417-
418453
#[derive(Debug, Deserialize, Serialize, PartialEq)]
419454
#[serde(untagged)]
420455
$vis enum [<$name Payload>] {
@@ -583,12 +618,16 @@ mod tests {
583618
Id(i32)
584619
New(#[serde(with="ts_microseconds")] chrono::NaiveDateTime, i32)
585620
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 }
586624
}
587625
}
588626
}
589627

590628
#[test]
591629
fn test_seek_macro_encode_and_decode() {
630+
use chrono::naive::serde::ts_microseconds;
592631
use chrono::{NaiveDate, NaiveDateTime};
593632
use seek::*;
594633

@@ -601,6 +640,7 @@ mod tests {
601640
assert_eq!(decoded, expect);
602641
};
603642

643+
// Tuple struct
604644
let seek = Seek::Id;
605645
let payload = SeekPayload::Id(Id(1234));
606646
let query = format!("seek={}", encode_seek(&payload).unwrap());
@@ -634,13 +674,62 @@ mod tests {
634674
assert_eq!(error.to_string(), "invalid seek parameter");
635675
let response = error.response();
636676
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+
);
637725
}
638726

639727
#[test]
640728
fn test_seek_macro_conv() {
641729
use chrono::{NaiveDate, NaiveDateTime};
642730
use seek::*;
643731

732+
// Tuple struct
644733
assert_eq!(Seek::from(SeekPayload::Id(Id(1234))), Seek::Id);
645734

646735
let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2016, 7, 8)
@@ -653,6 +742,31 @@ mod tests {
653742
Seek::from(SeekPayload::RecentDownloads(RecentDownloads(None, 1234))),
654743
Seek::RecentDownloads
655744
);
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+
);
656770
}
657771

658772
fn mock(query: &str) -> Request<()> {

0 commit comments

Comments
 (0)