bottle_orm/
any_struct.rs

1//! # Any Structure Support
2//!
3//! This module defines traits and structures to support mapping arbitrary database rows
4//! (specifically `AnyRow`) to Rust structs. It provides metadata about columns
5//! to facilitate dynamic query construction and result mapping.
6//!
7//! ## Features
8//!
9//! - **Dynamic Mapping**: Supports mapping `AnyRow` to struct fields
10//! - **Metadata Reflection**: Provides column names and types at runtime
11//! - **Extensible**: Can be implemented for custom types
12//!
13//! ## Example
14//!
15//! ```rust,ignore
16//! use bottle_orm::{AnyImpl, AnyInfo};
17//!
18//! struct MyStruct {
19//!     id: i32,
20//!     name: String,
21//! }
22//!
23//! impl AnyImpl for MyStruct {
24//!     fn columns() -> Vec<AnyInfo> {
25//!         vec![
26//!             AnyInfo { column: "id", sql_type: "INTEGER" },
27//!             AnyInfo { column: "name", sql_type: "TEXT" },
28//!         ]
29//!     }
30//! }
31//! ```
32
33use std::collections::HashMap;
34
35// ============================================================================
36// AnyInfo Structure
37// ============================================================================
38
39/// Contains metadata about a database column.
40///
41/// This struct is used to describe the schema of a model or query result,
42/// providing the necessary information for the query builder to construct
43/// valid SQL statements.
44#[derive(Debug, Clone)]
45pub struct AnyInfo {
46    /// The name of the column in the database.
47    pub column: &'static str,
48
49    /// The SQL type of the column (e.g., "INTEGER", "TEXT", "UUID").
50    pub sql_type: &'static str,
51}
52
53// ============================================================================
54// AnyImpl Trait
55// ============================================================================
56
57/// A trait for types that can be mapped from an `AnyRow` and provide column metadata.
58///
59/// This trait is the backbone of the ORM's reflection capabilities. It allows the
60/// system to know which columns correspond to which fields in a Rust struct.
61///
62/// This trait is typically implemented automatically via the `FromAnyRow` derive macro,
63/// but can be implemented manually for custom scenarios.
64pub trait AnyImpl {
65    /// Returns a vector of `AnyInfo` describing the columns associated with this type.
66    fn columns() -> Vec<AnyInfo>;
67
68    /// Converts this instance to a HashMap for dynamic query building.
69    fn to_map(&self) -> HashMap<String, String>;
70}
71
72// ============================================================================
73// Primitive Implementations
74// ============================================================================
75
76macro_rules! impl_any_primitive {
77    ($($t:ty),*) => {
78        $(
79            impl AnyImpl for $t {
80                fn columns() -> Vec<AnyInfo> {
81                    Vec::new()
82                }
83
84                fn to_map(&self) -> HashMap<String, String> {
85                    HashMap::new()
86                }
87            }
88        )*
89    };
90}
91
92impl_any_primitive!(
93    bool,
94    i8, i16, i32, i64, isize,
95    u8, u16, u32, u64, usize,
96    f32, f64,
97    String
98);
99
100// ============================================================================
101// External Type Implementations
102// ============================================================================
103
104impl AnyImpl for uuid::Uuid {
105    fn columns() -> Vec<AnyInfo> {
106        Vec::new()
107    }
108
109    fn to_map(&self) -> HashMap<String, String> {
110        HashMap::new()
111    }
112}
113
114impl AnyImpl for chrono::NaiveDateTime {
115    fn columns() -> Vec<AnyInfo> {
116        Vec::new()
117    }
118
119    fn to_map(&self) -> HashMap<String, String> {
120        HashMap::new()
121    }
122}
123
124impl AnyImpl for chrono::NaiveDate {
125    fn columns() -> Vec<AnyInfo> {
126        Vec::new()
127    }
128
129    fn to_map(&self) -> HashMap<String, String> {
130        HashMap::new()
131    }
132}
133
134impl AnyImpl for chrono::NaiveTime {
135    fn columns() -> Vec<AnyInfo> {
136        Vec::new()
137    }
138
139    fn to_map(&self) -> HashMap<String, String> {
140        HashMap::new()
141    }
142}
143
144impl AnyImpl for chrono::DateTime<chrono::Utc> {
145    fn columns() -> Vec<AnyInfo> {
146        Vec::new()
147    }
148
149    fn to_map(&self) -> HashMap<String, String> {
150        HashMap::new()
151    }
152}
153
154// ============================================================================
155// Option Implementation
156// ============================================================================
157
158impl<T: AnyImpl> AnyImpl for Option<T> {
159    fn columns() -> Vec<AnyInfo> {
160        T::columns()
161    }
162
163    fn to_map(&self) -> HashMap<String, String> {
164        match self {
165            Some(v) => v.to_map(),
166            None => HashMap::new(),
167        }
168    }
169}
170
171// ============================================================================
172// Tuple Implementations
173// ============================================================================
174
175macro_rules! impl_any_tuple {
176    ($($T:ident),+) => {
177        impl<$($T: AnyImpl),+> AnyImpl for ($($T,)+) {
178            fn columns() -> Vec<AnyInfo> {
179                Vec::new()
180            }
181
182            fn to_map(&self) -> HashMap<String, String> {
183                HashMap::new()
184            }
185        }
186    };
187}
188
189impl_any_tuple!(T1);
190impl_any_tuple!(T1, T2);
191impl_any_tuple!(T1, T2, T3);
192impl_any_tuple!(T1, T2, T3, T4);
193impl_any_tuple!(T1, T2, T3, T4, T5);
194impl_any_tuple!(T1, T2, T3, T4, T5, T6);
195impl_any_tuple!(T1, T2, T3, T4, T5, T6, T7);
196impl_any_tuple!(T1, T2, T3, T4, T5, T6, T7, T8);