soma_http_api/
pagination.rs1use serde::{Deserialize, Serialize};
9
10fn default_limit() -> usize {
11 50
12}
13
14#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
16#[serde(default)]
17pub struct PageParams {
18 #[serde(default = "default_limit")]
19 pub limit: usize,
20 pub offset: usize,
21}
22
23impl Default for PageParams {
24 fn default() -> Self {
25 Self {
26 limit: default_limit(),
27 offset: 0,
28 }
29 }
30}
31
32impl PageParams {
33 #[must_use]
39 pub fn clamped(mut self, max: usize) -> Self {
40 self.limit = self.limit.min(max);
41 self
42 }
43}
44
45#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
47pub struct Page<T> {
48 pub items: Vec<T>,
49 pub limit: usize,
50 pub offset: usize,
51 #[serde(skip_serializing_if = "Option::is_none")]
54 pub total: Option<usize>,
55}
56
57impl<T> Page<T> {
58 pub fn new(items: Vec<T>, params: PageParams, total: Option<usize>) -> Self {
59 Self {
60 items,
61 limit: params.limit,
62 offset: params.offset,
63 total,
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn page_params_default_limit_is_fifty() {
74 assert_eq!(
75 PageParams::default(),
76 PageParams {
77 limit: 50,
78 offset: 0
79 }
80 );
81 }
82
83 #[test]
84 fn page_params_clamped_never_exceeds_max() {
85 let params = PageParams {
86 limit: 500,
87 offset: 0,
88 }
89 .clamped(100);
90 assert_eq!(params.limit, 100);
91 }
92
93 #[test]
94 fn page_carries_params_and_total() {
95 let page = Page::new(
96 vec!["a", "b"],
97 PageParams {
98 limit: 2,
99 offset: 4,
100 },
101 Some(10),
102 );
103 assert_eq!(page.items, vec!["a", "b"]);
104 assert_eq!(page.limit, 2);
105 assert_eq!(page.offset, 4);
106 assert_eq!(page.total, Some(10));
107 }
108
109 #[test]
110 fn page_omits_total_when_unknown() {
111 let page = Page::new(vec!["a"], PageParams::default(), None);
112 assert_eq!(
113 serde_json::to_value(&page).unwrap(),
114 serde_json::json!({ "items": ["a"], "limit": 50, "offset": 0 })
115 );
116 }
117}