cot/db/
fields.rs

1//! `DatabaseField` implementations for common types.
2
3#[cfg(feature = "mysql")]
4use crate::db::impl_mysql::MySqlValueRef;
5#[cfg(feature = "postgres")]
6use crate::db::impl_postgres::PostgresValueRef;
7#[cfg(feature = "sqlite")]
8use crate::db::impl_sqlite::SqliteValueRef;
9use crate::db::{
10    Auto, ColumnType, DatabaseError, DatabaseField, DbFieldValue, DbValue, ForeignKey, FromDbValue,
11    LimitedString, Model, PrimaryKey, Result, SqlxValueRef, ToDbFieldValue, ToDbValue,
12};
13
14macro_rules! impl_from_sqlite_default {
15    () => {
16        #[cfg(feature = "sqlite")]
17        fn from_sqlite(value: SqliteValueRef<'_>) -> Result<Self> {
18            value.get::<Self>()
19        }
20    };
21}
22
23macro_rules! impl_from_postgres_default {
24    () => {
25        #[cfg(feature = "postgres")]
26        fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self> {
27            value.get::<Self>()
28        }
29    };
30}
31
32macro_rules! impl_from_mysql_default {
33    () => {
34        #[cfg(feature = "mysql")]
35        fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self> {
36            value.get::<Self>()
37        }
38    };
39}
40
41macro_rules! impl_to_db_value_default {
42    ($ty:ty) => {
43        impl ToDbValue for $ty {
44            fn to_db_value(&self) -> DbValue {
45                self.clone().into()
46            }
47        }
48
49        impl ToDbValue for Option<$ty> {
50            fn to_db_value(&self) -> DbValue {
51                self.clone().into()
52            }
53        }
54    };
55}
56
57macro_rules! impl_db_field {
58    ($ty:ty, $column_type:ident) => {
59        impl DatabaseField for $ty {
60            const TYPE: ColumnType = ColumnType::$column_type;
61        }
62
63        impl FromDbValue for $ty {
64            impl_from_sqlite_default!();
65
66            impl_from_postgres_default!();
67
68            impl_from_mysql_default!();
69        }
70
71        impl FromDbValue for Option<$ty> {
72            impl_from_sqlite_default!();
73
74            impl_from_postgres_default!();
75
76            impl_from_mysql_default!();
77        }
78
79        impl_to_db_value_default!($ty);
80    };
81}
82
83macro_rules! impl_db_field_with_postgres_int_cast {
84    ($dest_ty:ty, $src_ty:ty, $column_type:ident) => {
85        impl DatabaseField for $dest_ty {
86            const TYPE: ColumnType = ColumnType::$column_type;
87        }
88
89        impl FromDbValue for $dest_ty {
90            impl_from_sqlite_default!();
91
92            impl_from_mysql_default!();
93
94            #[cfg(feature = "postgres")]
95            fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self> {
96                #[allow(clippy::cast_possible_truncation)]
97                #[allow(clippy::cast_sign_loss)]
98                value.get::<$src_ty>().map(|v| v as $dest_ty)
99            }
100        }
101
102        impl FromDbValue for Option<$dest_ty> {
103            impl_from_sqlite_default!();
104
105            impl_from_mysql_default!();
106
107            #[cfg(feature = "postgres")]
108            fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self> {
109                #[allow(clippy::cast_possible_truncation)]
110                #[allow(clippy::cast_sign_loss)]
111                value
112                    .get::<Option<$src_ty>>()
113                    .map(|v| v.map(|v| v as $dest_ty))
114            }
115        }
116
117        impl_to_db_value_default!($dest_ty);
118    };
119}
120
121impl_db_field!(bool, Boolean);
122impl_db_field!(i16, SmallInteger);
123impl_db_field!(i32, Integer);
124impl_db_field!(i64, BigInteger);
125impl_db_field_with_postgres_int_cast!(i8, i16, TinyInteger);
126impl_db_field_with_postgres_int_cast!(u8, i16, TinyUnsignedInteger);
127impl_db_field_with_postgres_int_cast!(u16, i16, SmallUnsignedInteger);
128impl_db_field_with_postgres_int_cast!(u32, i32, UnsignedInteger);
129impl_db_field_with_postgres_int_cast!(u64, i64, BigUnsignedInteger);
130impl_db_field!(f32, Float);
131impl_db_field!(f64, Double);
132impl_db_field!(chrono::NaiveDate, Date);
133impl_db_field!(chrono::NaiveTime, Time);
134impl_db_field!(chrono::NaiveDateTime, DateTime);
135impl_db_field!(String, Text);
136impl_db_field!(Vec<u8>, Blob);
137
138impl ToDbValue for &str {
139    fn to_db_value(&self) -> DbValue {
140        (*self).to_string().into()
141    }
142}
143
144impl DatabaseField for chrono::DateTime<chrono::FixedOffset> {
145    const TYPE: ColumnType = ColumnType::DateTimeWithTimeZone;
146}
147
148impl FromDbValue for chrono::DateTime<chrono::FixedOffset> {
149    impl_from_sqlite_default!();
150
151    impl_from_postgres_default!();
152
153    #[cfg(feature = "mysql")]
154    fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self> {
155        Ok(value.get::<chrono::DateTime<chrono::Utc>>()?.fixed_offset())
156    }
157}
158impl FromDbValue for Option<chrono::DateTime<chrono::FixedOffset>> {
159    impl_from_sqlite_default!();
160
161    impl_from_postgres_default!();
162
163    #[cfg(feature = "mysql")]
164    fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self> {
165        Ok(value
166            .get::<Option<chrono::DateTime<chrono::Utc>>>()?
167            .map(|dt| dt.fixed_offset()))
168    }
169}
170
171impl_to_db_value_default!(chrono::DateTime<chrono::FixedOffset>);
172
173impl ToDbValue for Option<&str> {
174    fn to_db_value(&self) -> DbValue {
175        self.map(ToString::to_string).into()
176    }
177}
178
179impl<T: DatabaseField> DatabaseField for Option<T>
180where
181    Option<T>: ToDbFieldValue + FromDbValue,
182{
183    const NULLABLE: bool = true;
184    const TYPE: ColumnType = T::TYPE;
185}
186
187impl<const LIMIT: u32> DatabaseField for LimitedString<LIMIT> {
188    const TYPE: ColumnType = ColumnType::String(LIMIT);
189}
190
191impl<const LIMIT: u32> FromDbValue for LimitedString<LIMIT> {
192    #[cfg(feature = "sqlite")]
193    fn from_sqlite(value: SqliteValueRef<'_>) -> Result<Self> {
194        let str = value.get::<String>()?;
195        Self::new(str).map_err(DatabaseError::value_decode)
196    }
197
198    #[cfg(feature = "postgres")]
199    fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self> {
200        let str = value.get::<String>()?;
201        Self::new(str).map_err(DatabaseError::value_decode)
202    }
203
204    #[cfg(feature = "mysql")]
205    fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self> {
206        let str = value.get::<String>()?;
207        Self::new(str).map_err(DatabaseError::value_decode)
208    }
209}
210
211impl<const LIMIT: u32> ToDbValue for LimitedString<LIMIT> {
212    fn to_db_value(&self) -> DbValue {
213        self.0.clone().into()
214    }
215}
216
217impl<const LIMIT: u32> ToDbValue for Option<LimitedString<LIMIT>> {
218    fn to_db_value(&self) -> DbValue {
219        self.clone().map(|s| s.0).into()
220    }
221}
222
223impl<T: Model + Send + Sync> DatabaseField for ForeignKey<T> {
224    const NULLABLE: bool = T::PrimaryKey::NULLABLE;
225    const TYPE: ColumnType = T::PrimaryKey::TYPE;
226}
227
228impl<T: Model + Send + Sync> FromDbValue for ForeignKey<T> {
229    #[cfg(feature = "sqlite")]
230    fn from_sqlite(value: SqliteValueRef<'_>) -> Result<Self> {
231        T::PrimaryKey::from_sqlite(value).map(ForeignKey::PrimaryKey)
232    }
233
234    #[cfg(feature = "postgres")]
235    fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self> {
236        T::PrimaryKey::from_postgres(value).map(ForeignKey::PrimaryKey)
237    }
238
239    #[cfg(feature = "mysql")]
240    fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self> {
241        T::PrimaryKey::from_mysql(value).map(ForeignKey::PrimaryKey)
242    }
243}
244
245impl<T: Model + Send + Sync> ToDbFieldValue for ForeignKey<T> {
246    fn to_db_field_value(&self) -> DbFieldValue {
247        self.primary_key().to_db_field_value()
248    }
249}
250
251impl<T: Model + Send + Sync> FromDbValue for Option<ForeignKey<T>>
252where
253    Option<T::PrimaryKey>: FromDbValue,
254{
255    #[cfg(feature = "sqlite")]
256    fn from_sqlite(value: SqliteValueRef<'_>) -> Result<Self> {
257        Ok(<Option<T::PrimaryKey>>::from_sqlite(value)?.map(ForeignKey::PrimaryKey))
258    }
259
260    #[cfg(feature = "postgres")]
261    fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self> {
262        Ok(<Option<T::PrimaryKey>>::from_postgres(value)?.map(ForeignKey::PrimaryKey))
263    }
264
265    #[cfg(feature = "mysql")]
266    fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self> {
267        Ok(<Option<T::PrimaryKey>>::from_mysql(value)?.map(ForeignKey::PrimaryKey))
268    }
269}
270
271impl<T: Model + Send + Sync> ToDbFieldValue for Option<ForeignKey<T>>
272where
273    Option<T::PrimaryKey>: ToDbFieldValue,
274{
275    fn to_db_field_value(&self) -> DbFieldValue {
276        match self {
277            Some(foreign_key) => foreign_key.to_db_field_value(),
278            None => <Option<T::PrimaryKey>>::None.to_db_field_value(),
279        }
280    }
281}
282
283impl<T: DatabaseField> DatabaseField for Auto<T> {
284    const NULLABLE: bool = T::NULLABLE;
285    const TYPE: ColumnType = T::TYPE;
286}
287
288impl<T: DatabaseField> FromDbValue for Auto<T> {
289    #[cfg(feature = "sqlite")]
290    fn from_sqlite(value: SqliteValueRef<'_>) -> Result<Self>
291    where
292        Self: Sized,
293    {
294        Ok(Self::fixed(T::from_sqlite(value)?))
295    }
296
297    #[cfg(feature = "postgres")]
298    fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self>
299    where
300        Self: Sized,
301    {
302        Ok(Self::fixed(T::from_postgres(value)?))
303    }
304
305    #[cfg(feature = "mysql")]
306    fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self>
307    where
308        Self: Sized,
309    {
310        Ok(Self::fixed(T::from_mysql(value)?))
311    }
312}
313
314impl<T: DatabaseField> ToDbFieldValue for Auto<T> {
315    fn to_db_field_value(&self) -> DbFieldValue {
316        match self {
317            Self::Fixed(value) => value.to_db_field_value(),
318            Self::Auto => DbFieldValue::Auto,
319        }
320    }
321}
322
323impl<T: DatabaseField> FromDbValue for Option<Auto<T>>
324where
325    Option<T>: FromDbValue,
326{
327    #[cfg(feature = "sqlite")]
328    fn from_sqlite(value: SqliteValueRef<'_>) -> Result<Self>
329    where
330        Self: Sized,
331    {
332        <Option<T>>::from_sqlite(value).map(|value| value.map(Auto::fixed))
333    }
334
335    #[cfg(feature = "postgres")]
336    fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self>
337    where
338        Self: Sized,
339    {
340        <Option<T>>::from_postgres(value).map(|value| value.map(Auto::fixed))
341    }
342
343    #[cfg(feature = "mysql")]
344    fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self>
345    where
346        Self: Sized,
347    {
348        <Option<T>>::from_mysql(value).map(|value| value.map(Auto::fixed))
349    }
350}
351
352impl<T: DatabaseField> ToDbFieldValue for Option<Auto<T>>
353where
354    Option<T>: ToDbFieldValue,
355{
356    fn to_db_field_value(&self) -> DbFieldValue {
357        match self {
358            Some(auto) => auto.to_db_field_value(),
359            None => <Option<T>>::None.to_db_field_value(),
360        }
361    }
362}
363
364impl<T: PrimaryKey> PrimaryKey for Auto<T> {}
365
366impl PrimaryKey for i32 {}
367
368impl PrimaryKey for i64 {}