use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Meta {
pub pagination: Pagination,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Pagination {
pub page: u32,
pub limit: u32,
pub pages: u32,
pub total: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub next: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prev: Option<u32>,
}
impl Pagination {
pub fn has_next(&self) -> bool {
self.next.is_some()
}
pub fn has_prev(&self) -> bool {
self.prev.is_some()
}
pub fn is_first_page(&self) -> bool {
self.page == 1
}
pub fn is_last_page(&self) -> bool {
self.page == self.pages
}
pub fn items_on_page(&self) -> u32 {
if self.is_last_page() {
let items_before_last_page = (self.pages - 1) * self.limit;
self.total.saturating_sub(items_before_last_page)
} else {
self.limit
}
}
pub fn start_index(&self) -> u32 {
(self.page - 1) * self.limit
}
pub fn end_index(&self) -> u32 {
self.start_index() + self.items_on_page()
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_pagination_deserialization() {
let json = json!({
"page": 1,
"limit": 15,
"pages": 5,
"total": 73,
"next": 2,
"prev": null
});
let pagination: Pagination = serde_json::from_value(json).unwrap();
assert_eq!(pagination.page, 1);
assert_eq!(pagination.limit, 15);
assert_eq!(pagination.pages, 5);
assert_eq!(pagination.total, 73);
assert_eq!(pagination.next, Some(2));
assert_eq!(pagination.prev, None);
}
#[test]
fn test_pagination_middle_page() {
let json = json!({
"page": 3,
"limit": 10,
"pages": 5,
"total": 47,
"next": 4,
"prev": 2
});
let pagination: Pagination = serde_json::from_value(json).unwrap();
assert_eq!(pagination.page, 3);
assert_eq!(pagination.next, Some(4));
assert_eq!(pagination.prev, Some(2));
}
#[test]
fn test_pagination_last_page() {
let json = json!({
"page": 5,
"limit": 15,
"pages": 5,
"total": 73,
"next": null,
"prev": 4
});
let pagination: Pagination = serde_json::from_value(json).unwrap();
assert_eq!(pagination.page, 5);
assert_eq!(pagination.next, None);
assert_eq!(pagination.prev, Some(4));
}
#[test]
fn test_meta_deserialization() {
let json = json!({
"pagination": {
"page": 1,
"limit": 15,
"pages": 5,
"total": 73,
"next": 2,
"prev": null
}
});
let meta: Meta = serde_json::from_value(json).unwrap();
assert_eq!(meta.pagination.page, 1);
assert_eq!(meta.pagination.total, 73);
}
#[test]
fn test_has_next() {
let pagination = Pagination {
page: 1,
limit: 15,
pages: 5,
total: 73,
next: Some(2),
prev: None,
};
assert!(pagination.has_next());
let last_page = Pagination {
page: 5,
limit: 15,
pages: 5,
total: 73,
next: None,
prev: Some(4),
};
assert!(!last_page.has_next());
}
#[test]
fn test_has_prev() {
let pagination = Pagination {
page: 2,
limit: 15,
pages: 5,
total: 73,
next: Some(3),
prev: Some(1),
};
assert!(pagination.has_prev());
let first_page = Pagination {
page: 1,
limit: 15,
pages: 5,
total: 73,
next: Some(2),
prev: None,
};
assert!(!first_page.has_prev());
}
#[test]
fn test_is_first_page() {
let pagination = Pagination {
page: 1,
limit: 15,
pages: 5,
total: 73,
next: Some(2),
prev: None,
};
assert!(pagination.is_first_page());
let not_first = Pagination {
page: 2,
limit: 15,
pages: 5,
total: 73,
next: Some(3),
prev: Some(1),
};
assert!(!not_first.is_first_page());
}
#[test]
fn test_is_last_page() {
let pagination = Pagination {
page: 5,
limit: 15,
pages: 5,
total: 73,
next: None,
prev: Some(4),
};
assert!(pagination.is_last_page());
let not_last = Pagination {
page: 4,
limit: 15,
pages: 5,
total: 73,
next: Some(5),
prev: Some(3),
};
assert!(!not_last.is_last_page());
}
#[test]
fn test_items_on_page() {
let full_page = Pagination {
page: 1,
limit: 15,
pages: 5,
total: 73,
next: Some(2),
prev: None,
};
assert_eq!(full_page.items_on_page(), 15);
let last_page = Pagination {
page: 5,
limit: 15,
pages: 5,
total: 73,
next: None,
prev: Some(4),
};
assert_eq!(last_page.items_on_page(), 13);
}
#[test]
fn test_start_index() {
let page_1 = Pagination {
page: 1,
limit: 15,
pages: 5,
total: 73,
next: Some(2),
prev: None,
};
assert_eq!(page_1.start_index(), 0);
let page_2 = Pagination {
page: 2,
limit: 15,
pages: 5,
total: 73,
next: Some(3),
prev: Some(1),
};
assert_eq!(page_2.start_index(), 15);
let page_5 = Pagination {
page: 5,
limit: 15,
pages: 5,
total: 73,
next: None,
prev: Some(4),
};
assert_eq!(page_5.start_index(), 60);
}
#[test]
fn test_end_index() {
let page_1 = Pagination {
page: 1,
limit: 15,
pages: 5,
total: 73,
next: Some(2),
prev: None,
};
assert_eq!(page_1.end_index(), 15);
let page_2 = Pagination {
page: 2,
limit: 15,
pages: 5,
total: 73,
next: Some(3),
prev: Some(1),
};
assert_eq!(page_2.end_index(), 30);
let page_5 = Pagination {
page: 5,
limit: 15,
pages: 5,
total: 73,
next: None,
prev: Some(4),
};
assert_eq!(page_5.end_index(), 73);
}
#[test]
fn test_pagination_serialization() {
let pagination = Pagination {
page: 2,
limit: 10,
pages: 5,
total: 47,
next: Some(3),
prev: Some(1),
};
let json = serde_json::to_value(&pagination).unwrap();
assert_eq!(json["page"], 2);
assert_eq!(json["limit"], 10);
assert_eq!(json["pages"], 5);
assert_eq!(json["total"], 47);
assert_eq!(json["next"], 3);
assert_eq!(json["prev"], 1);
}
#[test]
fn test_pagination_serialization_with_nulls() {
let pagination = Pagination {
page: 1,
limit: 15,
pages: 1,
total: 10,
next: None,
prev: None,
};
let json = serde_json::to_value(&pagination).unwrap();
assert!(!json.as_object().unwrap().contains_key("next"));
assert!(!json.as_object().unwrap().contains_key("prev"));
}
#[test]
fn test_single_page() {
let pagination = Pagination {
page: 1,
limit: 15,
pages: 1,
total: 10,
next: None,
prev: None,
};
assert!(pagination.is_first_page());
assert!(pagination.is_last_page());
assert!(!pagination.has_next());
assert!(!pagination.has_prev());
assert_eq!(pagination.items_on_page(), 10);
assert_eq!(pagination.start_index(), 0);
assert_eq!(pagination.end_index(), 10);
}
#[test]
fn test_meta_serialization() {
let meta = Meta {
pagination: Pagination {
page: 1,
limit: 15,
pages: 5,
total: 73,
next: Some(2),
prev: None,
},
};
let json = serde_json::to_value(&meta).unwrap();
assert_eq!(json["pagination"]["page"], 1);
assert_eq!(json["pagination"]["total"], 73);
}
#[test]
fn test_pagination_clone_and_eq() {
let pagination = Pagination {
page: 1,
limit: 15,
pages: 5,
total: 73,
next: Some(2),
prev: None,
};
let cloned = pagination.clone();
assert_eq!(pagination, cloned);
}
#[test]
fn test_meta_clone_and_eq() {
let meta = Meta {
pagination: Pagination {
page: 1,
limit: 15,
pages: 5,
total: 73,
next: Some(2),
prev: None,
},
};
let cloned = meta.clone();
assert_eq!(meta, cloned);
}
}