Skip to main content

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!(bool, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64, String);
93
94// ============================================================================
95// External Type Implementations
96// ============================================================================
97
98impl AnyImpl for uuid::Uuid {
99    fn columns() -> Vec<AnyInfo> {
100        Vec::new()
101    }
102
103    fn to_map(&self) -> HashMap<String, String> {
104        HashMap::new()
105    }
106}
107
108impl AnyImpl for chrono::NaiveDateTime {
109    fn columns() -> Vec<AnyInfo> {
110        Vec::new()
111    }
112
113    fn to_map(&self) -> HashMap<String, String> {
114        HashMap::new()
115    }
116}
117
118impl AnyImpl for chrono::NaiveDate {
119    fn columns() -> Vec<AnyInfo> {
120        Vec::new()
121    }
122
123    fn to_map(&self) -> HashMap<String, String> {
124        HashMap::new()
125    }
126}
127
128impl AnyImpl for chrono::NaiveTime {
129    fn columns() -> Vec<AnyInfo> {
130        Vec::new()
131    }
132
133    fn to_map(&self) -> HashMap<String, String> {
134        HashMap::new()
135    }
136}
137
138impl AnyImpl for chrono::DateTime<chrono::Utc> {
139    fn columns() -> Vec<AnyInfo> {
140        Vec::new()
141    }
142
143    fn to_map(&self) -> HashMap<String, String> {
144        HashMap::new()
145    }
146}
147
148// ============================================================================
149// Option Implementation
150// ============================================================================
151
152impl<T: AnyImpl> AnyImpl for Option<T> {
153    fn columns() -> Vec<AnyInfo> {
154        T::columns()
155    }
156
157    fn to_map(&self) -> HashMap<String, String> {
158        match self {
159            Some(v) => v.to_map(),
160            None => HashMap::new(),
161        }
162    }
163}
164
165// ============================================================================
166// Tuple Implementations
167// ============================================================================
168
169macro_rules! impl_any_tuple {
170    ($($T:ident),+) => {
171        impl<$($T: AnyImpl),+> AnyImpl for ($($T,)+) {
172            fn columns() -> Vec<AnyInfo> {
173                Vec::new()
174            }
175
176            fn to_map(&self) -> HashMap<String, String> {
177                HashMap::new()
178            }
179        }
180    };
181}
182
183impl_any_tuple!(T1);
184impl_any_tuple!(T1, T2);
185impl_any_tuple!(T1, T2, T3);
186impl_any_tuple!(T1, T2, T3, T4);
187impl_any_tuple!(T1, T2, T3, T4, T5);
188impl_any_tuple!(T1, T2, T3, T4, T5, T6);
189impl_any_tuple!(T1, T2, T3, T4, T5, T6, T7);
190impl_any_tuple!(T1, T2, T3, T4, T5, T6, T7, T8);