Skip to main content

bottle_orm/
any_struct.rs

1use sqlx::{any::AnyRow, Error, Row};
2use std::collections::HashMap;
3use serde::{Serialize, Deserialize};
4
5// ============================================================================
6// AnyInfo Structure
7// ============================================================================
8
9/// Contains metadata about a database column.
10///
11/// This struct is used to describe the schema of a model or query result,
12/// providing the necessary information for the query builder to construct
13/// valid SQL statements.
14#[derive(Debug, Clone)]
15pub struct AnyInfo {
16    /// The name of the column in the database.
17    pub column: &'static str,
18
19    /// The SQL type of the column (e.g., "INTEGER", "TEXT", "UUID").
20    pub sql_type: &'static str,
21
22    /// The name of the table this column belongs to (empty for un-associated columns).
23    pub table: &'static str,
24}
25
26// ============================================================================
27// AnyImpl Trait
28// ============================================================================
29
30/// A trait for types that can be mapped from an `AnyRow` and provide column metadata.
31///
32/// This trait is the backbone of the ORM's reflection capabilities. It allows the
33/// system to know which columns correspond to which fields in a Rust struct.
34///
35/// This trait is typically implemented automatically via the `FromAnyRow` derive macro,
36/// but can be implemented manually for custom scenarios.
37pub trait AnyImpl {
38    /// Returns a vector of `AnyInfo` describing the columns associated with this type.
39    fn columns() -> Vec<AnyInfo>;
40
41    /// Converts this instance to a HashMap for dynamic query building.
42    fn to_map(&self) -> HashMap<String, Option<String>>;
43}
44
45/// A trait for types that can be mapped from an `AnyRow`.
46pub trait FromAnyRow: Sized {
47    /// Constructs the type from the whole row.
48    fn from_any_row(row: &AnyRow) -> Result<Self, Error>;
49
50    /// Constructs the type from the row starting at the given index,
51    /// incrementing the index for each column consumed.
52    fn from_any_row_at(row: &AnyRow, index: &mut usize) -> Result<Self, Error>;
53}
54
55// ============================================================================
56// Primitive Implementations
57// ============================================================================
58
59macro_rules! impl_supported_primitive {
60    ($($t:ty),*) => {
61        $(
62            impl AnyImpl for $t {
63                fn columns() -> Vec<AnyInfo> { Vec::new() }
64                fn to_map(&self) -> HashMap<String, Option<String>> { HashMap::new() }
65            }
66
67            impl FromAnyRow for $t {
68                fn from_any_row(row: &AnyRow) -> Result<Self, Error> {
69                    row.try_get(0).map_err(|e| Error::Decode(Box::new(e)))
70                }
71
72                fn from_any_row_at(row: &AnyRow, index: &mut usize) -> Result<Self, Error> {
73                    let val = row.try_get(*index).map_err(|e| Error::Decode(Box::new(e)))?;
74                    *index += 1;
75                    Ok(val)
76                }
77            }
78        )*
79    };
80}
81
82// Primitives directly supported by sqlx::Any (Decode implemented)
83impl_supported_primitive!(bool, i16, i32, i64, f32, f64, String);
84
85macro_rules! impl_cast_primitive {
86    ($($t:ty),*) => {
87        $(
88            impl AnyImpl for $t {
89                fn columns() -> Vec<AnyInfo> { Vec::new() }
90                fn to_map(&self) -> HashMap<String, Option<String>> { HashMap::new() }
91            }
92
93            impl FromAnyRow for $t {
94                fn from_any_row(row: &AnyRow) -> Result<Self, Error> {
95                    // Try to get as i64 and cast
96                    let val: i64 = row.try_get(0).map_err(|e| Error::Decode(Box::new(e)))?;
97                    Ok(val as $t)
98                }
99
100                fn from_any_row_at(row: &AnyRow, index: &mut usize) -> Result<Self, Error> {
101                    let val: i64 = row.try_get(*index).map_err(|e| Error::Decode(Box::new(e)))?;
102                    *index += 1;
103                    Ok(val as $t)
104                }
105            }
106        )*
107    };
108}
109
110// Primitives that might need casting from i64
111impl_cast_primitive!(i8, isize, u8, u16, u32, u64, usize);
112
113// ============================================================================
114// Array and JSON Implementations
115// ============================================================================
116
117impl<T> AnyImpl for Vec<T>
118where
119    T: AnyImpl + Serialize + for<'de> Deserialize<'de>,
120{
121    fn columns() -> Vec<AnyInfo> {
122        Vec::new()
123    }
124    fn to_map(&self) -> HashMap<String, Option<String>> {
125        let mut map = HashMap::new();
126        if let Ok(json) = serde_json::to_string(self) {
127            map.insert("".to_string(), Some(json));
128        }
129        map
130    }
131}
132
133impl<T> FromAnyRow for Vec<T>
134where
135    T: Serialize + for<'de> Deserialize<'de> + Send,
136{
137    fn from_any_row(row: &AnyRow) -> Result<Self, Error> {
138        let mut index = 0;
139        Self::from_any_row_at(row, &mut index)
140    }
141
142    fn from_any_row_at(row: &AnyRow, index: &mut usize) -> Result<Self, Error> {
143        // sqlx::Any typically returns complex types like Arrays and JSON as strings
144        // especially when we use our Postgres to_json/casting logic or in SQLite.
145        let s: String = row.try_get(*index).map_err(|e| Error::Decode(Box::new(e)))?;
146        *index += 1;
147        serde_json::from_str(&s).map_err(|e| Error::Decode(Box::new(e)))
148    }
149}
150
151impl AnyImpl for serde_json::Value {
152    fn columns() -> Vec<AnyInfo> {
153        Vec::new()
154    }
155    fn to_map(&self) -> HashMap<String, Option<String>> {
156        let mut map = HashMap::new();
157        map.insert("".to_string(), Some(self.to_string()));
158        map
159    }
160}
161
162impl FromAnyRow for serde_json::Value {
163    fn from_any_row(row: &AnyRow) -> Result<Self, Error> {
164        let mut index = 0;
165        Self::from_any_row_at(row, &mut index)
166    }
167
168    fn from_any_row_at(row: &AnyRow, index: &mut usize) -> Result<Self, Error> {
169        let s: String = row.try_get(*index).map_err(|e| Error::Decode(Box::new(e)))?;
170        *index += 1;
171        serde_json::from_str(&s).map_err(|e| Error::Decode(Box::new(e)))
172    }
173}
174
175// ============================================================================
176// External Type Implementations
177// ============================================================================
178
179impl AnyImpl for uuid::Uuid {
180    fn columns() -> Vec<AnyInfo> {
181        Vec::new()
182    }
183    fn to_map(&self) -> HashMap<String, Option<String>> {
184        HashMap::new()
185    }
186}
187
188impl FromAnyRow for uuid::Uuid {
189    fn from_any_row(row: &AnyRow) -> Result<Self, Error> {
190        let mut index = 0;
191        Self::from_any_row_at(row, &mut index)
192    }
193
194    fn from_any_row_at(row: &AnyRow, index: &mut usize) -> Result<Self, Error> {
195        let s: String = row.try_get(*index).map_err(|e| Error::Decode(Box::new(e)))?;
196        *index += 1;
197        s.parse().map_err(|e| Error::Decode(Box::new(e)))
198    }
199}
200
201impl AnyImpl for chrono::NaiveDateTime {
202    fn columns() -> Vec<AnyInfo> {
203        Vec::new()
204    }
205    fn to_map(&self) -> HashMap<String, Option<String>> {
206        HashMap::new()
207    }
208}
209
210impl FromAnyRow for chrono::NaiveDateTime {
211    fn from_any_row(row: &AnyRow) -> Result<Self, Error> {
212        let mut index = 0;
213        Self::from_any_row_at(row, &mut index)
214    }
215
216    fn from_any_row_at(row: &AnyRow, index: &mut usize) -> Result<Self, Error> {
217        let res = row.try_get::<String, _>(*index);
218        match res {
219            Ok(s) => {
220                *index += 1;
221                crate::temporal::parse_naive_datetime(&s).map_err(|e| Error::Decode(Box::new(e)))
222            }
223            Err(e) => {
224                // Try numeric fallback (some drivers might return i64 for timestamps)
225                if let Ok(i) = row.try_get::<i64, _>(*index) {
226                    *index += 1;
227                    return Ok(chrono::DateTime::from_timestamp(i, 0).map(|dt| dt.naive_utc()).unwrap_or_default());
228                }
229                Err(Error::Decode(Box::new(e)))
230            }
231        }
232    }
233}
234
235impl AnyImpl for chrono::NaiveDate {
236    fn columns() -> Vec<AnyInfo> {
237        Vec::new()
238    }
239    fn to_map(&self) -> HashMap<String, Option<String>> {
240        HashMap::new()
241    }
242}
243
244impl FromAnyRow for chrono::NaiveDate {
245    fn from_any_row(row: &AnyRow) -> Result<Self, Error> {
246        let mut index = 0;
247        Self::from_any_row_at(row, &mut index)
248    }
249
250    fn from_any_row_at(row: &AnyRow, index: &mut usize) -> Result<Self, Error> {
251        let s: String = row.try_get(*index).map_err(|e| Error::Decode(Box::new(e)))?;
252        *index += 1;
253        crate::temporal::parse_naive_date(&s).map_err(|e| Error::Decode(Box::new(e)))
254    }
255}
256
257impl AnyImpl for chrono::NaiveTime {
258    fn columns() -> Vec<AnyInfo> {
259        Vec::new()
260    }
261    fn to_map(&self) -> HashMap<String, Option<String>> {
262        HashMap::new()
263    }
264}
265
266impl FromAnyRow for chrono::NaiveTime {
267    fn from_any_row(row: &AnyRow) -> Result<Self, Error> {
268        let mut index = 0;
269        Self::from_any_row_at(row, &mut index)
270    }
271
272    fn from_any_row_at(row: &AnyRow, index: &mut usize) -> Result<Self, Error> {
273        let s: String = row.try_get(*index).map_err(|e| Error::Decode(Box::new(e)))?;
274        *index += 1;
275        crate::temporal::parse_naive_time(&s).map_err(|e| Error::Decode(Box::new(e)))
276    }
277}
278
279impl AnyImpl for chrono::DateTime<chrono::Utc> {
280    fn columns() -> Vec<AnyInfo> {
281        Vec::new()
282    }
283    fn to_map(&self) -> HashMap<String, Option<String>> {
284        HashMap::new()
285    }
286}
287
288impl FromAnyRow for chrono::DateTime<chrono::Utc> {
289    fn from_any_row(row: &AnyRow) -> Result<Self, Error> {
290        let mut index = 0;
291        Self::from_any_row_at(row, &mut index)
292    }
293
294    fn from_any_row_at(row: &AnyRow, index: &mut usize) -> Result<Self, Error> {
295        let res = row.try_get::<String, _>(*index);
296        match res {
297            Ok(s) => {
298                *index += 1;
299                crate::temporal::parse_datetime_utc(&s).map_err(|e| Error::Decode(Box::new(e)))
300            }
301            Err(e) => {
302                // Try numeric fallback
303                if let Ok(i) = row.try_get::<i64, _>(*index) {
304                    *index += 1;
305                    return Ok(chrono::DateTime::from_timestamp(i, 0).unwrap_or_else(|| chrono::DateTime::<chrono::Utc>::from_naive_utc_and_offset(chrono::NaiveDateTime::default(), chrono::Utc)));
306                }
307                Err(Error::Decode(Box::new(e)))
308            }
309        }
310    }
311}
312
313// ============================================================================
314// Option Implementation
315// ============================================================================
316
317impl<T: AnyImpl> AnyImpl for Option<T> {
318    fn columns() -> Vec<AnyInfo> {
319        T::columns()
320    }
321    fn to_map(&self) -> HashMap<String, Option<String>> {
322        match self {
323            Some(v) => v.to_map(),
324            None => HashMap::new(),
325        }
326    }
327}
328
329impl<T: FromAnyRow> FromAnyRow for Option<T> {
330    fn from_any_row(row: &AnyRow) -> Result<Self, Error> {
331        match T::from_any_row(row) {
332            Ok(v) => Ok(Some(v)),
333            Err(_) => Ok(None),
334        }
335    }
336
337    fn from_any_row_at(row: &AnyRow, index: &mut usize) -> Result<Self, Error> {
338        match T::from_any_row_at(row, index) {
339            Ok(v) => Ok(Some(v)),
340            Err(_) => Ok(None),
341        }
342    }
343}
344
345// ============================================================================
346// Tuple Implementations
347// ============================================================================
348
349macro_rules! impl_any_tuple {
350    ($($T:ident),+) => {
351        impl<$($T: AnyImpl),+> AnyImpl for ($($T,)+) {
352            fn columns() -> Vec<AnyInfo> {
353                let mut cols = Vec::new();
354                $(
355                    cols.extend($T::columns());
356                )+
357                cols
358            }
359
360            fn to_map(&self) -> HashMap<String, Option<String>> {
361                let mut map = HashMap::new();
362                #[allow(non_snake_case)]
363                let ($($T,)+) = self;
364                $(
365                    map.extend($T.to_map());
366                )+
367                map
368            }
369        }
370
371        impl<$($T: FromAnyRow),+> FromAnyRow for ($($T,)+) {
372            fn from_any_row(row: &AnyRow) -> Result<Self, Error> {
373                let mut index = 0;
374                Ok((
375                    $(
376                        $T::from_any_row_at(row, &mut index)?,
377                    )+
378                ))
379            }
380
381            fn from_any_row_at(row: &AnyRow, index: &mut usize) -> Result<Self, Error> {
382                Ok((
383                    $(
384                        $T::from_any_row_at(row, index)?,
385                    )+
386                ))
387            }
388        }
389    };
390}
391
392impl_any_tuple!(T1);
393impl_any_tuple!(T1, T2);
394impl_any_tuple!(T1, T2, T3);
395impl_any_tuple!(T1, T2, T3, T4);
396impl_any_tuple!(T1, T2, T3, T4, T5);
397impl_any_tuple!(T1, T2, T3, T4, T5, T6);
398impl_any_tuple!(T1, T2, T3, T4, T5, T6, T7);
399impl_any_tuple!(T1, T2, T3, T4, T5, T6, T7, T8);