1use std::fmt::{Debug, Display};
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5#[cfg(feature = "utoipa")]
6use utoipa::ToSchema;
7
8#[allow(unused_imports)]
9use crate::{Page, PaginationError};
10
11#[derive(Clone, Debug)]
15#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
16#[cfg_attr(feature = "utoipa", derive(ToSchema))]
17pub struct Book<E> {
18 sheets: Vec<Page<E>>,
19}
20
21impl<E> Book<E> {
22 pub fn get_sheets(&self) -> &Vec<Page<E>> {
24 &self.sheets
25 }
26
27 pub fn new(sheets: &Vec<Page<E>>) -> Book<E>
51 where
52 E: Clone,
53 {
54 Book {
55 sheets: sheets.to_owned(),
56 }
57 }
58}
59
60impl<E> Default for Book<E> {
62 fn default() -> Self {
63 Self { sheets: Vec::new() }
64 }
65}
66
67impl<E> Display for Book<E>
69where
70 E: Debug,
71{
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 write!(f, "Book {{ sheets: {:?} }}", self.sheets)
74 }
75}
76
77impl<E> IntoIterator for Book<E> {
79 type Item = Page<E>;
80 type IntoIter = std::vec::IntoIter<Self::Item>;
81
82 fn into_iter(self) -> Self::IntoIter {
83 self.sheets.into_iter()
84 }
85}
86
87#[cfg(test)]
88mod test_book {
89 use crate::*;
90
91 #[test]
93 fn test_book_constructor() {
94 let records: Vec<u32> = vec![1, 2, 3, 4, 5];
95 let size: usize = 2;
96
97 let page_1: Page<u32> = Page::new(&records[0..2].to_vec(), 0, size, records.len()).unwrap();
98 let page_2: Page<u32> = Page::new(&records[2..4].to_vec(), 1, size, records.len()).unwrap();
99 let page_3: Page<u32> = Page::new(&records[4..5].to_vec(), 2, size, records.len()).unwrap();
100
101 Book::new(&vec![page_1, page_2, page_3]);
102 }
103
104 #[test]
106 fn test_book_clone() {
107 let records: Vec<u32> = vec![1, 2, 3, 4, 5];
108 let size: usize = 2;
109
110 let page_1: Page<u32> = Page::new(&records[0..2].to_vec(), 0, size, records.len()).unwrap();
111 let page_2: Page<u32> = Page::new(&records[2..4].to_vec(), 1, size, records.len()).unwrap();
112 let page_3: Page<u32> = Page::new(&records[4..5].to_vec(), 2, size, records.len()).unwrap();
113
114 let book: Book<u32> = Book::new(&vec![page_1, page_2, page_3]);
115 let cloned_book: Book<u32> = book.clone();
116
117 assert_eq!(
118 book.get_sheets()[0].get_items(),
119 cloned_book.get_sheets()[0].get_items()
120 );
121 assert_eq!(
122 book.get_sheets()[1].get_items(),
123 cloned_book.get_sheets()[1].get_items()
124 );
125 assert_eq!(
126 book.get_sheets()[2].get_items(),
127 cloned_book.get_sheets()[2].get_items()
128 );
129
130 assert_eq!(
131 book.get_sheets()[0].get_page(),
132 cloned_book.get_sheets()[0].get_page()
133 );
134 assert_eq!(
135 book.get_sheets()[1].get_page(),
136 cloned_book.get_sheets()[1].get_page()
137 );
138 assert_eq!(
139 book.get_sheets()[2].get_page(),
140 cloned_book.get_sheets()[2].get_page()
141 );
142
143 assert_eq!(
144 book.get_sheets()[0].get_size(),
145 cloned_book.get_sheets()[0].get_size()
146 );
147 assert_eq!(
148 book.get_sheets()[1].get_size(),
149 cloned_book.get_sheets()[1].get_size()
150 );
151 assert_eq!(
152 book.get_sheets()[2].get_size(),
153 cloned_book.get_sheets()[2].get_size()
154 );
155
156 assert_eq!(
157 book.get_sheets()[0].get_total(),
158 cloned_book.get_sheets()[0].get_total()
159 );
160 assert_eq!(
161 book.get_sheets()[1].get_total(),
162 cloned_book.get_sheets()[1].get_total()
163 );
164 assert_eq!(
165 book.get_sheets()[2].get_total(),
166 cloned_book.get_sheets()[2].get_total()
167 );
168
169 assert_eq!(
170 book.get_sheets()[0].get_pages(),
171 cloned_book.get_sheets()[0].get_pages()
172 );
173 assert_eq!(
174 book.get_sheets()[1].get_pages(),
175 cloned_book.get_sheets()[1].get_pages()
176 );
177 assert_eq!(
178 book.get_sheets()[2].get_pages(),
179 cloned_book.get_sheets()[2].get_pages()
180 );
181
182 assert_eq!(
183 book.get_sheets()[0].get_previous_page(),
184 cloned_book.get_sheets()[0].get_previous_page()
185 );
186 assert_eq!(
187 book.get_sheets()[1].get_previous_page(),
188 cloned_book.get_sheets()[1].get_previous_page()
189 );
190 assert_eq!(
191 book.get_sheets()[2].get_previous_page(),
192 cloned_book.get_sheets()[2].get_previous_page()
193 );
194
195 assert_eq!(
196 book.get_sheets()[0].get_next_page(),
197 cloned_book.get_sheets()[0].get_next_page()
198 );
199 assert_eq!(
200 book.get_sheets()[1].get_next_page(),
201 cloned_book.get_sheets()[1].get_next_page()
202 );
203 assert_eq!(
204 book.get_sheets()[2].get_next_page(),
205 cloned_book.get_sheets()[2].get_next_page()
206 );
207 }
208
209 #[test]
211 fn test_book_display() {
212 let records: Vec<u32> = vec![1, 2, 3, 4, 5];
213 let size: usize = 2;
214
215 let page_1: Page<u32> = Page::new(&records[0..2].to_vec(), 0, size, records.len()).unwrap();
216 let page_2: Page<u32> = Page::new(&records[2..4].to_vec(), 1, size, records.len()).unwrap();
217 let page_3: Page<u32> = Page::new(&records[4..5].to_vec(), 2, size, records.len()).unwrap();
218
219 let book: Book<u32> = Book::new(&vec![page_1, page_2, page_3]);
220
221 assert_eq!(
222 format!("{}", book),
223 "Book { sheets: [Page { items: [1, 2], page: 0, size: 2, total: 5, pages: 3, previous_page: None, next_page: Some(1) }, Page { items: [3, 4], page: 1, size: 2, total: 5, pages: 3, previous_page: Some(0), next_page: Some(2) }, Page { items: [5], page: 2, size: 2, total: 5, pages: 3, previous_page: Some(1), next_page: None }] }"
224 );
225 }
226
227 #[test]
229 fn test_book_into_iter() {
230 let records: Vec<u32> = vec![1, 2, 3, 4, 5];
231 let size: usize = 2;
232
233 let page_1: Page<u32> = Page::new(&records[0..2].to_vec(), 0, size, records.len()).unwrap();
234 let page_2: Page<u32> = Page::new(&records[2..4].to_vec(), 1, size, records.len()).unwrap();
235 let page_3: Page<u32> = Page::new(&records[4..5].to_vec(), 2, size, records.len()).unwrap();
236
237 let book: Book<u32> = Book::new(&vec![page_1, page_2, page_3]);
238
239 let mut iter = book.into_iter();
240
241 assert!(iter.next().is_some());
242 assert!(iter.next().is_some());
243 assert!(iter.next().is_some());
244 assert!(iter.next().is_none());
245 }
246
247 #[test]
249 fn test_book_debug() {
250 let records: Vec<u32> = vec![1, 2, 3, 4, 5];
251 let size: usize = 2;
252
253 let page_1: Page<u32> = Page::new(&records[0..2].to_vec(), 0, size, records.len()).unwrap();
254 let page_2: Page<u32> = Page::new(&records[2..4].to_vec(), 1, size, records.len()).unwrap();
255
256 let book: Book<u32> = Book::new(&vec![page_1, page_2]);
257
258 assert_eq!(
259 format!("{:?}", book),
260 "Book { sheets: [Page { items: [1, 2], page: 0, size: 2, total: 5, pages: 3, previous_page: None, next_page: Some(1) }, Page { items: [3, 4], page: 1, size: 2, total: 5, pages: 3, previous_page: Some(0), next_page: Some(2) }] }"
261 );
262 }
263
264 #[test]
266 fn test_book_default() {
267 let book: Book<u32> = Book::default();
268 assert_eq!(book.get_sheets().len(), 0);
269 }
270
271 #[cfg(feature = "serde")]
273 #[test]
274 fn test_book_serialization_and_deserialization() {
275 let records: Vec<u32> = vec![1, 2, 3, 4, 5];
276 let size: usize = 2;
277
278 let page_1: Page<u32> = Page::new(&records[0..2].to_vec(), 0, size, records.len()).unwrap();
279 let page_2: Page<u32> = Page::new(&records[2..4].to_vec(), 1, size, records.len()).unwrap();
280 let page_3: Page<u32> = Page::new(&records[4..5].to_vec(), 2, size, records.len()).unwrap();
281
282 let book: Book<u32> = Book::new(&vec![page_1, page_2, page_3]);
283
284 let serialized_book: String = serde_json::to_string(&book).unwrap();
285 let _deserialized_book: Book<u32> = serde_json::from_str(&serialized_book).unwrap();
286 }
287
288 #[cfg(feature = "serde")]
290 #[test]
291 fn test_book_deserialization_error() {
292 let serialized_book: String = r#"{"sheets":[{"items":[1,2],"page":0,"size":2,"total":5,"pages":3,"previous_page":null,"next_page":1},{"items":[3,4],"page":1,"size":2,"total":5,"pages":3,"previous_page":0,"next_page":2},{"items":[5],"page":2,"size":2,"total":5,"pages":3,"previous_page":1,"next_page":3}]}"#.to_string();
293
294 let book_result: Result<Book<u32>, serde_json::Error> =
295 serde_json::from_str(&serialized_book);
296 assert!(book_result.is_err());
297 assert_eq!(
298 format!("{}", book_result.unwrap_err()),
299 "INVALID VALUE ERROR- Next page index error: expected 'None', found 'Some(3)' at line 1 column 270"
300 );
301 }
302
303 #[cfg(feature = "utoipa")]
305 #[test]
306 fn test_book_to_schema() {
307 use utoipa::{
308 PartialSchema, ToSchema,
309 openapi::{RefOr, Schema},
310 };
311
312 #[derive(Clone, ToSchema)]
313 #[allow(dead_code)]
314 struct Record {
315 number: u8,
316 }
317
318 let schema_object: RefOr<Schema> = Book::<Record>::schema();
319
320 let json_string: String = serde_json::to_string(&schema_object).unwrap();
321 assert_eq!(
322 json_string,
323 "{\"type\":\"object\",\"description\":\"Model to represent a book of paginated items.\\n#### Fields:\\n- **sheets**: Represents the ***sheets*** in a [`Book`] as a [`Vec`] of [`Page`].\",\"required\":[\"sheets\"],\"properties\":{\"sheets\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/components/schemas/Page_Record\"}}}}"
324 );
325 }
326}