From f62116aee5eb41f0c6de199890db596e2e202215 Mon Sep 17 00:00:00 2001 From: eth3lbert Date: Thu, 7 Mar 2024 04:48:59 +0800 Subject: [PATCH 1/7] controllers/helpers/pagination: Add named fields struct support for `seek!` --- src/controllers/helpers/pagination.rs | 127 ++++++++++++++++++++++++-- 1 file changed, 121 insertions(+), 6 deletions(-) diff --git a/src/controllers/helpers/pagination.rs b/src/controllers/helpers/pagination.rs index 0a396589af8..412260f638c 100644 --- a/src/controllers/helpers/pagination.rs +++ b/src/controllers/helpers/pagination.rs @@ -401,20 +401,56 @@ impl PaginatedQueryWithCountSubq { } } +#[allow(unused_macro_rules)] macro_rules! seek { + // Tuple struct + (@variant_struct $vis:vis $variant:ident($($(#[$field_meta:meta])? $ty:ty),*)) => { + #[derive(Debug, Default, Deserialize, Serialize, PartialEq)] + $vis struct $variant($($(#[$field_meta])? pub(super) $ty),*); + }; + // Field struct + (@variant_struct $vis:vis $variant:ident { + $($(#[$field_meta:meta])? $field:ident: $ty:ty),* + }) => { + paste::item! { + #[derive(Debug, Default, Deserialize, PartialEq)] + #[serde(from = $variant "Helper")] + $vis struct $variant { + $($(#[$field_meta])? pub(super) $field: $ty),* + } + + #[derive(Debug, Default, Deserialize, Serialize, PartialEq)] + struct [<$variant Helper>]($($(#[$field_meta])? pub(super) $ty),*); + + impl From<[<$variant Helper>]> for $variant { + fn from(helper: [<$variant Helper>]) -> Self { + let [<$variant Helper>]($($field,)*) = helper; + Self { $($field,)* } + } + } + + impl serde::Serialize for $variant { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let helper = [<$variant Helper>]($(self.$field,)*); + serde::Serialize::serialize(&helper, serializer) + } + } + } + }; ( $vis:vis enum $name:ident { $( - $variant:ident($($(#[$field_meta:meta])? $ty:ty),*) + $variant:ident $fields:tt )* } ) => { + $( + seek!(@variant_struct $vis $variant $fields); + )* paste::item! { - $( - #[derive(Debug, Default, Deserialize, Serialize, PartialEq)] - $vis struct $variant($($(#[$field_meta])? pub(super) $ty),*); - )* - #[derive(Debug, Deserialize, Serialize, PartialEq)] #[serde(untagged)] $vis enum [<$name Payload>] { @@ -583,12 +619,16 @@ mod tests { Id(i32) New(#[serde(with="ts_microseconds")] chrono::NaiveDateTime, i32) RecentDownloads(Option, i32) + NamedId{id: i32} + NamedNew{#[serde(with="ts_microseconds")] dt: chrono::NaiveDateTime, id: i32} + NamedRecentDownloads{ downloads: Option, id: i32 } } } } #[test] fn test_seek_macro_encode_and_decode() { + use chrono::naive::serde::ts_microseconds; use chrono::{NaiveDate, NaiveDateTime}; use seek::*; @@ -601,6 +641,7 @@ mod tests { assert_eq!(decoded, expect); }; + // Tuple struct let seek = Seek::Id; let payload = SeekPayload::Id(Id(1234)); let query = format!("seek={}", encode_seek(&payload).unwrap()); @@ -634,6 +675,54 @@ mod tests { assert_eq!(error.to_string(), "invalid seek parameter"); let response = error.response(); assert_eq!(response.status(), StatusCode::BAD_REQUEST); + + // Field struct + let id = 1234; + let seek = Seek::NamedId; + let payload = SeekPayload::NamedId(NamedId { id }); + let query = format!("seek={}", encode_seek(&payload).unwrap()); + assert_decode_after(seek, &query, Some(payload)); + + let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2016, 7, 8) + .unwrap() + .and_hms_opt(9, 10, 11) + .unwrap(); + let seek = Seek::NamedNew; + let payload = SeekPayload::NamedNew(NamedNew { dt, id }); + let query = format!("seek={}", encode_seek(&payload).unwrap()); + assert_decode_after(seek, &query, Some(payload)); + + let downloads = Some(5678); + let seek = Seek::NamedRecentDownloads; + let payload = SeekPayload::NamedRecentDownloads(NamedRecentDownloads { downloads, id }); + let query = format!("seek={}", encode_seek(&payload).unwrap()); + assert_decode_after(seek, &query, Some(payload)); + + let seek = Seek::NamedId; + assert_decode_after(seek, "", None); + + let seek = Seek::NamedId; + let payload = SeekPayload::NamedRecentDownloads(NamedRecentDownloads { downloads, id }); + let query = format!("seek={}", encode_seek(payload).unwrap()); + let pagination = PaginationOptions::builder() + .enable_seek(true) + .gather(&mock(&query)) + .unwrap(); + let error = seek.after(&pagination.page).unwrap_err(); + assert_eq!(error.to_string(), "invalid seek parameter"); + let response = error.response(); + assert_eq!(response.status(), StatusCode::BAD_REQUEST); + + // Ensures it still encodes compactly with a field struct + #[derive(Debug, Default, Serialize, PartialEq)] + struct NewTuple( + #[serde(with = "ts_microseconds")] chrono::NaiveDateTime, + i32, + ); + assert_eq!( + encode_seek(NewTuple(dt, id)).unwrap(), + encode_seek(SeekPayload::NamedNew(NamedNew { dt, id })).unwrap() + ); } #[test] @@ -641,6 +730,7 @@ mod tests { use chrono::{NaiveDate, NaiveDateTime}; use seek::*; + // Tuple struct assert_eq!(Seek::from(SeekPayload::Id(Id(1234))), Seek::Id); let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2016, 7, 8) @@ -653,6 +743,31 @@ mod tests { Seek::from(SeekPayload::RecentDownloads(RecentDownloads(None, 1234))), Seek::RecentDownloads ); + + // Field struct + let id = 1234; + assert_eq!( + Seek::from(SeekPayload::NamedId(NamedId { id })), + Seek::NamedId + ); + + let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2016, 7, 8) + .unwrap() + .and_hms_opt(9, 10, 11) + .unwrap(); + assert_eq!( + Seek::from(SeekPayload::NamedNew(NamedNew { dt, id })), + Seek::NamedNew + ); + + let downloads = None; + assert_eq!( + Seek::from(SeekPayload::NamedRecentDownloads(NamedRecentDownloads { + downloads, + id + })), + Seek::NamedRecentDownloads + ); } fn mock(query: &str) -> Request<()> { From 6ecf671ebec0a9ce8508fb22f65407cb79adb792 Mon Sep 17 00:00:00 2001 From: eth3lbert Date: Thu, 7 Mar 2024 05:21:13 +0800 Subject: [PATCH 2/7] controllers/krate/search: use named fields seek --- src/controllers/krate/search.rs | 75 +++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/src/controllers/krate/search.rs b/src/controllers/krate/search.rs index de00e028855..d0cf545922b 100644 --- a/src/controllers/krate/search.rs +++ b/src/controllers/krate/search.rs @@ -412,12 +412,12 @@ impl<'a> FilterParams<'a> { .single_value() }; let conditions: Vec> = match *seek_payload { - SeekPayload::Name(Name(id)) => { + SeekPayload::Name(Name { id }) => { // Equivalent of: // `WHERE name > name'` vec![Box::new(crates::name.nullable().gt(crate_name_by_id(id)))] } - SeekPayload::New(New(created_at, id)) => { + SeekPayload::New(New { created_at, id }) => { // Equivalent of: // `WHERE (created_at = created_at' AND id < id') OR created_at < created_at'` vec![ @@ -430,7 +430,7 @@ impl<'a> FilterParams<'a> { Box::new(crates::created_at.lt(created_at).nullable()), ] } - SeekPayload::RecentUpdates(RecentUpdates(updated_at, id)) => { + SeekPayload::RecentUpdates(RecentUpdates { updated_at, id }) => { // Equivalent of: // `WHERE (updated_at = updated_at' AND id < id') OR updated_at < updated_at'` vec![ @@ -443,7 +443,10 @@ impl<'a> FilterParams<'a> { Box::new(crates::updated_at.lt(updated_at).nullable()), ] } - SeekPayload::RecentDownloads(RecentDownloads(recent_downloads, id)) => { + SeekPayload::RecentDownloads(RecentDownloads { + recent_downloads, + id, + }) => { // Equivalent of: // for recent_downloads is not None: // `WHERE (recent_downloads = recent_downloads' AND id < id') @@ -477,7 +480,7 @@ impl<'a> FilterParams<'a> { } } } - SeekPayload::Downloads(Downloads(downloads, id)) => { + SeekPayload::Downloads(Downloads { downloads, id }) => { // Equivalent of: // `WHERE (downloads = downloads' AND id < id') OR downloads < downloads'` vec![ @@ -490,7 +493,7 @@ impl<'a> FilterParams<'a> { Box::new(crate_downloads::downloads.lt(downloads).nullable()), ] } - SeekPayload::Query(Query(exact_match, id)) => { + SeekPayload::Query(Query { exact_match, id }) => { // Equivalent of: // `WHERE (exact_match = exact_match' AND name < name') OR exact_match < // exact_match'` @@ -506,7 +509,11 @@ impl<'a> FilterParams<'a> { Box::new(name_exact_match.lt(exact_match).nullable()), ] } - SeekPayload::Relevance(Relevance(exact, rank_in, id)) => { + SeekPayload::Relevance(Relevance { + exact_match: exact, + rank: rank_in, + id, + }) => { // Equivalent of: // `WHERE (exact_match = exact_match' AND rank = rank' AND name > name') // OR (exact_match = exact_match' AND rank < rank') @@ -553,13 +560,13 @@ mod seek { seek! { pub enum Seek { - Name(i32) - New(#[serde(with="ts_microseconds")] chrono::NaiveDateTime, i32) - RecentUpdates(#[serde(with="ts_microseconds")] chrono::NaiveDateTime, i32) - RecentDownloads(Option, i32) - Downloads(i64, i32) - Query(bool, i32) - Relevance(bool, f32, i32) + Name{ id: i32 } + New{#[serde(with="ts_microseconds")] created_at: chrono::NaiveDateTime, id: i32} + RecentUpdates{#[serde(with="ts_microseconds")] updated_at: chrono::NaiveDateTime, id: i32} + RecentDownloads{recent_downloads: Option, id: i32} + Downloads{downloads: i64, id: i32} + Query{exact_match: bool, id: i32} + Relevance{exact_match: bool, rank: f32, id: i32} } } @@ -568,20 +575,34 @@ mod seek { &self, record: &(Crate, bool, i64, Option, f32), ) -> SeekPayload { + let ( + Crate { + id, + updated_at, + created_at, + .. + }, + exact_match, + downloads, + recent_downloads, + rank, + ) = *record; + match *self { - Seek::Name => SeekPayload::Name(Name(record.0.id)), - Seek::New => SeekPayload::New(New(record.0.created_at, record.0.id)), - Seek::RecentUpdates => { - SeekPayload::RecentUpdates(RecentUpdates(record.0.updated_at, record.0.id)) - } - Seek::RecentDownloads => { - SeekPayload::RecentDownloads(RecentDownloads(record.3, record.0.id)) - } - Seek::Downloads => SeekPayload::Downloads(Downloads(record.2, record.0.id)), - Seek::Query => SeekPayload::Query(Query(record.1, record.0.id)), - Seek::Relevance => { - SeekPayload::Relevance(Relevance(record.1, record.4, record.0.id)) - } + Seek::Name => SeekPayload::Name(Name { id }), + Seek::New => SeekPayload::New(New { created_at, id }), + Seek::RecentUpdates => SeekPayload::RecentUpdates(RecentUpdates { updated_at, id }), + Seek::RecentDownloads => SeekPayload::RecentDownloads(RecentDownloads { + recent_downloads, + id, + }), + Seek::Downloads => SeekPayload::Downloads(Downloads { downloads, id }), + Seek::Query => SeekPayload::Query(Query { exact_match, id }), + Seek::Relevance => SeekPayload::Relevance(Relevance { + exact_match, + rank, + id, + }), } } } From 63171849a06715f26ac09ee42a8151a10be8811e Mon Sep 17 00:00:00 2001 From: eth3lbert Date: Thu, 7 Mar 2024 05:27:53 +0800 Subject: [PATCH 3/7] controllers/krate/versions: use named fields seek --- src/controllers/krate/versions.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/controllers/krate/versions.rs b/src/controllers/krate/versions.rs index fda781cf936..45ce896ae10 100644 --- a/src/controllers/krate/versions.rs +++ b/src/controllers/krate/versions.rs @@ -92,7 +92,7 @@ fn list_by_date( !matches!(&options.page, Page::Numeric(_)), "?page= is not supported" ); - if let Some(SeekPayload::Date(Date(created_at, id))) = Seek::Date.after(&options.page)? { + if let Some(SeekPayload::Date(Date { created_at, id })) = Seek::Date.after(&options.page)? { query = query.filter( versions::created_at .eq(created_at) @@ -169,7 +169,7 @@ fn list_by_semver( "?page= is not supported" ); let mut idx = Some(0); - if let Some(SeekPayload::Semver(Semver(id))) = Seek::Semver.after(&options.page)? { + if let Some(SeekPayload::Semver(Semver { id })) = Seek::Semver.after(&options.page)? { idx = sorted_versions .get_index_of(&id) .filter(|i| i + 1 < sorted_versions.len()) @@ -236,16 +236,17 @@ mod seek { // doesn't include field names. seek! { pub enum Seek { - Semver(i32) - Date(#[serde(with="ts_microseconds")] chrono::NaiveDateTime, i32) + Semver{id: i32} + Date{#[serde(with="ts_microseconds")] created_at: chrono::NaiveDateTime, id: i32} } } impl Seek { pub(crate) fn to_payload(&self, record: &(Version, Option)) -> SeekPayload { + let (Version { id, created_at, .. }, _) = *record; match *self { - Seek::Semver => SeekPayload::Semver(Semver(record.0.id)), - Seek::Date => SeekPayload::Date(Date(record.0.created_at, record.0.id)), + Seek::Semver => SeekPayload::Semver(Semver { id }), + Seek::Date => SeekPayload::Date(Date { created_at, id }), } } } From 526e78536de2bac7622087bd7e5aa33b42612aa1 Mon Sep 17 00:00:00 2001 From: eth3lbert Date: Thu, 7 Mar 2024 05:30:23 +0800 Subject: [PATCH 4/7] controllers/helpers/pagination: Remove tuple struct support for `seek!` --- src/controllers/helpers/pagination.rs | 95 ++++----------------------- 1 file changed, 14 insertions(+), 81 deletions(-) diff --git a/src/controllers/helpers/pagination.rs b/src/controllers/helpers/pagination.rs index 412260f638c..6fe6425653a 100644 --- a/src/controllers/helpers/pagination.rs +++ b/src/controllers/helpers/pagination.rs @@ -401,13 +401,7 @@ impl PaginatedQueryWithCountSubq { } } -#[allow(unused_macro_rules)] macro_rules! seek { - // Tuple struct - (@variant_struct $vis:vis $variant:ident($($(#[$field_meta:meta])? $ty:ty),*)) => { - #[derive(Debug, Default, Deserialize, Serialize, PartialEq)] - $vis struct $variant($($(#[$field_meta])? pub(super) $ty),*); - }; // Field struct (@variant_struct $vis:vis $variant:ident { $($(#[$field_meta:meta])? $field:ident: $ty:ty),* @@ -616,12 +610,9 @@ mod tests { use chrono::naive::serde::ts_microseconds; seek! { pub(super) enum Seek { - Id(i32) - New(#[serde(with="ts_microseconds")] chrono::NaiveDateTime, i32) - RecentDownloads(Option, i32) - NamedId{id: i32} - NamedNew{#[serde(with="ts_microseconds")] dt: chrono::NaiveDateTime, id: i32} - NamedRecentDownloads{ downloads: Option, id: i32 } + Id{id: i32} + New{#[serde(with="ts_microseconds")] dt: chrono::NaiveDateTime, id: i32} + RecentDownloads{ downloads: Option, id: i32 } } } } @@ -641,9 +632,9 @@ mod tests { assert_eq!(decoded, expect); }; - // Tuple struct + let id = 1234; let seek = Seek::Id; - let payload = SeekPayload::Id(Id(1234)); + let payload = SeekPayload::Id(Id { id }); let query = format!("seek={}", encode_seek(&payload).unwrap()); assert_decode_after(seek, &query, Some(payload)); @@ -652,12 +643,13 @@ mod tests { .and_hms_opt(9, 10, 11) .unwrap(); let seek = Seek::New; - let payload = SeekPayload::New(New(dt, 1234)); + let payload = SeekPayload::New(New { dt, id }); let query = format!("seek={}", encode_seek(&payload).unwrap()); assert_decode_after(seek, &query, Some(payload)); + let downloads = Some(5678); let seek = Seek::RecentDownloads; - let payload = SeekPayload::RecentDownloads(RecentDownloads(Some(5678), 1234)); + let payload = SeekPayload::RecentDownloads(RecentDownloads { downloads, id }); let query = format!("seek={}", encode_seek(&payload).unwrap()); assert_decode_after(seek, &query, Some(payload)); @@ -665,44 +657,7 @@ mod tests { assert_decode_after(seek, "", None); let seek = Seek::Id; - let payload = SeekPayload::RecentDownloads(RecentDownloads(Some(5678), 1234)); - let query = format!("seek={}", encode_seek(payload).unwrap()); - let pagination = PaginationOptions::builder() - .enable_seek(true) - .gather(&mock(&query)) - .unwrap(); - let error = seek.after(&pagination.page).unwrap_err(); - assert_eq!(error.to_string(), "invalid seek parameter"); - let response = error.response(); - assert_eq!(response.status(), StatusCode::BAD_REQUEST); - - // Field struct - let id = 1234; - let seek = Seek::NamedId; - let payload = SeekPayload::NamedId(NamedId { id }); - let query = format!("seek={}", encode_seek(&payload).unwrap()); - assert_decode_after(seek, &query, Some(payload)); - - let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2016, 7, 8) - .unwrap() - .and_hms_opt(9, 10, 11) - .unwrap(); - let seek = Seek::NamedNew; - let payload = SeekPayload::NamedNew(NamedNew { dt, id }); - let query = format!("seek={}", encode_seek(&payload).unwrap()); - assert_decode_after(seek, &query, Some(payload)); - - let downloads = Some(5678); - let seek = Seek::NamedRecentDownloads; - let payload = SeekPayload::NamedRecentDownloads(NamedRecentDownloads { downloads, id }); - let query = format!("seek={}", encode_seek(&payload).unwrap()); - assert_decode_after(seek, &query, Some(payload)); - - let seek = Seek::NamedId; - assert_decode_after(seek, "", None); - - let seek = Seek::NamedId; - let payload = SeekPayload::NamedRecentDownloads(NamedRecentDownloads { downloads, id }); + let payload = SeekPayload::RecentDownloads(RecentDownloads { downloads, id }); let query = format!("seek={}", encode_seek(payload).unwrap()); let pagination = PaginationOptions::builder() .enable_seek(true) @@ -721,7 +676,7 @@ mod tests { ); assert_eq!( encode_seek(NewTuple(dt, id)).unwrap(), - encode_seek(SeekPayload::NamedNew(NamedNew { dt, id })).unwrap() + encode_seek(SeekPayload::New(New { dt, id })).unwrap() ); } @@ -729,44 +684,22 @@ mod tests { fn test_seek_macro_conv() { use chrono::{NaiveDate, NaiveDateTime}; use seek::*; - - // Tuple struct - assert_eq!(Seek::from(SeekPayload::Id(Id(1234))), Seek::Id); - - let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2016, 7, 8) - .unwrap() - .and_hms_opt(9, 10, 11) - .unwrap(); - assert_eq!(Seek::from(SeekPayload::New(New(dt, 1234))), Seek::New); - - assert_eq!( - Seek::from(SeekPayload::RecentDownloads(RecentDownloads(None, 1234))), - Seek::RecentDownloads - ); - - // Field struct let id = 1234; - assert_eq!( - Seek::from(SeekPayload::NamedId(NamedId { id })), - Seek::NamedId - ); + assert_eq!(Seek::from(SeekPayload::Id(Id { id })), Seek::Id); let dt: NaiveDateTime = NaiveDate::from_ymd_opt(2016, 7, 8) .unwrap() .and_hms_opt(9, 10, 11) .unwrap(); - assert_eq!( - Seek::from(SeekPayload::NamedNew(NamedNew { dt, id })), - Seek::NamedNew - ); + assert_eq!(Seek::from(SeekPayload::New(New { dt, id })), Seek::New); let downloads = None; assert_eq!( - Seek::from(SeekPayload::NamedRecentDownloads(NamedRecentDownloads { + Seek::from(SeekPayload::RecentDownloads(RecentDownloads { downloads, id })), - Seek::NamedRecentDownloads + Seek::RecentDownloads ); } From 59a3d4d677c8075331e5db3c076e713fa4cf29bd Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Thu, 7 Mar 2024 10:32:32 +0100 Subject: [PATCH 5/7] controllers/helpers/pagination: Add commas to variants in `seek!` macro rules --- src/controllers/helpers/pagination.rs | 8 ++++---- src/controllers/krate/search.rs | 14 +++++++------- src/controllers/krate/versions.rs | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/controllers/helpers/pagination.rs b/src/controllers/helpers/pagination.rs index 6fe6425653a..59a930558e1 100644 --- a/src/controllers/helpers/pagination.rs +++ b/src/controllers/helpers/pagination.rs @@ -437,7 +437,7 @@ macro_rules! seek { ( $vis:vis enum $name:ident { $( - $variant:ident $fields:tt + $variant:ident $fields:tt, )* } ) => { @@ -610,9 +610,9 @@ mod tests { use chrono::naive::serde::ts_microseconds; seek! { pub(super) enum Seek { - Id{id: i32} - New{#[serde(with="ts_microseconds")] dt: chrono::NaiveDateTime, id: i32} - RecentDownloads{ downloads: Option, id: i32 } + Id{id: i32}, + New{#[serde(with="ts_microseconds")] dt: chrono::NaiveDateTime, id: i32}, + RecentDownloads{ downloads: Option, id: i32 }, } } } diff --git a/src/controllers/krate/search.rs b/src/controllers/krate/search.rs index d0cf545922b..a42b4bd3be0 100644 --- a/src/controllers/krate/search.rs +++ b/src/controllers/krate/search.rs @@ -560,13 +560,13 @@ mod seek { seek! { pub enum Seek { - Name{ id: i32 } - New{#[serde(with="ts_microseconds")] created_at: chrono::NaiveDateTime, id: i32} - RecentUpdates{#[serde(with="ts_microseconds")] updated_at: chrono::NaiveDateTime, id: i32} - RecentDownloads{recent_downloads: Option, id: i32} - Downloads{downloads: i64, id: i32} - Query{exact_match: bool, id: i32} - Relevance{exact_match: bool, rank: f32, id: i32} + Name{ id: i32 }, + New{#[serde(with="ts_microseconds")] created_at: chrono::NaiveDateTime, id: i32}, + RecentUpdates{#[serde(with="ts_microseconds")] updated_at: chrono::NaiveDateTime, id: i32}, + RecentDownloads{recent_downloads: Option, id: i32}, + Downloads{downloads: i64, id: i32}, + Query{exact_match: bool, id: i32}, + Relevance{exact_match: bool, rank: f32, id: i32}, } } diff --git a/src/controllers/krate/versions.rs b/src/controllers/krate/versions.rs index 45ce896ae10..e8504cd5ab1 100644 --- a/src/controllers/krate/versions.rs +++ b/src/controllers/krate/versions.rs @@ -236,8 +236,8 @@ mod seek { // doesn't include field names. seek! { pub enum Seek { - Semver{id: i32} - Date{#[serde(with="ts_microseconds")] created_at: chrono::NaiveDateTime, id: i32} + Semver{id: i32}, + Date{#[serde(with="ts_microseconds")] created_at: chrono::NaiveDateTime, id: i32}, } } From 34a2a6dd92feda1aae5aa805687e7adfb9f4b875 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Thu, 7 Mar 2024 10:45:03 +0100 Subject: [PATCH 6/7] controllers/helpers/pagination: Allow trailing commas in variant field lists --- src/controllers/helpers/pagination.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/helpers/pagination.rs b/src/controllers/helpers/pagination.rs index 59a930558e1..4be87d8f8d6 100644 --- a/src/controllers/helpers/pagination.rs +++ b/src/controllers/helpers/pagination.rs @@ -404,7 +404,7 @@ impl PaginatedQueryWithCountSubq { macro_rules! seek { // Field struct (@variant_struct $vis:vis $variant:ident { - $($(#[$field_meta:meta])? $field:ident: $ty:ty),* + $($(#[$field_meta:meta])? $field:ident: $ty:ty),* $(,)? }) => { paste::item! { #[derive(Debug, Default, Deserialize, PartialEq)] From 03eb6fdf56680d20f38244508896a81ec983ba03 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Thu, 7 Mar 2024 10:34:58 +0100 Subject: [PATCH 7/7] Use `seek!(...);` instead of `seek! { ... }` to enable rustfmt see https://users.rust-lang.org/t/rustfmt-skips-macro-arguments/74807/4 --- src/controllers/helpers/pagination.rs | 19 +++++++++---- src/controllers/krate/search.rs | 41 +++++++++++++++++++++------ src/controllers/krate/versions.rs | 14 ++++++--- 3 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/controllers/helpers/pagination.rs b/src/controllers/helpers/pagination.rs index 4be87d8f8d6..0c194fd8294 100644 --- a/src/controllers/helpers/pagination.rs +++ b/src/controllers/helpers/pagination.rs @@ -608,13 +608,22 @@ mod tests { mod seek { use chrono::naive::serde::ts_microseconds; - seek! { + seek!( pub(super) enum Seek { - Id{id: i32}, - New{#[serde(with="ts_microseconds")] dt: chrono::NaiveDateTime, id: i32}, - RecentDownloads{ downloads: Option, id: i32 }, + Id { + id: i32, + }, + New { + #[serde(with = "ts_microseconds")] + dt: chrono::NaiveDateTime, + id: i32, + }, + RecentDownloads { + downloads: Option, + id: i32, + }, } - } + ); } #[test] diff --git a/src/controllers/krate/search.rs b/src/controllers/krate/search.rs index a42b4bd3be0..1c81cdddff0 100644 --- a/src/controllers/krate/search.rs +++ b/src/controllers/krate/search.rs @@ -558,17 +558,40 @@ mod seek { use crate::models::Crate; use chrono::naive::serde::ts_microseconds; - seek! { + seek!( pub enum Seek { - Name{ id: i32 }, - New{#[serde(with="ts_microseconds")] created_at: chrono::NaiveDateTime, id: i32}, - RecentUpdates{#[serde(with="ts_microseconds")] updated_at: chrono::NaiveDateTime, id: i32}, - RecentDownloads{recent_downloads: Option, id: i32}, - Downloads{downloads: i64, id: i32}, - Query{exact_match: bool, id: i32}, - Relevance{exact_match: bool, rank: f32, id: i32}, + Name { + id: i32, + }, + New { + #[serde(with = "ts_microseconds")] + created_at: chrono::NaiveDateTime, + id: i32, + }, + RecentUpdates { + #[serde(with = "ts_microseconds")] + updated_at: chrono::NaiveDateTime, + id: i32, + }, + RecentDownloads { + recent_downloads: Option, + id: i32, + }, + Downloads { + downloads: i64, + id: i32, + }, + Query { + exact_match: bool, + id: i32, + }, + Relevance { + exact_match: bool, + rank: f32, + id: i32, + }, } - } + ); impl Seek { pub(crate) fn to_payload( diff --git a/src/controllers/krate/versions.rs b/src/controllers/krate/versions.rs index e8504cd5ab1..07eaea4d2d8 100644 --- a/src/controllers/krate/versions.rs +++ b/src/controllers/krate/versions.rs @@ -234,12 +234,18 @@ mod seek { // We might consider refactoring this to use named fields, which would be clearer and more // flexible. It's also worth noting that we currently encode seek compactly as a Vec, which // doesn't include field names. - seek! { + seek!( pub enum Seek { - Semver{id: i32}, - Date{#[serde(with="ts_microseconds")] created_at: chrono::NaiveDateTime, id: i32}, + Semver { + id: i32, + }, + Date { + #[serde(with = "ts_microseconds")] + created_at: chrono::NaiveDateTime, + id: i32, + }, } - } + ); impl Seek { pub(crate) fn to_payload(&self, record: &(Version, Option)) -> SeekPayload {