1use serde::{Deserialize, Serialize};
2
3#[must_use]
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5pub struct SingleResponse<T> {
6 pub data: T,
7 pub message: String,
8}
9
10impl<T> SingleResponse<T> {
11 pub fn new(data: T, message: impl Into<String>) -> Self {
12 Self {
13 data,
14 message: message.into(),
15 }
16 }
17}
18
19#[must_use]
20#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
21pub struct ListResponse<T> {
22 pub data: Vec<T>,
23 pub pagination: PaginationMeta,
24}
25
26impl<T> ListResponse<T> {
27 pub fn new(data: Vec<T>, pagination: PaginationMeta) -> Self {
28 Self { data, pagination }
29 }
30}
31
32#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
33pub struct PaginationMeta {
34 pub page: u32,
35 pub size: u32,
36 pub total: u64,
37}
38
39impl PaginationMeta {
40 pub fn new(page: u32, size: u32, total: u64) -> Self {
41 Self { page, size, total }
42 }
43}
44
45#[cfg(test)]
46#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
47mod tests {
48 use super::*;
49
50 #[test]
51 fn single_response_serializes() {
52 let r = SingleResponse::new(42_i32, "ok");
53 let json = serde_json::to_string(&r).expect("serialize");
54 assert!(json.contains("\"data\":42"));
55 assert!(json.contains("\"message\":\"ok\""));
56 }
57
58 #[test]
59 fn list_response_carries_pagination() {
60 let r = ListResponse::new(vec![1_i32, 2, 3], PaginationMeta::new(0, 3, 3));
61 assert_eq!(r.data.len(), 3);
62 assert_eq!(r.pagination.total, 3);
63 }
64}