Skip to main content

bottle_orm/
any_struct.rs

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