sea_orm/executor/
query.rs

1pub use crate::error::TryGetError;
2use crate::{
3    SelectGetableValue, SelectorRaw, Statement,
4    error::{DbErr, type_err},
5};
6use std::{fmt::Debug, marker::PhantomData, sync::Arc};
7
8#[cfg(any(feature = "mock", feature = "proxy"))]
9use crate::debug_print;
10
11#[cfg(feature = "sqlx-dep")]
12use crate::driver::*;
13#[cfg(feature = "sqlx-dep")]
14use sqlx::Row;
15
16/// Defines the result of a query operation on a Model
17#[derive(Debug)]
18pub struct QueryResult {
19    pub(crate) row: QueryResultRow,
20}
21
22#[allow(clippy::enum_variant_names)]
23pub(crate) enum QueryResultRow {
24    #[cfg(feature = "sqlx-mysql")]
25    SqlxMySql(sqlx::mysql::MySqlRow),
26    #[cfg(feature = "sqlx-postgres")]
27    SqlxPostgres(sqlx::postgres::PgRow),
28    #[cfg(feature = "sqlx-sqlite")]
29    SqlxSqlite(sqlx::sqlite::SqliteRow),
30    #[cfg(feature = "rusqlite")]
31    Rusqlite(crate::driver::rusqlite::RusqliteRow),
32    #[cfg(feature = "mock")]
33    Mock(crate::MockRow),
34    #[cfg(feature = "proxy")]
35    Proxy(crate::ProxyRow),
36}
37
38/// An interface to get a value from the query result
39pub trait TryGetable: Sized {
40    /// Get a value from the query result with an ColIdx
41    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError>;
42
43    /// Get a value from the query result with prefixed column name
44    fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError> {
45        if pre.is_empty() {
46            Self::try_get_by(res, col)
47        } else {
48            Self::try_get_by(res, format!("{pre}{col}").as_str())
49        }
50    }
51
52    /// Get a value from the query result based on the order in the select expressions
53    fn try_get_by_index(res: &QueryResult, index: usize) -> Result<Self, TryGetError> {
54        Self::try_get_by(res, index)
55    }
56}
57
58impl From<TryGetError> for DbErr {
59    fn from(e: TryGetError) -> DbErr {
60        match e {
61            TryGetError::DbErr(e) => e,
62            TryGetError::Null(s) => {
63                type_err(format!("A null value was encountered while decoding {s}"))
64            }
65        }
66    }
67}
68
69impl From<DbErr> for TryGetError {
70    fn from(e: DbErr) -> TryGetError {
71        Self::DbErr(e)
72    }
73}
74
75// QueryResult //
76
77impl QueryResult {
78    /// Get a value from the query result with an ColIdx
79    pub fn try_get_by<T, I>(&self, index: I) -> Result<T, DbErr>
80    where
81        T: TryGetable,
82        I: ColIdx,
83    {
84        Ok(T::try_get_by(self, index)?)
85    }
86
87    /// Get a value from the query result with an ColIdx
88    pub fn try_get_by_nullable<T, I>(&self, index: I) -> Result<T, TryGetError>
89    where
90        T: TryGetable,
91        I: ColIdx,
92    {
93        T::try_get_by(self, index)
94    }
95
96    /// Get a value from the query result with prefixed column name
97    pub fn try_get<T>(&self, pre: &str, col: &str) -> Result<T, DbErr>
98    where
99        T: TryGetable,
100    {
101        Ok(T::try_get(self, pre, col)?)
102    }
103
104    /// Get a value from the query result with prefixed column name
105    pub fn try_get_nullable<T>(&self, pre: &str, col: &str) -> Result<T, TryGetError>
106    where
107        T: TryGetable,
108    {
109        T::try_get(self, pre, col)
110    }
111
112    /// Get a value from the query result based on the order in the select expressions
113    pub fn try_get_by_index<T>(&self, idx: usize) -> Result<T, DbErr>
114    where
115        T: TryGetable,
116    {
117        Ok(T::try_get_by_index(self, idx)?)
118    }
119
120    /// Get a value from the query result based on the order in the select expressions
121    pub fn try_get_by_index_nullable<T>(&self, idx: usize) -> Result<T, TryGetError>
122    where
123        T: TryGetable,
124    {
125        T::try_get_by_index(self, idx)
126    }
127
128    /// Get a tuple value from the query result with prefixed column name
129    pub fn try_get_many<T>(&self, pre: &str, cols: &[String]) -> Result<T, DbErr>
130    where
131        T: TryGetableMany,
132    {
133        Ok(T::try_get_many(self, pre, cols)?)
134    }
135
136    /// Get a tuple value from the query result based on the order in the select expressions
137    pub fn try_get_many_by_index<T>(&self) -> Result<T, DbErr>
138    where
139        T: TryGetableMany,
140    {
141        Ok(T::try_get_many_by_index(self)?)
142    }
143
144    /// Retrieves the names of the columns in the result set
145    pub fn column_names(&self) -> Vec<String> {
146        #[cfg(feature = "sqlx-dep")]
147        use sqlx::Column;
148
149        match &self.row {
150            #[cfg(feature = "sqlx-mysql")]
151            QueryResultRow::SqlxMySql(row) => {
152                row.columns().iter().map(|c| c.name().to_string()).collect()
153            }
154            #[cfg(feature = "sqlx-postgres")]
155            QueryResultRow::SqlxPostgres(row) => {
156                row.columns().iter().map(|c| c.name().to_string()).collect()
157            }
158            #[cfg(feature = "sqlx-sqlite")]
159            QueryResultRow::SqlxSqlite(row) => {
160                row.columns().iter().map(|c| c.name().to_string()).collect()
161            }
162            #[cfg(feature = "rusqlite")]
163            QueryResultRow::Rusqlite(row) => row.columns().iter().map(|c| c.to_string()).collect(),
164            #[cfg(feature = "mock")]
165            QueryResultRow::Mock(row) => row
166                .clone()
167                .into_column_value_tuples()
168                .map(|(c, _)| c.to_string())
169                .collect(),
170            #[cfg(feature = "proxy")]
171            QueryResultRow::Proxy(row) => row
172                .clone()
173                .into_column_value_tuples()
174                .map(|(c, _)| c.to_string())
175                .collect(),
176            #[allow(unreachable_patterns)]
177            _ => unreachable!(),
178        }
179    }
180
181    /// Access the underlying `MySqlRow` if we use the MySQL backend.
182    #[cfg(feature = "sqlx-mysql")]
183    pub fn try_as_mysql_row(&self) -> Option<&sqlx::mysql::MySqlRow> {
184        match &self.row {
185            QueryResultRow::SqlxMySql(mysql_row) => Some(mysql_row),
186            #[allow(unreachable_patterns)]
187            _ => None,
188        }
189    }
190
191    /// Access the underlying `PgRow` if we use the Postgres backend.
192    #[cfg(feature = "sqlx-postgres")]
193    pub fn try_as_pg_row(&self) -> Option<&sqlx::postgres::PgRow> {
194        match &self.row {
195            QueryResultRow::SqlxPostgres(pg_row) => Some(pg_row),
196            #[allow(unreachable_patterns)]
197            _ => None,
198        }
199    }
200
201    /// Access the underlying `SqliteRow` if we use the SQLite backend.
202    #[cfg(feature = "sqlx-sqlite")]
203    pub fn try_as_sqlite_row(&self) -> Option<&sqlx::sqlite::SqliteRow> {
204        match &self.row {
205            QueryResultRow::SqlxSqlite(sqlite_row) => Some(sqlite_row),
206            #[allow(unreachable_patterns)]
207            _ => None,
208        }
209    }
210
211    /// Access the underlying `MockRow` if we use a mock.
212    #[cfg(feature = "mock")]
213    pub fn try_as_mock_row(&self) -> Option<&crate::MockRow> {
214        match &self.row {
215            QueryResultRow::Mock(mock_row) => Some(mock_row),
216            #[allow(unreachable_patterns)]
217            _ => None,
218        }
219    }
220
221    /// Access the underlying `ProxyRow` if we use a proxy.
222    #[cfg(feature = "proxy")]
223    pub fn try_as_proxy_row(&self) -> Option<&crate::ProxyRow> {
224        match &self.row {
225            QueryResultRow::Proxy(proxy_row) => Some(proxy_row),
226            #[allow(unreachable_patterns)]
227            _ => None,
228        }
229    }
230}
231
232#[allow(unused_variables)]
233impl Debug for QueryResultRow {
234    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
235        match self {
236            #[cfg(feature = "sqlx-mysql")]
237            Self::SqlxMySql(row) => write!(f, "{row:?}"),
238            #[cfg(feature = "sqlx-postgres")]
239            Self::SqlxPostgres(_) => write!(f, "QueryResultRow::SqlxPostgres cannot be inspected"),
240            #[cfg(feature = "sqlx-sqlite")]
241            Self::SqlxSqlite(_) => write!(f, "QueryResultRow::SqlxSqlite cannot be inspected"),
242            #[cfg(feature = "rusqlite")]
243            Self::Rusqlite(row) => write!(f, "{row:?}"),
244            #[cfg(feature = "mock")]
245            Self::Mock(row) => write!(f, "{row:?}"),
246            #[cfg(feature = "proxy")]
247            Self::Proxy(row) => write!(f, "{row:?}"),
248            #[allow(unreachable_patterns)]
249            _ => unreachable!(),
250        }
251    }
252}
253
254// TryGetable //
255
256impl<T: TryGetable> TryGetable for Option<T> {
257    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
258        match T::try_get_by(res, index) {
259            Ok(v) => Ok(Some(v)),
260            Err(TryGetError::Null(_)) => Ok(None),
261            #[cfg(feature = "sqlx-dep")]
262            Err(TryGetError::DbErr(DbErr::Query(crate::RuntimeErr::SqlxError(err)))) => {
263                use std::ops::Deref;
264                match err.deref() {
265                    sqlx::Error::ColumnNotFound(_) => Ok(None),
266                    _ => Err(TryGetError::DbErr(DbErr::Query(
267                        crate::RuntimeErr::SqlxError(err),
268                    ))),
269                }
270            }
271            Err(e) => Err(e),
272        }
273    }
274}
275
276/// Column Index, used by [`TryGetable`]. Implemented for `&str` and `usize`
277pub trait ColIdx: Debug + Copy {
278    #[cfg(feature = "sqlx-mysql")]
279    /// Type surrogate
280    type SqlxMySqlIndex: sqlx::ColumnIndex<sqlx::mysql::MySqlRow>;
281    #[cfg(feature = "sqlx-postgres")]
282    /// Type surrogate
283    type SqlxPostgresIndex: sqlx::ColumnIndex<sqlx::postgres::PgRow>;
284    #[cfg(feature = "sqlx-sqlite")]
285    /// Type surrogate
286    type SqlxSqliteIndex: sqlx::ColumnIndex<sqlx::sqlite::SqliteRow>;
287
288    #[cfg(feature = "sqlx-mysql")]
289    /// Basically a no-op; only to satisfy trait bounds
290    fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex;
291    #[cfg(feature = "sqlx-postgres")]
292    /// Basically a no-op; only to satisfy trait bounds
293    fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex;
294    #[cfg(feature = "sqlx-sqlite")]
295    /// Basically a no-op; only to satisfy trait bounds
296    fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex;
297
298    /// Self must be `&str`, return `None` otherwise
299    fn as_str(&self) -> Option<&str>;
300    /// Self must be `usize`, return `None` otherwise
301    fn as_usize(&self) -> Option<&usize>;
302}
303
304impl ColIdx for &str {
305    #[cfg(feature = "sqlx-mysql")]
306    type SqlxMySqlIndex = Self;
307    #[cfg(feature = "sqlx-postgres")]
308    type SqlxPostgresIndex = Self;
309    #[cfg(feature = "sqlx-sqlite")]
310    type SqlxSqliteIndex = Self;
311
312    #[cfg(feature = "sqlx-mysql")]
313    #[inline]
314    fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex {
315        self
316    }
317    #[cfg(feature = "sqlx-postgres")]
318    #[inline]
319    fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex {
320        self
321    }
322    #[cfg(feature = "sqlx-sqlite")]
323    #[inline]
324    fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex {
325        self
326    }
327
328    #[inline]
329    fn as_str(&self) -> Option<&str> {
330        Some(self)
331    }
332    #[inline]
333    fn as_usize(&self) -> Option<&usize> {
334        None
335    }
336}
337
338impl ColIdx for usize {
339    #[cfg(feature = "sqlx-mysql")]
340    type SqlxMySqlIndex = Self;
341    #[cfg(feature = "sqlx-postgres")]
342    type SqlxPostgresIndex = Self;
343    #[cfg(feature = "sqlx-sqlite")]
344    type SqlxSqliteIndex = Self;
345
346    #[cfg(feature = "sqlx-mysql")]
347    #[inline]
348    fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex {
349        *self
350    }
351    #[cfg(feature = "sqlx-postgres")]
352    #[inline]
353    fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex {
354        *self
355    }
356    #[cfg(feature = "sqlx-sqlite")]
357    #[inline]
358    fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex {
359        *self
360    }
361
362    #[inline]
363    fn as_str(&self) -> Option<&str> {
364        None
365    }
366    #[inline]
367    fn as_usize(&self) -> Option<&usize> {
368        Some(self)
369    }
370}
371
372macro_rules! try_getable_all {
373    ( $type: ty ) => {
374        impl TryGetable for $type {
375            #[allow(unused_variables)]
376            fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
377                match &res.row {
378                    #[cfg(feature = "sqlx-mysql")]
379                    QueryResultRow::SqlxMySql(row) => row
380                        .try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
381                        .map_err(|e| sqlx_error_to_query_err(e).into())
382                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
383                    #[cfg(feature = "sqlx-postgres")]
384                    QueryResultRow::SqlxPostgres(row) => row
385                        .try_get::<Option<$type>, _>(idx.as_sqlx_postgres_index())
386                        .map_err(|e| sqlx_error_to_query_err(e).into())
387                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
388                    #[cfg(feature = "sqlx-sqlite")]
389                    QueryResultRow::SqlxSqlite(row) => row
390                        .try_get::<Option<$type>, _>(idx.as_sqlx_sqlite_index())
391                        .map_err(|e| sqlx_error_to_query_err(e).into())
392                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
393                    #[cfg(feature = "rusqlite")]
394                    QueryResultRow::Rusqlite(row) => row
395                        .try_get::<Option<$type>, _>(idx)
396                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
397                    #[cfg(feature = "mock")]
398                    QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
399                        debug_print!("{:#?}", e.to_string());
400                        err_null_idx_col(idx)
401                    }),
402                    #[cfg(feature = "proxy")]
403                    QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
404                        debug_print!("{:#?}", e.to_string());
405                        err_null_idx_col(idx)
406                    }),
407                    #[allow(unreachable_patterns)]
408                    _ => unreachable!(),
409                }
410            }
411        }
412    };
413}
414
415macro_rules! try_getable_unsigned {
416    ( $type: ty ) => {
417        impl TryGetable for $type {
418            #[allow(unused_variables)]
419            fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
420                match &res.row {
421                    #[cfg(feature = "sqlx-mysql")]
422                    QueryResultRow::SqlxMySql(row) => row
423                        .try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
424                        .map_err(|e| sqlx_error_to_query_err(e).into())
425                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
426                    #[cfg(feature = "sqlx-postgres")]
427                    QueryResultRow::SqlxPostgres(_) => Err(type_err(format!(
428                        "{} unsupported by sqlx-postgres",
429                        stringify!($type)
430                    ))
431                    .into()),
432                    #[cfg(feature = "sqlx-sqlite")]
433                    QueryResultRow::SqlxSqlite(row) => row
434                        .try_get::<Option<$type>, _>(idx.as_sqlx_sqlite_index())
435                        .map_err(|e| sqlx_error_to_query_err(e).into())
436                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
437                    #[cfg(feature = "rusqlite")]
438                    QueryResultRow::Rusqlite(row) => row
439                        .try_get::<Option<$type>, _>(idx)
440                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
441                    #[cfg(feature = "mock")]
442                    QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
443                        debug_print!("{:#?}", e.to_string());
444                        err_null_idx_col(idx)
445                    }),
446                    #[cfg(feature = "proxy")]
447                    QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
448                        debug_print!("{:#?}", e.to_string());
449                        err_null_idx_col(idx)
450                    }),
451                    #[allow(unreachable_patterns)]
452                    _ => unreachable!(),
453                }
454            }
455        }
456    };
457}
458
459macro_rules! try_getable_mysql {
460    ( $type: ty ) => {
461        impl TryGetable for $type {
462            #[allow(unused_variables)]
463            fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
464                match &res.row {
465                    #[cfg(feature = "sqlx-mysql")]
466                    QueryResultRow::SqlxMySql(row) => row
467                        .try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
468                        .map_err(|e| sqlx_error_to_query_err(e).into())
469                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
470                    #[cfg(feature = "sqlx-postgres")]
471                    QueryResultRow::SqlxPostgres(_) => Err(type_err(format!(
472                        "{} unsupported by sqlx-postgres",
473                        stringify!($type)
474                    ))
475                    .into()),
476                    #[cfg(feature = "sqlx-sqlite")]
477                    QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
478                        "{} unsupported by sqlx-sqlite",
479                        stringify!($type)
480                    ))
481                    .into()),
482                    #[cfg(feature = "rusqlite")]
483                    QueryResultRow::Rusqlite(row) => Err(type_err(format!(
484                        "{} unsupported by rusqlite",
485                        stringify!($type)
486                    ))
487                    .into()),
488                    #[cfg(feature = "mock")]
489                    QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
490                        debug_print!("{:#?}", e.to_string());
491                        err_null_idx_col(idx)
492                    }),
493                    #[cfg(feature = "proxy")]
494                    QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
495                        debug_print!("{:#?}", e.to_string());
496                        err_null_idx_col(idx)
497                    }),
498                    #[allow(unreachable_patterns)]
499                    _ => unreachable!(),
500                }
501            }
502        }
503    };
504}
505
506#[allow(unused_macros)]
507macro_rules! try_getable_postgres {
508    ( $type: ty ) => {
509        impl TryGetable for $type {
510            #[allow(unused_variables)]
511            fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
512                match &res.row {
513                    #[cfg(feature = "sqlx-mysql")]
514                    QueryResultRow::SqlxMySql(_) => Err(type_err(format!(
515                        "{} unsupported by sqlx-mysql",
516                        stringify!($type)
517                    ))
518                    .into()),
519                    #[cfg(feature = "sqlx-postgres")]
520                    QueryResultRow::SqlxPostgres(row) => row
521                        .try_get::<Option<$type>, _>(idx.as_sqlx_postgres_index())
522                        .map_err(|e| sqlx_error_to_query_err(e).into())
523                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
524                    #[cfg(feature = "sqlx-sqlite")]
525                    QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
526                        "{} unsupported by sqlx-sqlite",
527                        stringify!($type)
528                    ))
529                    .into()),
530                    #[cfg(feature = "rusqlite")]
531                    QueryResultRow::Rusqlite(row) => Err(type_err(format!(
532                        "{} unsupported by rusqlite",
533                        stringify!($type)
534                    ))
535                    .into()),
536                    #[cfg(feature = "mock")]
537                    QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
538                        debug_print!("{:#?}", e.to_string());
539                        err_null_idx_col(idx)
540                    }),
541                    #[cfg(feature = "proxy")]
542                    QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
543                        debug_print!("{:#?}", e.to_string());
544                        err_null_idx_col(idx)
545                    }),
546                    #[allow(unreachable_patterns)]
547                    _ => unreachable!(),
548                }
549            }
550        }
551    };
552}
553
554#[allow(unused_macros)]
555macro_rules! try_getable_date_time {
556    ( $type: ty ) => {
557        impl TryGetable for $type {
558            #[allow(unused_variables)]
559            fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
560                match &res.row {
561                    #[cfg(feature = "sqlx-mysql")]
562                    QueryResultRow::SqlxMySql(row) => {
563                        use chrono::{DateTime, Utc};
564                        row.try_get::<Option<DateTime<Utc>>, _>(idx.as_sqlx_mysql_index())
565                            .map_err(|e| sqlx_error_to_query_err(e).into())
566                            .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
567                            .map(|v| v.into())
568                    }
569                    #[cfg(feature = "sqlx-postgres")]
570                    QueryResultRow::SqlxPostgres(row) => row
571                        .try_get::<Option<$type>, _>(idx.as_sqlx_postgres_index())
572                        .map_err(|e| sqlx_error_to_query_err(e).into())
573                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
574                    #[cfg(feature = "sqlx-sqlite")]
575                    QueryResultRow::SqlxSqlite(row) => {
576                        use chrono::{DateTime, Utc};
577                        row.try_get::<Option<DateTime<Utc>>, _>(idx.as_sqlx_sqlite_index())
578                            .map_err(|e| sqlx_error_to_query_err(e).into())
579                            .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
580                            .map(|v| v.into())
581                    }
582                    #[cfg(feature = "rusqlite")]
583                    QueryResultRow::Rusqlite(row) => {
584                        use chrono::{DateTime, Utc};
585                        row.try_get::<Option<DateTime<Utc>>, _>(idx)
586                            .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
587                            .map(|v| v.into())
588                    }
589                    #[cfg(feature = "mock")]
590                    QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
591                        debug_print!("{:#?}", e.to_string());
592                        err_null_idx_col(idx)
593                    }),
594                    #[cfg(feature = "proxy")]
595                    QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
596                        debug_print!("{:#?}", e.to_string());
597                        err_null_idx_col(idx)
598                    }),
599                    #[allow(unreachable_patterns)]
600                    _ => unreachable!(),
601                }
602            }
603        }
604    };
605}
606
607try_getable_all!(bool);
608try_getable_all!(i8);
609try_getable_all!(i16);
610try_getable_all!(i32);
611try_getable_all!(i64);
612try_getable_unsigned!(u8);
613try_getable_unsigned!(u16);
614try_getable_mysql!(u64);
615try_getable_all!(f32);
616try_getable_all!(f64);
617try_getable_all!(Vec<u8>);
618
619#[cfg(feature = "with-json")]
620try_getable_all!(serde_json::Value);
621
622#[cfg(feature = "with-chrono")]
623try_getable_all!(chrono::NaiveDate);
624
625#[cfg(feature = "with-chrono")]
626try_getable_all!(chrono::NaiveTime);
627
628#[cfg(feature = "with-chrono")]
629try_getable_all!(chrono::NaiveDateTime);
630
631#[cfg(feature = "with-chrono")]
632try_getable_date_time!(chrono::DateTime<chrono::FixedOffset>);
633
634#[cfg(feature = "with-chrono")]
635try_getable_all!(chrono::DateTime<chrono::Utc>);
636
637#[cfg(feature = "with-chrono")]
638try_getable_all!(chrono::DateTime<chrono::Local>);
639
640#[cfg(feature = "with-time")]
641try_getable_all!(time::Date);
642
643#[cfg(feature = "with-time")]
644try_getable_all!(time::Time);
645
646#[cfg(feature = "with-time")]
647try_getable_all!(time::PrimitiveDateTime);
648
649#[cfg(feature = "with-time")]
650try_getable_all!(time::OffsetDateTime);
651
652#[cfg(feature = "with-rust_decimal")]
653use rust_decimal::Decimal;
654
655#[cfg(feature = "with-rust_decimal")]
656impl TryGetable for Decimal {
657    #[allow(unused_variables)]
658    fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
659        match &res.row {
660            #[cfg(feature = "sqlx-mysql")]
661            QueryResultRow::SqlxMySql(row) => row
662                .try_get::<Option<Decimal>, _>(idx.as_sqlx_mysql_index())
663                .map_err(|e| sqlx_error_to_query_err(e).into())
664                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
665            #[cfg(feature = "sqlx-postgres")]
666            QueryResultRow::SqlxPostgres(row) => row
667                .try_get::<Option<Decimal>, _>(idx.as_sqlx_postgres_index())
668                .map_err(|e| sqlx_error_to_query_err(e).into())
669                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
670            #[cfg(feature = "sqlx-sqlite")]
671            QueryResultRow::SqlxSqlite(row) => {
672                let val: Option<f64> = row
673                    .try_get(idx.as_sqlx_sqlite_index())
674                    .map_err(sqlx_error_to_query_err)?;
675                match val {
676                    Some(v) => Decimal::try_from(v).map_err(|e| {
677                        DbErr::TryIntoErr {
678                            from: "f64",
679                            into: "Decimal",
680                            source: Arc::new(e),
681                        }
682                        .into()
683                    }),
684                    None => Err(err_null_idx_col(idx)),
685                }
686            }
687            #[cfg(feature = "rusqlite")]
688            QueryResultRow::Rusqlite(row) => {
689                let val: Option<f64> = row.try_get(idx)?;
690                match val {
691                    Some(v) => Decimal::try_from(v).map_err(|e| {
692                        DbErr::TryIntoErr {
693                            from: "f64",
694                            into: "Decimal",
695                            source: Arc::new(e),
696                        }
697                        .into()
698                    }),
699                    None => Err(err_null_idx_col(idx)),
700                }
701            }
702            #[cfg(feature = "mock")]
703            #[allow(unused_variables)]
704            QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
705                debug_print!("{:#?}", e.to_string());
706                err_null_idx_col(idx)
707            }),
708            #[cfg(feature = "proxy")]
709            #[allow(unused_variables)]
710            QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
711                debug_print!("{:#?}", e.to_string());
712                err_null_idx_col(idx)
713            }),
714            #[allow(unreachable_patterns)]
715            _ => unreachable!(),
716        }
717    }
718}
719
720#[cfg(feature = "with-bigdecimal")]
721use bigdecimal::BigDecimal;
722
723#[cfg(feature = "with-bigdecimal")]
724impl TryGetable for BigDecimal {
725    #[allow(unused_variables)]
726    fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
727        match &res.row {
728            #[cfg(feature = "sqlx-mysql")]
729            QueryResultRow::SqlxMySql(row) => row
730                .try_get::<Option<BigDecimal>, _>(idx.as_sqlx_mysql_index())
731                .map_err(|e| sqlx_error_to_query_err(e).into())
732                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
733            #[cfg(feature = "sqlx-postgres")]
734            QueryResultRow::SqlxPostgres(row) => row
735                .try_get::<Option<BigDecimal>, _>(idx.as_sqlx_postgres_index())
736                .map_err(|e| sqlx_error_to_query_err(e).into())
737                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
738            #[cfg(feature = "sqlx-sqlite")]
739            QueryResultRow::SqlxSqlite(row) => {
740                let val: Option<f64> = row
741                    .try_get(idx.as_sqlx_sqlite_index())
742                    .map_err(sqlx_error_to_query_err)?;
743                match val {
744                    Some(v) => BigDecimal::try_from(v).map_err(|e| {
745                        DbErr::TryIntoErr {
746                            from: "f64",
747                            into: "BigDecimal",
748                            source: Arc::new(e),
749                        }
750                        .into()
751                    }),
752                    None => Err(err_null_idx_col(idx)),
753                }
754            }
755            #[cfg(feature = "rusqlite")]
756            QueryResultRow::Rusqlite(row) => {
757                let val: Option<f64> = row.try_get(idx)?;
758                match val {
759                    Some(v) => BigDecimal::try_from(v).map_err(|e| {
760                        DbErr::TryIntoErr {
761                            from: "f64",
762                            into: "BigDecimal",
763                            source: Arc::new(e),
764                        }
765                        .into()
766                    }),
767                    None => Err(err_null_idx_col(idx)),
768                }
769            }
770            #[cfg(feature = "mock")]
771            #[allow(unused_variables)]
772            QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
773                debug_print!("{:#?}", e.to_string());
774                err_null_idx_col(idx)
775            }),
776            #[cfg(feature = "proxy")]
777            #[allow(unused_variables)]
778            QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
779                debug_print!("{:#?}", e.to_string());
780                err_null_idx_col(idx)
781            }),
782            #[allow(unreachable_patterns)]
783            _ => unreachable!(),
784        }
785    }
786}
787
788#[allow(unused_macros)]
789macro_rules! try_getable_uuid {
790    ( $type: ty, $conversion_fn: expr ) => {
791        #[allow(unused_variables, unreachable_code)]
792        impl TryGetable for $type {
793            fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
794                let res: Result<uuid::Uuid, TryGetError> = match &res.row {
795                    #[cfg(feature = "sqlx-mysql")]
796                    QueryResultRow::SqlxMySql(row) => row
797                        .try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_mysql_index())
798                        .map_err(|e| sqlx_error_to_query_err(e).into())
799                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
800                        .or_else(|_| {
801                            // MariaDB's UUID type stores UUIDs as hyphenated strings.
802                            // reference: https://github.com/SeaQL/sea-orm/pull/2485
803                            row.try_get::<Option<Vec<u8>>, _>(idx.as_sqlx_mysql_index())
804                                .map_err(|e| sqlx_error_to_query_err(e).into())
805                                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
806                                .map(|bytes| {
807                                    String::from_utf8(bytes).map_err(|e| {
808                                        DbErr::TryIntoErr {
809                                            from: "Vec<u8>",
810                                            into: "String",
811                                            source: Arc::new(e),
812                                        }
813                                        .into()
814                                    })
815                                })?
816                                .and_then(|s| {
817                                    uuid::Uuid::parse_str(&s).map_err(|e| {
818                                        DbErr::TryIntoErr {
819                                            from: "String",
820                                            into: "uuid::Uuid",
821                                            source: Arc::new(e),
822                                        }
823                                        .into()
824                                    })
825                                })
826                        }),
827                    #[cfg(feature = "sqlx-postgres")]
828                    QueryResultRow::SqlxPostgres(row) => row
829                        .try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_postgres_index())
830                        .map_err(|e| sqlx_error_to_query_err(e).into())
831                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
832                    #[cfg(feature = "sqlx-sqlite")]
833                    QueryResultRow::SqlxSqlite(row) => row
834                        .try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_sqlite_index())
835                        .map_err(|e| sqlx_error_to_query_err(e).into())
836                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
837                    #[cfg(feature = "rusqlite")]
838                    QueryResultRow::Rusqlite(row) => row
839                        .try_get::<Option<uuid::Uuid>, _>(idx)
840                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
841                    #[cfg(feature = "mock")]
842                    #[allow(unused_variables)]
843                    QueryResultRow::Mock(row) => row.try_get::<uuid::Uuid, _>(idx).map_err(|e| {
844                        debug_print!("{:#?}", e.to_string());
845                        err_null_idx_col(idx)
846                    }),
847                    #[cfg(feature = "proxy")]
848                    #[allow(unused_variables)]
849                    QueryResultRow::Proxy(row) => row.try_get::<uuid::Uuid, _>(idx).map_err(|e| {
850                        debug_print!("{:#?}", e.to_string());
851                        err_null_idx_col(idx)
852                    }),
853                    #[allow(unreachable_patterns)]
854                    _ => unreachable!(),
855                };
856                res.map($conversion_fn)
857            }
858        }
859    };
860}
861
862#[cfg(feature = "with-uuid")]
863try_getable_uuid!(uuid::Uuid, Into::into);
864
865#[cfg(feature = "with-uuid")]
866try_getable_uuid!(uuid::fmt::Braced, uuid::Uuid::braced);
867
868#[cfg(feature = "with-uuid")]
869try_getable_uuid!(uuid::fmt::Hyphenated, uuid::Uuid::hyphenated);
870
871#[cfg(feature = "with-uuid")]
872try_getable_uuid!(uuid::fmt::Simple, uuid::Uuid::simple);
873
874#[cfg(feature = "with-uuid")]
875try_getable_uuid!(uuid::fmt::Urn, uuid::Uuid::urn);
876
877#[cfg(feature = "with-ipnetwork")]
878try_getable_postgres!(ipnetwork::IpNetwork);
879
880impl TryGetable for u32 {
881    #[allow(unused_variables)]
882    fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
883        match &res.row {
884            #[cfg(feature = "sqlx-mysql")]
885            QueryResultRow::SqlxMySql(row) => row
886                .try_get::<Option<u32>, _>(idx.as_sqlx_mysql_index())
887                .map_err(|e| sqlx_error_to_query_err(e).into())
888                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
889            #[cfg(feature = "sqlx-postgres")]
890            QueryResultRow::SqlxPostgres(row) => {
891                use sqlx::postgres::types::Oid;
892                // Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`;
893                // Instead, `u32` was wrapped by a `sqlx::Oid`.
894                match row.try_get::<Option<Oid>, _>(idx.as_sqlx_postgres_index()) {
895                    Ok(opt) => opt.ok_or_else(|| err_null_idx_col(idx)).map(|oid| oid.0),
896                    Err(_) => row
897                        // Integers are always signed in PostgreSQL, so we try to get an `i32` and convert it to `u32`.
898                        .try_get::<i32, _>(idx.as_sqlx_postgres_index())
899                        .map_err(|e| sqlx_error_to_query_err(e).into())
900                        .map(|v| {
901                            v.try_into().map_err(|e| {
902                                DbErr::TryIntoErr {
903                                    from: "i32",
904                                    into: "u32",
905                                    source: Arc::new(e),
906                                }
907                                .into()
908                            })
909                        })
910                        .and_then(|r| r),
911                }
912            }
913            #[cfg(feature = "sqlx-sqlite")]
914            QueryResultRow::SqlxSqlite(row) => row
915                .try_get::<Option<u32>, _>(idx.as_sqlx_sqlite_index())
916                .map_err(|e| sqlx_error_to_query_err(e).into())
917                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
918            #[cfg(feature = "rusqlite")]
919            QueryResultRow::Rusqlite(row) => row
920                .try_get::<Option<u32>, _>(idx)
921                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
922            #[cfg(feature = "mock")]
923            #[allow(unused_variables)]
924            QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
925                debug_print!("{:#?}", e.to_string());
926                err_null_idx_col(idx)
927            }),
928            #[cfg(feature = "proxy")]
929            #[allow(unused_variables)]
930            QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
931                debug_print!("{:#?}", e.to_string());
932                err_null_idx_col(idx)
933            }),
934            #[allow(unreachable_patterns)]
935            _ => unreachable!(),
936        }
937    }
938}
939
940impl TryGetable for String {
941    #[allow(unused_variables)]
942    fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
943        match &res.row {
944            #[cfg(feature = "sqlx-mysql")]
945            QueryResultRow::SqlxMySql(row) => row
946                .try_get::<Option<Vec<u8>>, _>(idx.as_sqlx_mysql_index())
947                .map_err(|e| sqlx_error_to_query_err(e).into())
948                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
949                .map(|bytes| {
950                    String::from_utf8(bytes).map_err(|e| {
951                        DbErr::TryIntoErr {
952                            from: "Vec<u8>",
953                            into: "String",
954                            source: Arc::new(e),
955                        }
956                        .into()
957                    })
958                })?,
959            #[cfg(feature = "sqlx-postgres")]
960            QueryResultRow::SqlxPostgres(row) => row
961                .try_get::<Option<String>, _>(idx.as_sqlx_postgres_index())
962                .map_err(|e| sqlx_error_to_query_err(e).into())
963                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
964            #[cfg(feature = "sqlx-sqlite")]
965            QueryResultRow::SqlxSqlite(row) => row
966                .try_get::<Option<String>, _>(idx.as_sqlx_sqlite_index())
967                .map_err(|e| sqlx_error_to_query_err(e).into())
968                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
969            #[cfg(feature = "rusqlite")]
970            QueryResultRow::Rusqlite(row) => row
971                .try_get::<Option<String>, _>(idx)
972                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
973            #[cfg(feature = "mock")]
974            QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
975                debug_print!("{:#?}", e.to_string());
976                err_null_idx_col(idx)
977            }),
978            #[cfg(feature = "proxy")]
979            QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
980                debug_print!("{:#?}", e.to_string());
981                err_null_idx_col(idx)
982            }),
983            #[allow(unreachable_patterns)]
984            _ => unreachable!(),
985        }
986    }
987}
988
989#[allow(dead_code)]
990fn err_null_idx_col<I: ColIdx>(idx: I) -> TryGetError {
991    TryGetError::Null(format!("{idx:?}"))
992}
993
994#[cfg(feature = "postgres-array")]
995mod postgres_array {
996    use super::*;
997
998    #[allow(unused_macros)]
999    macro_rules! try_getable_postgres_array {
1000        ( $type: ty ) => {
1001            #[allow(unused_variables)]
1002            impl TryGetable for Vec<Option<$type>> {
1003                fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1004                    match &res.row {
1005                        #[cfg(feature = "sqlx-mysql")]
1006                        QueryResultRow::SqlxMySql(_) => Err(type_err(format!(
1007                            "{} unsupported by sqlx-mysql",
1008                            stringify!($type)
1009                        ))
1010                        .into()),
1011                        #[cfg(feature = "sqlx-postgres")]
1012                        QueryResultRow::SqlxPostgres(row) => row
1013                            .try_get::<Option<Vec<Option<$type>>>, _>(idx.as_sqlx_postgres_index())
1014                            .map_err(|e| sqlx_error_to_query_err(e).into())
1015                            .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
1016                        #[cfg(feature = "sqlx-sqlite")]
1017                        QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
1018                            "{} unsupported by sqlx-sqlite",
1019                            stringify!($type)
1020                        ))
1021                        .into()),
1022                        #[cfg(feature = "rusqlite")]
1023                        QueryResultRow::Rusqlite(_) => Err(type_err(format!(
1024                            "{} unsupported by rusqlite",
1025                            stringify!($type)
1026                        ))
1027                        .into()),
1028                        #[cfg(feature = "mock")]
1029                        #[allow(unused_variables)]
1030                        QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
1031                            debug_print!("{:#?}", e.to_string());
1032                            err_null_idx_col(idx)
1033                        }),
1034                        #[cfg(feature = "proxy")]
1035                        #[allow(unused_variables)]
1036                        QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
1037                            debug_print!("{:#?}", e.to_string());
1038                            err_null_idx_col(idx)
1039                        }),
1040                        #[allow(unreachable_patterns)]
1041                        _ => unreachable!(),
1042                    }
1043                }
1044            }
1045        };
1046    }
1047
1048    try_getable_postgres_array!(bool);
1049    try_getable_postgres_array!(i8);
1050    try_getable_postgres_array!(i16);
1051    try_getable_postgres_array!(i32);
1052    try_getable_postgres_array!(i64);
1053    try_getable_postgres_array!(f32);
1054    try_getable_postgres_array!(f64);
1055    try_getable_postgres_array!(String);
1056    try_getable_postgres_array!(Vec<u8>);
1057
1058    #[cfg(feature = "with-json")]
1059    try_getable_postgres_array!(serde_json::Value);
1060
1061    #[cfg(feature = "with-chrono")]
1062    try_getable_postgres_array!(chrono::NaiveDate);
1063
1064    #[cfg(feature = "with-chrono")]
1065    try_getable_postgres_array!(chrono::NaiveTime);
1066
1067    #[cfg(feature = "with-chrono")]
1068    try_getable_postgres_array!(chrono::NaiveDateTime);
1069
1070    #[cfg(feature = "with-chrono")]
1071    try_getable_postgres_array!(chrono::DateTime<chrono::FixedOffset>);
1072
1073    #[cfg(feature = "with-chrono")]
1074    try_getable_postgres_array!(chrono::DateTime<chrono::Utc>);
1075
1076    #[cfg(feature = "with-chrono")]
1077    try_getable_postgres_array!(chrono::DateTime<chrono::Local>);
1078
1079    #[cfg(feature = "with-time")]
1080    try_getable_postgres_array!(time::Date);
1081
1082    #[cfg(feature = "with-time")]
1083    try_getable_postgres_array!(time::Time);
1084
1085    #[cfg(feature = "with-time")]
1086    try_getable_postgres_array!(time::PrimitiveDateTime);
1087
1088    #[cfg(feature = "with-time")]
1089    try_getable_postgres_array!(time::OffsetDateTime);
1090
1091    #[cfg(feature = "with-rust_decimal")]
1092    try_getable_postgres_array!(rust_decimal::Decimal);
1093
1094    #[cfg(feature = "with-bigdecimal")]
1095    try_getable_postgres_array!(bigdecimal::BigDecimal);
1096
1097    #[cfg(feature = "with-ipnetwork")]
1098    try_getable_postgres_array!(ipnetwork::IpNetwork);
1099
1100    #[allow(unused_macros)]
1101    macro_rules! try_getable_postgres_array_uuid {
1102        ( $type: ty, $conversion_fn: expr ) => {
1103            #[allow(unused_variables, unreachable_code)]
1104            impl TryGetable for Vec<Option<$type>> {
1105                fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1106                    let res: Result<Vec<Option<uuid::Uuid>>, TryGetError> = match &res.row {
1107                        #[cfg(feature = "sqlx-mysql")]
1108                        QueryResultRow::SqlxMySql(_) => Err(type_err(format!(
1109                            "{} unsupported by sqlx-mysql",
1110                            stringify!($type)
1111                        ))
1112                        .into()),
1113                        #[cfg(feature = "sqlx-postgres")]
1114                        QueryResultRow::SqlxPostgres(row) => row
1115                            .try_get::<Option<Vec<Option<uuid::Uuid>>>, _>(
1116                                idx.as_sqlx_postgres_index(),
1117                            )
1118                            .map_err(|e| sqlx_error_to_query_err(e).into())
1119                            .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
1120                        #[cfg(feature = "sqlx-sqlite")]
1121                        QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
1122                            "{} unsupported by sqlx-sqlite",
1123                            stringify!($type)
1124                        ))
1125                        .into()),
1126                        #[cfg(feature = "rusqlite")]
1127                        QueryResultRow::Rusqlite(_) => Err(type_err(format!(
1128                            "{} unsupported by rusqlite",
1129                            stringify!($type)
1130                        ))
1131                        .into()),
1132                        #[cfg(feature = "mock")]
1133                        QueryResultRow::Mock(row) => {
1134                            row.try_get::<Vec<Option<uuid::Uuid>>, _>(idx).map_err(|e| {
1135                                debug_print!("{:#?}", e.to_string());
1136                                err_null_idx_col(idx)
1137                            })
1138                        }
1139                        #[cfg(feature = "proxy")]
1140                        QueryResultRow::Proxy(row) => {
1141                            row.try_get::<Vec<Option<uuid::Uuid>>, _>(idx).map_err(|e| {
1142                                debug_print!("{:#?}", e.to_string());
1143                                err_null_idx_col(idx)
1144                            })
1145                        }
1146                        #[allow(unreachable_patterns)]
1147                        _ => unreachable!(),
1148                    };
1149                    res.map(|vec| vec.into_iter().map(|opt| opt.map($conversion_fn)).collect())
1150                }
1151            }
1152        };
1153    }
1154
1155    #[cfg(feature = "with-uuid")]
1156    try_getable_postgres_array_uuid!(uuid::Uuid, Into::into);
1157
1158    #[cfg(feature = "with-uuid")]
1159    try_getable_postgres_array_uuid!(uuid::fmt::Braced, uuid::Uuid::braced);
1160
1161    #[cfg(feature = "with-uuid")]
1162    try_getable_postgres_array_uuid!(uuid::fmt::Hyphenated, uuid::Uuid::hyphenated);
1163
1164    #[cfg(feature = "with-uuid")]
1165    try_getable_postgres_array_uuid!(uuid::fmt::Simple, uuid::Uuid::simple);
1166
1167    #[cfg(feature = "with-uuid")]
1168    try_getable_postgres_array_uuid!(uuid::fmt::Urn, uuid::Uuid::urn);
1169
1170    impl TryGetable for Vec<Option<u32>> {
1171        #[allow(unused_variables)]
1172        fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1173            match &res.row {
1174                #[cfg(feature = "sqlx-mysql")]
1175                QueryResultRow::SqlxMySql(_) => {
1176                    Err(type_err(format!("{} unsupported by sqlx-mysql", stringify!($type))).into())
1177                }
1178                #[cfg(feature = "sqlx-postgres")]
1179                QueryResultRow::SqlxPostgres(row) => {
1180                    use sqlx::postgres::types::Oid;
1181                    // Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`;
1182                    // Instead, `u32` was wrapped by a `sqlx::Oid`.
1183                    row.try_get::<Option<Vec<Option<Oid>>>, _>(idx.as_sqlx_postgres_index())
1184                        .map_err(|e| sqlx_error_to_query_err(e).into())
1185                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
1186                        .map(|oids| oids.into_iter().map(|opt| opt.map(|oid| oid.0)).collect())
1187                }
1188                #[cfg(feature = "sqlx-sqlite")]
1189                QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
1190                    "{} unsupported by sqlx-sqlite",
1191                    stringify!($type)
1192                ))
1193                .into()),
1194                #[cfg(feature = "rusqlite")]
1195                QueryResultRow::Rusqlite(_) => {
1196                    Err(type_err(format!("{} unsupported by rusqlite", stringify!($type))).into())
1197                }
1198                #[cfg(feature = "mock")]
1199                #[allow(unused_variables)]
1200                QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
1201                    debug_print!("{:#?}", e.to_string());
1202                    err_null_idx_col(idx)
1203                }),
1204                #[cfg(feature = "proxy")]
1205                #[allow(unused_variables)]
1206                QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
1207                    debug_print!("{:#?}", e.to_string());
1208                    err_null_idx_col(idx)
1209                }),
1210                #[allow(unreachable_patterns)]
1211                _ => unreachable!(),
1212            }
1213        }
1214    }
1215
1216    macro_rules! try_getable_postgres_non_null_array_from_opt {
1217        ( $($type: ty),* $(,)?) => {
1218            $(
1219                impl TryGetable for Vec<$type> {
1220                    fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1221                        let vec_opt = <Vec<Option<$type>> as TryGetable>::try_get_by(res, idx)?;
1222                        vec_opt
1223                            .into_iter()
1224                            .enumerate()
1225                            .map(|(i, opt)| {
1226                                opt.ok_or_else(|| {
1227                                    TryGetError::DbErr(type_err(format!(
1228                                        "NULL element at index {} in non-nullable array of {}",
1229                                        i,
1230                                        std::any::type_name::<$type>()
1231                                    )))
1232                                })
1233                            })
1234                            .collect()
1235                    }
1236                }
1237            )*
1238        };
1239    }
1240
1241    try_getable_postgres_non_null_array_from_opt!(
1242        bool,
1243        i8,
1244        i16,
1245        i32,
1246        i64,
1247        f32,
1248        f64,
1249        String,
1250        Vec<u8>,
1251        u32
1252    );
1253
1254    #[cfg(feature = "with-json")]
1255    try_getable_postgres_non_null_array_from_opt!(serde_json::Value);
1256
1257    #[cfg(feature = "with-chrono")]
1258    try_getable_postgres_non_null_array_from_opt!(
1259        chrono::NaiveDate,
1260        chrono::NaiveTime,
1261        chrono::NaiveDateTime,
1262        chrono::DateTime<chrono::FixedOffset>,
1263        chrono::DateTime<chrono::Utc>,
1264        chrono::DateTime<chrono::Local>,
1265    );
1266
1267    #[cfg(feature = "with-time")]
1268    try_getable_postgres_non_null_array_from_opt!(
1269        time::Date,
1270        time::Time,
1271        time::PrimitiveDateTime,
1272        time::OffsetDateTime,
1273    );
1274
1275    #[cfg(feature = "with-rust_decimal")]
1276    try_getable_postgres_non_null_array_from_opt!(rust_decimal::Decimal);
1277
1278    #[cfg(feature = "with-bigdecimal")]
1279    try_getable_postgres_non_null_array_from_opt!(bigdecimal::BigDecimal);
1280
1281    #[cfg(feature = "with-ipnetwork")]
1282    try_getable_postgres_non_null_array_from_opt!(ipnetwork::IpNetwork);
1283
1284    #[cfg(feature = "with-uuid")]
1285    try_getable_postgres_non_null_array_from_opt!(
1286        uuid::Uuid,
1287        uuid::fmt::Braced,
1288        uuid::fmt::Hyphenated,
1289        uuid::fmt::Simple,
1290        uuid::fmt::Urn,
1291    );
1292}
1293
1294#[cfg(feature = "postgres-vector")]
1295impl TryGetable for pgvector::Vector {
1296    #[allow(unused_variables)]
1297    fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1298        match &res.row {
1299            #[cfg(feature = "sqlx-mysql")]
1300            QueryResultRow::SqlxMySql(_) => {
1301                Err(type_err("Vector unsupported by sqlx-mysql").into())
1302            }
1303            #[cfg(feature = "sqlx-postgres")]
1304            QueryResultRow::SqlxPostgres(row) => row
1305                .try_get::<Option<pgvector::Vector>, _>(idx.as_sqlx_postgres_index())
1306                .map_err(|e| sqlx_error_to_query_err(e).into())
1307                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
1308            #[cfg(feature = "sqlx-sqlite")]
1309            QueryResultRow::SqlxSqlite(_) => {
1310                Err(type_err("Vector unsupported by sqlx-sqlite").into())
1311            }
1312            #[cfg(feature = "rusqlite")]
1313            QueryResultRow::Rusqlite(_) => Err(type_err("Vector unsupported by rusqlite").into()),
1314            #[cfg(feature = "mock")]
1315            QueryResultRow::Mock(row) => row.try_get::<pgvector::Vector, _>(idx).map_err(|e| {
1316                debug_print!("{:#?}", e.to_string());
1317                err_null_idx_col(idx)
1318            }),
1319            #[cfg(feature = "proxy")]
1320            QueryResultRow::Proxy(row) => row.try_get::<pgvector::Vector, _>(idx).map_err(|e| {
1321                debug_print!("{:#?}", e.to_string());
1322                err_null_idx_col(idx)
1323            }),
1324            #[allow(unreachable_patterns)]
1325            _ => unreachable!(),
1326        }
1327    }
1328}
1329
1330// TryGetableMany //
1331
1332/// An interface to get a tuple value from the query result
1333pub trait TryGetableMany: Sized {
1334    /// Get a tuple value from the query result with prefixed column name
1335    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
1336
1337    /// Get a tuple value from the query result based on the order in the select expressions
1338    fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError>;
1339
1340    /// ```
1341    /// # use sea_orm::{error::*, tests_cfg::*, *};
1342    /// #
1343    /// # #[smol_potat::main]
1344    /// # #[cfg(all(feature = "mock", feature = "macros"))]
1345    /// # pub async fn main() -> Result<(), DbErr> {
1346    /// #
1347    /// # let db = MockDatabase::new(DbBackend::Postgres)
1348    /// #     .append_query_results([[
1349    /// #         maplit::btreemap! {
1350    /// #             "name" => Into::<Value>::into("Chocolate Forest"),
1351    /// #             "num_of_cakes" => Into::<Value>::into(1),
1352    /// #         },
1353    /// #         maplit::btreemap! {
1354    /// #             "name" => Into::<Value>::into("New York Cheese"),
1355    /// #             "num_of_cakes" => Into::<Value>::into(1),
1356    /// #         },
1357    /// #     ]])
1358    /// #     .into_connection();
1359    /// #
1360    /// use sea_orm::{DeriveIden, EnumIter, TryGetableMany, entity::*, query::*, tests_cfg::cake};
1361    ///
1362    /// #[derive(EnumIter, DeriveIden)]
1363    /// enum ResultCol {
1364    ///     Name,
1365    ///     NumOfCakes,
1366    /// }
1367    ///
1368    /// let res: Vec<(String, i32)> =
1369    ///     <(String, i32)>::find_by_statement::<ResultCol>(Statement::from_sql_and_values(
1370    ///         DbBackend::Postgres,
1371    ///         r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
1372    ///         [],
1373    ///     ))
1374    ///     .all(&db)
1375    ///     .await?;
1376    ///
1377    /// assert_eq!(
1378    ///     res,
1379    ///     [
1380    ///         ("Chocolate Forest".to_owned(), 1),
1381    ///         ("New York Cheese".to_owned(), 1),
1382    ///     ]
1383    /// );
1384    ///
1385    /// assert_eq!(
1386    ///     db.into_transaction_log(),
1387    ///     [Transaction::from_sql_and_values(
1388    ///         DbBackend::Postgres,
1389    ///         r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
1390    ///         []
1391    ///     ),]
1392    /// );
1393    /// #
1394    /// # Ok(())
1395    /// # }
1396    /// ```
1397    fn find_by_statement<C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<Self, C>>
1398    where
1399        C: strum::IntoEnumIterator + sea_query::Iden,
1400    {
1401        SelectorRaw {
1402            stmt,
1403            selector: PhantomData,
1404        }
1405    }
1406}
1407
1408impl<T> TryGetableMany for T
1409where
1410    T: TryGetable,
1411{
1412    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1413        try_get_many_with_slice_len_of(1, cols)?;
1414        T::try_get(res, pre, &cols[0])
1415    }
1416
1417    fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1418        T::try_get_by_index(res, 0)
1419    }
1420}
1421
1422impl<T> TryGetableMany for (T,)
1423where
1424    T: TryGetableMany,
1425{
1426    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1427        T::try_get_many(res, pre, cols).map(|r| (r,))
1428    }
1429
1430    fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1431        T::try_get_many_by_index(res).map(|r| (r,))
1432    }
1433}
1434
1435macro_rules! impl_try_get_many {
1436    ( $LEN:expr, $($T:ident : $N:expr),+ $(,)? ) => {
1437        impl< $($T),+ > TryGetableMany for ( $($T),+ )
1438        where
1439            $($T: TryGetable),+
1440        {
1441            fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1442                try_get_many_with_slice_len_of($LEN, cols)?;
1443                Ok((
1444                    $($T::try_get(res, pre, &cols[$N])?),+
1445                ))
1446            }
1447
1448            fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1449                Ok((
1450                    $($T::try_get_by_index(res, $N)?),+
1451                ))
1452            }
1453        }
1454    };
1455}
1456
1457#[rustfmt::skip]
1458mod impl_try_get_many {
1459    use super::*;
1460
1461    impl_try_get_many!( 2, T0:0, T1:1);
1462    impl_try_get_many!( 3, T0:0, T1:1, T2:2);
1463    impl_try_get_many!( 4, T0:0, T1:1, T2:2, T3:3);
1464    impl_try_get_many!( 5, T0:0, T1:1, T2:2, T3:3, T4:4);
1465    impl_try_get_many!( 6, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5);
1466    impl_try_get_many!( 7, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6);
1467    impl_try_get_many!( 8, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7);
1468    impl_try_get_many!( 9, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8);
1469    impl_try_get_many!(10, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9);
1470    impl_try_get_many!(11, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10);
1471    impl_try_get_many!(12, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10, T11:11);
1472}
1473
1474fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), TryGetError> {
1475    if cols.len() < len {
1476        Err(type_err(format!(
1477            "Expect {} column names supplied but got slice of length {}",
1478            len,
1479            cols.len()
1480        ))
1481        .into())
1482    } else {
1483        Ok(())
1484    }
1485}
1486
1487/// An interface to get an array of values from the query result.
1488/// A type can only implement `ActiveEnum` or `TryGetableFromJson`, but not both.
1489/// A blanket impl is provided for `TryGetableFromJson`, while the impl for `ActiveEnum`
1490/// is provided by the `DeriveActiveEnum` macro. So as an end user you won't normally
1491/// touch this trait.
1492pub trait TryGetableArray: Sized {
1493    /// Just a delegate
1494    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I)
1495    -> Result<Vec<Option<Self>>, TryGetError>;
1496}
1497
1498impl<T> TryGetable for Vec<Option<T>>
1499where
1500    T: TryGetableArray,
1501{
1502    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1503        T::try_get_by(res, index)
1504    }
1505}
1506
1507impl<T> TryGetable for Vec<T>
1508where
1509    T: TryGetableArray,
1510{
1511    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1512        let vec_opt = T::try_get_by(res, index)?;
1513        let ty = std::any::type_name::<T>();
1514        vec_opt
1515            .into_iter()
1516            .enumerate()
1517            .map(|(i, opt)| {
1518                opt.ok_or_else(|| {
1519                    TryGetError::DbErr(type_err(format!(
1520                        "NULL element at index {} in non-nullable array of {}",
1521                        i, ty
1522                    )))
1523                })
1524            })
1525            .collect()
1526    }
1527}
1528
1529// TryGetableFromJson //
1530
1531/// An interface to get a JSON from the query result
1532#[cfg(feature = "with-json")]
1533pub trait TryGetableFromJson: Sized
1534where
1535    for<'de> Self: serde::Deserialize<'de>,
1536{
1537    /// Get a JSON from the query result with prefixed column name
1538    #[allow(unused_variables, unreachable_code)]
1539    fn try_get_from_json<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1540        match &res.row {
1541            #[cfg(feature = "sqlx-mysql")]
1542            QueryResultRow::SqlxMySql(row) => row
1543                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_mysql_index())
1544                .map_err(|e| sqlx_error_to_query_err(e).into())
1545                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1546            #[cfg(feature = "sqlx-postgres")]
1547            QueryResultRow::SqlxPostgres(row) => row
1548                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_postgres_index())
1549                .map_err(|e| sqlx_error_to_query_err(e).into())
1550                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1551            #[cfg(feature = "sqlx-sqlite")]
1552            QueryResultRow::SqlxSqlite(row) => row
1553                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_sqlite_index())
1554                .map_err(|e| sqlx_error_to_query_err(e).into())
1555                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1556            #[cfg(feature = "rusqlite")]
1557            QueryResultRow::Rusqlite(row) => row
1558                .try_get::<Option<serde_json::Value>, _>(idx)?
1559                .ok_or_else(|| err_null_idx_col(idx))
1560                .and_then(|json| {
1561                    serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1562                }),
1563            #[cfg(feature = "mock")]
1564            QueryResultRow::Mock(row) => row
1565                .try_get::<serde_json::Value, I>(idx)
1566                .map_err(|e| {
1567                    debug_print!("{:#?}", e.to_string());
1568                    err_null_idx_col(idx)
1569                })
1570                .and_then(|json| {
1571                    serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1572                }),
1573            #[cfg(feature = "proxy")]
1574            QueryResultRow::Proxy(row) => row
1575                .try_get::<serde_json::Value, I>(idx)
1576                .map_err(|e| {
1577                    debug_print!("{:#?}", e.to_string());
1578                    err_null_idx_col(idx)
1579                })
1580                .and_then(|json| {
1581                    serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1582                }),
1583            #[allow(unreachable_patterns)]
1584            _ => unreachable!(),
1585        }
1586    }
1587
1588    /// Get a Vec<Self> from an Array of Json
1589    fn from_json_vec(value: serde_json::Value) -> Result<Vec<Self>, TryGetError> {
1590        match value {
1591            serde_json::Value::Array(values) => {
1592                let mut res = Vec::new();
1593                for item in values {
1594                    res.push(serde_json::from_value(item).map_err(crate::error::json_err)?);
1595                }
1596                Ok(res)
1597            }
1598            _ => Err(TryGetError::DbErr(DbErr::Json(
1599                "Value is not an Array".to_owned(),
1600            ))),
1601        }
1602    }
1603
1604    /// Get a Vec<Option<Self>> from an Array of Json
1605    fn from_json_vec_option(value: serde_json::Value) -> Result<Vec<Option<Self>>, TryGetError> {
1606        match value {
1607            serde_json::Value::Array(values) => {
1608                let mut res = Vec::new();
1609                for item in values {
1610                    if item.is_null() {
1611                        res.push(None);
1612                    } else {
1613                        res.push(Some(
1614                            serde_json::from_value(item).map_err(crate::error::json_err)?,
1615                        ));
1616                    }
1617                }
1618                Ok(res)
1619            }
1620            _ => Err(TryGetError::DbErr(DbErr::Json(
1621                "Value is not an Array".to_owned(),
1622            ))),
1623        }
1624    }
1625}
1626
1627#[cfg(feature = "with-json")]
1628impl<T> TryGetable for T
1629where
1630    T: TryGetableFromJson,
1631{
1632    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1633        T::try_get_from_json(res, index)
1634    }
1635}
1636
1637#[cfg(feature = "with-json")]
1638impl<T> TryGetableArray for T
1639where
1640    T: TryGetableFromJson,
1641{
1642    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Vec<Option<T>>, TryGetError> {
1643        T::from_json_vec_option(serde_json::Value::try_get_by(res, index)?)
1644    }
1645}
1646
1647// TryFromU64 //
1648/// Try to convert a type to a u64
1649pub trait TryFromU64: Sized {
1650    /// The method to convert the type to a u64
1651    fn try_from_u64(n: u64) -> Result<Self, DbErr>;
1652}
1653
1654macro_rules! try_from_u64_err {
1655    ( $type: ty ) => {
1656        impl TryFromU64 for $type {
1657            fn try_from_u64(_: u64) -> Result<Self, DbErr> {
1658                Err(DbErr::ConvertFromU64(stringify!($type)))
1659            }
1660        }
1661    };
1662
1663    ( $($gen_type: ident),* ) => {
1664        impl<$( $gen_type, )*> TryFromU64 for ($( $gen_type, )*)
1665        where
1666            $( $gen_type: TryFromU64, )*
1667        {
1668            fn try_from_u64(_: u64) -> Result<Self, DbErr> {
1669                Err(DbErr::ConvertFromU64(stringify!($($gen_type,)*)))
1670            }
1671        }
1672    };
1673}
1674
1675#[rustfmt::skip]
1676mod try_from_u64_err {
1677    use super::*;
1678
1679    try_from_u64_err!(T0, T1);
1680    try_from_u64_err!(T0, T1, T2);
1681    try_from_u64_err!(T0, T1, T2, T3);
1682    try_from_u64_err!(T0, T1, T2, T3, T4);
1683    try_from_u64_err!(T0, T1, T2, T3, T4, T5);
1684    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6);
1685    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7);
1686    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
1687    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
1688    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
1689    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
1690}
1691
1692macro_rules! try_from_u64_numeric {
1693    ( $type: ty ) => {
1694        impl TryFromU64 for $type {
1695            fn try_from_u64(n: u64) -> Result<Self, DbErr> {
1696                use std::convert::TryInto;
1697                n.try_into().map_err(|e| DbErr::TryIntoErr {
1698                    from: stringify!(u64),
1699                    into: stringify!($type),
1700                    source: Arc::new(e),
1701                })
1702            }
1703        }
1704    };
1705}
1706
1707try_from_u64_numeric!(i8);
1708try_from_u64_numeric!(i16);
1709try_from_u64_numeric!(i32);
1710try_from_u64_numeric!(i64);
1711try_from_u64_numeric!(u8);
1712try_from_u64_numeric!(u16);
1713try_from_u64_numeric!(u32);
1714try_from_u64_numeric!(u64);
1715
1716macro_rules! try_from_u64_string {
1717    ( $type: ty ) => {
1718        impl TryFromU64 for $type {
1719            fn try_from_u64(n: u64) -> Result<Self, DbErr> {
1720                Ok(n.to_string())
1721            }
1722        }
1723    };
1724}
1725
1726try_from_u64_string!(String);
1727
1728try_from_u64_err!(bool);
1729try_from_u64_err!(f32);
1730try_from_u64_err!(f64);
1731try_from_u64_err!(Vec<u8>);
1732
1733#[cfg(feature = "with-json")]
1734try_from_u64_err!(serde_json::Value);
1735
1736#[cfg(feature = "with-chrono")]
1737try_from_u64_err!(chrono::NaiveDate);
1738
1739#[cfg(feature = "with-chrono")]
1740try_from_u64_err!(chrono::NaiveTime);
1741
1742#[cfg(feature = "with-chrono")]
1743try_from_u64_err!(chrono::NaiveDateTime);
1744
1745#[cfg(feature = "with-chrono")]
1746try_from_u64_err!(chrono::DateTime<chrono::FixedOffset>);
1747
1748#[cfg(feature = "with-chrono")]
1749try_from_u64_err!(chrono::DateTime<chrono::Utc>);
1750
1751#[cfg(feature = "with-chrono")]
1752try_from_u64_err!(chrono::DateTime<chrono::Local>);
1753
1754#[cfg(feature = "with-time")]
1755try_from_u64_err!(time::Date);
1756
1757#[cfg(feature = "with-time")]
1758try_from_u64_err!(time::Time);
1759
1760#[cfg(feature = "with-time")]
1761try_from_u64_err!(time::PrimitiveDateTime);
1762
1763#[cfg(feature = "with-time")]
1764try_from_u64_err!(time::OffsetDateTime);
1765
1766#[cfg(feature = "with-rust_decimal")]
1767try_from_u64_err!(rust_decimal::Decimal);
1768
1769#[cfg(feature = "with-uuid")]
1770try_from_u64_err!(uuid::Uuid);
1771
1772#[cfg(feature = "with-ipnetwork")]
1773try_from_u64_err!(ipnetwork::IpNetwork);
1774
1775#[cfg(test)]
1776mod tests {
1777    use super::*;
1778    use crate::RuntimeErr;
1779    use sea_query::Value;
1780    use std::collections::BTreeMap;
1781
1782    #[test]
1783    fn from_try_get_error() {
1784        // TryGetError::DbErr
1785        let try_get_error = TryGetError::DbErr(DbErr::Query(RuntimeErr::Internal(
1786            "expected error message".to_owned(),
1787        )));
1788        assert_eq!(
1789            DbErr::from(try_get_error),
1790            DbErr::Query(RuntimeErr::Internal("expected error message".to_owned()))
1791        );
1792
1793        // TryGetError::Null
1794        let try_get_error = TryGetError::Null("column".to_owned());
1795        let expected = "A null value was encountered while decoding column".to_owned();
1796        assert_eq!(DbErr::from(try_get_error), DbErr::Type(expected));
1797    }
1798
1799    #[test]
1800    fn build_with_query() {
1801        use sea_orm::{DbBackend, Statement};
1802        use sea_query::{
1803            ColumnRef, CommonTableExpression, Cycle, Expr, ExprTrait, JoinType, SelectStatement,
1804            UnionType, WithClause,
1805        };
1806
1807        let base_query = SelectStatement::new()
1808            .column("id")
1809            .expr(1i32)
1810            .column("next")
1811            .column("value")
1812            .from("table")
1813            .to_owned();
1814
1815        let cte_referencing = SelectStatement::new()
1816            .column("id")
1817            .expr(Expr::col("depth").add(1i32))
1818            .column("next")
1819            .column("value")
1820            .from("table")
1821            .join(
1822                JoinType::InnerJoin,
1823                "cte_traversal",
1824                Expr::col(("cte_traversal", "next")).equals(("table", "id")),
1825            )
1826            .to_owned();
1827
1828        let common_table_expression = CommonTableExpression::new()
1829            .query(
1830                base_query
1831                    .clone()
1832                    .union(UnionType::All, cte_referencing)
1833                    .to_owned(),
1834            )
1835            .columns(["id", "depth", "next", "value"])
1836            .table_name("cte_traversal")
1837            .to_owned();
1838
1839        let select = SelectStatement::new()
1840            .column(ColumnRef::Asterisk(None))
1841            .from("cte_traversal")
1842            .to_owned();
1843
1844        let with_clause = WithClause::new()
1845            .recursive(true)
1846            .cte(common_table_expression)
1847            .cycle(Cycle::new_from_expr_set_using(
1848                Expr::column("id"),
1849                "looped",
1850                "traversal_path",
1851            ))
1852            .to_owned();
1853
1854        let with_query = select.with(with_clause).to_owned();
1855
1856        assert_eq!(
1857            DbBackend::MySql.build(&with_query),
1858            Statement::from_sql_and_values(
1859                DbBackend::MySql,
1860                r#"WITH RECURSIVE `cte_traversal` (`id`, `depth`, `next`, `value`) AS (SELECT `id`, ?, `next`, `value` FROM `table` UNION ALL (SELECT `id`, `depth` + ?, `next`, `value` FROM `table` INNER JOIN `cte_traversal` ON `cte_traversal`.`next` = `table`.`id`)) SELECT * FROM `cte_traversal`"#,
1861                [1.into(), 1.into()]
1862            )
1863        );
1864    }
1865
1866    #[test]
1867    fn column_names_from_query_result() {
1868        let mut values = BTreeMap::new();
1869        values.insert("id".to_string(), Value::Int(Some(1)));
1870        values.insert("name".to_string(), Value::String(Some("Abc".to_owned())));
1871        let query_result = QueryResult {
1872            row: QueryResultRow::Mock(crate::MockRow { values }),
1873        };
1874        assert_eq!(
1875            query_result.column_names(),
1876            vec!["id".to_owned(), "name".to_owned()]
1877        );
1878    }
1879}