page_hunter/
page.rs

1use std::fmt::{Debug, Display};
2
3#[cfg(feature = "serde")]
4use serde::{
5    Deserialize, Serialize,
6    de::{Deserialize as DeDeserialize, Deserializer as DeDeserializer, Error as DeError},
7};
8#[cfg(feature = "utoipa")]
9use utoipa::ToSchema;
10
11use crate::{ErrorKind, PaginationError, PaginationResult};
12
13/// Model to represent paginated items.
14///
15/// #### Fields:
16/// - **items**: Represents the items in a [`Page`] as a [`Vec`] of `E`.
17/// - **page**: Represents the page index in a [`Page`]. It starts from 0 to ***pages*** - 1.
18/// - **size**: Represents the maximum number of elements per [`Page`]. ***items*** length must be equal to ***size*** for all pages except the last page, when ***items*** length could be less than or equal to ***size***.
19/// - **total**: Represents the total number of records used for pagination.
20/// - **pages**: Represents the total number of pages required for paginate the items.
21/// - **previous_page**: Represents the previous page index in a [`Page`]. If there is no previous page, it will be [`None`].
22/// - **next_page**: Represents the next page index in a [`Page`]. If there is no next page, it will be [`None`].
23#[derive(Clone, Debug)]
24#[cfg_attr(feature = "serde", derive(Serialize))]
25#[cfg_attr(feature = "utoipa", derive(ToSchema))]
26pub struct Page<E> {
27    items: Vec<E>,
28    page: usize,
29    size: usize,
30    total: usize,
31    pages: usize,
32    previous_page: Option<usize>,
33    next_page: Option<usize>,
34}
35
36impl<E> Page<E> {
37    /// Get ***items***
38    pub fn get_items(&self) -> &Vec<E> {
39        &self.items
40    }
41
42    /// Get ***page***
43    pub fn get_page(&self) -> usize {
44        self.page
45    }
46
47    /// Get ***size***
48    pub fn get_size(&self) -> usize {
49        self.size
50    }
51
52    /// Get ***total***
53    pub fn get_total(&self) -> usize {
54        self.total
55    }
56
57    /// Get ***pages***
58    pub fn get_pages(&self) -> usize {
59        self.pages
60    }
61
62    /// Get ***previous_page***
63    pub fn get_previous_page(&self) -> Option<usize> {
64        self.previous_page
65    }
66
67    /// Get ***next_page***
68    pub fn get_next_page(&self) -> Option<usize> {
69        self.next_page
70    }
71
72    /// Verify [`Page`] fields.
73    ///
74    /// ### Arguments:
75    /// *No arguments*
76    ///
77    /// ### Returns:
78    /// A [`PaginationResult`]  with a `()` if successful, otherwise a [`PaginationError`] is returned.
79    ///
80    /// This method is used to check if the fields of a [`Page`] are valid based on the following criteria:
81    /// - ***pages*** must be equal to ***total*** divided by ***size*** rounded up. When ***size*** is 0, ***pages*** must be 1.
82    /// - ***page*** must be less than or equal to ***pages*** - 1.
83    /// - if ***page*** is less than ***pages*** - 1, ***items*** length must be equal to ***size***.
84    /// - if ***page*** is equal to ***pages*** - 1, ***total*** must be equal to (***pages*** - 1) * ***size*** + ***items*** length.
85    /// - ***previous_page*** must be equal to ***page*** - 1 if ***page*** is greater than 0, otherwise it must be [`None`].
86    /// - ***next_page*** must be equal to ***page*** + 1 if ***page*** is less than ***pages*** - 1, otherwise it must be [`None`].
87    fn verify_fields(&self) -> PaginationResult<()> {
88        let items_length: usize = self.get_items().len();
89
90        // pages must be equal to total divided by size rounded up. When size is 0, pages must be 1.
91        let expected_pages: usize = match self.get_size().eq(&0) {
92            true => 1,
93            false => self.get_total().div_ceil(self.get_size()).max(1),
94        };
95        if expected_pages.ne(&self.get_pages()) {
96            return Err(PaginationError::from(ErrorKind::InvalidValue(format!(
97                "Total pages error: expected '{}', found '{}'",
98                expected_pages,
99                self.get_pages(),
100            ))));
101        }
102
103        // page must be less than pages - 1.
104        if self.get_page().gt(&(self.get_pages() - 1)) {
105            return Err(PaginationError::from(ErrorKind::InvalidValue(format!(
106                "Page index '{}' exceeds total pages '{}'",
107                self.get_page(),
108                self.get_pages(),
109            ))));
110        }
111
112        // if page is less than pages - 1, items length must be equal to size.
113        if self.get_page().lt(&(self.get_pages() - 1)) && items_length.ne(&self.get_size()) {
114            return Err(PaginationError::from(ErrorKind::InvalidValue(format!(
115                "Items length '{}' is not equal to page size '{}' for an intermediate page '{}'",
116                &items_length,
117                self.get_size(),
118                self.get_page(),
119            ))));
120        }
121
122        // if page is equal to pages - 1, total must be equal to (pages - 1) * size + items length.
123        if self.get_page().eq(&(self.get_pages() - 1))
124            && self
125                .get_total()
126                .ne(&((self.get_pages() - 1) * self.get_size() + items_length))
127        {
128            return Err(PaginationError::from(ErrorKind::InvalidValue(format!(
129                "Total elements error: expected '{}', found '{}'",
130                (self.get_pages() - 1) * self.get_size() + items_length,
131                self.get_total(),
132            ))));
133        }
134
135        // Previous page index must be equal to page - 1 if page is greater than 0, otherwise it must be None.
136        let expected_previous_page: Option<usize> = match self.get_page().eq(&0) {
137            true => None,
138            false => Some(self.get_page() - 1),
139        };
140
141        if expected_previous_page.ne(&self.get_previous_page()) {
142            return Err(PaginationError::from(ErrorKind::InvalidValue(format!(
143                "Previous page index error: expected '{:?}', found '{:?}'",
144                expected_previous_page,
145                self.get_previous_page(),
146            ))));
147        }
148
149        // Next page index must be equal to page + 1 if page is less than pages - 1, otherwise it must be None.
150        let expected_next_page: Option<usize> = match self.get_page().eq(&(self.get_pages() - 1)) {
151            true => None,
152            false => Some(self.get_page() + 1),
153        };
154
155        if expected_next_page.ne(&self.get_next_page()) {
156            return Err(PaginationError::from(ErrorKind::InvalidValue(format!(
157                "Next page index error: expected '{:?}', found '{:?}'",
158                expected_next_page,
159                self.get_next_page(),
160            ))));
161        }
162
163        Ok(())
164    }
165
166    /// Create a new [`Page`] instance.
167    ///
168    /// ### Arguments:
169    /// - **items**: A reference to a collection of items `E`, where `E` must implement [`Clone`].
170    /// - **page**: The page index.
171    /// - **size**: The maximum number of elements per page.
172    /// - **total**: The total number of records used for pagination.
173    ///
174    /// ### Returns:
175    /// A [`PaginationResult`] with a [`Page`] if successful, otherwise a [`PaginationError`] is returned.
176    ///
177    /// ### Example:
178    ///```rust,no_run
179    ///   use page_hunter::*;
180    ///
181    ///   let items: Vec<u32> = vec![1, 2];
182    ///   let page: usize = 0;
183    ///   let size: usize = 2;
184    ///   let total_elements: usize = 5;
185    ///
186    ///   let pagination_result: PaginationResult<Page<u32>> = Page::new(
187    ///     &items,
188    ///     page,
189    ///     size,
190    ///     total_elements,
191    ///   );
192    ///
193    ///   let page: Page<u32> = match pagination_result {
194    ///     Ok(page) => page,
195    ///     Err(error) => panic!("Error: {}", error),
196    ///   };
197    /// ````
198    pub fn new(items: &Vec<E>, page: usize, size: usize, total: usize) -> PaginationResult<Page<E>>
199    where
200        E: Clone,
201    {
202        let pages: usize = match size.eq(&0) {
203            true => 1,
204            false => total.div_ceil(size).max(1),
205        };
206
207        let page: Page<E> = Page {
208            items: items.to_owned(),
209            page,
210            size,
211            total,
212            pages,
213            previous_page: match page.eq(&0) {
214                true => None,
215                false => Some(page - 1),
216            },
217            next_page: match page.eq(&(pages - 1)) {
218                true => None,
219                false => Some(page + 1),
220            },
221        };
222        page.verify_fields()?;
223
224        Ok(page)
225    }
226}
227
228/// Implementation of [`Default`] for [`Page`].
229impl<E> Default for Page<E> {
230    fn default() -> Self {
231        Self {
232            items: Vec::new(),
233            page: 0,
234            size: 0,
235            total: 0,
236            pages: 1,
237            previous_page: None,
238            next_page: None,
239        }
240    }
241}
242
243/// Implementation of [`Display`] for [`Page`].
244impl<E> Display for Page<E>
245where
246    E: Debug,
247{
248    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249        write!(
250            f,
251            "Page {{ items: {:?}, page: {}, size: {}, total: {}, pages: {}, previous_page: {:?}, next_page: {:?} }}",
252            self.items,
253            self.page,
254            self.size,
255            self.total,
256            self.pages,
257            self.previous_page,
258            self.next_page
259        )
260    }
261}
262
263/// Implementation of [`IntoIterator`] for [`Page`].
264impl<E> IntoIterator for Page<E> {
265    type Item = E;
266    type IntoIter = std::vec::IntoIter<Self::Item>;
267
268    fn into_iter(self) -> Self::IntoIter {
269        self.items.into_iter()
270    }
271}
272
273/// Implementation of [`Deserialize`] for [`Page`] if the feature `serde` is enabled.
274#[cfg(feature = "serde")]
275impl<'de, E> DeDeserialize<'de> for Page<E>
276where
277    E: Deserialize<'de>,
278{
279    fn deserialize<D>(deserializer: D) -> Result<Page<E>, D::Error>
280    where
281        D: DeDeserializer<'de>,
282    {
283        #[derive(Deserialize)]
284        struct PageModel<E> {
285            items: Vec<E>,
286            page: usize,
287            size: usize,
288            total: usize,
289            pages: usize,
290            previous_page: Option<usize>,
291            next_page: Option<usize>,
292        }
293
294        let page_model: PageModel<E> = DeDeserialize::deserialize(deserializer)?;
295
296        let page: Page<E> = Page {
297            items: page_model.items,
298            page: page_model.page,
299            size: page_model.size,
300            total: page_model.total,
301            pages: page_model.pages,
302            previous_page: page_model.previous_page,
303            next_page: page_model.next_page,
304        };
305
306        page.verify_fields().map_err(DeError::custom)?;
307
308        Ok(page)
309    }
310}
311
312#[cfg(test)]
313mod test_page_model {
314    use crate::*;
315    use std::vec::IntoIter;
316
317    /// Test [`Page`] constructor.
318    #[test]
319    fn test_page_model_constructor() {
320        let items: Vec<u32> = vec![2, 3];
321        let page: usize = 1;
322        let size: usize = 2;
323        let total_elements: usize = 5;
324
325        let expected_total_pages: usize = 3;
326        let expected_previous_page: Option<usize> = Some(0);
327        let expected_next_page: Option<usize> = Some(2);
328
329        let pagination_result: PaginationResult<Page<u32>> =
330            Page::new(&items, page, size, total_elements);
331        assert!(pagination_result.is_ok());
332
333        let page_model: Page<u32> = pagination_result.unwrap();
334        assert_eq!(page_model.get_items(), &items);
335        assert_eq!(page_model.get_page(), page);
336        assert_eq!(page_model.get_size(), size);
337        assert_eq!(page_model.get_total(), total_elements);
338        assert_eq!(page_model.get_pages(), expected_total_pages);
339        assert_eq!(page_model.get_previous_page(), expected_previous_page);
340        assert_eq!(page_model.get_next_page(), expected_next_page);
341    }
342
343    /// Test [`Page`] constructor with invalid `page` value: `page` exceeds `pages`.
344    #[test]
345    fn test_page_index_exceeds_total_pages() {
346        let items: Vec<u32> = vec![1, 2];
347        let page: usize = 3;
348        let size: usize = 2;
349        let total_elements: usize = 5;
350
351        let pagination_result: PaginationResult<Page<u32>> =
352            Page::new(&items, page, size, total_elements);
353        assert!(pagination_result.is_err());
354
355        let pagination_error: PaginationError = pagination_result.unwrap_err();
356        assert!(
357            pagination_error
358                .to_string()
359                .eq("INVALID VALUE ERROR- Page index '3' exceeds total pages '3'")
360        );
361    }
362
363    /// Test [`Page`] constructor with invalid `items` value: `items` length exceeds `total` elements.
364    #[test]
365    fn test_items_length_not_equal_to_size_for_not_last_page() {
366        let items: Vec<u32> = vec![1, 2, 3, 4];
367        let page: usize = 0;
368        let size: usize = 2;
369        let total_elements: usize = 3;
370
371        let pagination_result: PaginationResult<Page<u32>> =
372            Page::new(&items, page, size, total_elements);
373        assert!(pagination_result.is_err());
374
375        let pagination_error: PaginationError = pagination_result.unwrap_err();
376        assert!(pagination_error
377            .to_string()
378            .eq("INVALID VALUE ERROR- Items length '4' is not equal to page size '2' for an intermediate page '0'",));
379    }
380
381    /// Test [`Page`] constructor with invalid `items` value: `items` length is not equal to `size` for an intermediate `page`.
382    #[test]
383    fn test_item_length_error_for_intermediate_page_index() {
384        let items: Vec<u32> = vec![1];
385        let page: usize = 0;
386        let size: usize = 2;
387        let total_elements: usize = 3;
388
389        let pagination_result: PaginationResult<Page<u32>> =
390            Page::new(&items, page, size, total_elements);
391        assert!(pagination_result.is_err());
392
393        let pagination_error: PaginationError = pagination_result.unwrap_err();
394        assert!(pagination_error
395            .to_string()
396            .eq("INVALID VALUE ERROR- Items length '1' is not equal to page size '2' for an intermediate page '0'"));
397    }
398
399    /// Test [`Page`] into_iter method.
400    #[test]
401    fn test_page_model_into_iter() {
402        let items: Vec<u32> = vec![1, 2];
403        let page: usize = 0;
404        let size: usize = 2;
405        let total_elements: usize = 5;
406
407        let pagination_result: PaginationResult<Page<u32>> =
408            Page::new(&items, page, size, total_elements);
409        assert!(pagination_result.is_ok());
410
411        let page_model: Page<u32> = pagination_result.unwrap();
412        let mut iter: IntoIter<u32> = page_model.into_iter();
413        assert_eq!(iter.next(), Some(1));
414        assert_eq!(iter.next(), Some(2));
415        assert_eq!(iter.next(), None);
416    }
417
418    /// Test [`Page`] from size equals to 0.
419    #[test]
420    fn test_page_model_from_size_equals_to_0() {
421        let items: Vec<u32> = vec![1, 2];
422        let page: usize = 0;
423        let size: usize = 0;
424        let total_elements: usize = 5;
425
426        let pagination_result: PaginationResult<Page<u32>> =
427            Page::new(&items, page, size, total_elements);
428        assert!(pagination_result.is_err());
429
430        let pagination_error: PaginationError = pagination_result.unwrap_err();
431        assert!(
432            pagination_error
433                .to_string()
434                .eq("INVALID VALUE ERROR- Total elements error: expected '2', found '5'")
435        );
436    }
437
438    /// Test default [`Page`] constructor.
439    #[test]
440    fn test_default_page_model_constructor() {
441        let expected_items: Vec<u32> = vec![];
442        let expected_page: usize = 0;
443        let expected_size: usize = 0;
444        let expected_total_elements: usize = 0;
445        let expected_total_pages: usize = 1;
446        let expected_previous_page: Option<usize> = None;
447        let expected_next_page: Option<usize> = None;
448
449        let page_model: Page<u32> = Page::default();
450
451        assert_eq!(page_model.get_items(), &expected_items);
452        assert_eq!(page_model.get_page(), expected_page);
453        assert_eq!(page_model.get_size(), expected_size);
454        assert_eq!(page_model.get_total(), expected_total_elements);
455        assert_eq!(page_model.get_pages(), expected_total_pages);
456        assert_eq!(page_model.get_previous_page(), expected_previous_page);
457        assert_eq!(page_model.get_next_page(), expected_next_page);
458    }
459
460    /// Test ['Page'] display method.
461    #[test]
462    fn test_page_model_display() {
463        let items: Vec<u32> = vec![1, 2];
464        let page: usize = 0;
465        let size: usize = 2;
466        let total_elements: usize = 5;
467
468        let pagination_result: PaginationResult<Page<u32>> =
469            Page::new(&items, page, size, total_elements);
470        assert!(pagination_result.is_ok());
471
472        let page_model: Page<u32> = pagination_result.unwrap();
473        let page_model_display: String = format!("{}", page_model);
474        assert!(page_model_display.eq("Page { items: [1, 2], page: 0, size: 2, total: 5, pages: 3, previous_page: None, next_page: Some(1) }"));
475    }
476
477    /// Test ['Page'] debug method.
478    #[test]
479    fn test_page_model_debug() {
480        let items: Vec<u32> = vec![1, 2];
481        let page: usize = 0;
482        let size: usize = 2;
483        let total_elements: usize = 5;
484
485        let pagination_result: PaginationResult<Page<u32>> =
486            Page::new(&items, page, size, total_elements);
487        assert!(pagination_result.is_ok());
488
489        let page_model: Page<u32> = pagination_result.unwrap();
490        let page_model_debug: String = format!("{:?}", page_model);
491        assert!(page_model_debug.eq("Page { items: [1, 2], page: 0, size: 2, total: 5, pages: 3, previous_page: None, next_page: Some(1) }"));
492    }
493
494    /// Test ['Page'] clone method.
495    #[test]
496    fn test_page_model_clone() {
497        let items: Vec<u32> = vec![5];
498        let page: usize = 2;
499        let size: usize = 2;
500        let total_elements: usize = 5;
501
502        let pagination_result: PaginationResult<Page<u32>> =
503            Page::new(&items, page, size, total_elements);
504        assert!(pagination_result.is_ok());
505
506        let page_model: Page<u32> = pagination_result.unwrap();
507        let cloned_page_model: Page<u32> = page_model.clone();
508        assert_eq!(cloned_page_model.get_items(), page_model.get_items());
509        assert_eq!(cloned_page_model.get_page(), page_model.get_page());
510        assert_eq!(cloned_page_model.get_size(), page_model.get_size());
511        assert_eq!(cloned_page_model.get_total(), page_model.get_total());
512        assert_eq!(cloned_page_model.get_pages(), page_model.get_pages());
513        assert_eq!(
514            cloned_page_model.get_previous_page(),
515            page_model.get_previous_page()
516        );
517        assert_eq!(
518            cloned_page_model.get_next_page(),
519            page_model.get_next_page()
520        );
521    }
522
523    /// Test ['Page'] serialization and deserialization.
524    #[cfg(feature = "serde")]
525    #[test]
526    fn test_page_model_serialization_and_deserialization() {
527        use serde::{Deserialize, Serialize};
528
529        #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
530        struct Person {
531            name: String,
532            age: u8,
533        }
534
535        let items: Vec<Person> = vec![
536            Person {
537                name: "John".to_string(),
538                age: 20,
539            },
540            Person {
541                name: "Jane".to_string(),
542                age: 25,
543            },
544        ];
545        let page: usize = 0;
546        let size: usize = 2;
547        let total_elements: usize = 5;
548        let total_pages: usize = 3;
549        let previous_page: Option<usize> = None;
550        let next_page: Option<usize> = Some(1);
551
552        let pagination_result: PaginationResult<Page<Person>> =
553            Page::new(&items, page, size, total_elements);
554        assert!(pagination_result.is_ok());
555
556        let page_model: Page<Person> = pagination_result.unwrap();
557
558        let serialized: String = serde_json::to_string(&page_model).unwrap();
559        assert!(serialized.eq("{\"items\":[{\"name\":\"John\",\"age\":20},{\"name\":\"Jane\",\"age\":25}],\"page\":0,\"size\":2,\"total\":5,\"pages\":3,\"previous_page\":null,\"next_page\":1}"));
560
561        let deserialized: Page<Person> = serde_json::from_str(&serialized).unwrap();
562        assert_eq!(deserialized.get_items(), &items);
563        assert_eq!(deserialized.get_page(), page);
564        assert_eq!(deserialized.get_size(), size);
565        assert_eq!(deserialized.get_total(), total_elements);
566        assert_eq!(deserialized.get_pages(), total_pages);
567        assert_eq!(deserialized.get_previous_page(), previous_page);
568        assert_eq!(deserialized.get_next_page(), next_page);
569    }
570
571    /// Test [`Page`] deserialization with invalid `pages` value.
572    #[cfg(feature = "serde")]
573    #[test]
574    fn test_page_model_deserialization_with_invalid_pages() {
575        use serde::{Deserialize, Serialize};
576        use serde_json::Error as SerdeJsonError;
577
578        #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
579        struct Person {
580            name: String,
581            age: u8,
582        }
583
584        let serialized: String = "{\"items\":[{\"name\":\"John\",\"age\":20},{\"name\":\"Jane\",\"age\":25}],\"page\":0,\"size\":2,\"total\":5,\"pages\":0,\"previous_page\":null,\"next_page\":1}".to_string();
585        let deserialized: Result<Page<Person>, serde_json::Error> =
586            serde_json::from_str(&serialized);
587
588        assert!(deserialized.is_err());
589
590        let error: SerdeJsonError = deserialized.unwrap_err();
591        assert_eq!(
592            error.to_string(),
593            "INVALID VALUE ERROR- Total pages error: expected '3', found '0'"
594        );
595    }
596
597    /// Test [`Page`] deserialization with invalid items' length.
598    #[cfg(feature = "serde")]
599    #[test]
600    fn test_page_model_deserialization_with_invalid_previous_page() {
601        use serde::{Deserialize, Serialize};
602        use serde_json::Error as SerdeJsonError;
603
604        #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
605        struct Person {
606            name: String,
607            age: u8,
608        }
609
610        let serialized: String = "{\"items\":[{\"name\":\"John\",\"age\":20},{\"name\":\"Jane\",\"age\":25}],\"page\":0,\"size\":2,\"total\":5,\"pages\":3,\"previous_page\":2,\"next_page\":1}".to_string();
611        let deserialized: Result<Page<Person>, serde_json::Error> =
612            serde_json::from_str(&serialized);
613
614        assert!(deserialized.is_err());
615
616        let error: SerdeJsonError = deserialized.unwrap_err();
617        assert_eq!(
618            error.to_string(),
619            "INVALID VALUE ERROR- Previous page index error: expected 'None', found 'Some(2)'"
620        );
621    }
622
623    /// Test [`Page`] deserialization with invalid `next_page` value.
624    #[cfg(feature = "serde")]
625    #[test]
626    fn test_page_model_deserialization_with_invalid_next_page() {
627        use serde::{Deserialize, Serialize};
628        use serde_json::Error as SerdeJsonError;
629
630        #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
631        struct Person {
632            name: String,
633            age: u8,
634        }
635
636        let serialized: String = "{\"items\":[{\"name\":\"John\",\"age\":20},{\"name\":\"Jane\",\"age\":25}],\"page\":0,\"size\":2,\"total\":5,\"pages\":3,\"previous_page\":null,\"next_page\":2}".to_string();
637        let deserialized: Result<Page<Person>, serde_json::Error> =
638            serde_json::from_str(&serialized);
639
640        assert!(deserialized.is_err());
641
642        let error: SerdeJsonError = deserialized.unwrap_err();
643        assert_eq!(
644            error.to_string(),
645            "INVALID VALUE ERROR- Next page index error: expected 'Some(1)', found 'Some(2)'"
646        );
647    }
648
649    /// Test [`Page`] deserialization error.
650    #[cfg(feature = "serde")]
651    #[test]
652    fn test_page_deserialization_error() {
653        use serde_json::json;
654
655        let invalid_json = json!({
656            "items": ["item1", "item2"],
657            "page": "invalid_page",
658            "size": 2,
659            "total": 2,
660            "pages": 1,
661            "previous_page": null,
662            "next_page": null
663        });
664
665        let result: Result<Page<String>, _> = serde_json::from_value(invalid_json);
666
667        assert!(result.is_err());
668    }
669
670    /// Test [`Page`] to schema.
671    #[cfg(feature = "utoipa")]
672    #[test]
673    fn test_page_to_schema() {
674        use utoipa::{
675            PartialSchema, ToSchema,
676            openapi::{RefOr, Schema},
677        };
678
679        #[derive(Clone, ToSchema)]
680        #[allow(dead_code)]
681        struct Record {
682            number: u8,
683        }
684
685        let schema_object: RefOr<Schema> = Page::<Record>::schema();
686
687        let json_string: String = serde_json::to_string(&schema_object).unwrap();
688        assert_eq!(
689            json_string,
690            "{\"type\":\"object\",\"description\":\"Model to represent paginated items.\\n\\n#### Fields:\\n- **items**: Represents the items in a [`Page`] as a [`Vec`] of `E`.\\n- **page**: Represents the page index in a [`Page`]. It starts from 0 to ***pages*** - 1.\\n- **size**: Represents the maximum number of elements per [`Page`]. ***items*** length must be equal to ***size*** for all pages except the last page, when ***items*** length could be less than or equal to ***size***.\\n- **total**: Represents the total number of records used for pagination.\\n- **pages**: Represents the total number of pages required for paginate the items.\\n- **previous_page**: Represents the previous page index in a [`Page`]. If there is no previous page, it will be [`None`].\\n- **next_page**: Represents the next page index in a [`Page`]. If there is no next page, it will be [`None`].\",\"required\":[\"items\",\"page\",\"size\",\"total\",\"pages\"],\"properties\":{\"items\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/components/schemas/Record\"}},\"next_page\":{\"type\":[\"integer\",\"null\"],\"minimum\":0},\"page\":{\"type\":\"integer\",\"minimum\":0},\"pages\":{\"type\":\"integer\",\"minimum\":0},\"previous_page\":{\"type\":[\"integer\",\"null\"],\"minimum\":0},\"size\":{\"type\":\"integer\",\"minimum\":0},\"total\":{\"type\":\"integer\",\"minimum\":0}}}"
691        );
692    }
693}