Skip to main content

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
880#[cfg(feature = "with-mac_address")]
881try_getable_postgres!(mac_address::MacAddress);
882
883impl TryGetable for u32 {
884    #[allow(unused_variables)]
885    fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
886        match &res.row {
887            #[cfg(feature = "sqlx-mysql")]
888            QueryResultRow::SqlxMySql(row) => row
889                .try_get::<Option<u32>, _>(idx.as_sqlx_mysql_index())
890                .map_err(|e| sqlx_error_to_query_err(e).into())
891                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
892            #[cfg(feature = "sqlx-postgres")]
893            QueryResultRow::SqlxPostgres(row) => {
894                use sqlx::postgres::types::Oid;
895                // Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`;
896                // Instead, `u32` was wrapped by a `sqlx::Oid`.
897                match row.try_get::<Option<Oid>, _>(idx.as_sqlx_postgres_index()) {
898                    Ok(opt) => opt.ok_or_else(|| err_null_idx_col(idx)).map(|oid| oid.0),
899                    Err(_) => row
900                        // Integers are always signed in PostgreSQL, so we try to get an `i32` and convert it to `u32`.
901                        .try_get::<i32, _>(idx.as_sqlx_postgres_index())
902                        .map_err(|e| sqlx_error_to_query_err(e).into())
903                        .map(|v| {
904                            v.try_into().map_err(|e| {
905                                DbErr::TryIntoErr {
906                                    from: "i32",
907                                    into: "u32",
908                                    source: Arc::new(e),
909                                }
910                                .into()
911                            })
912                        })
913                        .and_then(|r| r),
914                }
915            }
916            #[cfg(feature = "sqlx-sqlite")]
917            QueryResultRow::SqlxSqlite(row) => row
918                .try_get::<Option<u32>, _>(idx.as_sqlx_sqlite_index())
919                .map_err(|e| sqlx_error_to_query_err(e).into())
920                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
921            #[cfg(feature = "rusqlite")]
922            QueryResultRow::Rusqlite(row) => row
923                .try_get::<Option<u32>, _>(idx)
924                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
925            #[cfg(feature = "mock")]
926            #[allow(unused_variables)]
927            QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
928                debug_print!("{:#?}", e.to_string());
929                err_null_idx_col(idx)
930            }),
931            #[cfg(feature = "proxy")]
932            #[allow(unused_variables)]
933            QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
934                debug_print!("{:#?}", e.to_string());
935                err_null_idx_col(idx)
936            }),
937            #[allow(unreachable_patterns)]
938            _ => unreachable!(),
939        }
940    }
941}
942
943impl TryGetable for String {
944    #[allow(unused_variables)]
945    fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
946        match &res.row {
947            #[cfg(feature = "sqlx-mysql")]
948            QueryResultRow::SqlxMySql(row) => row
949                .try_get::<Option<Vec<u8>>, _>(idx.as_sqlx_mysql_index())
950                .map_err(|e| sqlx_error_to_query_err(e).into())
951                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
952                .map(|bytes| {
953                    String::from_utf8(bytes).map_err(|e| {
954                        DbErr::TryIntoErr {
955                            from: "Vec<u8>",
956                            into: "String",
957                            source: Arc::new(e),
958                        }
959                        .into()
960                    })
961                })?,
962            #[cfg(feature = "sqlx-postgres")]
963            QueryResultRow::SqlxPostgres(row) => row
964                .try_get::<Option<String>, _>(idx.as_sqlx_postgres_index())
965                .map_err(|e| sqlx_error_to_query_err(e).into())
966                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
967            #[cfg(feature = "sqlx-sqlite")]
968            QueryResultRow::SqlxSqlite(row) => row
969                .try_get::<Option<String>, _>(idx.as_sqlx_sqlite_index())
970                .map_err(|e| sqlx_error_to_query_err(e).into())
971                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
972            #[cfg(feature = "rusqlite")]
973            QueryResultRow::Rusqlite(row) => row
974                .try_get::<Option<String>, _>(idx)
975                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
976            #[cfg(feature = "mock")]
977            QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
978                debug_print!("{:#?}", e.to_string());
979                err_null_idx_col(idx)
980            }),
981            #[cfg(feature = "proxy")]
982            QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
983                debug_print!("{:#?}", e.to_string());
984                err_null_idx_col(idx)
985            }),
986            #[allow(unreachable_patterns)]
987            _ => unreachable!(),
988        }
989    }
990}
991
992#[allow(dead_code)]
993fn err_null_idx_col<I: ColIdx>(idx: I) -> TryGetError {
994    TryGetError::Null(format!("{idx:?}"))
995}
996
997#[cfg(feature = "postgres-array")]
998mod postgres_array {
999    use super::*;
1000
1001    #[allow(unused_macros)]
1002    macro_rules! try_getable_postgres_array {
1003        ( $type: ty ) => {
1004            #[allow(unused_variables)]
1005            impl TryGetable for Vec<$type> {
1006                fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1007                    match &res.row {
1008                        #[cfg(feature = "sqlx-mysql")]
1009                        QueryResultRow::SqlxMySql(_) => Err(type_err(format!(
1010                            "{} unsupported by sqlx-mysql",
1011                            stringify!($type)
1012                        ))
1013                        .into()),
1014                        #[cfg(feature = "sqlx-postgres")]
1015                        QueryResultRow::SqlxPostgres(row) => row
1016                            .try_get::<Option<Vec<$type>>, _>(idx.as_sqlx_postgres_index())
1017                            .map_err(|e| sqlx_error_to_query_err(e).into())
1018                            .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
1019                        #[cfg(feature = "sqlx-sqlite")]
1020                        QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
1021                            "{} unsupported by sqlx-sqlite",
1022                            stringify!($type)
1023                        ))
1024                        .into()),
1025                        #[cfg(feature = "rusqlite")]
1026                        QueryResultRow::Rusqlite(_) => Err(type_err(format!(
1027                            "{} unsupported by rusqlite",
1028                            stringify!($type)
1029                        ))
1030                        .into()),
1031                        #[cfg(feature = "mock")]
1032                        #[allow(unused_variables)]
1033                        QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
1034                            debug_print!("{:#?}", e.to_string());
1035                            err_null_idx_col(idx)
1036                        }),
1037                        #[cfg(feature = "proxy")]
1038                        #[allow(unused_variables)]
1039                        QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
1040                            debug_print!("{:#?}", e.to_string());
1041                            err_null_idx_col(idx)
1042                        }),
1043                        #[allow(unreachable_patterns)]
1044                        _ => unreachable!(),
1045                    }
1046                }
1047            }
1048        };
1049    }
1050
1051    try_getable_postgres_array!(bool);
1052    try_getable_postgres_array!(i8);
1053    try_getable_postgres_array!(i16);
1054    try_getable_postgres_array!(i32);
1055    try_getable_postgres_array!(i64);
1056    try_getable_postgres_array!(f32);
1057    try_getable_postgres_array!(f64);
1058    try_getable_postgres_array!(String);
1059    try_getable_postgres_array!(Vec<u8>);
1060
1061    #[cfg(feature = "with-json")]
1062    try_getable_postgres_array!(serde_json::Value);
1063
1064    #[cfg(feature = "with-chrono")]
1065    try_getable_postgres_array!(chrono::NaiveDate);
1066
1067    #[cfg(feature = "with-chrono")]
1068    try_getable_postgres_array!(chrono::NaiveTime);
1069
1070    #[cfg(feature = "with-chrono")]
1071    try_getable_postgres_array!(chrono::NaiveDateTime);
1072
1073    #[cfg(feature = "with-chrono")]
1074    try_getable_postgres_array!(chrono::DateTime<chrono::FixedOffset>);
1075
1076    #[cfg(feature = "with-chrono")]
1077    try_getable_postgres_array!(chrono::DateTime<chrono::Utc>);
1078
1079    #[cfg(feature = "with-chrono")]
1080    try_getable_postgres_array!(chrono::DateTime<chrono::Local>);
1081
1082    #[cfg(feature = "with-time")]
1083    try_getable_postgres_array!(time::Date);
1084
1085    #[cfg(feature = "with-time")]
1086    try_getable_postgres_array!(time::Time);
1087
1088    #[cfg(feature = "with-time")]
1089    try_getable_postgres_array!(time::PrimitiveDateTime);
1090
1091    #[cfg(feature = "with-time")]
1092    try_getable_postgres_array!(time::OffsetDateTime);
1093
1094    #[cfg(feature = "with-rust_decimal")]
1095    try_getable_postgres_array!(rust_decimal::Decimal);
1096
1097    #[cfg(feature = "with-bigdecimal")]
1098    try_getable_postgres_array!(bigdecimal::BigDecimal);
1099
1100    #[cfg(feature = "with-ipnetwork")]
1101    try_getable_postgres_array!(ipnetwork::IpNetwork);
1102
1103    #[cfg(feature = "with-mac_address")]
1104    try_getable_postgres_array!(mac_address::MacAddress);
1105
1106    #[allow(unused_macros)]
1107    macro_rules! try_getable_postgres_array_uuid {
1108        ( $type: ty, $conversion_fn: expr ) => {
1109            #[allow(unused_variables, unreachable_code)]
1110            impl TryGetable for Vec<$type> {
1111                fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1112                    let res: Result<Vec<uuid::Uuid>, TryGetError> = match &res.row {
1113                        #[cfg(feature = "sqlx-mysql")]
1114                        QueryResultRow::SqlxMySql(_) => Err(type_err(format!(
1115                            "{} unsupported by sqlx-mysql",
1116                            stringify!($type)
1117                        ))
1118                        .into()),
1119                        #[cfg(feature = "sqlx-postgres")]
1120                        QueryResultRow::SqlxPostgres(row) => row
1121                            .try_get::<Option<Vec<uuid::Uuid>>, _>(idx.as_sqlx_postgres_index())
1122                            .map_err(|e| sqlx_error_to_query_err(e).into())
1123                            .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
1124                        #[cfg(feature = "sqlx-sqlite")]
1125                        QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
1126                            "{} unsupported by sqlx-sqlite",
1127                            stringify!($type)
1128                        ))
1129                        .into()),
1130                        #[cfg(feature = "rusqlite")]
1131                        QueryResultRow::Rusqlite(_) => Err(type_err(format!(
1132                            "{} unsupported by rusqlite",
1133                            stringify!($type)
1134                        ))
1135                        .into()),
1136                        #[cfg(feature = "mock")]
1137                        QueryResultRow::Mock(row) => {
1138                            row.try_get::<Vec<uuid::Uuid>, _>(idx).map_err(|e| {
1139                                debug_print!("{:#?}", e.to_string());
1140                                err_null_idx_col(idx)
1141                            })
1142                        }
1143                        #[cfg(feature = "proxy")]
1144                        QueryResultRow::Proxy(row) => {
1145                            row.try_get::<Vec<uuid::Uuid>, _>(idx).map_err(|e| {
1146                                debug_print!("{:#?}", e.to_string());
1147                                err_null_idx_col(idx)
1148                            })
1149                        }
1150                        #[allow(unreachable_patterns)]
1151                        _ => unreachable!(),
1152                    };
1153                    res.map(|vec| vec.into_iter().map($conversion_fn).collect())
1154                }
1155            }
1156        };
1157    }
1158
1159    #[cfg(feature = "with-uuid")]
1160    try_getable_postgres_array_uuid!(uuid::Uuid, Into::into);
1161
1162    #[cfg(feature = "with-uuid")]
1163    try_getable_postgres_array_uuid!(uuid::fmt::Braced, uuid::Uuid::braced);
1164
1165    #[cfg(feature = "with-uuid")]
1166    try_getable_postgres_array_uuid!(uuid::fmt::Hyphenated, uuid::Uuid::hyphenated);
1167
1168    #[cfg(feature = "with-uuid")]
1169    try_getable_postgres_array_uuid!(uuid::fmt::Simple, uuid::Uuid::simple);
1170
1171    #[cfg(feature = "with-uuid")]
1172    try_getable_postgres_array_uuid!(uuid::fmt::Urn, uuid::Uuid::urn);
1173
1174    impl TryGetable for Vec<u32> {
1175        #[allow(unused_variables)]
1176        fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1177            match &res.row {
1178                #[cfg(feature = "sqlx-mysql")]
1179                QueryResultRow::SqlxMySql(_) => {
1180                    Err(type_err(format!("{} unsupported by sqlx-mysql", stringify!($type))).into())
1181                }
1182                #[cfg(feature = "sqlx-postgres")]
1183                QueryResultRow::SqlxPostgres(row) => {
1184                    use sqlx::postgres::types::Oid;
1185                    // Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`;
1186                    // Instead, `u32` was wrapped by a `sqlx::Oid`.
1187                    row.try_get::<Option<Vec<Oid>>, _>(idx.as_sqlx_postgres_index())
1188                        .map_err(|e| sqlx_error_to_query_err(e).into())
1189                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
1190                        .map(|oids| oids.into_iter().map(|oid| oid.0).collect())
1191                }
1192                #[cfg(feature = "sqlx-sqlite")]
1193                QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
1194                    "{} unsupported by sqlx-sqlite",
1195                    stringify!($type)
1196                ))
1197                .into()),
1198                #[cfg(feature = "rusqlite")]
1199                QueryResultRow::Rusqlite(_) => {
1200                    Err(type_err(format!("{} unsupported by rusqlite", stringify!($type))).into())
1201                }
1202                #[cfg(feature = "mock")]
1203                #[allow(unused_variables)]
1204                QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
1205                    debug_print!("{:#?}", e.to_string());
1206                    err_null_idx_col(idx)
1207                }),
1208                #[cfg(feature = "proxy")]
1209                #[allow(unused_variables)]
1210                QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
1211                    debug_print!("{:#?}", e.to_string());
1212                    err_null_idx_col(idx)
1213                }),
1214                #[allow(unreachable_patterns)]
1215                _ => unreachable!(),
1216            }
1217        }
1218    }
1219}
1220
1221#[cfg(feature = "postgres-vector")]
1222impl TryGetable for pgvector::Vector {
1223    #[allow(unused_variables)]
1224    fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1225        match &res.row {
1226            #[cfg(feature = "sqlx-mysql")]
1227            QueryResultRow::SqlxMySql(_) => {
1228                Err(type_err("Vector unsupported by sqlx-mysql").into())
1229            }
1230            #[cfg(feature = "sqlx-postgres")]
1231            QueryResultRow::SqlxPostgres(row) => row
1232                .try_get::<Option<pgvector::Vector>, _>(idx.as_sqlx_postgres_index())
1233                .map_err(|e| sqlx_error_to_query_err(e).into())
1234                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
1235            #[cfg(feature = "sqlx-sqlite")]
1236            QueryResultRow::SqlxSqlite(_) => {
1237                Err(type_err("Vector unsupported by sqlx-sqlite").into())
1238            }
1239            #[cfg(feature = "rusqlite")]
1240            QueryResultRow::Rusqlite(_) => Err(type_err("Vector unsupported by rusqlite").into()),
1241            #[cfg(feature = "mock")]
1242            QueryResultRow::Mock(row) => row.try_get::<pgvector::Vector, _>(idx).map_err(|e| {
1243                debug_print!("{:#?}", e.to_string());
1244                err_null_idx_col(idx)
1245            }),
1246            #[cfg(feature = "proxy")]
1247            QueryResultRow::Proxy(row) => row.try_get::<pgvector::Vector, _>(idx).map_err(|e| {
1248                debug_print!("{:#?}", e.to_string());
1249                err_null_idx_col(idx)
1250            }),
1251            #[allow(unreachable_patterns)]
1252            _ => unreachable!(),
1253        }
1254    }
1255}
1256
1257// TryGetableMany //
1258
1259/// An interface to get a tuple value from the query result
1260pub trait TryGetableMany: Sized {
1261    /// Get a tuple value from the query result with prefixed column name
1262    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
1263
1264    /// Get a tuple value from the query result based on the order in the select expressions
1265    fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError>;
1266
1267    /// ```
1268    /// # use sea_orm::{error::*, tests_cfg::*, *};
1269    /// #
1270    /// # #[smol_potat::main]
1271    /// # #[cfg(all(feature = "mock", feature = "macros"))]
1272    /// # pub async fn main() -> Result<(), DbErr> {
1273    /// #
1274    /// # let db = MockDatabase::new(DbBackend::Postgres)
1275    /// #     .append_query_results([[
1276    /// #         maplit::btreemap! {
1277    /// #             "name" => Into::<Value>::into("Chocolate Forest"),
1278    /// #             "num_of_cakes" => Into::<Value>::into(1),
1279    /// #         },
1280    /// #         maplit::btreemap! {
1281    /// #             "name" => Into::<Value>::into("New York Cheese"),
1282    /// #             "num_of_cakes" => Into::<Value>::into(1),
1283    /// #         },
1284    /// #     ]])
1285    /// #     .into_connection();
1286    /// #
1287    /// use sea_orm::{DeriveIden, EnumIter, TryGetableMany, entity::*, query::*, tests_cfg::cake};
1288    ///
1289    /// #[derive(EnumIter, DeriveIden)]
1290    /// enum ResultCol {
1291    ///     Name,
1292    ///     NumOfCakes,
1293    /// }
1294    ///
1295    /// let res: Vec<(String, i32)> =
1296    ///     <(String, i32)>::find_by_statement::<ResultCol>(Statement::from_sql_and_values(
1297    ///         DbBackend::Postgres,
1298    ///         r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
1299    ///         [],
1300    ///     ))
1301    ///     .all(&db)
1302    ///     .await?;
1303    ///
1304    /// assert_eq!(
1305    ///     res,
1306    ///     [
1307    ///         ("Chocolate Forest".to_owned(), 1),
1308    ///         ("New York Cheese".to_owned(), 1),
1309    ///     ]
1310    /// );
1311    ///
1312    /// assert_eq!(
1313    ///     db.into_transaction_log(),
1314    ///     [Transaction::from_sql_and_values(
1315    ///         DbBackend::Postgres,
1316    ///         r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
1317    ///         []
1318    ///     ),]
1319    /// );
1320    /// #
1321    /// # Ok(())
1322    /// # }
1323    /// ```
1324    fn find_by_statement<C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<Self, C>>
1325    where
1326        C: strum::IntoEnumIterator + sea_query::Iden,
1327    {
1328        SelectorRaw {
1329            stmt,
1330            selector: PhantomData,
1331        }
1332    }
1333}
1334
1335impl<T> TryGetableMany for T
1336where
1337    T: TryGetable,
1338{
1339    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1340        try_get_many_with_slice_len_of(1, cols)?;
1341        T::try_get(res, pre, &cols[0])
1342    }
1343
1344    fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1345        T::try_get_by_index(res, 0)
1346    }
1347}
1348
1349impl<T> TryGetableMany for (T,)
1350where
1351    T: TryGetableMany,
1352{
1353    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1354        T::try_get_many(res, pre, cols).map(|r| (r,))
1355    }
1356
1357    fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1358        T::try_get_many_by_index(res).map(|r| (r,))
1359    }
1360}
1361
1362macro_rules! impl_try_get_many {
1363    ( $LEN:expr, $($T:ident : $N:expr),+ $(,)? ) => {
1364        impl< $($T),+ > TryGetableMany for ( $($T),+ )
1365        where
1366            $($T: TryGetable),+
1367        {
1368            fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1369                try_get_many_with_slice_len_of($LEN, cols)?;
1370                Ok((
1371                    $($T::try_get(res, pre, &cols[$N])?),+
1372                ))
1373            }
1374
1375            fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1376                Ok((
1377                    $($T::try_get_by_index(res, $N)?),+
1378                ))
1379            }
1380        }
1381    };
1382}
1383
1384#[rustfmt::skip]
1385mod impl_try_get_many {
1386    use super::*;
1387
1388    impl_try_get_many!( 2, T0:0, T1:1);
1389    impl_try_get_many!( 3, T0:0, T1:1, T2:2);
1390    impl_try_get_many!( 4, T0:0, T1:1, T2:2, T3:3);
1391    impl_try_get_many!( 5, T0:0, T1:1, T2:2, T3:3, T4:4);
1392    impl_try_get_many!( 6, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5);
1393    impl_try_get_many!( 7, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6);
1394    impl_try_get_many!( 8, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7);
1395    impl_try_get_many!( 9, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8);
1396    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);
1397    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);
1398    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);
1399}
1400
1401fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), TryGetError> {
1402    if cols.len() < len {
1403        Err(type_err(format!(
1404            "Expect {} column names supplied but got slice of length {}",
1405            len,
1406            cols.len()
1407        ))
1408        .into())
1409    } else {
1410        Ok(())
1411    }
1412}
1413
1414/// An interface to get an array of values from the query result.
1415/// A type can only implement `ActiveEnum` or `TryGetableFromJson`, but not both.
1416/// A blanket impl is provided for `TryGetableFromJson`, while the impl for `ActiveEnum`
1417/// is provided by the `DeriveActiveEnum` macro. So as an end user you won't normally
1418/// touch this trait.
1419pub trait TryGetableArray: Sized {
1420    /// Just a delegate
1421    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Vec<Self>, TryGetError>;
1422}
1423
1424impl<T> TryGetable for Vec<T>
1425where
1426    T: TryGetableArray,
1427{
1428    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1429        T::try_get_by(res, index)
1430    }
1431}
1432
1433// TryGetableFromJson //
1434
1435/// An interface to get a JSON from the query result
1436#[cfg(feature = "with-json")]
1437pub trait TryGetableFromJson: Sized
1438where
1439    for<'de> Self: serde::Deserialize<'de>,
1440{
1441    /// Get a JSON from the query result with prefixed column name
1442    #[allow(unused_variables, unreachable_code)]
1443    fn try_get_from_json<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1444        match &res.row {
1445            #[cfg(feature = "sqlx-mysql")]
1446            QueryResultRow::SqlxMySql(row) => row
1447                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_mysql_index())
1448                .map_err(|e| sqlx_error_to_query_err(e).into())
1449                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1450            #[cfg(feature = "sqlx-postgres")]
1451            QueryResultRow::SqlxPostgres(row) => row
1452                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_postgres_index())
1453                .map_err(|e| sqlx_error_to_query_err(e).into())
1454                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1455            #[cfg(feature = "sqlx-sqlite")]
1456            QueryResultRow::SqlxSqlite(row) => row
1457                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_sqlite_index())
1458                .map_err(|e| sqlx_error_to_query_err(e).into())
1459                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1460            #[cfg(feature = "rusqlite")]
1461            QueryResultRow::Rusqlite(row) => row
1462                .try_get::<Option<serde_json::Value>, _>(idx)?
1463                .ok_or_else(|| err_null_idx_col(idx))
1464                .and_then(|json| {
1465                    serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1466                }),
1467            #[cfg(feature = "mock")]
1468            QueryResultRow::Mock(row) => row
1469                .try_get::<serde_json::Value, I>(idx)
1470                .map_err(|e| {
1471                    debug_print!("{:#?}", e.to_string());
1472                    err_null_idx_col(idx)
1473                })
1474                .and_then(|json| {
1475                    serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1476                }),
1477            #[cfg(feature = "proxy")]
1478            QueryResultRow::Proxy(row) => row
1479                .try_get::<serde_json::Value, I>(idx)
1480                .map_err(|e| {
1481                    debug_print!("{:#?}", e.to_string());
1482                    err_null_idx_col(idx)
1483                })
1484                .and_then(|json| {
1485                    serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1486                }),
1487            #[allow(unreachable_patterns)]
1488            _ => unreachable!(),
1489        }
1490    }
1491
1492    /// Get a Vec<Self> from an Array of Json
1493    fn from_json_vec(value: serde_json::Value) -> Result<Vec<Self>, TryGetError> {
1494        match value {
1495            serde_json::Value::Array(values) => {
1496                let mut res = Vec::new();
1497                for item in values {
1498                    res.push(serde_json::from_value(item).map_err(crate::error::json_err)?);
1499                }
1500                Ok(res)
1501            }
1502            _ => Err(TryGetError::DbErr(DbErr::Json(
1503                "Value is not an Array".to_owned(),
1504            ))),
1505        }
1506    }
1507}
1508
1509#[cfg(feature = "with-json")]
1510impl<T> TryGetable for T
1511where
1512    T: TryGetableFromJson,
1513{
1514    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1515        T::try_get_from_json(res, index)
1516    }
1517}
1518
1519#[cfg(feature = "with-json")]
1520impl<T> TryGetableArray for T
1521where
1522    T: TryGetableFromJson,
1523{
1524    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Vec<T>, TryGetError> {
1525        T::from_json_vec(serde_json::Value::try_get_by(res, index)?)
1526    }
1527}
1528
1529// TryFromU64 //
1530/// Try to convert a type to a u64
1531pub trait TryFromU64: Sized {
1532    /// The method to convert the type to a u64
1533    fn try_from_u64(n: u64) -> Result<Self, DbErr>;
1534}
1535
1536macro_rules! try_from_u64_err {
1537    ( $type: ty ) => {
1538        impl TryFromU64 for $type {
1539            fn try_from_u64(_: u64) -> Result<Self, DbErr> {
1540                Err(DbErr::ConvertFromU64(stringify!($type)))
1541            }
1542        }
1543    };
1544
1545    ( $($gen_type: ident),* ) => {
1546        impl<$( $gen_type, )*> TryFromU64 for ($( $gen_type, )*)
1547        where
1548            $( $gen_type: TryFromU64, )*
1549        {
1550            fn try_from_u64(_: u64) -> Result<Self, DbErr> {
1551                Err(DbErr::ConvertFromU64(stringify!($($gen_type,)*)))
1552            }
1553        }
1554    };
1555}
1556
1557#[rustfmt::skip]
1558mod try_from_u64_err {
1559    use super::*;
1560
1561    try_from_u64_err!(T0, T1);
1562    try_from_u64_err!(T0, T1, T2);
1563    try_from_u64_err!(T0, T1, T2, T3);
1564    try_from_u64_err!(T0, T1, T2, T3, T4);
1565    try_from_u64_err!(T0, T1, T2, T3, T4, T5);
1566    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6);
1567    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7);
1568    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
1569    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
1570    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
1571    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
1572}
1573
1574macro_rules! try_from_u64_numeric {
1575    ( $type: ty ) => {
1576        impl TryFromU64 for $type {
1577            fn try_from_u64(n: u64) -> Result<Self, DbErr> {
1578                use std::convert::TryInto;
1579                n.try_into().map_err(|e| DbErr::TryIntoErr {
1580                    from: stringify!(u64),
1581                    into: stringify!($type),
1582                    source: Arc::new(e),
1583                })
1584            }
1585        }
1586    };
1587}
1588
1589try_from_u64_numeric!(i8);
1590try_from_u64_numeric!(i16);
1591try_from_u64_numeric!(i32);
1592try_from_u64_numeric!(i64);
1593try_from_u64_numeric!(u8);
1594try_from_u64_numeric!(u16);
1595try_from_u64_numeric!(u32);
1596try_from_u64_numeric!(u64);
1597
1598macro_rules! try_from_u64_string {
1599    ( $type: ty ) => {
1600        impl TryFromU64 for $type {
1601            fn try_from_u64(n: u64) -> Result<Self, DbErr> {
1602                Ok(n.to_string())
1603            }
1604        }
1605    };
1606}
1607
1608try_from_u64_string!(String);
1609
1610try_from_u64_err!(bool);
1611try_from_u64_err!(f32);
1612try_from_u64_err!(f64);
1613try_from_u64_err!(Vec<u8>);
1614
1615#[cfg(feature = "with-json")]
1616try_from_u64_err!(serde_json::Value);
1617
1618#[cfg(feature = "with-chrono")]
1619try_from_u64_err!(chrono::NaiveDate);
1620
1621#[cfg(feature = "with-chrono")]
1622try_from_u64_err!(chrono::NaiveTime);
1623
1624#[cfg(feature = "with-chrono")]
1625try_from_u64_err!(chrono::NaiveDateTime);
1626
1627#[cfg(feature = "with-chrono")]
1628try_from_u64_err!(chrono::DateTime<chrono::FixedOffset>);
1629
1630#[cfg(feature = "with-chrono")]
1631try_from_u64_err!(chrono::DateTime<chrono::Utc>);
1632
1633#[cfg(feature = "with-chrono")]
1634try_from_u64_err!(chrono::DateTime<chrono::Local>);
1635
1636#[cfg(feature = "with-time")]
1637try_from_u64_err!(time::Date);
1638
1639#[cfg(feature = "with-time")]
1640try_from_u64_err!(time::Time);
1641
1642#[cfg(feature = "with-time")]
1643try_from_u64_err!(time::PrimitiveDateTime);
1644
1645#[cfg(feature = "with-time")]
1646try_from_u64_err!(time::OffsetDateTime);
1647
1648#[cfg(feature = "with-rust_decimal")]
1649try_from_u64_err!(rust_decimal::Decimal);
1650
1651#[cfg(feature = "with-uuid")]
1652try_from_u64_err!(uuid::Uuid);
1653
1654#[cfg(feature = "with-ipnetwork")]
1655try_from_u64_err!(ipnetwork::IpNetwork);
1656
1657#[cfg(feature = "with-mac_address")]
1658try_from_u64_err!(mac_address::MacAddress);
1659
1660#[cfg(test)]
1661mod tests {
1662    use super::*;
1663    use crate::RuntimeErr;
1664    use sea_query::Value;
1665    use std::collections::BTreeMap;
1666
1667    #[test]
1668    fn from_try_get_error() {
1669        // TryGetError::DbErr
1670        let try_get_error = TryGetError::DbErr(DbErr::Query(RuntimeErr::Internal(
1671            "expected error message".to_owned(),
1672        )));
1673        assert_eq!(
1674            DbErr::from(try_get_error),
1675            DbErr::Query(RuntimeErr::Internal("expected error message".to_owned()))
1676        );
1677
1678        // TryGetError::Null
1679        let try_get_error = TryGetError::Null("column".to_owned());
1680        let expected = "A null value was encountered while decoding column".to_owned();
1681        assert_eq!(DbErr::from(try_get_error), DbErr::Type(expected));
1682    }
1683
1684    #[test]
1685    fn build_with_query() {
1686        use sea_orm::{DbBackend, Statement};
1687        use sea_query::{
1688            ColumnRef, CommonTableExpression, Cycle, Expr, ExprTrait, JoinType, SelectStatement,
1689            UnionType, WithClause,
1690        };
1691
1692        let base_query = SelectStatement::new()
1693            .column("id")
1694            .expr(1i32)
1695            .column("next")
1696            .column("value")
1697            .from("table")
1698            .to_owned();
1699
1700        let cte_referencing = SelectStatement::new()
1701            .column("id")
1702            .expr(Expr::col("depth").add(1i32))
1703            .column("next")
1704            .column("value")
1705            .from("table")
1706            .join(
1707                JoinType::InnerJoin,
1708                "cte_traversal",
1709                Expr::col(("cte_traversal", "next")).equals(("table", "id")),
1710            )
1711            .to_owned();
1712
1713        let common_table_expression = CommonTableExpression::new()
1714            .query(
1715                base_query
1716                    .clone()
1717                    .union(UnionType::All, cte_referencing)
1718                    .to_owned(),
1719            )
1720            .columns(["id", "depth", "next", "value"])
1721            .table_name("cte_traversal")
1722            .to_owned();
1723
1724        let select = SelectStatement::new()
1725            .column(ColumnRef::Asterisk(None))
1726            .from("cte_traversal")
1727            .to_owned();
1728
1729        let with_clause = WithClause::new()
1730            .recursive(true)
1731            .cte(common_table_expression)
1732            .cycle(Cycle::new_from_expr_set_using(
1733                Expr::column("id"),
1734                "looped",
1735                "traversal_path",
1736            ))
1737            .to_owned();
1738
1739        let with_query = select.with(with_clause).to_owned();
1740
1741        assert_eq!(
1742            DbBackend::MySql.build(&with_query),
1743            Statement::from_sql_and_values(
1744                DbBackend::MySql,
1745                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`",
1746                [1.into(), 1.into()]
1747            )
1748        );
1749    }
1750
1751    #[test]
1752    fn column_names_from_query_result() {
1753        let mut values = BTreeMap::new();
1754        values.insert("id".to_string(), Value::Int(Some(1)));
1755        values.insert("name".to_string(), Value::String(Some("Abc".to_owned())));
1756        let query_result = QueryResult {
1757            row: QueryResultRow::Mock(crate::MockRow { values }),
1758        };
1759        assert_eq!(
1760            query_result.column_names(),
1761            vec!["id".to_owned(), "name".to_owned()]
1762        );
1763    }
1764}