From b9f604dd1875dc4ffac0e7920fffdff26f0c5892 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 4 Dec 2023 23:11:41 -0500 Subject: [PATCH] reusable pagination types --- .../src/http_server/common_responses/mod.rs | 2 + .../common_responses/pagination_cursors.rs | 53 +++++++++++++++++++ .../common_responses/pagination_page.rs | 33 ++++++++++++ .../media_files/list_media_files_for_user.rs | 11 ++-- 4 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 crates/service/web/storyteller_web/src/http_server/common_responses/pagination_cursors.rs create mode 100644 crates/service/web/storyteller_web/src/http_server/common_responses/pagination_page.rs diff --git a/crates/service/web/storyteller_web/src/http_server/common_responses/mod.rs b/crates/service/web/storyteller_web/src/http_server/common_responses/mod.rs index 1aa45ef781..d84a319a04 100644 --- a/crates/service/web/storyteller_web/src/http_server/common_responses/mod.rs +++ b/crates/service/web/storyteller_web/src/http_server/common_responses/mod.rs @@ -1 +1,3 @@ +pub mod pagination_cursors; +pub mod pagination_page; pub mod user_details_lite; \ No newline at end of file diff --git a/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_cursors.rs b/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_cursors.rs new file mode 100644 index 0000000000..c801faea59 --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_cursors.rs @@ -0,0 +1,53 @@ +/// Pagination by cursors +/// These types of pagination are for "infinite scrolling", which do not reveal a number of pages. +/// This is good so that investors and competitors cannot reveal how many database records we have. +/// This is typically used for "discovery" type pages, not user profiles. +/// +/// See `PaginationPage` for the other type of pagination. +#[derive(Serialize)] +pub struct PaginationCursors { + + /// The "next" cursor. + /// This is an opaque (typically even encrypted) handle. + pub maybe_next: Option, + + /// The "previous" cursor. + /// This is an opaque (typically even encrypted) handle. + pub maybe_previous: Option, + + /// Details whether we're walking forward or backward. + pub cursor_is_reversed: bool, +} + +#[cfg(test)] +mod tests { + use crate::http_server::common_responses::pagination_cursors::PaginationCursors; + + #[test] + fn test_serialize_empty_json() { + // Make sure this interface doesn't change. + let pagination = PaginationCursors { + maybe_next: None, + maybe_previous: None, + cursor_is_reversed: false, + }; + + let json = serde_json::to_string(&pagination).expect("serialization"); + + assert_eq!(json, "{\"maybe_next\":null,\"maybe_previous\":null,\"cursor_is_reversed\":false}") + } + + #[test] + fn test_serialize_full_json() { + // Make sure this interface doesn't change. + let pagination = PaginationCursors { + maybe_next: Some("foo".to_string()), + maybe_previous: Some("bar".to_string()), + cursor_is_reversed: true, + }; + + let json = serde_json::to_string(&pagination).expect("serialization"); + + assert_eq!(json, "{\"maybe_next\":\"foo\",\"maybe_previous\":\"bar\",\"cursor_is_reversed\":true}") + } +} diff --git a/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_page.rs b/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_page.rs new file mode 100644 index 0000000000..3e64af9626 --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_page.rs @@ -0,0 +1,33 @@ +/// Pagination by page id +/// This type of pagination is by "page id" and "page count". +/// This should never be used to walk the entire public database as competitors and investors +/// can use it to glean information about the scale of our service. +/// This is best used for user profiles and scoped down results. +/// +/// See `PaginationCursors` for the other type of pagination. +#[derive(Serialize)] +pub struct PaginationPage { + /// The current page number + pub current: u64, + + /// How many pages there are in total + pub total_page_count: u64, +} + +#[cfg(test)] +mod tests { + use crate::http_server::common_responses::pagination_page::PaginationPage; + + #[test] + fn test_serialize() { + let pagination = PaginationPage { + current: 5, + total_page_count: 123, + + }; + + let json = serde_json::to_string(&pagination).expect("serialization"); + + assert_eq!(json, "{\"current\":5,\"total_page_count\":123}") + } +} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs index 35ae3f074c..9cfe696a27 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs @@ -15,6 +15,7 @@ use enums::common::visibility::Visibility; use mysql_queries::queries::media_files::list_media_files_for_user::{list_media_files_for_user, ListMediaFileForUserArgs, ViewAs}; use tokens::tokens::media_files::MediaFileToken; +use crate::http_server::common_responses::pagination_cursors::PaginationCursors; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::server_state::ServerState; @@ -36,8 +37,7 @@ pub struct QueryParams { pub struct SuccessResponse { pub success: bool, pub results: Vec, - pub cursor_next: Option, - pub cursor_previous: Option, + pub pagination: PaginationCursors, } #[derive(Serialize)] @@ -202,8 +202,11 @@ pub async fn list_media_files_for_user_handler( let response = SuccessResponse { success: true, results, - cursor_next, - cursor_previous, + pagination: PaginationCursors { + maybe_next: cursor_next, + maybe_previous: cursor_previous, + cursor_is_reversed, + } }; let body = serde_json::to_string(&response)