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<$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<$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<$type> {
1105                fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1106                    let res: Result<Vec<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<uuid::Uuid>>, _>(idx.as_sqlx_postgres_index())
1116                            .map_err(|e| sqlx_error_to_query_err(e).into())
1117                            .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
1118                        #[cfg(feature = "sqlx-sqlite")]
1119                        QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
1120                            "{} unsupported by sqlx-sqlite",
1121                            stringify!($type)
1122                        ))
1123                        .into()),
1124                        #[cfg(feature = "rusqlite")]
1125                        QueryResultRow::Rusqlite(_) => Err(type_err(format!(
1126                            "{} unsupported by rusqlite",
1127                            stringify!($type)
1128                        ))
1129                        .into()),
1130                        #[cfg(feature = "mock")]
1131                        QueryResultRow::Mock(row) => {
1132                            row.try_get::<Vec<uuid::Uuid>, _>(idx).map_err(|e| {
1133                                debug_print!("{:#?}", e.to_string());
1134                                err_null_idx_col(idx)
1135                            })
1136                        }
1137                        #[cfg(feature = "proxy")]
1138                        QueryResultRow::Proxy(row) => {
1139                            row.try_get::<Vec<uuid::Uuid>, _>(idx).map_err(|e| {
1140                                debug_print!("{:#?}", e.to_string());
1141                                err_null_idx_col(idx)
1142                            })
1143                        }
1144                        #[allow(unreachable_patterns)]
1145                        _ => unreachable!(),
1146                    };
1147                    res.map(|vec| vec.into_iter().map($conversion_fn).collect())
1148                }
1149            }
1150        };
1151    }
1152
1153    #[cfg(feature = "with-uuid")]
1154    try_getable_postgres_array_uuid!(uuid::Uuid, Into::into);
1155
1156    #[cfg(feature = "with-uuid")]
1157    try_getable_postgres_array_uuid!(uuid::fmt::Braced, uuid::Uuid::braced);
1158
1159    #[cfg(feature = "with-uuid")]
1160    try_getable_postgres_array_uuid!(uuid::fmt::Hyphenated, uuid::Uuid::hyphenated);
1161
1162    #[cfg(feature = "with-uuid")]
1163    try_getable_postgres_array_uuid!(uuid::fmt::Simple, uuid::Uuid::simple);
1164
1165    #[cfg(feature = "with-uuid")]
1166    try_getable_postgres_array_uuid!(uuid::fmt::Urn, uuid::Uuid::urn);
1167
1168    impl TryGetable for Vec<u32> {
1169        #[allow(unused_variables)]
1170        fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1171            match &res.row {
1172                #[cfg(feature = "sqlx-mysql")]
1173                QueryResultRow::SqlxMySql(_) => {
1174                    Err(type_err(format!("{} unsupported by sqlx-mysql", stringify!($type))).into())
1175                }
1176                #[cfg(feature = "sqlx-postgres")]
1177                QueryResultRow::SqlxPostgres(row) => {
1178                    use sqlx::postgres::types::Oid;
1179                    // Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`;
1180                    // Instead, `u32` was wrapped by a `sqlx::Oid`.
1181                    row.try_get::<Option<Vec<Oid>>, _>(idx.as_sqlx_postgres_index())
1182                        .map_err(|e| sqlx_error_to_query_err(e).into())
1183                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
1184                        .map(|oids| oids.into_iter().map(|oid| oid.0).collect())
1185                }
1186                #[cfg(feature = "sqlx-sqlite")]
1187                QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
1188                    "{} unsupported by sqlx-sqlite",
1189                    stringify!($type)
1190                ))
1191                .into()),
1192                #[cfg(feature = "rusqlite")]
1193                QueryResultRow::Rusqlite(_) => {
1194                    Err(type_err(format!("{} unsupported by rusqlite", stringify!($type))).into())
1195                }
1196                #[cfg(feature = "mock")]
1197                #[allow(unused_variables)]
1198                QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
1199                    debug_print!("{:#?}", e.to_string());
1200                    err_null_idx_col(idx)
1201                }),
1202                #[cfg(feature = "proxy")]
1203                #[allow(unused_variables)]
1204                QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
1205                    debug_print!("{:#?}", e.to_string());
1206                    err_null_idx_col(idx)
1207                }),
1208                #[allow(unreachable_patterns)]
1209                _ => unreachable!(),
1210            }
1211        }
1212    }
1213}
1214
1215#[cfg(feature = "postgres-vector")]
1216impl TryGetable for pgvector::Vector {
1217    #[allow(unused_variables)]
1218    fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1219        match &res.row {
1220            #[cfg(feature = "sqlx-mysql")]
1221            QueryResultRow::SqlxMySql(_) => {
1222                Err(type_err("Vector unsupported by sqlx-mysql").into())
1223            }
1224            #[cfg(feature = "sqlx-postgres")]
1225            QueryResultRow::SqlxPostgres(row) => row
1226                .try_get::<Option<pgvector::Vector>, _>(idx.as_sqlx_postgres_index())
1227                .map_err(|e| sqlx_error_to_query_err(e).into())
1228                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
1229            #[cfg(feature = "sqlx-sqlite")]
1230            QueryResultRow::SqlxSqlite(_) => {
1231                Err(type_err("Vector unsupported by sqlx-sqlite").into())
1232            }
1233            #[cfg(feature = "rusqlite")]
1234            QueryResultRow::Rusqlite(_) => Err(type_err("Vector unsupported by rusqlite").into()),
1235            #[cfg(feature = "mock")]
1236            QueryResultRow::Mock(row) => row.try_get::<pgvector::Vector, _>(idx).map_err(|e| {
1237                debug_print!("{:#?}", e.to_string());
1238                err_null_idx_col(idx)
1239            }),
1240            #[cfg(feature = "proxy")]
1241            QueryResultRow::Proxy(row) => row.try_get::<pgvector::Vector, _>(idx).map_err(|e| {
1242                debug_print!("{:#?}", e.to_string());
1243                err_null_idx_col(idx)
1244            }),
1245            #[allow(unreachable_patterns)]
1246            _ => unreachable!(),
1247        }
1248    }
1249}
1250
1251// TryGetableMany //
1252
1253/// An interface to get a tuple value from the query result
1254pub trait TryGetableMany: Sized {
1255    /// Get a tuple value from the query result with prefixed column name
1256    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
1257
1258    /// Get a tuple value from the query result based on the order in the select expressions
1259    fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError>;
1260
1261    /// ```
1262    /// # use sea_orm::{error::*, tests_cfg::*, *};
1263    /// #
1264    /// # #[cfg(all(feature = "mock", feature = "macros"))]
1265    /// # pub fn main() -> Result<(), DbErr> {
1266    /// #
1267    /// # let db = MockDatabase::new(DbBackend::Postgres)
1268    /// #     .append_query_results([[
1269    /// #         maplit::btreemap! {
1270    /// #             "name" => Into::<Value>::into("Chocolate Forest"),
1271    /// #             "num_of_cakes" => Into::<Value>::into(1),
1272    /// #         },
1273    /// #         maplit::btreemap! {
1274    /// #             "name" => Into::<Value>::into("New York Cheese"),
1275    /// #             "num_of_cakes" => Into::<Value>::into(1),
1276    /// #         },
1277    /// #     ]])
1278    /// #     .into_connection();
1279    /// #
1280    /// use sea_orm::{DeriveIden, EnumIter, TryGetableMany, entity::*, query::*, tests_cfg::cake};
1281    ///
1282    /// #[derive(EnumIter, DeriveIden)]
1283    /// enum ResultCol {
1284    ///     Name,
1285    ///     NumOfCakes,
1286    /// }
1287    ///
1288    /// let res: Vec<(String, i32)> =
1289    ///     <(String, i32)>::find_by_statement::<ResultCol>(Statement::from_sql_and_values(
1290    ///         DbBackend::Postgres,
1291    ///         r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
1292    ///         [],
1293    ///     ))
1294    ///     .all(&db)
1295    ///     ?;
1296    ///
1297    /// assert_eq!(
1298    ///     res,
1299    ///     [
1300    ///         ("Chocolate Forest".to_owned(), 1),
1301    ///         ("New York Cheese".to_owned(), 1),
1302    ///     ]
1303    /// );
1304    ///
1305    /// assert_eq!(
1306    ///     db.into_transaction_log(),
1307    ///     [Transaction::from_sql_and_values(
1308    ///         DbBackend::Postgres,
1309    ///         r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
1310    ///         []
1311    ///     ),]
1312    /// );
1313    /// #
1314    /// # Ok(())
1315    /// # }
1316    /// ```
1317    fn find_by_statement<C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<Self, C>>
1318    where
1319        C: strum::IntoEnumIterator + sea_query::Iden,
1320    {
1321        SelectorRaw {
1322            stmt,
1323            selector: PhantomData,
1324        }
1325    }
1326}
1327
1328impl<T> TryGetableMany for T
1329where
1330    T: TryGetable,
1331{
1332    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1333        try_get_many_with_slice_len_of(1, cols)?;
1334        T::try_get(res, pre, &cols[0])
1335    }
1336
1337    fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1338        T::try_get_by_index(res, 0)
1339    }
1340}
1341
1342impl<T> TryGetableMany for (T,)
1343where
1344    T: TryGetableMany,
1345{
1346    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1347        T::try_get_many(res, pre, cols).map(|r| (r,))
1348    }
1349
1350    fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1351        T::try_get_many_by_index(res).map(|r| (r,))
1352    }
1353}
1354
1355macro_rules! impl_try_get_many {
1356    ( $LEN:expr, $($T:ident : $N:expr),+ $(,)? ) => {
1357        impl< $($T),+ > TryGetableMany for ( $($T),+ )
1358        where
1359            $($T: TryGetable),+
1360        {
1361            fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1362                try_get_many_with_slice_len_of($LEN, cols)?;
1363                Ok((
1364                    $($T::try_get(res, pre, &cols[$N])?),+
1365                ))
1366            }
1367
1368            fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1369                Ok((
1370                    $($T::try_get_by_index(res, $N)?),+
1371                ))
1372            }
1373        }
1374    };
1375}
1376
1377#[rustfmt::skip]
1378mod impl_try_get_many {
1379    use super::*;
1380
1381    impl_try_get_many!( 2, T0:0, T1:1);
1382    impl_try_get_many!( 3, T0:0, T1:1, T2:2);
1383    impl_try_get_many!( 4, T0:0, T1:1, T2:2, T3:3);
1384    impl_try_get_many!( 5, T0:0, T1:1, T2:2, T3:3, T4:4);
1385    impl_try_get_many!( 6, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5);
1386    impl_try_get_many!( 7, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6);
1387    impl_try_get_many!( 8, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7);
1388    impl_try_get_many!( 9, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8);
1389    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);
1390    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);
1391    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);
1392}
1393
1394fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), TryGetError> {
1395    if cols.len() < len {
1396        Err(type_err(format!(
1397            "Expect {} column names supplied but got slice of length {}",
1398            len,
1399            cols.len()
1400        ))
1401        .into())
1402    } else {
1403        Ok(())
1404    }
1405}
1406
1407/// An interface to get an array of values from the query result.
1408/// A type can only implement `ActiveEnum` or `TryGetableFromJson`, but not both.
1409/// A blanket impl is provided for `TryGetableFromJson`, while the impl for `ActiveEnum`
1410/// is provided by the `DeriveActiveEnum` macro. So as an end user you won't normally
1411/// touch this trait.
1412pub trait TryGetableArray: Sized {
1413    /// Just a delegate
1414    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Vec<Self>, TryGetError>;
1415}
1416
1417impl<T> TryGetable for Vec<T>
1418where
1419    T: TryGetableArray,
1420{
1421    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1422        T::try_get_by(res, index)
1423    }
1424}
1425
1426// TryGetableFromJson //
1427
1428/// An interface to get a JSON from the query result
1429#[cfg(feature = "with-json")]
1430pub trait TryGetableFromJson: Sized
1431where
1432    for<'de> Self: serde::Deserialize<'de>,
1433{
1434    /// Get a JSON from the query result with prefixed column name
1435    #[allow(unused_variables, unreachable_code)]
1436    fn try_get_from_json<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1437        match &res.row {
1438            #[cfg(feature = "sqlx-mysql")]
1439            QueryResultRow::SqlxMySql(row) => row
1440                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_mysql_index())
1441                .map_err(|e| sqlx_error_to_query_err(e).into())
1442                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1443            #[cfg(feature = "sqlx-postgres")]
1444            QueryResultRow::SqlxPostgres(row) => row
1445                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_postgres_index())
1446                .map_err(|e| sqlx_error_to_query_err(e).into())
1447                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1448            #[cfg(feature = "sqlx-sqlite")]
1449            QueryResultRow::SqlxSqlite(row) => row
1450                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_sqlite_index())
1451                .map_err(|e| sqlx_error_to_query_err(e).into())
1452                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1453            #[cfg(feature = "rusqlite")]
1454            QueryResultRow::Rusqlite(row) => row
1455                .try_get::<Option<serde_json::Value>, _>(idx)?
1456                .ok_or_else(|| err_null_idx_col(idx))
1457                .and_then(|json| {
1458                    serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1459                }),
1460            #[cfg(feature = "mock")]
1461            QueryResultRow::Mock(row) => row
1462                .try_get::<serde_json::Value, I>(idx)
1463                .map_err(|e| {
1464                    debug_print!("{:#?}", e.to_string());
1465                    err_null_idx_col(idx)
1466                })
1467                .and_then(|json| {
1468                    serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1469                }),
1470            #[cfg(feature = "proxy")]
1471            QueryResultRow::Proxy(row) => row
1472                .try_get::<serde_json::Value, I>(idx)
1473                .map_err(|e| {
1474                    debug_print!("{:#?}", e.to_string());
1475                    err_null_idx_col(idx)
1476                })
1477                .and_then(|json| {
1478                    serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1479                }),
1480            #[allow(unreachable_patterns)]
1481            _ => unreachable!(),
1482        }
1483    }
1484
1485    /// Get a Vec<Self> from an Array of Json
1486    fn from_json_vec(value: serde_json::Value) -> Result<Vec<Self>, TryGetError> {
1487        match value {
1488            serde_json::Value::Array(values) => {
1489                let mut res = Vec::new();
1490                for item in values {
1491                    res.push(serde_json::from_value(item).map_err(crate::error::json_err)?);
1492                }
1493                Ok(res)
1494            }
1495            _ => Err(TryGetError::DbErr(DbErr::Json(
1496                "Value is not an Array".to_owned(),
1497            ))),
1498        }
1499    }
1500}
1501
1502#[cfg(feature = "with-json")]
1503impl<T> TryGetable for T
1504where
1505    T: TryGetableFromJson,
1506{
1507    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1508        T::try_get_from_json(res, index)
1509    }
1510}
1511
1512#[cfg(feature = "with-json")]
1513impl<T> TryGetableArray for T
1514where
1515    T: TryGetableFromJson,
1516{
1517    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Vec<T>, TryGetError> {
1518        T::from_json_vec(serde_json::Value::try_get_by(res, index)?)
1519    }
1520}
1521
1522// TryFromU64 //
1523/// Try to convert a type to a u64
1524pub trait TryFromU64: Sized {
1525    /// The method to convert the type to a u64
1526    fn try_from_u64(n: u64) -> Result<Self, DbErr>;
1527}
1528
1529macro_rules! try_from_u64_err {
1530    ( $type: ty ) => {
1531        impl TryFromU64 for $type {
1532            fn try_from_u64(_: u64) -> Result<Self, DbErr> {
1533                Err(DbErr::ConvertFromU64(stringify!($type)))
1534            }
1535        }
1536    };
1537
1538    ( $($gen_type: ident),* ) => {
1539        impl<$( $gen_type, )*> TryFromU64 for ($( $gen_type, )*)
1540        where
1541            $( $gen_type: TryFromU64, )*
1542        {
1543            fn try_from_u64(_: u64) -> Result<Self, DbErr> {
1544                Err(DbErr::ConvertFromU64(stringify!($($gen_type,)*)))
1545            }
1546        }
1547    };
1548}
1549
1550#[rustfmt::skip]
1551mod try_from_u64_err {
1552    use super::*;
1553
1554    try_from_u64_err!(T0, T1);
1555    try_from_u64_err!(T0, T1, T2);
1556    try_from_u64_err!(T0, T1, T2, T3);
1557    try_from_u64_err!(T0, T1, T2, T3, T4);
1558    try_from_u64_err!(T0, T1, T2, T3, T4, T5);
1559    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6);
1560    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7);
1561    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
1562    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
1563    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
1564    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
1565}
1566
1567macro_rules! try_from_u64_numeric {
1568    ( $type: ty ) => {
1569        impl TryFromU64 for $type {
1570            fn try_from_u64(n: u64) -> Result<Self, DbErr> {
1571                use std::convert::TryInto;
1572                n.try_into().map_err(|e| DbErr::TryIntoErr {
1573                    from: stringify!(u64),
1574                    into: stringify!($type),
1575                    source: Arc::new(e),
1576                })
1577            }
1578        }
1579    };
1580}
1581
1582try_from_u64_numeric!(i8);
1583try_from_u64_numeric!(i16);
1584try_from_u64_numeric!(i32);
1585try_from_u64_numeric!(i64);
1586try_from_u64_numeric!(u8);
1587try_from_u64_numeric!(u16);
1588try_from_u64_numeric!(u32);
1589try_from_u64_numeric!(u64);
1590
1591macro_rules! try_from_u64_string {
1592    ( $type: ty ) => {
1593        impl TryFromU64 for $type {
1594            fn try_from_u64(n: u64) -> Result<Self, DbErr> {
1595                Ok(n.to_string())
1596            }
1597        }
1598    };
1599}
1600
1601try_from_u64_string!(String);
1602
1603try_from_u64_err!(bool);
1604try_from_u64_err!(f32);
1605try_from_u64_err!(f64);
1606try_from_u64_err!(Vec<u8>);
1607
1608#[cfg(feature = "with-json")]
1609try_from_u64_err!(serde_json::Value);
1610
1611#[cfg(feature = "with-chrono")]
1612try_from_u64_err!(chrono::NaiveDate);
1613
1614#[cfg(feature = "with-chrono")]
1615try_from_u64_err!(chrono::NaiveTime);
1616
1617#[cfg(feature = "with-chrono")]
1618try_from_u64_err!(chrono::NaiveDateTime);
1619
1620#[cfg(feature = "with-chrono")]
1621try_from_u64_err!(chrono::DateTime<chrono::FixedOffset>);
1622
1623#[cfg(feature = "with-chrono")]
1624try_from_u64_err!(chrono::DateTime<chrono::Utc>);
1625
1626#[cfg(feature = "with-chrono")]
1627try_from_u64_err!(chrono::DateTime<chrono::Local>);
1628
1629#[cfg(feature = "with-time")]
1630try_from_u64_err!(time::Date);
1631
1632#[cfg(feature = "with-time")]
1633try_from_u64_err!(time::Time);
1634
1635#[cfg(feature = "with-time")]
1636try_from_u64_err!(time::PrimitiveDateTime);
1637
1638#[cfg(feature = "with-time")]
1639try_from_u64_err!(time::OffsetDateTime);
1640
1641#[cfg(feature = "with-rust_decimal")]
1642try_from_u64_err!(rust_decimal::Decimal);
1643
1644#[cfg(feature = "with-uuid")]
1645try_from_u64_err!(uuid::Uuid);
1646
1647#[cfg(feature = "with-ipnetwork")]
1648try_from_u64_err!(ipnetwork::IpNetwork);
1649
1650#[cfg(test)]
1651mod tests {
1652    use super::*;
1653    use crate::RuntimeErr;
1654    use sea_query::Value;
1655    use std::collections::BTreeMap;
1656
1657    #[test]
1658    fn from_try_get_error() {
1659        // TryGetError::DbErr
1660        let try_get_error = TryGetError::DbErr(DbErr::Query(RuntimeErr::Internal(
1661            "expected error message".to_owned(),
1662        )));
1663        assert_eq!(
1664            DbErr::from(try_get_error),
1665            DbErr::Query(RuntimeErr::Internal("expected error message".to_owned()))
1666        );
1667
1668        // TryGetError::Null
1669        let try_get_error = TryGetError::Null("column".to_owned());
1670        let expected = "A null value was encountered while decoding column".to_owned();
1671        assert_eq!(DbErr::from(try_get_error), DbErr::Type(expected));
1672    }
1673
1674    #[test]
1675    fn build_with_query() {
1676        use sea_orm::{DbBackend, Statement};
1677        use sea_query::{
1678            ColumnRef, CommonTableExpression, Cycle, Expr, ExprTrait, JoinType, SelectStatement,
1679            UnionType, WithClause,
1680        };
1681
1682        let base_query = SelectStatement::new()
1683            .column("id")
1684            .expr(1i32)
1685            .column("next")
1686            .column("value")
1687            .from("table")
1688            .to_owned();
1689
1690        let cte_referencing = SelectStatement::new()
1691            .column("id")
1692            .expr(Expr::col("depth").add(1i32))
1693            .column("next")
1694            .column("value")
1695            .from("table")
1696            .join(
1697                JoinType::InnerJoin,
1698                "cte_traversal",
1699                Expr::col(("cte_traversal", "next")).equals(("table", "id")),
1700            )
1701            .to_owned();
1702
1703        let common_table_expression = CommonTableExpression::new()
1704            .query(
1705                base_query
1706                    .clone()
1707                    .union(UnionType::All, cte_referencing)
1708                    .to_owned(),
1709            )
1710            .columns(["id", "depth", "next", "value"])
1711            .table_name("cte_traversal")
1712            .to_owned();
1713
1714        let select = SelectStatement::new()
1715            .column(ColumnRef::Asterisk(None))
1716            .from("cte_traversal")
1717            .to_owned();
1718
1719        let with_clause = WithClause::new()
1720            .recursive(true)
1721            .cte(common_table_expression)
1722            .cycle(Cycle::new_from_expr_set_using(
1723                Expr::column("id"),
1724                "looped",
1725                "traversal_path",
1726            ))
1727            .to_owned();
1728
1729        let with_query = select.with(with_clause).to_owned();
1730
1731        assert_eq!(
1732            DbBackend::MySql.build(&with_query),
1733            Statement::from_sql_and_values(
1734                DbBackend::MySql,
1735                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`"#,
1736                [1.into(), 1.into()]
1737            )
1738        );
1739    }
1740
1741    #[test]
1742    fn column_names_from_query_result() {
1743        let mut values = BTreeMap::new();
1744        values.insert("id".to_string(), Value::Int(Some(1)));
1745        values.insert("name".to_string(), Value::String(Some("Abc".to_owned())));
1746        let query_result = QueryResult {
1747            row: QueryResultRow::Mock(crate::MockRow { values }),
1748        };
1749        assert_eq!(
1750            query_result.column_names(),
1751            vec!["id".to_owned(), "name".to_owned()]
1752        );
1753    }
1754}