datadog_api/
pagination.rs1use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize)]
9pub struct PageParams {
10 #[serde(rename = "page[size]")]
12 pub page_size: i32,
13 #[serde(rename = "page[offset]", skip_serializing_if = "Option::is_none")]
15 pub page_offset: Option<i64>,
16}
17
18impl PageParams {
19 pub fn new(page_size: i32) -> Self {
21 Self {
22 page_size,
23 page_offset: None,
24 }
25 }
26
27 pub fn with_offset(page_size: i32, offset: i64) -> Self {
29 Self {
30 page_size,
31 page_offset: Some(offset),
32 }
33 }
34}
35
36impl Default for PageParams {
37 fn default() -> Self {
38 Self::new(100)
39 }
40}
41
42#[derive(Debug, Clone, Serialize)]
44pub struct CursorParams {
45 #[serde(rename = "page[limit]")]
47 pub limit: i32,
48 #[serde(rename = "page[cursor]", skip_serializing_if = "Option::is_none")]
50 pub cursor: Option<String>,
51}
52
53impl CursorParams {
54 pub fn new(limit: i32) -> Self {
56 Self {
57 limit,
58 cursor: None,
59 }
60 }
61
62 pub fn with_cursor(limit: i32, cursor: String) -> Self {
64 Self {
65 limit,
66 cursor: Some(cursor),
67 }
68 }
69}
70
71impl Default for CursorParams {
72 fn default() -> Self {
73 Self::new(100)
74 }
75}
76
77#[derive(Debug, Clone, Deserialize, Default)]
79pub struct PaginationMeta {
80 #[serde(default)]
82 pub total_count: Option<i64>,
83 #[serde(default)]
85 pub total_pages: Option<i64>,
86 #[serde(default)]
88 pub next_offset: Option<i64>,
89 #[serde(default)]
91 pub next_cursor: Option<String>,
92}
93
94impl PaginationMeta {
95 pub fn has_next(&self) -> bool {
97 self.next_offset.is_some() || self.next_cursor.is_some()
98 }
99}
100
101#[derive(Debug, Clone)]
103pub struct PaginatedResponse<T> {
104 pub items: Vec<T>,
106 pub meta: PaginationMeta,
108}
109
110impl<T> PaginatedResponse<T> {
111 pub fn new(items: Vec<T>, meta: PaginationMeta) -> Self {
113 Self { items, meta }
114 }
115
116 pub fn has_next(&self) -> bool {
118 self.meta.has_next()
119 }
120
121 pub fn total_count(&self) -> Option<i64> {
123 self.meta.total_count
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn test_page_params_default() {
133 let params = PageParams::default();
134 assert_eq!(params.page_size, 100);
135 assert!(params.page_offset.is_none());
136 }
137
138 #[test]
139 fn test_page_params_with_offset() {
140 let params = PageParams::with_offset(50, 100);
141 assert_eq!(params.page_size, 50);
142 assert_eq!(params.page_offset, Some(100));
143 }
144
145 #[test]
146 fn test_cursor_params_default() {
147 let params = CursorParams::default();
148 assert_eq!(params.limit, 100);
149 assert!(params.cursor.is_none());
150 }
151
152 #[test]
153 fn test_cursor_params_with_cursor() {
154 let params = CursorParams::with_cursor(50, "abc123".to_string());
155 assert_eq!(params.limit, 50);
156 assert_eq!(params.cursor, Some("abc123".to_string()));
157 }
158
159 #[test]
160 fn test_pagination_meta_has_next() {
161 let meta_with_offset = PaginationMeta {
162 next_offset: Some(100),
163 ..Default::default()
164 };
165 assert!(meta_with_offset.has_next());
166
167 let meta_with_cursor = PaginationMeta {
168 next_cursor: Some("abc".to_string()),
169 ..Default::default()
170 };
171 assert!(meta_with_cursor.has_next());
172
173 let meta_empty = PaginationMeta::default();
174 assert!(!meta_empty.has_next());
175 }
176
177 #[test]
178 fn test_paginated_response() {
179 let response = PaginatedResponse::new(
180 vec![1, 2, 3],
181 PaginationMeta {
182 total_count: Some(100),
183 next_offset: Some(3),
184 ..Default::default()
185 },
186 );
187
188 assert_eq!(response.items.len(), 3);
189 assert!(response.has_next());
190 assert_eq!(response.total_count(), Some(100));
191 }
192}