1pub mod backend;
27pub mod connection;
28pub mod migration;
29pub mod pool;
30pub mod query;
31pub mod relation;
32pub mod repository;
33#[cfg(test)]
34mod tests;
35#[cfg(test)]
36mod tls_tests;
37
38pub use backend::Backend;
39pub use connection::{DbConfig, DbSslMode, DbTls};
40pub use migration::MigrationStatus;
41pub use pool::{DbPool, DbTransaction};
42pub use query::{Order, QueryBuilder};
43pub use relation::{BelongsTo, HasMany, HasOne};
44pub use repository::{ModelRepository, Repository};
45pub use crate::pagination::{CursorPage, Page};
46
47#[derive(Debug, Clone, PartialEq)]
51pub enum Value {
52 Null,
53 Bool(bool),
54 Int(i64),
55 Float(f64),
56 Text(String),
57 Bytes(Vec<u8>),
58}
59
60#[derive(Debug)]
64pub struct DbError(pub String);
65
66impl std::fmt::Display for DbError {
67 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68 write!(f, "DbError: {}", self.0)
69 }
70}
71
72impl std::error::Error for DbError {}
73
74impl DbError {
75 pub fn new(msg: impl Into<String>) -> Self {
76 DbError(msg.into())
77 }
78}
79
80#[derive(Debug, Clone)]
84pub struct ModelRow {
85 #[doc(hidden)]
86 pub columns: Vec<(String, Value)>,
87}
88
89impl ModelRow {
90 pub fn new(columns: Vec<(String, Value)>) -> Self {
91 ModelRow { columns }
92 }
93
94 pub fn get<T: FromColumn>(&self, col: &str) -> Result<T, DbError> {
96 for (name, val) in &self.columns {
97 if name.eq_ignore_ascii_case(col) {
98 return T::from_column(val.clone());
99 }
100 }
101 Err(DbError::new(format!("column '{}' not found in row", col)))
102 }
103}
104
105pub trait FromColumn: Sized {
109 fn from_column(v: Value) -> Result<Self, DbError>;
110}
111
112pub trait ToColumn {
114 fn to_column(&self) -> Value;
115}
116
117impl FromColumn for i16 {
120 fn from_column(v: Value) -> Result<Self, DbError> {
121 match v {
122 Value::Int(n) => Ok(n as i16),
123 Value::Null => Err(DbError::new("unexpected NULL for i16")),
124 other => Err(DbError::new(format!("cannot convert {:?} to i16", other))),
125 }
126 }
127}
128
129impl FromColumn for i32 {
130 fn from_column(v: Value) -> Result<Self, DbError> {
131 match v {
132 Value::Int(n) => Ok(n as i32),
133 Value::Null => Err(DbError::new("unexpected NULL for i32")),
134 other => Err(DbError::new(format!("cannot convert {:?} to i32", other))),
135 }
136 }
137}
138
139impl FromColumn for i64 {
140 fn from_column(v: Value) -> Result<Self, DbError> {
141 match v {
142 Value::Int(n) => Ok(n),
143 Value::Null => Err(DbError::new("unexpected NULL for i64")),
144 other => Err(DbError::new(format!("cannot convert {:?} to i64", other))),
145 }
146 }
147}
148
149impl FromColumn for u32 {
150 fn from_column(v: Value) -> Result<Self, DbError> {
151 match v {
152 Value::Int(n) => Ok(n as u32),
153 Value::Null => Err(DbError::new("unexpected NULL for u32")),
154 other => Err(DbError::new(format!("cannot convert {:?} to u32", other))),
155 }
156 }
157}
158
159impl FromColumn for u64 {
160 fn from_column(v: Value) -> Result<Self, DbError> {
161 match v {
162 Value::Int(n) => Ok(n as u64),
163 Value::Null => Err(DbError::new("unexpected NULL for u64")),
164 other => Err(DbError::new(format!("cannot convert {:?} to u64", other))),
165 }
166 }
167}
168
169impl FromColumn for f32 {
170 fn from_column(v: Value) -> Result<Self, DbError> {
171 match v {
172 Value::Float(f) => Ok(f as f32),
173 Value::Int(n) => Ok(n as f32),
174 Value::Null => Err(DbError::new("unexpected NULL for f32")),
175 other => Err(DbError::new(format!("cannot convert {:?} to f32", other))),
176 }
177 }
178}
179
180impl FromColumn for f64 {
181 fn from_column(v: Value) -> Result<Self, DbError> {
182 match v {
183 Value::Float(f) => Ok(f),
184 Value::Int(n) => Ok(n as f64),
185 Value::Null => Err(DbError::new("unexpected NULL for f64")),
186 other => Err(DbError::new(format!("cannot convert {:?} to f64", other))),
187 }
188 }
189}
190
191impl FromColumn for bool {
192 fn from_column(v: Value) -> Result<Self, DbError> {
193 match v {
194 Value::Bool(b) => Ok(b),
195 Value::Int(n) => Ok(n != 0),
196 Value::Null => Err(DbError::new("unexpected NULL for bool")),
197 other => Err(DbError::new(format!("cannot convert {:?} to bool", other))),
198 }
199 }
200}
201
202impl FromColumn for String {
203 fn from_column(v: Value) -> Result<Self, DbError> {
204 match v {
205 Value::Text(s) => Ok(s),
206 Value::Null => Err(DbError::new("unexpected NULL for String")),
207 other => Err(DbError::new(format!("cannot convert {:?} to String", other))),
208 }
209 }
210}
211
212impl<T: FromColumn> FromColumn for Option<T> {
213 fn from_column(v: Value) -> Result<Self, DbError> {
214 match v {
215 Value::Null => Ok(None),
216 other => Ok(Some(T::from_column(other)?)),
217 }
218 }
219}
220
221impl ToColumn for i16 {
224 fn to_column(&self) -> Value { Value::Int(*self as i64) }
225}
226impl ToColumn for i32 {
227 fn to_column(&self) -> Value { Value::Int(*self as i64) }
228}
229impl ToColumn for i64 {
230 fn to_column(&self) -> Value { Value::Int(*self) }
231}
232impl ToColumn for u32 {
233 fn to_column(&self) -> Value { Value::Int(*self as i64) }
234}
235impl ToColumn for u64 {
236 fn to_column(&self) -> Value { Value::Int(*self as i64) }
237}
238impl ToColumn for f32 {
239 fn to_column(&self) -> Value { Value::Float(*self as f64) }
240}
241impl ToColumn for f64 {
242 fn to_column(&self) -> Value { Value::Float(*self) }
243}
244impl ToColumn for bool {
245 fn to_column(&self) -> Value { Value::Bool(*self) }
246}
247impl ToColumn for String {
248 fn to_column(&self) -> Value { Value::Text(self.clone()) }
249}
250impl ToColumn for str {
251 fn to_column(&self) -> Value { Value::Text(self.to_owned()) }
252}
253impl ToColumn for &str {
254 fn to_column(&self) -> Value { Value::Text((*self).to_owned()) }
255}
256impl<T: ToColumn> ToColumn for Option<T> {
257 fn to_column(&self) -> Value {
258 match self {
259 Some(v) => v.to_column(),
260 None => Value::Null,
261 }
262 }
263}
264
265pub trait Model: Sized + Send + Sync {
269 fn table_name() -> &'static str;
271
272 fn column_names() -> &'static [&'static str];
274
275 fn primary_key_name() -> &'static str;
277
278 fn primary_key_value(&self) -> Value;
280
281 fn primary_key_auto_increment() -> bool {
283 false
284 }
285
286 fn from_row(row: &ModelRow) -> Result<Self, DbError>;
288
289 fn to_values(&self) -> Vec<(&'static str, Value)>;
292}
293
294#[derive(Clone, Debug, PartialEq, Eq)]
305pub struct ModelInfo {
306 pub type_name: &'static str,
308 pub table: &'static str,
310 pub columns: &'static [&'static str],
312 pub primary_key: &'static str,
314 pub auto_increment: bool,
316}
317
318impl ModelInfo {
319 pub fn of<T: Model>() -> Self {
321 ModelInfo {
322 type_name: std::any::type_name::<T>(),
323 table: T::table_name(),
324 columns: T::column_names(),
325 primary_key: T::primary_key_name(),
326 auto_increment: T::primary_key_auto_increment(),
327 }
328 }
329
330 pub fn short_name(&self) -> &'static str {
333 let base = self.type_name.split('<').next().unwrap_or(self.type_name);
334 base.rsplit("::").next().unwrap_or(base)
335 }
336}