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);