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