metabase_api_rs/core/models/
common.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use std::fmt;
4
5/// Metabase ID type - a newtype wrapper around i64
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
7#[serde(transparent)]
8pub struct MetabaseId(pub i64);
9
10/// User ID type - a newtype wrapper around i64
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12#[serde(transparent)]
13pub struct UserId(pub i64);
14
15/// Card ID type - a newtype wrapper around i32
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
17#[serde(transparent)]
18pub struct CardId(pub i32);
19
20/// Collection ID type - a newtype wrapper around i32
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
22#[serde(transparent)]
23pub struct CollectionId(pub i32);
24
25/// Dashboard ID type - a newtype wrapper around i32
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
27#[serde(transparent)]
28pub struct DashboardId(pub i32);
29
30/// Database ID type - a newtype wrapper around i32
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
32#[serde(transparent)]
33pub struct DatabaseId(pub i32);
34
35impl UserId {
36    /// Create a new UserId
37    pub fn new(id: i64) -> Self {
38        Self(id)
39    }
40
41    /// Get the inner i64 value
42    pub fn as_i64(&self) -> i64 {
43        self.0
44    }
45}
46
47impl fmt::Display for UserId {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        write!(f, "{}", self.0)
50    }
51}
52
53impl MetabaseId {
54    /// Create a new MetabaseId
55    pub fn new(id: i64) -> Self {
56        Self(id)
57    }
58
59    /// Get the inner i64 value
60    pub fn as_i64(&self) -> i64 {
61        self.0
62    }
63}
64
65impl fmt::Display for MetabaseId {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        write!(f, "{}", self.0)
68    }
69}
70
71/// Metabase DateTime type - a wrapper around `chrono::DateTime<Utc>`
72#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
73#[serde(transparent)]
74pub struct MetabaseDateTime(DateTime<Utc>);
75
76impl MetabaseDateTime {
77    /// Create a new MetabaseDateTime
78    pub fn new(dt: DateTime<Utc>) -> Self {
79        Self(dt)
80    }
81
82    /// Get the inner `DateTime<Utc>` value
83    pub fn into_inner(self) -> DateTime<Utc> {
84        self.0
85    }
86}
87
88/// Pagination parameters
89#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
90pub struct Pagination {
91    limit: usize,
92    offset: usize,
93}
94
95impl Pagination {
96    /// Create new pagination parameters
97    pub fn new(limit: usize, offset: usize) -> Self {
98        Self { limit, offset }
99    }
100
101    /// Create pagination for a specific page (1-indexed)
102    pub fn with_page(limit: usize, page: usize) -> Self {
103        let offset = if page > 0 { (page - 1) * limit } else { 0 };
104        Self { limit, offset }
105    }
106
107    /// Get the limit
108    pub fn limit(&self) -> usize {
109        self.limit
110    }
111
112    /// Get the offset
113    pub fn offset(&self) -> usize {
114        self.offset
115    }
116}
117
118/// Visibility enum for collections and other resources
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
120#[serde(rename_all = "lowercase")]
121pub enum Visibility {
122    Public,
123    Private,
124    Limited,
125}
126
127/// Export format for query results
128#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
129#[serde(rename_all = "lowercase")]
130pub enum ExportFormat {
131    /// CSV format
132    Csv,
133    /// JSON format
134    Json,
135    /// Excel format
136    Xlsx,
137}
138
139impl ExportFormat {
140    /// Get the format as a string for API endpoints
141    pub fn as_str(&self) -> &str {
142        match self {
143            Self::Csv => "csv",
144            Self::Json => "json",
145            Self::Xlsx => "xlsx",
146        }
147    }
148}
149
150impl fmt::Display for ExportFormat {
151    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152        write!(f, "{}", self.as_str())
153    }
154}
155
156#[cfg(test)]
157mod tests {
158    use super::*;
159    use serde_json;
160
161    #[test]
162    fn test_metabase_id_serialize_deserialize() {
163        let id = MetabaseId::new(123);
164
165        // Serialize
166        let json = serde_json::to_string(&id).unwrap();
167        assert_eq!(json, "123");
168
169        // Deserialize
170        let deserialized: MetabaseId = serde_json::from_str("456").unwrap();
171        assert_eq!(deserialized.as_i64(), 456);
172    }
173
174    #[test]
175    fn test_metabase_id_display() {
176        let id = MetabaseId::new(789);
177        assert_eq!(format!("{}", id), "789");
178    }
179
180    #[test]
181    fn test_metabase_datetime_serialize_deserialize() {
182        let dt_str = "2023-08-08T10:30:00Z";
183        let dt: MetabaseDateTime = serde_json::from_str(&format!("\"{}\"", dt_str)).unwrap();
184
185        // Check inner value
186        let inner: DateTime<Utc> = dt.into_inner();
187        assert_eq!(inner.to_rfc3339(), "2023-08-08T10:30:00+00:00");
188    }
189
190    #[test]
191    fn test_pagination() {
192        let pagination = Pagination::new(10, 20);
193        assert_eq!(pagination.limit(), 10);
194        assert_eq!(pagination.offset(), 20);
195
196        // Test with_page helper
197        let page_2 = Pagination::with_page(50, 2);
198        assert_eq!(page_2.limit(), 50);
199        assert_eq!(page_2.offset(), 50); // Page 2 with 50 items per page
200    }
201
202    #[test]
203    fn test_visibility_enum() {
204        let public = Visibility::Public;
205        let json = serde_json::to_string(&public).unwrap();
206        assert_eq!(json, "\"public\"");
207
208        let private: Visibility = serde_json::from_str("\"private\"").unwrap();
209        assert_eq!(private, Visibility::Private);
210    }
211
212    #[test]
213    fn test_export_format() {
214        // Test serialization
215        let csv = ExportFormat::Csv;
216        let json_str = serde_json::to_string(&csv).unwrap();
217        assert_eq!(json_str, "\"csv\"");
218
219        // Test deserialization
220        let xlsx: ExportFormat = serde_json::from_str("\"xlsx\"").unwrap();
221        assert_eq!(xlsx, ExportFormat::Xlsx);
222
223        // Test as_str method
224        assert_eq!(ExportFormat::Csv.as_str(), "csv");
225        assert_eq!(ExportFormat::Json.as_str(), "json");
226        assert_eq!(ExportFormat::Xlsx.as_str(), "xlsx");
227
228        // Test Display trait
229        assert_eq!(format!("{}", ExportFormat::Json), "json");
230    }
231}