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
14mod chrono_wrapper;
15
16macro_rules! impl_from_sqlite_default {
17    () => {
18        #[cfg(feature = "sqlite")]
19        fn from_sqlite(value: SqliteValueRef<'_>) -> Result<Self> {
20            value.get::<Self>()
21        }
22    };
23    ($wrapper_ty:ty) => {
24        #[cfg(feature = "sqlite")]
25        fn from_sqlite(value: SqliteValueRef<'_>) -> Result<Self> {
26            <$wrapper_ty as FromDbValue>::from_sqlite(value).map(|val| val.into())
27        }
28    };
29    ($wrapper_ty:ty, option) => {
30        #[cfg(feature = "sqlite")]
31        fn from_sqlite(value: SqliteValueRef<'_>) -> Result<Self> {
32            <$wrapper_ty as FromDbValue>::from_sqlite(value).map(|val| val.map(|val| val.into()))
33        }
34    };
35}
36
37macro_rules! impl_from_postgres_default {
38    () => {
39        #[cfg(feature = "postgres")]
40        fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self> {
41            value.get::<Self>()
42        }
43    };
44    ($wrapper_ty:ty) => {
45        #[cfg(feature = "postgres")]
46        fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self> {
47            <$wrapper_ty as FromDbValue>::from_postgres(value).map(|val| val.into())
48        }
49    };
50    ($wrapper_ty:ty, option) => {
51        #[cfg(feature = "postgres")]
52        fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self> {
53            <$wrapper_ty as FromDbValue>::from_postgres(value).map(|val| val.map(|val| val.into()))
54        }
55    };
56}
57
58macro_rules! impl_from_mysql_default {
59    () => {
60        #[cfg(feature = "mysql")]
61        fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self> {
62            value.get::<Self>()
63        }
64    };
65    ($wrapper_ty:ty) => {
66        #[cfg(feature = "mysql")]
67        fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self> {
68            <$wrapper_ty as FromDbValue>::from_mysql(value).map(|val| val.into())
69        }
70    };
71    ($wrapper_ty:ty, option) => {
72        #[cfg(feature = "mysql")]
73        fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self> {
74            <$wrapper_ty as FromDbValue>::from_mysql(value).map(|val| val.map(|val| val.into()))
75        }
76    };
77}
78
79macro_rules! impl_to_db_value_default {
80    ($ty:ty) => {
81        impl ToDbValue for $ty {
82            fn to_db_value(&self) -> DbValue {
83                self.clone().into()
84            }
85        }
86
87        impl ToDbValue for Option<$ty> {
88            fn to_db_value(&self) -> DbValue {
89                self.clone().into()
90            }
91        }
92    };
93
94    ($ty:ty, $wrapper_ty:ty) => {
95        impl ToDbValue for $ty {
96            fn to_db_value(&self) -> DbValue {
97                Into::<$wrapper_ty>::into(self.clone()).to_db_value()
98            }
99        }
100
101        impl ToDbValue for Option<$ty> {
102            fn to_db_value(&self) -> DbValue {
103                self.clone()
104                    .map(|val| Into::<$wrapper_ty>::into(val))
105                    .to_db_value()
106            }
107        }
108    };
109}
110
111macro_rules! impl_db_field {
112    ($ty:ty, $column_type:ident) => {
113        impl DatabaseField for $ty {
114            const TYPE: ColumnType = ColumnType::$column_type;
115        }
116
117        impl FromDbValue for $ty {
118            impl_from_sqlite_default!();
119
120            impl_from_postgres_default!();
121
122            impl_from_mysql_default!();
123        }
124
125        impl FromDbValue for Option<$ty> {
126            impl_from_sqlite_default!();
127
128            impl_from_postgres_default!();
129
130            impl_from_mysql_default!();
131        }
132
133        impl_to_db_value_default!($ty);
134    };
135    ($ty:ty, $column_type:ident, with $wrapper_ty:ty) => {
136        impl DatabaseField for $ty {
137            const TYPE: ColumnType = ColumnType::$column_type;
138        }
139
140        impl FromDbValue for $ty {
141            impl_from_sqlite_default!($wrapper_ty);
142
143            impl_from_postgres_default!($wrapper_ty);
144
145            impl_from_mysql_default!($wrapper_ty);
146        }
147
148        impl FromDbValue for Option<$ty> {
149            impl_from_sqlite_default!(Option<$wrapper_ty>, option);
150
151            impl_from_postgres_default!(Option<$wrapper_ty>, option);
152
153            impl_from_mysql_default!(Option<$wrapper_ty>, option);
154        }
155
156        impl_to_db_value_default!($ty, $wrapper_ty);
157    };
158}
159
160macro_rules! impl_db_field_with_postgres_int_cast {
161    ($dest_ty:ty, $src_ty:ty, $column_type:ident) => {
162        impl DatabaseField for $dest_ty {
163            const TYPE: ColumnType = ColumnType::$column_type;
164        }
165
166        impl FromDbValue for $dest_ty {
167            impl_from_sqlite_default!();
168
169            impl_from_mysql_default!();
170
171            #[cfg(feature = "postgres")]
172            fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self> {
173                #[allow(
174                    clippy::allow_attributes,
175                    clippy::cast_possible_truncation,
176                    clippy::cast_sign_loss,
177                    reason = "needed for casting from larger to smaller integer types"
178                )]
179                value.get::<$src_ty>().map(|v| v as $dest_ty)
180            }
181        }
182
183        impl FromDbValue for Option<$dest_ty> {
184            impl_from_sqlite_default!();
185
186            impl_from_mysql_default!();
187
188            #[cfg(feature = "postgres")]
189            fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self> {
190                #[allow(
191                    clippy::allow_attributes,
192                    clippy::cast_possible_truncation,
193                    clippy::cast_sign_loss,
194                    reason = "needed for casting from larger to smaller integer types"
195                )]
196                value
197                    .get::<Option<$src_ty>>()
198                    .map(|v| v.map(|v| v as $dest_ty))
199            }
200        }
201
202        impl_to_db_value_default!($dest_ty);
203    };
204}
205
206impl_db_field!(bool, Boolean);
207impl_db_field!(i16, SmallInteger);
208impl_db_field!(i32, Integer);
209impl_db_field!(i64, BigInteger);
210impl_db_field_with_postgres_int_cast!(i8, i16, TinyInteger);
211impl_db_field_with_postgres_int_cast!(u8, i16, TinyUnsignedInteger);
212impl_db_field_with_postgres_int_cast!(u16, i16, SmallUnsignedInteger);
213impl_db_field_with_postgres_int_cast!(u32, i32, UnsignedInteger);
214impl_db_field_with_postgres_int_cast!(u64, i64, BigUnsignedInteger);
215impl_db_field!(f32, Float);
216impl_db_field!(f64, Double);
217impl_db_field!(chrono::NaiveDate, Date);
218impl_db_field!(chrono::NaiveTime, Time);
219impl_db_field!(chrono::NaiveDateTime, DateTime);
220impl_db_field!(
221    chrono::WeekdaySet,
222    TinyUnsignedInteger,
223    with chrono_wrapper::WeekdaySet
224);
225impl_db_field!(String, Text);
226impl_db_field!(Vec<u8>, Blob);
227
228impl ToDbValue for &str {
229    fn to_db_value(&self) -> DbValue {
230        (*self).to_string().into()
231    }
232}
233
234impl DatabaseField for chrono::DateTime<chrono::FixedOffset> {
235    const TYPE: ColumnType = ColumnType::DateTimeWithTimeZone;
236}
237
238impl FromDbValue for chrono::DateTime<chrono::FixedOffset> {
239    impl_from_sqlite_default!();
240
241    impl_from_postgres_default!();
242
243    #[cfg(feature = "mysql")]
244    fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self> {
245        Ok(value.get::<chrono::DateTime<chrono::Utc>>()?.fixed_offset())
246    }
247}
248impl FromDbValue for Option<chrono::DateTime<chrono::FixedOffset>> {
249    impl_from_sqlite_default!();
250
251    impl_from_postgres_default!();
252
253    #[cfg(feature = "mysql")]
254    fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self> {
255        Ok(value
256            .get::<Option<chrono::DateTime<chrono::Utc>>>()?
257            .map(|dt| dt.fixed_offset()))
258    }
259}
260
261impl_to_db_value_default!(chrono::DateTime<chrono::FixedOffset>);
262
263impl ToDbValue for Option<&str> {
264    fn to_db_value(&self) -> DbValue {
265        self.map(ToString::to_string).into()
266    }
267}
268
269impl<T: DatabaseField> DatabaseField for Option<T>
270where
271    Option<T>: ToDbFieldValue + FromDbValue,
272{
273    const NULLABLE: bool = true;
274    const TYPE: ColumnType = T::TYPE;
275}
276
277impl<const LIMIT: u32> DatabaseField for LimitedString<LIMIT> {
278    const TYPE: ColumnType = ColumnType::String(LIMIT);
279}
280
281impl<const LIMIT: u32> FromDbValue for LimitedString<LIMIT> {
282    #[cfg(feature = "sqlite")]
283    fn from_sqlite(value: SqliteValueRef<'_>) -> Result<Self> {
284        let str = value.get::<String>()?;
285        Self::new(str).map_err(DatabaseError::value_decode)
286    }
287
288    #[cfg(feature = "postgres")]
289    fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self> {
290        let str = value.get::<String>()?;
291        Self::new(str).map_err(DatabaseError::value_decode)
292    }
293
294    #[cfg(feature = "mysql")]
295    fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self> {
296        let str = value.get::<String>()?;
297        Self::new(str).map_err(DatabaseError::value_decode)
298    }
299}
300
301impl<const LIMIT: u32> ToDbValue for LimitedString<LIMIT> {
302    fn to_db_value(&self) -> DbValue {
303        self.0.clone().into()
304    }
305}
306
307impl<const LIMIT: u32> ToDbValue for Option<LimitedString<LIMIT>> {
308    fn to_db_value(&self) -> DbValue {
309        self.clone().map(|s| s.0).into()
310    }
311}
312
313impl<T: Model + Send + Sync> DatabaseField for ForeignKey<T> {
314    const NULLABLE: bool = T::PrimaryKey::NULLABLE;
315    const TYPE: ColumnType = T::PrimaryKey::TYPE;
316}
317
318impl<T: Model + Send + Sync> FromDbValue for ForeignKey<T> {
319    #[cfg(feature = "sqlite")]
320    fn from_sqlite(value: SqliteValueRef<'_>) -> Result<Self> {
321        T::PrimaryKey::from_sqlite(value).map(ForeignKey::PrimaryKey)
322    }
323
324    #[cfg(feature = "postgres")]
325    fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self> {
326        T::PrimaryKey::from_postgres(value).map(ForeignKey::PrimaryKey)
327    }
328
329    #[cfg(feature = "mysql")]
330    fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self> {
331        T::PrimaryKey::from_mysql(value).map(ForeignKey::PrimaryKey)
332    }
333}
334
335impl<T: Model + Send + Sync> ToDbFieldValue for ForeignKey<T> {
336    fn to_db_field_value(&self) -> DbFieldValue {
337        self.primary_key().to_db_field_value()
338    }
339}
340
341impl<T: Model + Send + Sync> FromDbValue for Option<ForeignKey<T>>
342where
343    Option<T::PrimaryKey>: FromDbValue,
344{
345    #[cfg(feature = "sqlite")]
346    fn from_sqlite(value: SqliteValueRef<'_>) -> Result<Self> {
347        Ok(<Option<T::PrimaryKey>>::from_sqlite(value)?.map(ForeignKey::PrimaryKey))
348    }
349
350    #[cfg(feature = "postgres")]
351    fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self> {
352        Ok(<Option<T::PrimaryKey>>::from_postgres(value)?.map(ForeignKey::PrimaryKey))
353    }
354
355    #[cfg(feature = "mysql")]
356    fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self> {
357        Ok(<Option<T::PrimaryKey>>::from_mysql(value)?.map(ForeignKey::PrimaryKey))
358    }
359}
360
361impl<T: Model + Send + Sync> ToDbFieldValue for Option<ForeignKey<T>>
362where
363    Option<T::PrimaryKey>: ToDbFieldValue,
364{
365    fn to_db_field_value(&self) -> DbFieldValue {
366        match self {
367            Some(foreign_key) => foreign_key.to_db_field_value(),
368            None => <Option<T::PrimaryKey>>::None.to_db_field_value(),
369        }
370    }
371}
372
373impl<T: DatabaseField> DatabaseField for Auto<T> {
374    const NULLABLE: bool = T::NULLABLE;
375    const TYPE: ColumnType = T::TYPE;
376}
377
378impl<T: DatabaseField> FromDbValue for Auto<T> {
379    #[cfg(feature = "sqlite")]
380    fn from_sqlite(value: SqliteValueRef<'_>) -> Result<Self>
381    where
382        Self: Sized,
383    {
384        Ok(Self::fixed(T::from_sqlite(value)?))
385    }
386
387    #[cfg(feature = "postgres")]
388    fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self>
389    where
390        Self: Sized,
391    {
392        Ok(Self::fixed(T::from_postgres(value)?))
393    }
394
395    #[cfg(feature = "mysql")]
396    fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self>
397    where
398        Self: Sized,
399    {
400        Ok(Self::fixed(T::from_mysql(value)?))
401    }
402}
403
404impl<T: DatabaseField> ToDbFieldValue for Auto<T> {
405    fn to_db_field_value(&self) -> DbFieldValue {
406        match self {
407            Self::Fixed(value) => value.to_db_field_value(),
408            Self::Auto => DbFieldValue::Auto,
409        }
410    }
411}
412
413impl<T: DatabaseField> FromDbValue for Option<Auto<T>>
414where
415    Option<T>: FromDbValue,
416{
417    #[cfg(feature = "sqlite")]
418    fn from_sqlite(value: SqliteValueRef<'_>) -> Result<Self>
419    where
420        Self: Sized,
421    {
422        <Option<T>>::from_sqlite(value).map(|value| value.map(Auto::fixed))
423    }
424
425    #[cfg(feature = "postgres")]
426    fn from_postgres(value: PostgresValueRef<'_>) -> Result<Self>
427    where
428        Self: Sized,
429    {
430        <Option<T>>::from_postgres(value).map(|value| value.map(Auto::fixed))
431    }
432
433    #[cfg(feature = "mysql")]
434    fn from_mysql(value: MySqlValueRef<'_>) -> Result<Self>
435    where
436        Self: Sized,
437    {
438        <Option<T>>::from_mysql(value).map(|value| value.map(Auto::fixed))
439    }
440}
441
442impl<T: DatabaseField> ToDbFieldValue for Option<Auto<T>>
443where
444    Option<T>: ToDbFieldValue,
445{
446    fn to_db_field_value(&self) -> DbFieldValue {
447        match self {
448            Some(auto) => auto.to_db_field_value(),
449            None => <Option<T>>::None.to_db_field_value(),
450        }
451    }
452}
453
454impl<T: PrimaryKey> PrimaryKey for Auto<T> {}
455
456impl PrimaryKey for i32 {}
457
458impl PrimaryKey for i64 {}
459
460impl PrimaryKey for u32 {}
461
462impl PrimaryKey for u64 {}
463
464impl PrimaryKey for String {}