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