sea_orm/executor/
query.rs

1use crate::{error::*, SelectGetableValue, SelectorRaw, Statement};
2use std::fmt;
3
4#[cfg(any(feature = "mock", feature = "proxy"))]
5use crate::debug_print;
6
7#[cfg(feature = "sqlx-dep")]
8use crate::driver::*;
9#[cfg(feature = "sqlx-dep")]
10use sqlx::Row;
11
12/// Defines the result of a query operation on a Model
13#[derive(Debug)]
14pub struct QueryResult {
15    pub(crate) row: QueryResultRow,
16}
17
18#[allow(clippy::enum_variant_names)]
19pub(crate) enum QueryResultRow {
20    #[cfg(feature = "sqlx-mysql")]
21    SqlxMySql(sqlx::mysql::MySqlRow),
22    #[cfg(feature = "sqlx-postgres")]
23    SqlxPostgres(sqlx::postgres::PgRow),
24    #[cfg(feature = "sqlx-sqlite")]
25    SqlxSqlite(sqlx::sqlite::SqliteRow),
26    #[cfg(feature = "mock")]
27    Mock(crate::MockRow),
28    #[cfg(feature = "proxy")]
29    Proxy(crate::ProxyRow),
30}
31
32/// An interface to get a value from the query result
33pub trait TryGetable: Sized {
34    /// Get a value from the query result with an ColIdx
35    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError>;
36
37    /// Get a value from the query result with prefixed column name
38    fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError> {
39        if pre.is_empty() {
40            Self::try_get_by(res, col)
41        } else {
42            Self::try_get_by(res, format!("{pre}{col}").as_str())
43        }
44    }
45
46    /// Get a value from the query result based on the order in the select expressions
47    fn try_get_by_index(res: &QueryResult, index: usize) -> Result<Self, TryGetError> {
48        Self::try_get_by(res, index)
49    }
50}
51
52/// An error from trying to get a row from a Model
53#[derive(Debug)]
54pub enum TryGetError {
55    /// A database error was encountered as defined in [crate::DbErr]
56    DbErr(DbErr),
57    /// A null value was encountered
58    Null(String),
59}
60
61impl From<TryGetError> for DbErr {
62    fn from(e: TryGetError) -> DbErr {
63        match e {
64            TryGetError::DbErr(e) => e,
65            TryGetError::Null(s) => {
66                type_err(format!("A null value was encountered while decoding {s}"))
67            }
68        }
69    }
70}
71
72impl From<DbErr> for TryGetError {
73    fn from(e: DbErr) -> TryGetError {
74        Self::DbErr(e)
75    }
76}
77
78// QueryResult //
79
80impl QueryResult {
81    /// Get a value from the query result with an ColIdx
82    pub fn try_get_by<T, I>(&self, index: I) -> Result<T, DbErr>
83    where
84        T: TryGetable,
85        I: ColIdx,
86    {
87        Ok(T::try_get_by(self, index)?)
88    }
89
90    /// Get a value from the query result with prefixed column name
91    pub fn try_get<T>(&self, pre: &str, col: &str) -> Result<T, DbErr>
92    where
93        T: TryGetable,
94    {
95        Ok(T::try_get(self, pre, col)?)
96    }
97
98    /// Get a value from the query result based on the order in the select expressions
99    pub fn try_get_by_index<T>(&self, idx: usize) -> Result<T, DbErr>
100    where
101        T: TryGetable,
102    {
103        Ok(T::try_get_by_index(self, idx)?)
104    }
105
106    /// Get a tuple value from the query result with prefixed column name
107    pub fn try_get_many<T>(&self, pre: &str, cols: &[String]) -> Result<T, DbErr>
108    where
109        T: TryGetableMany,
110    {
111        Ok(T::try_get_many(self, pre, cols)?)
112    }
113
114    /// Get a tuple value from the query result based on the order in the select expressions
115    pub fn try_get_many_by_index<T>(&self) -> Result<T, DbErr>
116    where
117        T: TryGetableMany,
118    {
119        Ok(T::try_get_many_by_index(self)?)
120    }
121
122    /// Retrieves the names of the columns in the result set
123    pub fn column_names(&self) -> Vec<String> {
124        #[cfg(feature = "sqlx-dep")]
125        use sqlx::Column;
126
127        match &self.row {
128            #[cfg(feature = "sqlx-mysql")]
129            QueryResultRow::SqlxMySql(row) => {
130                row.columns().iter().map(|c| c.name().to_string()).collect()
131            }
132            #[cfg(feature = "sqlx-postgres")]
133            QueryResultRow::SqlxPostgres(row) => {
134                row.columns().iter().map(|c| c.name().to_string()).collect()
135            }
136            #[cfg(feature = "sqlx-sqlite")]
137            QueryResultRow::SqlxSqlite(row) => {
138                row.columns().iter().map(|c| c.name().to_string()).collect()
139            }
140            #[cfg(feature = "mock")]
141            QueryResultRow::Mock(row) => row
142                .clone()
143                .into_column_value_tuples()
144                .map(|(c, _)| c.to_string())
145                .collect(),
146            #[cfg(feature = "proxy")]
147            QueryResultRow::Proxy(row) => row
148                .clone()
149                .into_column_value_tuples()
150                .map(|(c, _)| c.to_string())
151                .collect(),
152            #[allow(unreachable_patterns)]
153            _ => unreachable!(),
154        }
155    }
156}
157
158#[allow(unused_variables)]
159impl fmt::Debug for QueryResultRow {
160    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161        match self {
162            #[cfg(feature = "sqlx-mysql")]
163            Self::SqlxMySql(row) => write!(f, "{row:?}"),
164            #[cfg(feature = "sqlx-postgres")]
165            Self::SqlxPostgres(_) => write!(f, "QueryResultRow::SqlxPostgres cannot be inspected"),
166            #[cfg(feature = "sqlx-sqlite")]
167            Self::SqlxSqlite(_) => write!(f, "QueryResultRow::SqlxSqlite cannot be inspected"),
168            #[cfg(feature = "mock")]
169            Self::Mock(row) => write!(f, "{row:?}"),
170            #[cfg(feature = "proxy")]
171            Self::Proxy(row) => write!(f, "{row:?}"),
172            #[allow(unreachable_patterns)]
173            _ => unreachable!(),
174        }
175    }
176}
177
178// TryGetable //
179
180impl<T: TryGetable> TryGetable for Option<T> {
181    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
182        match T::try_get_by(res, index) {
183            Ok(v) => Ok(Some(v)),
184            Err(TryGetError::Null(_)) => Ok(None),
185            #[cfg(feature = "sqlx-dep")]
186            Err(TryGetError::DbErr(DbErr::Query(RuntimeErr::SqlxError(
187                sqlx::Error::ColumnNotFound(_),
188            )))) => Ok(None),
189            Err(e) => Err(e),
190        }
191    }
192}
193
194/// Column Index, used by [`TryGetable`]. Implemented for `&str` and `usize`
195pub trait ColIdx: std::fmt::Debug + Copy {
196    #[cfg(feature = "sqlx-mysql")]
197    /// Type surrogate
198    type SqlxMySqlIndex: sqlx::ColumnIndex<sqlx::mysql::MySqlRow>;
199    #[cfg(feature = "sqlx-postgres")]
200    /// Type surrogate
201    type SqlxPostgresIndex: sqlx::ColumnIndex<sqlx::postgres::PgRow>;
202    #[cfg(feature = "sqlx-sqlite")]
203    /// Type surrogate
204    type SqlxSqliteIndex: sqlx::ColumnIndex<sqlx::sqlite::SqliteRow>;
205
206    #[cfg(feature = "sqlx-mysql")]
207    /// Basically a no-op; only to satisfy trait bounds
208    fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex;
209    #[cfg(feature = "sqlx-postgres")]
210    /// Basically a no-op; only to satisfy trait bounds
211    fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex;
212    #[cfg(feature = "sqlx-sqlite")]
213    /// Basically a no-op; only to satisfy trait bounds
214    fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex;
215
216    /// Self must be `&str`, return `None` otherwise
217    fn as_str(&self) -> Option<&str>;
218    /// Self must be `usize`, return `None` otherwise
219    fn as_usize(&self) -> Option<&usize>;
220}
221
222impl ColIdx for &str {
223    #[cfg(feature = "sqlx-mysql")]
224    type SqlxMySqlIndex = Self;
225    #[cfg(feature = "sqlx-postgres")]
226    type SqlxPostgresIndex = Self;
227    #[cfg(feature = "sqlx-sqlite")]
228    type SqlxSqliteIndex = Self;
229
230    #[cfg(feature = "sqlx-mysql")]
231    #[inline]
232    fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex {
233        self
234    }
235    #[cfg(feature = "sqlx-postgres")]
236    #[inline]
237    fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex {
238        self
239    }
240    #[cfg(feature = "sqlx-sqlite")]
241    #[inline]
242    fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex {
243        self
244    }
245
246    #[inline]
247    fn as_str(&self) -> Option<&str> {
248        Some(self)
249    }
250    #[inline]
251    fn as_usize(&self) -> Option<&usize> {
252        None
253    }
254}
255
256impl ColIdx for usize {
257    #[cfg(feature = "sqlx-mysql")]
258    type SqlxMySqlIndex = Self;
259    #[cfg(feature = "sqlx-postgres")]
260    type SqlxPostgresIndex = Self;
261    #[cfg(feature = "sqlx-sqlite")]
262    type SqlxSqliteIndex = Self;
263
264    #[cfg(feature = "sqlx-mysql")]
265    #[inline]
266    fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex {
267        *self
268    }
269    #[cfg(feature = "sqlx-postgres")]
270    #[inline]
271    fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex {
272        *self
273    }
274    #[cfg(feature = "sqlx-sqlite")]
275    #[inline]
276    fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex {
277        *self
278    }
279
280    #[inline]
281    fn as_str(&self) -> Option<&str> {
282        None
283    }
284    #[inline]
285    fn as_usize(&self) -> Option<&usize> {
286        Some(self)
287    }
288}
289
290macro_rules! try_getable_all {
291    ( $type: ty ) => {
292        impl TryGetable for $type {
293            #[allow(unused_variables)]
294            fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
295                match &res.row {
296                    #[cfg(feature = "sqlx-mysql")]
297                    QueryResultRow::SqlxMySql(row) => row
298                        .try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
299                        .map_err(|e| sqlx_error_to_query_err(e).into())
300                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
301                    #[cfg(feature = "sqlx-postgres")]
302                    QueryResultRow::SqlxPostgres(row) => row
303                        .try_get::<Option<$type>, _>(idx.as_sqlx_postgres_index())
304                        .map_err(|e| sqlx_error_to_query_err(e).into())
305                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
306                    #[cfg(feature = "sqlx-sqlite")]
307                    QueryResultRow::SqlxSqlite(row) => row
308                        .try_get::<Option<$type>, _>(idx.as_sqlx_sqlite_index())
309                        .map_err(|e| sqlx_error_to_query_err(e).into())
310                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
311                    #[cfg(feature = "mock")]
312                    QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
313                        debug_print!("{:#?}", e.to_string());
314                        err_null_idx_col(idx)
315                    }),
316                    #[cfg(feature = "proxy")]
317                    QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
318                        debug_print!("{:#?}", e.to_string());
319                        err_null_idx_col(idx)
320                    }),
321                    #[allow(unreachable_patterns)]
322                    _ => unreachable!(),
323                }
324            }
325        }
326    };
327}
328
329macro_rules! try_getable_unsigned {
330    ( $type: ty ) => {
331        impl TryGetable for $type {
332            #[allow(unused_variables)]
333            fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
334                match &res.row {
335                    #[cfg(feature = "sqlx-mysql")]
336                    QueryResultRow::SqlxMySql(row) => row
337                        .try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
338                        .map_err(|e| sqlx_error_to_query_err(e).into())
339                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
340                    #[cfg(feature = "sqlx-postgres")]
341                    QueryResultRow::SqlxPostgres(_) => Err(type_err(format!(
342                        "{} unsupported by sqlx-postgres",
343                        stringify!($type)
344                    ))
345                    .into()),
346                    #[cfg(feature = "sqlx-sqlite")]
347                    QueryResultRow::SqlxSqlite(row) => row
348                        .try_get::<Option<$type>, _>(idx.as_sqlx_sqlite_index())
349                        .map_err(|e| sqlx_error_to_query_err(e).into())
350                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
351                    #[cfg(feature = "mock")]
352                    QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
353                        debug_print!("{:#?}", e.to_string());
354                        err_null_idx_col(idx)
355                    }),
356                    #[cfg(feature = "proxy")]
357                    QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
358                        debug_print!("{:#?}", e.to_string());
359                        err_null_idx_col(idx)
360                    }),
361                    #[allow(unreachable_patterns)]
362                    _ => unreachable!(),
363                }
364            }
365        }
366    };
367}
368
369macro_rules! try_getable_mysql {
370    ( $type: ty ) => {
371        impl TryGetable for $type {
372            #[allow(unused_variables)]
373            fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
374                match &res.row {
375                    #[cfg(feature = "sqlx-mysql")]
376                    QueryResultRow::SqlxMySql(row) => row
377                        .try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
378                        .map_err(|e| sqlx_error_to_query_err(e).into())
379                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
380                    #[cfg(feature = "sqlx-postgres")]
381                    QueryResultRow::SqlxPostgres(_) => Err(type_err(format!(
382                        "{} unsupported by sqlx-postgres",
383                        stringify!($type)
384                    ))
385                    .into()),
386                    #[cfg(feature = "sqlx-sqlite")]
387                    QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
388                        "{} unsupported by sqlx-sqlite",
389                        stringify!($type)
390                    ))
391                    .into()),
392                    #[cfg(feature = "mock")]
393                    QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
394                        debug_print!("{:#?}", e.to_string());
395                        err_null_idx_col(idx)
396                    }),
397                    #[cfg(feature = "proxy")]
398                    QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
399                        debug_print!("{:#?}", e.to_string());
400                        err_null_idx_col(idx)
401                    }),
402                    #[allow(unreachable_patterns)]
403                    _ => unreachable!(),
404                }
405            }
406        }
407    };
408}
409
410#[allow(unused_macros)]
411macro_rules! try_getable_date_time {
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) => {
419                        use chrono::{DateTime, Utc};
420                        row.try_get::<Option<DateTime<Utc>>, _>(idx.as_sqlx_mysql_index())
421                            .map_err(|e| sqlx_error_to_query_err(e).into())
422                            .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
423                            .map(|v| v.into())
424                    }
425                    #[cfg(feature = "sqlx-postgres")]
426                    QueryResultRow::SqlxPostgres(row) => row
427                        .try_get::<Option<$type>, _>(idx.as_sqlx_postgres_index())
428                        .map_err(|e| sqlx_error_to_query_err(e).into())
429                        .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
430                    #[cfg(feature = "sqlx-sqlite")]
431                    QueryResultRow::SqlxSqlite(row) => {
432                        use chrono::{DateTime, Utc};
433                        row.try_get::<Option<DateTime<Utc>>, _>(idx.as_sqlx_sqlite_index())
434                            .map_err(|e| sqlx_error_to_query_err(e).into())
435                            .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
436                            .map(|v| v.into())
437                    }
438                    #[cfg(feature = "mock")]
439                    QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
440                        debug_print!("{:#?}", e.to_string());
441                        err_null_idx_col(idx)
442                    }),
443                    #[cfg(feature = "proxy")]
444                    QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
445                        debug_print!("{:#?}", e.to_string());
446                        err_null_idx_col(idx)
447                    }),
448                    #[allow(unreachable_patterns)]
449                    _ => unreachable!(),
450                }
451            }
452        }
453    };
454}
455
456try_getable_all!(bool);
457try_getable_all!(i8);
458try_getable_all!(i16);
459try_getable_all!(i32);
460try_getable_all!(i64);
461try_getable_unsigned!(u8);
462try_getable_unsigned!(u16);
463try_getable_mysql!(u64);
464try_getable_all!(f32);
465try_getable_all!(f64);
466try_getable_all!(Vec<u8>);
467
468#[cfg(feature = "with-json")]
469try_getable_all!(serde_json::Value);
470
471#[cfg(feature = "with-chrono")]
472try_getable_all!(chrono::NaiveDate);
473
474#[cfg(feature = "with-chrono")]
475try_getable_all!(chrono::NaiveTime);
476
477#[cfg(feature = "with-chrono")]
478try_getable_all!(chrono::NaiveDateTime);
479
480#[cfg(feature = "with-chrono")]
481try_getable_date_time!(chrono::DateTime<chrono::FixedOffset>);
482
483#[cfg(feature = "with-chrono")]
484try_getable_all!(chrono::DateTime<chrono::Utc>);
485
486#[cfg(feature = "with-chrono")]
487try_getable_all!(chrono::DateTime<chrono::Local>);
488
489#[cfg(feature = "with-time")]
490try_getable_all!(time::Date);
491
492#[cfg(feature = "with-time")]
493try_getable_all!(time::Time);
494
495#[cfg(feature = "with-time")]
496try_getable_all!(time::PrimitiveDateTime);
497
498#[cfg(feature = "with-time")]
499try_getable_all!(time::OffsetDateTime);
500
501#[cfg(feature = "with-rust_decimal")]
502use rust_decimal::Decimal;
503
504#[cfg(feature = "with-rust_decimal")]
505impl TryGetable for Decimal {
506    #[allow(unused_variables)]
507    fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
508        match &res.row {
509            #[cfg(feature = "sqlx-mysql")]
510            QueryResultRow::SqlxMySql(row) => row
511                .try_get::<Option<Decimal>, _>(idx.as_sqlx_mysql_index())
512                .map_err(|e| sqlx_error_to_query_err(e).into())
513                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
514            #[cfg(feature = "sqlx-postgres")]
515            QueryResultRow::SqlxPostgres(row) => row
516                .try_get::<Option<Decimal>, _>(idx.as_sqlx_postgres_index())
517                .map_err(|e| sqlx_error_to_query_err(e).into())
518                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
519            #[cfg(feature = "sqlx-sqlite")]
520            QueryResultRow::SqlxSqlite(row) => {
521                let val: Option<f64> = row
522                    .try_get(idx.as_sqlx_sqlite_index())
523                    .map_err(sqlx_error_to_query_err)?;
524                match val {
525                    Some(v) => Decimal::try_from(v).map_err(|e| {
526                        DbErr::TryIntoErr {
527                            from: "f64",
528                            into: "Decimal",
529                            source: Box::new(e),
530                        }
531                        .into()
532                    }),
533                    None => Err(err_null_idx_col(idx)),
534                }
535            }
536            #[cfg(feature = "mock")]
537            #[allow(unused_variables)]
538            QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
539                debug_print!("{:#?}", e.to_string());
540                err_null_idx_col(idx)
541            }),
542            #[cfg(feature = "proxy")]
543            #[allow(unused_variables)]
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#[cfg(feature = "with-bigdecimal")]
555use bigdecimal::BigDecimal;
556
557#[cfg(feature = "with-bigdecimal")]
558impl TryGetable for BigDecimal {
559    #[allow(unused_variables)]
560    fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
561        match &res.row {
562            #[cfg(feature = "sqlx-mysql")]
563            QueryResultRow::SqlxMySql(row) => row
564                .try_get::<Option<BigDecimal>, _>(idx.as_sqlx_mysql_index())
565                .map_err(|e| sqlx_error_to_query_err(e).into())
566                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
567            #[cfg(feature = "sqlx-postgres")]
568            QueryResultRow::SqlxPostgres(row) => row
569                .try_get::<Option<BigDecimal>, _>(idx.as_sqlx_postgres_index())
570                .map_err(|e| sqlx_error_to_query_err(e).into())
571                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
572            #[cfg(feature = "sqlx-sqlite")]
573            QueryResultRow::SqlxSqlite(row) => {
574                let val: Option<f64> = row
575                    .try_get(idx.as_sqlx_sqlite_index())
576                    .map_err(sqlx_error_to_query_err)?;
577                match val {
578                    Some(v) => BigDecimal::try_from(v).map_err(|e| {
579                        DbErr::TryIntoErr {
580                            from: "f64",
581                            into: "BigDecimal",
582                            source: Box::new(e),
583                        }
584                        .into()
585                    }),
586                    None => Err(err_null_idx_col(idx)),
587                }
588            }
589            #[cfg(feature = "mock")]
590            #[allow(unused_variables)]
591            QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
592                debug_print!("{:#?}", e.to_string());
593                err_null_idx_col(idx)
594            }),
595            #[cfg(feature = "proxy")]
596            #[allow(unused_variables)]
597            QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
598                debug_print!("{:#?}", e.to_string());
599                err_null_idx_col(idx)
600            }),
601            #[allow(unreachable_patterns)]
602            _ => unreachable!(),
603        }
604    }
605}
606
607#[allow(unused_macros)]
608macro_rules! try_getable_uuid {
609    ( $type: ty, $conversion_fn: expr ) => {
610        #[allow(unused_variables, unreachable_code)]
611        impl TryGetable for $type {
612            fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
613                let res: Result<uuid::Uuid, TryGetError> = match &res.row {
614                    #[cfg(feature = "sqlx-mysql")]
615                    QueryResultRow::SqlxMySql(row) => row
616                        .try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_mysql_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                    #[cfg(feature = "sqlx-postgres")]
620                    QueryResultRow::SqlxPostgres(row) => row
621                        .try_get::<Option<uuid::Uuid>, _>(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<uuid::Uuid>, _>(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 = "mock")]
630                    #[allow(unused_variables)]
631                    QueryResultRow::Mock(row) => row.try_get::<uuid::Uuid, _>(idx).map_err(|e| {
632                        debug_print!("{:#?}", e.to_string());
633                        err_null_idx_col(idx)
634                    }),
635                    #[cfg(feature = "proxy")]
636                    #[allow(unused_variables)]
637                    QueryResultRow::Proxy(row) => row.try_get::<uuid::Uuid, _>(idx).map_err(|e| {
638                        debug_print!("{:#?}", e.to_string());
639                        err_null_idx_col(idx)
640                    }),
641                    #[allow(unreachable_patterns)]
642                    _ => unreachable!(),
643                };
644                res.map($conversion_fn)
645            }
646        }
647    };
648}
649
650#[cfg(feature = "with-uuid")]
651try_getable_uuid!(uuid::Uuid, Into::into);
652
653#[cfg(feature = "with-uuid")]
654try_getable_uuid!(uuid::fmt::Braced, uuid::Uuid::braced);
655
656#[cfg(feature = "with-uuid")]
657try_getable_uuid!(uuid::fmt::Hyphenated, uuid::Uuid::hyphenated);
658
659#[cfg(feature = "with-uuid")]
660try_getable_uuid!(uuid::fmt::Simple, uuid::Uuid::simple);
661
662#[cfg(feature = "with-uuid")]
663try_getable_uuid!(uuid::fmt::Urn, uuid::Uuid::urn);
664
665impl TryGetable for u32 {
666    #[allow(unused_variables)]
667    fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
668        match &res.row {
669            #[cfg(feature = "sqlx-mysql")]
670            QueryResultRow::SqlxMySql(row) => row
671                .try_get::<Option<u32>, _>(idx.as_sqlx_mysql_index())
672                .map_err(|e| sqlx_error_to_query_err(e).into())
673                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
674            #[cfg(feature = "sqlx-postgres")]
675            QueryResultRow::SqlxPostgres(row) => {
676                use sqlx::postgres::types::Oid;
677                // Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`;
678                // Instead, `u32` was wrapped by a `sqlx::Oid`.
679                row.try_get::<Option<Oid>, _>(idx.as_sqlx_postgres_index())
680                    .map_err(|e| sqlx_error_to_query_err(e).into())
681                    .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
682                    .map(|oid| oid.0)
683            }
684            #[cfg(feature = "sqlx-sqlite")]
685            QueryResultRow::SqlxSqlite(row) => row
686                .try_get::<Option<u32>, _>(idx.as_sqlx_sqlite_index())
687                .map_err(|e| sqlx_error_to_query_err(e).into())
688                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
689            #[cfg(feature = "mock")]
690            #[allow(unused_variables)]
691            QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
692                debug_print!("{:#?}", e.to_string());
693                err_null_idx_col(idx)
694            }),
695            #[cfg(feature = "proxy")]
696            #[allow(unused_variables)]
697            QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
698                debug_print!("{:#?}", e.to_string());
699                err_null_idx_col(idx)
700            }),
701            #[allow(unreachable_patterns)]
702            _ => unreachable!(),
703        }
704    }
705}
706
707impl TryGetable for String {
708    #[allow(unused_variables)]
709    fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
710        match &res.row {
711            #[cfg(feature = "sqlx-mysql")]
712            QueryResultRow::SqlxMySql(row) => row
713                .try_get::<Option<Vec<u8>>, _>(idx.as_sqlx_mysql_index())
714                .map_err(|e| sqlx_error_to_query_err(e).into())
715                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
716                .map(|bytes| {
717                    String::from_utf8(bytes).map_err(|e| {
718                        DbErr::TryIntoErr {
719                            from: "Vec<u8>",
720                            into: "String",
721                            source: Box::new(e),
722                        }
723                        .into()
724                    })
725                })?,
726            #[cfg(feature = "sqlx-postgres")]
727            QueryResultRow::SqlxPostgres(row) => row
728                .try_get::<Option<String>, _>(idx.as_sqlx_postgres_index())
729                .map_err(|e| sqlx_error_to_query_err(e).into())
730                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
731            #[cfg(feature = "sqlx-sqlite")]
732            QueryResultRow::SqlxSqlite(row) => row
733                .try_get::<Option<String>, _>(idx.as_sqlx_sqlite_index())
734                .map_err(|e| sqlx_error_to_query_err(e).into())
735                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
736            #[cfg(feature = "mock")]
737            QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
738                debug_print!("{:#?}", e.to_string());
739                err_null_idx_col(idx)
740            }),
741            #[cfg(feature = "proxy")]
742            QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
743                debug_print!("{:#?}", e.to_string());
744                err_null_idx_col(idx)
745            }),
746            #[allow(unreachable_patterns)]
747            _ => unreachable!(),
748        }
749    }
750}
751
752#[allow(dead_code)]
753fn err_null_idx_col<I: ColIdx>(idx: I) -> TryGetError {
754    TryGetError::Null(format!("{idx:?}"))
755}
756
757#[cfg(feature = "postgres-array")]
758mod postgres_array {
759    use super::*;
760
761    #[allow(unused_macros)]
762    macro_rules! try_getable_postgres_array {
763        ( $type: ty ) => {
764            #[allow(unused_variables)]
765            impl TryGetable for Vec<$type> {
766                fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
767                    match &res.row {
768                        #[cfg(feature = "sqlx-mysql")]
769                        QueryResultRow::SqlxMySql(_) => Err(type_err(format!(
770                            "{} unsupported by sqlx-mysql",
771                            stringify!($type)
772                        ))
773                        .into()),
774                        #[cfg(feature = "sqlx-postgres")]
775                        QueryResultRow::SqlxPostgres(row) => row
776                            .try_get::<Option<Vec<$type>>, _>(idx.as_sqlx_postgres_index())
777                            .map_err(|e| sqlx_error_to_query_err(e).into())
778                            .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
779                        #[cfg(feature = "sqlx-sqlite")]
780                        QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
781                            "{} unsupported by sqlx-sqlite",
782                            stringify!($type)
783                        ))
784                        .into()),
785                        #[cfg(feature = "mock")]
786                        #[allow(unused_variables)]
787                        QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
788                            debug_print!("{:#?}", e.to_string());
789                            err_null_idx_col(idx)
790                        }),
791                        #[cfg(feature = "proxy")]
792                        #[allow(unused_variables)]
793                        QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
794                            debug_print!("{:#?}", e.to_string());
795                            err_null_idx_col(idx)
796                        }),
797                        #[allow(unreachable_patterns)]
798                        _ => unreachable!(),
799                    }
800                }
801            }
802        };
803    }
804
805    try_getable_postgres_array!(bool);
806    try_getable_postgres_array!(i8);
807    try_getable_postgres_array!(i16);
808    try_getable_postgres_array!(i32);
809    try_getable_postgres_array!(i64);
810    try_getable_postgres_array!(f32);
811    try_getable_postgres_array!(f64);
812    try_getable_postgres_array!(String);
813
814    #[cfg(feature = "with-json")]
815    try_getable_postgres_array!(serde_json::Value);
816
817    #[cfg(feature = "with-chrono")]
818    try_getable_postgres_array!(chrono::NaiveDate);
819
820    #[cfg(feature = "with-chrono")]
821    try_getable_postgres_array!(chrono::NaiveTime);
822
823    #[cfg(feature = "with-chrono")]
824    try_getable_postgres_array!(chrono::NaiveDateTime);
825
826    #[cfg(feature = "with-chrono")]
827    try_getable_postgres_array!(chrono::DateTime<chrono::FixedOffset>);
828
829    #[cfg(feature = "with-chrono")]
830    try_getable_postgres_array!(chrono::DateTime<chrono::Utc>);
831
832    #[cfg(feature = "with-chrono")]
833    try_getable_postgres_array!(chrono::DateTime<chrono::Local>);
834
835    #[cfg(feature = "with-time")]
836    try_getable_postgres_array!(time::Date);
837
838    #[cfg(feature = "with-time")]
839    try_getable_postgres_array!(time::Time);
840
841    #[cfg(feature = "with-time")]
842    try_getable_postgres_array!(time::PrimitiveDateTime);
843
844    #[cfg(feature = "with-time")]
845    try_getable_postgres_array!(time::OffsetDateTime);
846
847    #[cfg(feature = "with-rust_decimal")]
848    try_getable_postgres_array!(rust_decimal::Decimal);
849
850    #[cfg(feature = "with-bigdecimal")]
851    try_getable_postgres_array!(bigdecimal::BigDecimal);
852
853    #[allow(unused_macros)]
854    macro_rules! try_getable_postgres_array_uuid {
855        ( $type: ty, $conversion_fn: expr ) => {
856            #[allow(unused_variables, unreachable_code)]
857            impl TryGetable for Vec<$type> {
858                fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
859                    let res: Result<Vec<uuid::Uuid>, TryGetError> = match &res.row {
860                        #[cfg(feature = "sqlx-mysql")]
861                        QueryResultRow::SqlxMySql(_) => Err(type_err(format!(
862                            "{} unsupported by sqlx-mysql",
863                            stringify!($type)
864                        ))
865                        .into()),
866                        #[cfg(feature = "sqlx-postgres")]
867                        QueryResultRow::SqlxPostgres(row) => row
868                            .try_get::<Option<Vec<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(_) => Err(type_err(format!(
873                            "{} unsupported by sqlx-sqlite",
874                            stringify!($type)
875                        ))
876                        .into()),
877                        #[cfg(feature = "mock")]
878                        QueryResultRow::Mock(row) => {
879                            row.try_get::<Vec<uuid::Uuid>, _>(idx).map_err(|e| {
880                                debug_print!("{:#?}", e.to_string());
881                                err_null_idx_col(idx)
882                            })
883                        }
884                        #[cfg(feature = "proxy")]
885                        QueryResultRow::Proxy(row) => {
886                            row.try_get::<Vec<uuid::Uuid>, _>(idx).map_err(|e| {
887                                debug_print!("{:#?}", e.to_string());
888                                err_null_idx_col(idx)
889                            })
890                        }
891                        #[allow(unreachable_patterns)]
892                        _ => unreachable!(),
893                    };
894                    res.map(|vec| vec.into_iter().map($conversion_fn).collect())
895                }
896            }
897        };
898    }
899
900    #[cfg(feature = "with-uuid")]
901    try_getable_postgres_array_uuid!(uuid::Uuid, Into::into);
902
903    #[cfg(feature = "with-uuid")]
904    try_getable_postgres_array_uuid!(uuid::fmt::Braced, uuid::Uuid::braced);
905
906    #[cfg(feature = "with-uuid")]
907    try_getable_postgres_array_uuid!(uuid::fmt::Hyphenated, uuid::Uuid::hyphenated);
908
909    #[cfg(feature = "with-uuid")]
910    try_getable_postgres_array_uuid!(uuid::fmt::Simple, uuid::Uuid::simple);
911
912    #[cfg(feature = "with-uuid")]
913    try_getable_postgres_array_uuid!(uuid::fmt::Urn, uuid::Uuid::urn);
914
915    impl TryGetable for Vec<u32> {
916        #[allow(unused_variables)]
917        fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
918            match &res.row {
919                #[cfg(feature = "sqlx-mysql")]
920                QueryResultRow::SqlxMySql(_) => {
921                    Err(type_err(format!("{} unsupported by sqlx-mysql", stringify!($type))).into())
922                }
923                #[cfg(feature = "sqlx-postgres")]
924                QueryResultRow::SqlxPostgres(row) => {
925                    use sqlx::postgres::types::Oid;
926                    // Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`;
927                    // Instead, `u32` was wrapped by a `sqlx::Oid`.
928                    row.try_get::<Option<Vec<Oid>>, _>(idx.as_sqlx_postgres_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                        .map(|oids| oids.into_iter().map(|oid| oid.0).collect())
932                }
933                #[cfg(feature = "sqlx-sqlite")]
934                QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
935                    "{} unsupported by sqlx-sqlite",
936                    stringify!($type)
937                ))
938                .into()),
939                #[cfg(feature = "mock")]
940                #[allow(unused_variables)]
941                QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
942                    debug_print!("{:#?}", e.to_string());
943                    err_null_idx_col(idx)
944                }),
945                #[cfg(feature = "proxy")]
946                #[allow(unused_variables)]
947                QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
948                    debug_print!("{:#?}", e.to_string());
949                    err_null_idx_col(idx)
950                }),
951                #[allow(unreachable_patterns)]
952                _ => unreachable!(),
953            }
954        }
955    }
956}
957
958// TryGetableMany //
959
960/// An interface to get a tuple value from the query result
961pub trait TryGetableMany: Sized {
962    /// Get a tuple value from the query result with prefixed column name
963    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
964
965    /// Get a tuple value from the query result based on the order in the select expressions
966    fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError>;
967
968    /// ```
969    /// # use sea_orm::{error::*, tests_cfg::*, *};
970    /// #
971    /// # #[smol_potat::main]
972    /// # #[cfg(all(feature = "mock", feature = "macros"))]
973    /// # pub async fn main() -> Result<(), DbErr> {
974    /// #
975    /// # let db = MockDatabase::new(DbBackend::Postgres)
976    /// #     .append_query_results([[
977    /// #         maplit::btreemap! {
978    /// #             "name" => Into::<Value>::into("Chocolate Forest"),
979    /// #             "num_of_cakes" => Into::<Value>::into(1),
980    /// #         },
981    /// #         maplit::btreemap! {
982    /// #             "name" => Into::<Value>::into("New York Cheese"),
983    /// #             "num_of_cakes" => Into::<Value>::into(1),
984    /// #         },
985    /// #     ]])
986    /// #     .into_connection();
987    /// #
988    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DeriveIden, EnumIter, TryGetableMany};
989    ///
990    /// #[derive(EnumIter, DeriveIden)]
991    /// enum ResultCol {
992    ///     Name,
993    ///     NumOfCakes,
994    /// }
995    ///
996    /// let res: Vec<(String, i32)> =
997    ///     <(String, i32)>::find_by_statement::<ResultCol>(Statement::from_sql_and_values(
998    ///         DbBackend::Postgres,
999    ///         r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
1000    ///         [],
1001    ///     ))
1002    ///     .all(&db)
1003    ///     .await?;
1004    ///
1005    /// assert_eq!(
1006    ///     res,
1007    ///     [
1008    ///         ("Chocolate Forest".to_owned(), 1),
1009    ///         ("New York Cheese".to_owned(), 1),
1010    ///     ]
1011    /// );
1012    ///
1013    /// assert_eq!(
1014    ///     db.into_transaction_log(),
1015    ///     [Transaction::from_sql_and_values(
1016    ///         DbBackend::Postgres,
1017    ///         r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
1018    ///         []
1019    ///     ),]
1020    /// );
1021    /// #
1022    /// # Ok(())
1023    /// # }
1024    /// ```
1025    fn find_by_statement<C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<Self, C>>
1026    where
1027        C: strum::IntoEnumIterator + sea_query::Iden,
1028    {
1029        SelectorRaw::<SelectGetableValue<Self, C>>::with_columns(stmt)
1030    }
1031}
1032
1033impl<T> TryGetableMany for T
1034where
1035    T: TryGetable,
1036{
1037    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1038        try_get_many_with_slice_len_of(1, cols)?;
1039        T::try_get(res, pre, &cols[0])
1040    }
1041
1042    fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1043        T::try_get_by_index(res, 0)
1044    }
1045}
1046
1047impl<T> TryGetableMany for (T,)
1048where
1049    T: TryGetableMany,
1050{
1051    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1052        T::try_get_many(res, pre, cols).map(|r| (r,))
1053    }
1054
1055    fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1056        T::try_get_many_by_index(res).map(|r| (r,))
1057    }
1058}
1059
1060macro_rules! impl_try_get_many {
1061    ( $LEN:expr, $($T:ident : $N:expr),+ $(,)? ) => {
1062        impl< $($T),+ > TryGetableMany for ( $($T),+ )
1063        where
1064            $($T: TryGetable),+
1065        {
1066            fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1067                try_get_many_with_slice_len_of($LEN, cols)?;
1068                Ok((
1069                    $($T::try_get(res, pre, &cols[$N])?),+
1070                ))
1071            }
1072
1073            fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1074                Ok((
1075                    $($T::try_get_by_index(res, $N)?),+
1076                ))
1077            }
1078        }
1079    };
1080}
1081
1082#[rustfmt::skip]
1083mod impl_try_get_many {
1084    use super::*;
1085
1086    impl_try_get_many!( 2, T0:0, T1:1);
1087    impl_try_get_many!( 3, T0:0, T1:1, T2:2);
1088    impl_try_get_many!( 4, T0:0, T1:1, T2:2, T3:3);
1089    impl_try_get_many!( 5, T0:0, T1:1, T2:2, T3:3, T4:4);
1090    impl_try_get_many!( 6, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5);
1091    impl_try_get_many!( 7, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6);
1092    impl_try_get_many!( 8, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7);
1093    impl_try_get_many!( 9, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8);
1094    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);
1095    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);
1096    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);
1097}
1098
1099fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), TryGetError> {
1100    if cols.len() < len {
1101        Err(type_err(format!(
1102            "Expect {} column names supplied but got slice of length {}",
1103            len,
1104            cols.len()
1105        ))
1106        .into())
1107    } else {
1108        Ok(())
1109    }
1110}
1111
1112/// An interface to get an array of values from the query result.
1113/// A type can only implement `ActiveEnum` or `TryGetableFromJson`, but not both.
1114/// A blanket impl is provided for `TryGetableFromJson`, while the impl for `ActiveEnum`
1115/// is provided by the `DeriveActiveEnum` macro. So as an end user you won't normally
1116/// touch this trait.
1117pub trait TryGetableArray: Sized {
1118    /// Just a delegate
1119    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Vec<Self>, TryGetError>;
1120}
1121
1122impl<T> TryGetable for Vec<T>
1123where
1124    T: TryGetableArray,
1125{
1126    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1127        T::try_get_by(res, index)
1128    }
1129}
1130
1131// TryGetableFromJson //
1132
1133/// An interface to get a JSON from the query result
1134#[cfg(feature = "with-json")]
1135pub trait TryGetableFromJson: Sized
1136where
1137    for<'de> Self: serde::Deserialize<'de>,
1138{
1139    /// Get a JSON from the query result with prefixed column name
1140    #[allow(unused_variables, unreachable_code)]
1141    fn try_get_from_json<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1142        match &res.row {
1143            #[cfg(feature = "sqlx-mysql")]
1144            QueryResultRow::SqlxMySql(row) => row
1145                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_mysql_index())
1146                .map_err(|e| sqlx_error_to_query_err(e).into())
1147                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1148            #[cfg(feature = "sqlx-postgres")]
1149            QueryResultRow::SqlxPostgres(row) => row
1150                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_postgres_index())
1151                .map_err(|e| sqlx_error_to_query_err(e).into())
1152                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1153            #[cfg(feature = "sqlx-sqlite")]
1154            QueryResultRow::SqlxSqlite(row) => row
1155                .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_sqlite_index())
1156                .map_err(|e| sqlx_error_to_query_err(e).into())
1157                .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1158            #[cfg(feature = "mock")]
1159            QueryResultRow::Mock(row) => row
1160                .try_get::<serde_json::Value, I>(idx)
1161                .map_err(|e| {
1162                    debug_print!("{:#?}", e.to_string());
1163                    err_null_idx_col(idx)
1164                })
1165                .and_then(|json| serde_json::from_value(json).map_err(|e| json_err(e).into())),
1166            #[cfg(feature = "proxy")]
1167            QueryResultRow::Proxy(row) => row
1168                .try_get::<serde_json::Value, I>(idx)
1169                .map_err(|e| {
1170                    debug_print!("{:#?}", e.to_string());
1171                    err_null_idx_col(idx)
1172                })
1173                .and_then(|json| serde_json::from_value(json).map_err(|e| json_err(e).into())),
1174            #[allow(unreachable_patterns)]
1175            _ => unreachable!(),
1176        }
1177    }
1178
1179    /// Get a Vec<Self> from an Array of Json
1180    fn from_json_vec(value: serde_json::Value) -> Result<Vec<Self>, TryGetError> {
1181        match value {
1182            serde_json::Value::Array(values) => {
1183                let mut res = Vec::new();
1184                for item in values {
1185                    res.push(serde_json::from_value(item).map_err(json_err)?);
1186                }
1187                Ok(res)
1188            }
1189            _ => Err(TryGetError::DbErr(DbErr::Json(
1190                "Value is not an Array".to_owned(),
1191            ))),
1192        }
1193    }
1194}
1195
1196#[cfg(feature = "with-json")]
1197impl<T> TryGetable for T
1198where
1199    T: TryGetableFromJson,
1200{
1201    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1202        T::try_get_from_json(res, index)
1203    }
1204}
1205
1206#[cfg(feature = "with-json")]
1207impl<T> TryGetableArray for T
1208where
1209    T: TryGetableFromJson,
1210{
1211    fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Vec<T>, TryGetError> {
1212        T::from_json_vec(serde_json::Value::try_get_by(res, index)?)
1213    }
1214}
1215
1216// TryFromU64 //
1217/// Try to convert a type to a u64
1218pub trait TryFromU64: Sized {
1219    /// The method to convert the type to a u64
1220    fn try_from_u64(n: u64) -> Result<Self, DbErr>;
1221}
1222
1223macro_rules! try_from_u64_err {
1224    ( $type: ty ) => {
1225        impl TryFromU64 for $type {
1226            fn try_from_u64(_: u64) -> Result<Self, DbErr> {
1227                Err(DbErr::ConvertFromU64(stringify!($type)))
1228            }
1229        }
1230    };
1231
1232    ( $($gen_type: ident),* ) => {
1233        impl<$( $gen_type, )*> TryFromU64 for ($( $gen_type, )*)
1234        where
1235            $( $gen_type: TryFromU64, )*
1236        {
1237            fn try_from_u64(_: u64) -> Result<Self, DbErr> {
1238                Err(DbErr::ConvertFromU64(stringify!($($gen_type,)*)))
1239            }
1240        }
1241    };
1242}
1243
1244#[rustfmt::skip]
1245mod try_from_u64_err {
1246    use super::*;
1247
1248    try_from_u64_err!(T0, T1);
1249    try_from_u64_err!(T0, T1, T2);
1250    try_from_u64_err!(T0, T1, T2, T3);
1251    try_from_u64_err!(T0, T1, T2, T3, T4);
1252    try_from_u64_err!(T0, T1, T2, T3, T4, T5);
1253    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6);
1254    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7);
1255    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
1256    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
1257    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
1258    try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
1259}
1260
1261macro_rules! try_from_u64_numeric {
1262    ( $type: ty ) => {
1263        impl TryFromU64 for $type {
1264            fn try_from_u64(n: u64) -> Result<Self, DbErr> {
1265                use std::convert::TryInto;
1266                n.try_into().map_err(|e| DbErr::TryIntoErr {
1267                    from: stringify!(u64),
1268                    into: stringify!($type),
1269                    source: Box::new(e),
1270                })
1271            }
1272        }
1273    };
1274}
1275
1276try_from_u64_numeric!(i8);
1277try_from_u64_numeric!(i16);
1278try_from_u64_numeric!(i32);
1279try_from_u64_numeric!(i64);
1280try_from_u64_numeric!(u8);
1281try_from_u64_numeric!(u16);
1282try_from_u64_numeric!(u32);
1283try_from_u64_numeric!(u64);
1284
1285macro_rules! try_from_u64_string {
1286    ( $type: ty ) => {
1287        impl TryFromU64 for $type {
1288            fn try_from_u64(n: u64) -> Result<Self, DbErr> {
1289                Ok(n.to_string())
1290            }
1291        }
1292    };
1293}
1294
1295try_from_u64_string!(String);
1296
1297try_from_u64_err!(bool);
1298try_from_u64_err!(f32);
1299try_from_u64_err!(f64);
1300try_from_u64_err!(Vec<u8>);
1301
1302#[cfg(feature = "with-json")]
1303try_from_u64_err!(serde_json::Value);
1304
1305#[cfg(feature = "with-chrono")]
1306try_from_u64_err!(chrono::NaiveDate);
1307
1308#[cfg(feature = "with-chrono")]
1309try_from_u64_err!(chrono::NaiveTime);
1310
1311#[cfg(feature = "with-chrono")]
1312try_from_u64_err!(chrono::NaiveDateTime);
1313
1314#[cfg(feature = "with-chrono")]
1315try_from_u64_err!(chrono::DateTime<chrono::FixedOffset>);
1316
1317#[cfg(feature = "with-chrono")]
1318try_from_u64_err!(chrono::DateTime<chrono::Utc>);
1319
1320#[cfg(feature = "with-chrono")]
1321try_from_u64_err!(chrono::DateTime<chrono::Local>);
1322
1323#[cfg(feature = "with-time")]
1324try_from_u64_err!(time::Date);
1325
1326#[cfg(feature = "with-time")]
1327try_from_u64_err!(time::Time);
1328
1329#[cfg(feature = "with-time")]
1330try_from_u64_err!(time::PrimitiveDateTime);
1331
1332#[cfg(feature = "with-time")]
1333try_from_u64_err!(time::OffsetDateTime);
1334
1335#[cfg(feature = "with-rust_decimal")]
1336try_from_u64_err!(rust_decimal::Decimal);
1337
1338#[cfg(feature = "with-uuid")]
1339try_from_u64_err!(uuid::Uuid);
1340
1341#[cfg(test)]
1342mod tests {
1343    use std::collections::BTreeMap;
1344
1345    use sea_query::Value;
1346
1347    use super::*;
1348
1349    #[test]
1350    fn from_try_get_error() {
1351        // TryGetError::DbErr
1352        let try_get_error = TryGetError::DbErr(DbErr::Query(RuntimeErr::Internal(
1353            "expected error message".to_owned(),
1354        )));
1355        assert_eq!(
1356            DbErr::from(try_get_error),
1357            DbErr::Query(RuntimeErr::Internal("expected error message".to_owned()))
1358        );
1359
1360        // TryGetError::Null
1361        let try_get_error = TryGetError::Null("column".to_owned());
1362        let expected = "A null value was encountered while decoding column".to_owned();
1363        assert_eq!(DbErr::from(try_get_error), DbErr::Type(expected));
1364    }
1365
1366    #[test]
1367    fn build_with_query() {
1368        use sea_orm::{DbBackend, Statement};
1369        use sea_query::*;
1370
1371        let base_query = SelectStatement::new()
1372            .column(Alias::new("id"))
1373            .expr(1i32)
1374            .column(Alias::new("next"))
1375            .column(Alias::new("value"))
1376            .from(Alias::new("table"))
1377            .to_owned();
1378
1379        let cte_referencing = SelectStatement::new()
1380            .column(Alias::new("id"))
1381            .expr(Expr::col(Alias::new("depth")).add(1i32))
1382            .column(Alias::new("next"))
1383            .column(Alias::new("value"))
1384            .from(Alias::new("table"))
1385            .join(
1386                JoinType::InnerJoin,
1387                Alias::new("cte_traversal"),
1388                Expr::col((Alias::new("cte_traversal"), Alias::new("next")))
1389                    .equals((Alias::new("table"), Alias::new("id"))),
1390            )
1391            .to_owned();
1392
1393        let common_table_expression = CommonTableExpression::new()
1394            .query(
1395                base_query
1396                    .clone()
1397                    .union(UnionType::All, cte_referencing)
1398                    .to_owned(),
1399            )
1400            .columns([
1401                Alias::new("id"),
1402                Alias::new("depth"),
1403                Alias::new("next"),
1404                Alias::new("value"),
1405            ])
1406            .table_name(Alias::new("cte_traversal"))
1407            .to_owned();
1408
1409        let select = SelectStatement::new()
1410            .column(ColumnRef::Asterisk)
1411            .from(Alias::new("cte_traversal"))
1412            .to_owned();
1413
1414        let with_clause = WithClause::new()
1415            .recursive(true)
1416            .cte(common_table_expression)
1417            .cycle(Cycle::new_from_expr_set_using(
1418                SimpleExpr::Column(ColumnRef::Column(Alias::new("id").into_iden())),
1419                Alias::new("looped"),
1420                Alias::new("traversal_path"),
1421            ))
1422            .to_owned();
1423
1424        let with_query = select.with(with_clause).to_owned();
1425
1426        assert_eq!(
1427            DbBackend::MySql.build(&with_query),
1428            Statement::from_sql_and_values(
1429                DbBackend::MySql,
1430                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`"#,
1431                [1.into(), 1.into()]
1432            )
1433        );
1434    }
1435
1436    #[test]
1437    fn column_names_from_query_result() {
1438        let mut values = BTreeMap::new();
1439        values.insert("id".to_string(), Value::Int(Some(1)));
1440        values.insert(
1441            "name".to_string(),
1442            Value::String(Some(Box::new("Abc".to_owned()))),
1443        );
1444        let query_result = QueryResult {
1445            row: QueryResultRow::Mock(crate::MockRow { values }),
1446        };
1447        assert_eq!(
1448            query_result.column_names(),
1449            vec!["id".to_owned(), "name".to_owned()]
1450        );
1451    }
1452}