1#[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 {}