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    /// # #[cfg(all(feature = "mock", feature = "macros"))]
1344    /// # pub fn main() -> Result<(), DbErr> {
1345    /// #
1346    /// # let db = MockDatabase::new(DbBackend::Postgres)
1347    /// #     .append_query_results([[
1348    /// #         maplit::btreemap! {
1349    /// #             "name" => Into::<Value>::into("Chocolate Forest"),
1350    /// #             "num_of_cakes" => Into::<Value>::into(1),
1351    /// #         },
1352    /// #         maplit::btreemap! {
1353    /// #             "name" => Into::<Value>::into("New York Cheese"),
1354    /// #             "num_of_cakes" => Into::<Value>::into(1),
1355    /// #         },
1356    /// #     ]])
1357    /// #     .into_connection();
1358    /// #
1359    /// use sea_orm::{DeriveIden, EnumIter, TryGetableMany, entity::*, query::*, tests_cfg::cake};
1360    ///
1361    /// #[derive(EnumIter, DeriveIden)]
1362    /// enum ResultCol {
1363    ///     Name,
1364    ///     NumOfCakes,
1365    /// }
1366    ///
1367    /// let res: Vec<(String, i32)> =
1368    ///     <(String, i32)>::find_by_statement::<ResultCol>(Statement::from_sql_and_values(
1369    ///         DbBackend::Postgres,
1370    ///         r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
1371    ///         [],
1372    ///     ))
1373    ///     .all(&db)
1374    ///     ?;
1375    ///
1376    /// assert_eq!(
1377    ///     res,
1378    ///     [
1379    ///         ("Chocolate Forest".to_owned(), 1),
1380    ///         ("New York Cheese".to_owned(), 1),
1381    ///     ]
1382    /// );
1383    ///
1384    /// assert_eq!(
1385    ///     db.into_transaction_log(),
1386    ///     [Transaction::from_sql_and_values(
1387    ///         DbBackend::Postgres,
1388    ///         r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
1389    ///         []
1390    ///     ),]
1391    /// );
1392    /// #
1393    /// # Ok(())
1394    /// # }
1395    /// ```
1396    fn find_by_statement<C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<Self, C>>
1397    where
1398        C: strum::IntoEnumIterator + sea_query::Iden,
1399    {
1400        SelectorRaw {
1401            stmt,
1402            selector: PhantomData,
1403        }
1404    }
1405}
1406
1407impl<T> TryGetableMany for T
1408where
1409    T: TryGetable,
1410{
1411    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1412        try_get_many_with_slice_len_of(1, cols)?;
1413        T::try_get(res, pre, &cols[0])
1414    }
1415
1416    fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1417        T::try_get_by_index(res, 0)
1418    }
1419}
1420
1421impl<T> TryGetableMany for (T,)
1422where
1423    T: TryGetableMany,
1424{
1425    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1426        T::try_get_many(res, pre, cols).map(|r| (r,))
1427    }
1428
1429    fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1430        T::try_get_many_by_index(res).map(|r| (r,))
1431    }
1432}
1433
1434macro_rules! impl_try_get_many {
1435    ( $LEN:expr, $($T:ident : $N:expr),+ $(,)? ) => {
1436        impl< $($T),+ > TryGetableMany for ( $($T),+ )
1437        where
1438            $($T: TryGetable),+
1439        {
1440            fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1441                try_get_many_with_slice_len_of($LEN, cols)?;
1442                Ok((
1443                    $($T::try_get(res, pre, &cols[$N])?),+
1444                ))
1445            }
1446
1447            fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1448                Ok((
1449                    $($T::try_get_by_index(res, $N)?),+
1450                ))
1451            }
1452        }
1453    };
1454}
1455
1456#[rustfmt::skip]
1457mod impl_try_get_many {
1458    use super::*;
1459
1460    impl_try_get_many!( 2, T0:0, T1:1);
1461    impl_try_get_many!( 3, T0:0, T1:1, T2:2);
1462    impl_try_get_many!( 4, T0:0, T1:1, T2:2, T3:3);
1463    impl_try_get_many!( 5, T0:0, T1:1, T2:2, T3:3, T4:4);
1464    impl_try_get_many!( 6, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5);
1465    impl_try_get_many!( 7, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6);
1466    impl_try_get_many!( 8, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7);
1467    impl_try_get_many!( 9, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8);
1468    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);
1469    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);
1470    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);
1471}
1472
1473fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), TryGetError> {
1474    if cols.len() < len {
1475        Err(type_err(format!(
1476            "Expect {} column names supplied but got slice of length {}",
1477            len,
1478            cols.len()
1479        ))
1480        .into())
1481    } else {
1482        Ok(())
1483    }
1484}
1485
1486/// An interface to get an array of values from the query result.
1487/// A type can only implement `ActiveEnum` or `TryGetableFromJson`, but not both.
1488/// A blanket impl is provided for `TryGetableFromJson`, while the impl for `ActiveEnum`
1489/// is provided by the `DeriveActiveEnum` macro. So as an end user you won't normally
1490/// touch this trait.
1491pub trait TryGetableArray: Sized {
1492    /// Just a delegate
1493    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I)
1494    -> Result<Vec<Option<Self>>, TryGetError>;
1495}
1496
1497impl<T> TryGetable for Vec<Option<T>>
1498where
1499    T: TryGetableArray,
1500{
1501    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1502        T::try_get_by(res, index)
1503    }
1504}
1505
1506impl<T> TryGetable for Vec<T>
1507where
1508    T: TryGetableArray,
1509{
1510    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1511        let vec_opt = T::try_get_by(res, index)?;
1512        let ty = std::any::type_name::<T>();
1513        vec_opt
1514            .into_iter()
1515            .enumerate()
1516            .map(|(i, opt)| {
1517                opt.ok_or_else(|| {
1518                    TryGetError::DbErr(type_err(format!(
1519                        "NULL element at index {} in non-nullable array of {}",
1520                        i, ty
1521                    )))
1522                })
1523            })
1524            .collect()
1525    }
1526}
1527
1528// TryGetableFromJson //
1529
1530/// An interface to get a JSON from the query result
1531#[cfg(feature = "with-json")]
1532pub trait TryGetableFromJson: Sized
1533where
1534    for<'de> Self: serde::Deserialize<'de>,
1535{
1536    /// Get a JSON from the query result with prefixed column name
1537    #[allow(unused_variables, unreachable_code)]
1538    fn try_get_from_json<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1539        match &res.row {
1540            #[cfg(feature = "sqlx-mysql")]
1541            QueryResultRow::SqlxMySql(row) => row
1542                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_mysql_index())
1543                .map_err(|e| sqlx_error_to_query_err(e).into())
1544                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1545            #[cfg(feature = "sqlx-postgres")]
1546            QueryResultRow::SqlxPostgres(row) => row
1547                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_postgres_index())
1548                .map_err(|e| sqlx_error_to_query_err(e).into())
1549                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1550            #[cfg(feature = "sqlx-sqlite")]
1551            QueryResultRow::SqlxSqlite(row) => row
1552                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_sqlite_index())
1553                .map_err(|e| sqlx_error_to_query_err(e).into())
1554                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1555            #[cfg(feature = "rusqlite")]
1556            QueryResultRow::Rusqlite(row) => row
1557                .try_get::<Option<serde_json::Value>, _>(idx)?
1558                .ok_or_else(|| err_null_idx_col(idx))
1559                .and_then(|json| {
1560                    serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1561                }),
1562            #[cfg(feature = "mock")]
1563            QueryResultRow::Mock(row) => row
1564                .try_get::<serde_json::Value, I>(idx)
1565                .map_err(|e| {
1566                    debug_print!("{:#?}", e.to_string());
1567                    err_null_idx_col(idx)
1568                })
1569                .and_then(|json| {
1570                    serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1571                }),
1572            #[cfg(feature = "proxy")]
1573            QueryResultRow::Proxy(row) => row
1574                .try_get::<serde_json::Value, I>(idx)
1575                .map_err(|e| {
1576                    debug_print!("{:#?}", e.to_string());
1577                    err_null_idx_col(idx)
1578                })
1579                .and_then(|json| {
1580                    serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1581                }),
1582            #[allow(unreachable_patterns)]
1583            _ => unreachable!(),
1584        }
1585    }
1586
1587    /// Get a Vec<Self> from an Array of Json
1588    fn from_json_vec(value: serde_json::Value) -> Result<Vec<Self>, TryGetError> {
1589        match value {
1590            serde_json::Value::Array(values) => {
1591                let mut res = Vec::new();
1592                for item in values {
1593                    res.push(serde_json::from_value(item).map_err(crate::error::json_err)?);
1594                }
1595                Ok(res)
1596            }
1597            _ => Err(TryGetError::DbErr(DbErr::Json(
1598                "Value is not an Array".to_owned(),
1599            ))),
1600        }
1601    }
1602
1603    /// Get a Vec<Option<Self>> from an Array of Json
1604    fn from_json_vec_option(value: serde_json::Value) -> Result<Vec<Option<Self>>, TryGetError> {
1605        match value {
1606            serde_json::Value::Array(values) => {
1607                let mut res = Vec::new();
1608                for item in values {
1609                    if item.is_null() {
1610                        res.push(None);
1611                    } else {
1612                        res.push(Some(
1613                            serde_json::from_value(item).map_err(crate::error::json_err)?,
1614                        ));
1615                    }
1616                }
1617                Ok(res)
1618            }
1619            _ => Err(TryGetError::DbErr(DbErr::Json(
1620                "Value is not an Array".to_owned(),
1621            ))),
1622        }
1623    }
1624}
1625
1626#[cfg(feature = "with-json")]
1627impl<T> TryGetable for T
1628where
1629    T: TryGetableFromJson,
1630{
1631    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1632        T::try_get_from_json(res, index)
1633    }
1634}
1635
1636#[cfg(feature = "with-json")]
1637impl<T> TryGetableArray for T
1638where
1639    T: TryGetableFromJson,
1640{
1641    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Vec<Option<T>>, TryGetError> {
1642        T::from_json_vec_option(serde_json::Value::try_get_by(res, index)?)
1643    }
1644}
1645
1646// TryFromU64 //
1647/// Try to convert a type to a u64
1648pub trait TryFromU64: Sized {
1649    /// The method to convert the type to a u64
1650    fn try_from_u64(n: u64) -> Result<Self, DbErr>;
1651}
1652
1653macro_rules! try_from_u64_err {
1654    ( $type: ty ) => {
1655        impl TryFromU64 for $type {
1656            fn try_from_u64(_: u64) -> Result<Self, DbErr> {
1657                Err(DbErr::ConvertFromU64(stringify!($type)))
1658            }
1659        }
1660    };
1661
1662    ( $($gen_type: ident),* ) => {
1663        impl<$( $gen_type, )*> TryFromU64 for ($( $gen_type, )*)
1664        where
1665            $( $gen_type: TryFromU64, )*
1666        {
1667            fn try_from_u64(_: u64) -> Result<Self, DbErr> {
1668                Err(DbErr::ConvertFromU64(stringify!($($gen_type,)*)))
1669            }
1670        }
1671    };
1672}
1673
1674#[rustfmt::skip]
1675mod try_from_u64_err {
1676    use super::*;
1677
1678    try_from_u64_err!(T0, T1);
1679    try_from_u64_err!(T0, T1, T2);
1680    try_from_u64_err!(T0, T1, T2, T3);
1681    try_from_u64_err!(T0, T1, T2, T3, T4);
1682    try_from_u64_err!(T0, T1, T2, T3, T4, T5);
1683    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6);
1684    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7);
1685    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
1686    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
1687    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
1688    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
1689}
1690
1691macro_rules! try_from_u64_numeric {
1692    ( $type: ty ) => {
1693        impl TryFromU64 for $type {
1694            fn try_from_u64(n: u64) -> Result<Self, DbErr> {
1695                use std::convert::TryInto;
1696                n.try_into().map_err(|e| DbErr::TryIntoErr {
1697                    from: stringify!(u64),
1698                    into: stringify!($type),
1699                    source: Arc::new(e),
1700                })
1701            }
1702        }
1703    };
1704}
1705
1706try_from_u64_numeric!(i8);
1707try_from_u64_numeric!(i16);
1708try_from_u64_numeric!(i32);
1709try_from_u64_numeric!(i64);
1710try_from_u64_numeric!(u8);
1711try_from_u64_numeric!(u16);
1712try_from_u64_numeric!(u32);
1713try_from_u64_numeric!(u64);
1714
1715macro_rules! try_from_u64_string {
1716    ( $type: ty ) => {
1717        impl TryFromU64 for $type {
1718            fn try_from_u64(n: u64) -> Result<Self, DbErr> {
1719                Ok(n.to_string())
1720            }
1721        }
1722    };
1723}
1724
1725try_from_u64_string!(String);
1726
1727try_from_u64_err!(bool);
1728try_from_u64_err!(f32);
1729try_from_u64_err!(f64);
1730try_from_u64_err!(Vec<u8>);
1731
1732#[cfg(feature = "with-json")]
1733try_from_u64_err!(serde_json::Value);
1734
1735#[cfg(feature = "with-chrono")]
1736try_from_u64_err!(chrono::NaiveDate);
1737
1738#[cfg(feature = "with-chrono")]
1739try_from_u64_err!(chrono::NaiveTime);
1740
1741#[cfg(feature = "with-chrono")]
1742try_from_u64_err!(chrono::NaiveDateTime);
1743
1744#[cfg(feature = "with-chrono")]
1745try_from_u64_err!(chrono::DateTime<chrono::FixedOffset>);
1746
1747#[cfg(feature = "with-chrono")]
1748try_from_u64_err!(chrono::DateTime<chrono::Utc>);
1749
1750#[cfg(feature = "with-chrono")]
1751try_from_u64_err!(chrono::DateTime<chrono::Local>);
1752
1753#[cfg(feature = "with-time")]
1754try_from_u64_err!(time::Date);
1755
1756#[cfg(feature = "with-time")]
1757try_from_u64_err!(time::Time);
1758
1759#[cfg(feature = "with-time")]
1760try_from_u64_err!(time::PrimitiveDateTime);
1761
1762#[cfg(feature = "with-time")]
1763try_from_u64_err!(time::OffsetDateTime);
1764
1765#[cfg(feature = "with-rust_decimal")]
1766try_from_u64_err!(rust_decimal::Decimal);
1767
1768#[cfg(feature = "with-uuid")]
1769try_from_u64_err!(uuid::Uuid);
1770
1771#[cfg(feature = "with-ipnetwork")]
1772try_from_u64_err!(ipnetwork::IpNetwork);
1773
1774#[cfg(test)]
1775mod tests {
1776    use super::*;
1777    use crate::RuntimeErr;
1778    use sea_query::Value;
1779    use std::collections::BTreeMap;
1780
1781    #[test]
1782    fn from_try_get_error() {
1783        // TryGetError::DbErr
1784        let try_get_error = TryGetError::DbErr(DbErr::Query(RuntimeErr::Internal(
1785            "expected error message".to_owned(),
1786        )));
1787        assert_eq!(
1788            DbErr::from(try_get_error),
1789            DbErr::Query(RuntimeErr::Internal("expected error message".to_owned()))
1790        );
1791
1792        // TryGetError::Null
1793        let try_get_error = TryGetError::Null("column".to_owned());
1794        let expected = "A null value was encountered while decoding column".to_owned();
1795        assert_eq!(DbErr::from(try_get_error), DbErr::Type(expected));
1796    }
1797
1798    #[test]
1799    fn build_with_query() {
1800        use sea_orm::{DbBackend, Statement};
1801        use sea_query::{
1802            ColumnRef, CommonTableExpression, Cycle, Expr, ExprTrait, JoinType, SelectStatement,
1803            UnionType, WithClause,
1804        };
1805
1806        let base_query = SelectStatement::new()
1807            .column("id")
1808            .expr(1i32)
1809            .column("next")
1810            .column("value")
1811            .from("table")
1812            .to_owned();
1813
1814        let cte_referencing = SelectStatement::new()
1815            .column("id")
1816            .expr(Expr::col("depth").add(1i32))
1817            .column("next")
1818            .column("value")
1819            .from("table")
1820            .join(
1821                JoinType::InnerJoin,
1822                "cte_traversal",
1823                Expr::col(("cte_traversal", "next")).equals(("table", "id")),
1824            )
1825            .to_owned();
1826
1827        let common_table_expression = CommonTableExpression::new()
1828            .query(
1829                base_query
1830                    .clone()
1831                    .union(UnionType::All, cte_referencing)
1832                    .to_owned(),
1833            )
1834            .columns(["id", "depth", "next", "value"])
1835            .table_name("cte_traversal")
1836            .to_owned();
1837
1838        let select = SelectStatement::new()
1839            .column(ColumnRef::Asterisk(None))
1840            .from("cte_traversal")
1841            .to_owned();
1842
1843        let with_clause = WithClause::new()
1844            .recursive(true)
1845            .cte(common_table_expression)
1846            .cycle(Cycle::new_from_expr_set_using(
1847                Expr::column("id"),
1848                "looped",
1849                "traversal_path",
1850            ))
1851            .to_owned();
1852
1853        let with_query = select.with(with_clause).to_owned();
1854
1855        assert_eq!(
1856            DbBackend::MySql.build(&with_query),
1857            Statement::from_sql_and_values(
1858                DbBackend::MySql,
1859                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`"#,
1860                [1.into(), 1.into()]
1861            )
1862        );
1863    }
1864
1865    #[test]
1866    fn column_names_from_query_result() {
1867        let mut values = BTreeMap::new();
1868        values.insert("id".to_string(), Value::Int(Some(1)));
1869        values.insert("name".to_string(), Value::String(Some("Abc".to_owned())));
1870        let query_result = QueryResult {
1871            row: QueryResultRow::Mock(crate::MockRow { values }),
1872        };
1873        assert_eq!(
1874            query_result.column_names(),
1875            vec!["id".to_owned(), "name".to_owned()]
1876        );
1877    }
1878}