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