From a11c57d337593e61c98090eb2af6fa021848662e Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 9 Jan 2023 14:02:23 +0800 Subject: [PATCH] Introduce ColIdx --- src/database/mock.rs | 35 ++- src/entity/active_enum.rs | 11 +- src/executor/query.rs | 588 +++++++++----------------------------- 3 files changed, 162 insertions(+), 472 deletions(-) diff --git a/src/database/mock.rs b/src/database/mock.rs index da12e858..744fa234 100644 --- a/src/database/mock.rs +++ b/src/database/mock.rs @@ -204,27 +204,26 @@ impl MockDatabaseTrait for MockDatabase { impl MockRow { /// Get a value from the [MockRow] - pub fn try_get(&self, col: &str) -> Result + pub fn try_get_by(&self, index: I) -> Result where T: ValueType, { - T::try_from(self.values.get(col).unwrap().clone()).map_err(|e| DbErr::Type(e.to_string())) - } - - /// Get a value from the [MockRow] based on the order of column name - pub fn try_get_by_index(&self, idx: usize) -> Result - where - T: ValueType, - { - let (_, value) = self - .values - .iter() - .nth(idx) - .ok_or(DbErr::Query(RuntimeErr::Internal(format!( - "Column at index {} not found", - idx - ))))?; - T::try_from(value.clone()).map_err(|e| DbErr::Type(e.to_string())) + if let Some(index) = index.as_str() { + T::try_from(self.values.get(index).unwrap().clone()) + .map_err(|e| DbErr::Type(e.to_string())) + } else if let Some(index) = index.as_usize() { + let (_, value) = + self.values + .iter() + .nth(*index) + .ok_or(DbErr::Query(RuntimeErr::Internal(format!( + "Column at index {} not found", + index + ))))?; + T::try_from(value.clone()).map_err(|e| DbErr::Type(e.to_string())) + } else { + unreachable!("Missing ColIdx implementation for MockRow"); + } } /// An iterator over the keys and values of a mock row diff --git a/src/entity/active_enum.rs b/src/entity/active_enum.rs index 6fdf676a..229f6197 100644 --- a/src/entity/active_enum.rs +++ b/src/entity/active_enum.rs @@ -152,15 +152,8 @@ where T: ActiveEnum, T::ValueVec: TryGetable, { - fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - ::try_get(res, pre, col)? - .into_iter() - .map(|value| T::try_from_value(&value).map_err(TryGetError::DbErr)) - .collect() - } - - fn try_get_by_index(res: &QueryResult, idx: usize) -> Result { - ::try_get_by_index(res, idx)? + fn try_get_by(res: &QueryResult, index: I) -> Result { + ::try_get_by(res, index)? .into_iter() .map(|value| T::try_from_value(&value).map_err(TryGetError::DbErr)) .collect() diff --git a/src/executor/query.rs b/src/executor/query.rs index ba682c32..479dfbb1 100644 --- a/src/executor/query.rs +++ b/src/executor/query.rs @@ -23,11 +23,19 @@ pub(crate) enum QueryResultRow { /// An interface to get a value from the query result pub trait TryGetable: Sized { + /// Get a value from the query result with an ColIdx + fn try_get_by(res: &QueryResult, index: I) -> Result; + /// Get a value from the query result with prefixed column name - fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result; + fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { + let index = format!("{}{}", pre, col); + Self::try_get_by(res, index.as_str()) + } /// Get a value from the query result based on the order in the select expressions - fn try_get_by_index(res: &QueryResult, idx: usize) -> Result; + fn try_get_by_index(res: &QueryResult, index: usize) -> Result { + Self::try_get_by(res, index) + } } /// An error from trying to get a row from a Model @@ -107,16 +115,8 @@ impl fmt::Debug for QueryResultRow { // TryGetable // impl TryGetable for Option { - fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - match T::try_get(res, pre, col) { - Ok(v) => Ok(Some(v)), - Err(TryGetError::Null(_)) => Ok(None), - Err(e) => Err(e), - } - } - - fn try_get_by_index(res: &QueryResult, idx: usize) -> Result { - match T::try_get_by_index(res, idx) { + fn try_get_by(res: &QueryResult, index: I) -> Result { + match T::try_get_by(res, index) { Ok(v) => Ok(Some(v)), Err(TryGetError::Null(_)) => Ok(None), Err(e) => Err(e), @@ -124,74 +124,119 @@ impl TryGetable for Option { } } +pub trait ColIdx: std::fmt::Debug { + #[cfg(feature = "sqlx-mysql")] + type SqlxMySqlIndex: sqlx::ColumnIndex; + #[cfg(feature = "sqlx-postgres")] + type SqlxPostgresIndex: sqlx::ColumnIndex; + #[cfg(feature = "sqlx-sqlite")] + type SqlxSqliteIndex: sqlx::ColumnIndex; + + #[cfg(feature = "sqlx-mysql")] + fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex; + #[cfg(feature = "sqlx-postgres")] + fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex; + #[cfg(feature = "sqlx-sqlite")] + fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex; + + fn as_str(&self) -> Option<&str>; + fn as_usize(&self) -> Option<&usize>; +} + +impl ColIdx for &str { + #[cfg(feature = "sqlx-mysql")] + type SqlxMySqlIndex = Self; + #[cfg(feature = "sqlx-postgres")] + type SqlxPostgresIndex = Self; + #[cfg(feature = "sqlx-sqlite")] + type SqlxSqliteIndex = Self; + + #[cfg(feature = "sqlx-mysql")] + fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex { + self + } + #[cfg(feature = "sqlx-postgres")] + fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex { + self + } + #[cfg(feature = "sqlx-sqlite")] + fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex { + self + } + + #[inline] + fn as_str(&self) -> Option<&str> { + Some(self) + } + #[inline] + fn as_usize(&self) -> Option<&usize> { + None + } +} + +impl ColIdx for usize { + #[cfg(feature = "sqlx-mysql")] + type SqlxMySqlIndex = Self; + #[cfg(feature = "sqlx-postgres")] + type SqlxPostgresIndex = Self; + #[cfg(feature = "sqlx-sqlite")] + type SqlxSqliteIndex = Self; + + #[cfg(feature = "sqlx-mysql")] + fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex { + *self + } + #[cfg(feature = "sqlx-postgres")] + fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex { + *self + } + #[cfg(feature = "sqlx-sqlite")] + fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex { + *self + } + + #[inline] + fn as_str(&self) -> Option<&str> { + None + } + #[inline] + fn as_usize(&self) -> Option<&usize> { + Some(self) + } +} + macro_rules! try_getable_all { ( $type: ty ) => { #[allow(unused_variables)] impl TryGetable for $type { - fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - let column = format!("{}{}", pre, col); + fn try_get_by(res: &QueryResult, idx: I) -> Result { match &res.row { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(row) => { use sqlx::Row; - row.try_get::, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - } - #[cfg(feature = "sqlx-postgres")] - QueryResultRow::SqlxPostgres(row) => { - use sqlx::Row; - row.try_get::, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - } - #[cfg(feature = "sqlx-sqlite")] - QueryResultRow::SqlxSqlite(row) => { - use sqlx::Row; - row.try_get::, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - } - #[cfg(feature = "mock")] - #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get(column.as_str()).map_err(|e| { - debug_print!("{:#?}", e.to_string()); - TryGetError::Null(column) - }), - #[allow(unreachable_patterns)] - _ => unreachable!(), - } - } - - #[allow(unused_variables)] - fn try_get_by_index(res: &QueryResult, idx: usize) -> Result { - match &res.row { - #[cfg(feature = "sqlx-mysql")] - QueryResultRow::SqlxMySql(row) => { - use sqlx::Row; - row.try_get::, _>(idx) + row.try_get::, _>(idx.as_sqlx_mysql_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) } #[cfg(feature = "sqlx-postgres")] QueryResultRow::SqlxPostgres(row) => { use sqlx::Row; - row.try_get::, _>(idx) + row.try_get::, _>(idx.as_sqlx_postgres_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) } #[cfg(feature = "sqlx-sqlite")] QueryResultRow::SqlxSqlite(row) => { use sqlx::Row; - row.try_get::, _>(idx) + row.try_get::, _>(idx.as_sqlx_sqlite_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) } #[cfg(feature = "mock")] #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get_by_index(idx).map_err(|e| { + QueryResultRow::Mock(row) => row.try_get_by(idx).map_err(|e| { debug_print!("{:#?}", e.to_string()); - TryGetError::Null(idx.to_string()) + err_null_idx_col(idx) }), #[allow(unreachable_patterns)] _ => unreachable!(), @@ -204,46 +249,12 @@ macro_rules! try_getable_all { macro_rules! try_getable_unsigned { ( $type: ty ) => { impl TryGetable for $type { - fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - #[allow(unused_variables)] - let column = format!("{}{}", pre, col); + fn try_get_by(res: &QueryResult, idx: I) -> Result { match &res.row { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(row) => { use sqlx::Row; - row.try_get::, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - } - #[cfg(feature = "sqlx-postgres")] - QueryResultRow::SqlxPostgres(_) => { - panic!("{} unsupported by sqlx-postgres", stringify!($type)) - } - #[cfg(feature = "sqlx-sqlite")] - QueryResultRow::SqlxSqlite(row) => { - use sqlx::Row; - row.try_get::, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - } - #[cfg(feature = "mock")] - #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get(column.as_str()).map_err(|e| { - debug_print!("{:#?}", e.to_string()); - TryGetError::Null(column) - }), - #[allow(unreachable_patterns)] - _ => unreachable!(), - } - } - - #[allow(unused_variables)] - fn try_get_by_index(res: &QueryResult, idx: usize) -> Result { - match &res.row { - #[cfg(feature = "sqlx-mysql")] - QueryResultRow::SqlxMySql(row) => { - use sqlx::Row; - row.try_get::, _>(idx) + row.try_get::, _>(idx.as_sqlx_mysql_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) } @@ -254,13 +265,13 @@ macro_rules! try_getable_unsigned { #[cfg(feature = "sqlx-sqlite")] QueryResultRow::SqlxSqlite(row) => { use sqlx::Row; - row.try_get::, _>(idx) + row.try_get::, _>(idx.as_sqlx_sqlite_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) } #[cfg(feature = "mock")] #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get_by_index(idx).map_err(|e| { + QueryResultRow::Mock(row) => row.try_get_by(idx).map_err(|e| { debug_print!("{:#?}", e.to_string()); err_null_idx_col(idx) }), @@ -275,43 +286,12 @@ macro_rules! try_getable_unsigned { macro_rules! try_getable_mysql { ( $type: ty ) => { impl TryGetable for $type { - fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - #[allow(unused_variables)] - let column = format!("{}{}", pre, col); + fn try_get_by(res: &QueryResult, idx: I) -> Result { match &res.row { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(row) => { use sqlx::Row; - row.try_get::, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - } - #[cfg(feature = "sqlx-postgres")] - QueryResultRow::SqlxPostgres(_) => { - panic!("{} unsupported by sqlx-postgres", stringify!($type)) - } - #[cfg(feature = "sqlx-sqlite")] - QueryResultRow::SqlxSqlite(_) => { - panic!("{} unsupported by sqlx-sqlite", stringify!($type)) - } - #[cfg(feature = "mock")] - #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get(column.as_str()).map_err(|e| { - debug_print!("{:#?}", e.to_string()); - TryGetError::Null(column) - }), - #[allow(unreachable_patterns)] - _ => unreachable!(), - } - } - - #[allow(unused_variables)] - fn try_get_by_index(res: &QueryResult, idx: usize) -> Result { - match &res.row { - #[cfg(feature = "sqlx-mysql")] - QueryResultRow::SqlxMySql(row) => { - use sqlx::Row; - row.try_get::, _>(idx) + row.try_get::, _>(idx.as_sqlx_mysql_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) } @@ -325,7 +305,7 @@ macro_rules! try_getable_mysql { } #[cfg(feature = "mock")] #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get_by_index(idx).map_err(|e| { + QueryResultRow::Mock(row) => row.try_get_by(idx).map_err(|e| { debug_print!("{:#?}", e.to_string()); err_null_idx_col(idx) }), @@ -341,54 +321,13 @@ macro_rules! try_getable_mysql { macro_rules! try_getable_date_time { ( $type: ty ) => { impl TryGetable for $type { - fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - #[allow(unused_variables)] - let column = format!("{}{}", pre, col); + fn try_get_by(res: &QueryResult, idx: I) -> Result { match &res.row { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(row) => { use chrono::{DateTime, Utc}; use sqlx::Row; - row.try_get::>, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - .map(|v| v.into()) - } - #[cfg(feature = "sqlx-postgres")] - QueryResultRow::SqlxPostgres(row) => { - use sqlx::Row; - row.try_get::, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - } - #[cfg(feature = "sqlx-sqlite")] - QueryResultRow::SqlxSqlite(row) => { - use chrono::{DateTime, Utc}; - use sqlx::Row; - row.try_get::>, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - .map(|v| v.into()) - } - #[cfg(feature = "mock")] - #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get(column.as_str()).map_err(|e| { - debug_print!("{:#?}", e.to_string()); - TryGetError::Null(column) - }), - #[allow(unreachable_patterns)] - _ => unreachable!(), - } - } - - #[allow(unused_variables)] - fn try_get_by_index(res: &QueryResult, idx: usize) -> Result { - match &res.row { - #[cfg(feature = "sqlx-mysql")] - QueryResultRow::SqlxMySql(row) => { - use chrono::{DateTime, Utc}; - use sqlx::Row; - row.try_get::>, _>(idx) + row.try_get::>, _>(idx.as_sqlx_mysql_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) .map(|v| v.into()) @@ -396,7 +335,7 @@ macro_rules! try_getable_date_time { #[cfg(feature = "sqlx-postgres")] QueryResultRow::SqlxPostgres(row) => { use sqlx::Row; - row.try_get::, _>(idx) + row.try_get::, _>(idx.as_sqlx_postgres_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) } @@ -404,14 +343,14 @@ macro_rules! try_getable_date_time { QueryResultRow::SqlxSqlite(row) => { use chrono::{DateTime, Utc}; use sqlx::Row; - row.try_get::>, _>(idx) + row.try_get::>, _>(idx.as_sqlx_sqlite_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) .map(|v| v.into()) } #[cfg(feature = "mock")] #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get_by_index(idx).map_err(|e| { + QueryResultRow::Mock(row) => row.try_get_by(idx).map_err(|e| { debug_print!("{:#?}", e.to_string()); err_null_idx_col(idx) }), @@ -475,65 +414,19 @@ use rust_decimal::Decimal; #[cfg(feature = "with-rust_decimal")] impl TryGetable for Decimal { #[allow(unused_variables)] - fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - let column = format!("{}{}", pre, col); + fn try_get_by(res: &QueryResult, idx: I) -> Result { match &res.row { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(row) => { use sqlx::Row; - row.try_get::, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - } - #[cfg(feature = "sqlx-postgres")] - QueryResultRow::SqlxPostgres(row) => { - use sqlx::Row; - row.try_get::, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - } - #[cfg(feature = "sqlx-sqlite")] - QueryResultRow::SqlxSqlite(row) => { - use sqlx::Row; - let val: Option = row - .try_get(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))?; - match val { - Some(v) => Decimal::try_from(v).map_err(|e| { - TryGetError::DbErr(DbErr::TryIntoErr { - from: "f64", - into: "Decimal", - source: Box::new(e), - }) - }), - None => Err(TryGetError::Null(column)), - } - } - #[cfg(feature = "mock")] - #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get(column.as_str()).map_err(|e| { - debug_print!("{:#?}", e.to_string()); - TryGetError::Null(column) - }), - #[allow(unreachable_patterns)] - _ => unreachable!(), - } - } - - #[allow(unused_variables)] - fn try_get_by_index(res: &QueryResult, idx: usize) -> Result { - match &res.row { - #[cfg(feature = "sqlx-mysql")] - QueryResultRow::SqlxMySql(row) => { - use sqlx::Row; - row.try_get::, _>(idx) + row.try_get::, _>(idx.as_sqlx_mysql_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) } #[cfg(feature = "sqlx-postgres")] QueryResultRow::SqlxPostgres(row) => { use sqlx::Row; - row.try_get::, _>(idx) + row.try_get::, _>(idx.as_sqlx_postgres_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) } @@ -541,7 +434,7 @@ impl TryGetable for Decimal { QueryResultRow::SqlxSqlite(row) => { use sqlx::Row; let val: Option = row - .try_get(idx) + .try_get((idx.as_sqlx_sqlite_index())) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))?; match val { Some(v) => Decimal::try_from(v).map_err(|e| { @@ -556,7 +449,7 @@ impl TryGetable for Decimal { } #[cfg(feature = "mock")] #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get_by_index(idx).map_err(|e| { + QueryResultRow::Mock(row) => row.try_get_by(idx).map_err(|e| { debug_print!("{:#?}", e.to_string()); err_null_idx_col(idx) }), @@ -572,65 +465,19 @@ use bigdecimal::BigDecimal; #[cfg(feature = "with-bigdecimal")] impl TryGetable for BigDecimal { #[allow(unused_variables)] - fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - let column = format!("{}{}", pre, col); + fn try_get_by(res: &QueryResult, idx: I) -> Result { match &res.row { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(row) => { use sqlx::Row; - row.try_get::, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - } - #[cfg(feature = "sqlx-postgres")] - QueryResultRow::SqlxPostgres(row) => { - use sqlx::Row; - row.try_get::, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - } - #[cfg(feature = "sqlx-sqlite")] - QueryResultRow::SqlxSqlite(row) => { - use sqlx::Row; - let val: Option = row - .try_get(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))?; - match val { - Some(v) => BigDecimal::try_from(v).map_err(|e| { - TryGetError::DbErr(DbErr::TryIntoErr { - from: "f64", - into: "BigDecimal", - source: Box::new(e), - }) - }), - None => Err(TryGetError::Null(column)), - } - } - #[cfg(feature = "mock")] - #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get(column.as_str()).map_err(|e| { - debug_print!("{:#?}", e.to_string()); - TryGetError::Null(column) - }), - #[allow(unreachable_patterns)] - _ => unreachable!(), - } - } - - #[allow(unused_variables)] - fn try_get_by_index(res: &QueryResult, idx: usize) -> Result { - match &res.row { - #[cfg(feature = "sqlx-mysql")] - QueryResultRow::SqlxMySql(row) => { - use sqlx::Row; - row.try_get::, _>(idx) + row.try_get::, _>((idx.as_sqlx_mysql_index())) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) } #[cfg(feature = "sqlx-postgres")] QueryResultRow::SqlxPostgres(row) => { use sqlx::Row; - row.try_get::, _>(idx) + row.try_get::, _>((idx.as_sqlx_postgres_index())) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) } @@ -638,7 +485,7 @@ impl TryGetable for BigDecimal { QueryResultRow::SqlxSqlite(row) => { use sqlx::Row; let val: Option = row - .try_get(idx) + .try_get((idx.as_sqlx_sqlite_index())) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))?; match val { Some(v) => BigDecimal::try_from(v).map_err(|e| { @@ -653,7 +500,7 @@ impl TryGetable for BigDecimal { } #[cfg(feature = "mock")] #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get_by_index(idx).map_err(|e| { + QueryResultRow::Mock(row) => row.try_get_by(idx).map_err(|e| { debug_print!("{:#?}", e.to_string()); err_null_idx_col(idx) }), @@ -667,53 +514,12 @@ impl TryGetable for BigDecimal { try_getable_all!(uuid::Uuid); impl TryGetable for u32 { - fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - #[allow(unused_variables)] - let column = format!("{}{}", pre, col); + fn try_get_by(res: &QueryResult, idx: I) -> Result { match &res.row { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(row) => { use sqlx::Row; - row.try_get::, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - } - #[cfg(feature = "sqlx-postgres")] - QueryResultRow::SqlxPostgres(row) => { - use sqlx::postgres::types::Oid; - // Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`; - // Instead, `u32` was wrapped by a `sqlx::Oid`. - use sqlx::Row; - row.try_get::, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - .map(|oid| oid.0) - } - #[cfg(feature = "sqlx-sqlite")] - QueryResultRow::SqlxSqlite(row) => { - use sqlx::Row; - row.try_get::, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - } - #[cfg(feature = "mock")] - #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get(column.as_str()).map_err(|e| { - debug_print!("{:#?}", e.to_string()); - TryGetError::Null(column) - }), - #[allow(unreachable_patterns)] - _ => unreachable!(), - } - } - - #[allow(unused_variables)] - fn try_get_by_index(res: &QueryResult, idx: usize) -> Result { - match &res.row { - #[cfg(feature = "sqlx-mysql")] - QueryResultRow::SqlxMySql(row) => { - use sqlx::Row; - row.try_get::, _>(idx) + row.try_get::, _>(idx.as_sqlx_mysql_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) } @@ -723,7 +529,7 @@ impl TryGetable for u32 { // Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`; // Instead, `u32` was wrapped by a `sqlx::Oid`. use sqlx::Row; - row.try_get::, _>(idx) + row.try_get::, _>(idx.as_sqlx_postgres_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) .map(|oid| oid.0) @@ -731,13 +537,13 @@ impl TryGetable for u32 { #[cfg(feature = "sqlx-sqlite")] QueryResultRow::SqlxSqlite(row) => { use sqlx::Row; - row.try_get::, _>(idx) + row.try_get::, _>(idx.as_sqlx_sqlite_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) } #[cfg(feature = "mock")] #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get_by_index(idx).map_err(|e| { + QueryResultRow::Mock(row) => row.try_get_by(idx).map_err(|e| { debug_print!("{:#?}", e.to_string()); err_null_idx_col(idx) }), @@ -748,8 +554,8 @@ impl TryGetable for u32 { } #[allow(dead_code)] -fn err_null_idx_col(idx: usize) -> TryGetError { - TryGetError::Null(format!("column at index {}", idx)) +fn err_null_idx_col(idx: I) -> TryGetError { + TryGetError::Null(format!("{:?}", idx)) } #[cfg(feature = "postgres-array")] @@ -760,9 +566,7 @@ mod postgres_array { macro_rules! try_getable_postgres_array { ( $type: ty ) => { impl TryGetable for Vec<$type> { - #[allow(unused_variables)] - fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - let column = format!("{}{}", pre, col); + fn try_get_by(res: &QueryResult, idx: I) -> Result { match &res.row { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(_) => { @@ -771,35 +575,7 @@ mod postgres_array { #[cfg(feature = "sqlx-postgres")] QueryResultRow::SqlxPostgres(row) => { use sqlx::Row; - row.try_get::>, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - } - #[cfg(feature = "sqlx-sqlite")] - QueryResultRow::SqlxSqlite(_) => { - panic!("{} unsupported by sqlx-sqlite", stringify!($type)) - } - #[cfg(feature = "mock")] - QueryResultRow::Mock(row) => row.try_get(column.as_str()).map_err(|e| { - debug_print!("{:#?}", e.to_string()); - TryGetError::Null(column) - }), - #[allow(unreachable_patterns)] - _ => unreachable!(), - } - } - - #[allow(unused_variables)] - fn try_get_by_index(res: &QueryResult, idx: usize) -> Result { - match &res.row { - #[cfg(feature = "sqlx-mysql")] - QueryResultRow::SqlxMySql(_) => { - panic!("{} unsupported by sqlx-mysql", stringify!($type)) - } - #[cfg(feature = "sqlx-postgres")] - QueryResultRow::SqlxPostgres(row) => { - use sqlx::Row; - row.try_get::>, _>(idx) + row.try_get::>, _>((idx.as_sqlx_postgres_index())) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) } @@ -808,7 +584,8 @@ mod postgres_array { panic!("{} unsupported by sqlx-sqlite", stringify!($type)) } #[cfg(feature = "mock")] - QueryResultRow::Mock(row) => row.try_get_by_index(idx).map_err(|e| { + #[allow(unused_variables)] + QueryResultRow::Mock(row) => row.try_get_by(idx).map_err(|e| { debug_print!("{:#?}", e.to_string()); err_null_idx_col(idx) }), @@ -872,9 +649,7 @@ mod postgres_array { try_getable_postgres_array!(uuid::Uuid); impl TryGetable for Vec { - #[allow(unused_variables)] - fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - let column = format!("{}{}", pre, col); + fn try_get_by(res: &QueryResult, idx: I) -> Result { match &res.row { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(_) => { @@ -886,39 +661,7 @@ mod postgres_array { // Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`; // Instead, `u32` was wrapped by a `sqlx::Oid`. use sqlx::Row; - row.try_get::>, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column))) - .map(|oids| oids.into_iter().map(|oid| oid.0).collect()) - } - #[cfg(feature = "sqlx-sqlite")] - QueryResultRow::SqlxSqlite(_) => { - panic!("{} unsupported by sqlx-sqlite", stringify!($type)) - } - #[cfg(feature = "mock")] - QueryResultRow::Mock(row) => row.try_get(column.as_str()).map_err(|e| { - debug_print!("{:#?}", e.to_string()); - TryGetError::Null(column) - }), - #[allow(unreachable_patterns)] - _ => unreachable!(), - } - } - - #[allow(unused_variables)] - fn try_get_by_index(res: &QueryResult, idx: usize) -> Result { - match &res.row { - #[cfg(feature = "sqlx-mysql")] - QueryResultRow::SqlxMySql(_) => { - panic!("{} unsupported by sqlx-mysql", stringify!($type)) - } - #[cfg(feature = "sqlx-postgres")] - QueryResultRow::SqlxPostgres(row) => { - use sqlx::postgres::types::Oid; - // Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`; - // Instead, `u32` was wrapped by a `sqlx::Oid`. - use sqlx::Row; - row.try_get::>, _>(idx) + row.try_get::>, _>((idx.as_sqlx_postgres_index())) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx))) .map(|oids| oids.into_iter().map(|oid| oid.0).collect()) @@ -928,7 +671,8 @@ mod postgres_array { panic!("{} unsupported by sqlx-sqlite", stringify!($type)) } #[cfg(feature = "mock")] - QueryResultRow::Mock(row) => row.try_get_by_index(idx).map_err(|e| { + #[allow(unused_variables)] + QueryResultRow::Mock(row) => row.try_get_by(idx).map_err(|e| { debug_print!("{:#?}", e.to_string()); err_null_idx_col(idx) }), @@ -1195,74 +939,32 @@ where { /// Get a JSON from the query result with prefixed column name #[allow(unused_variables, unreachable_code)] - fn try_get_from_json(res: &QueryResult, pre: &str, col: &str) -> Result { - let column = format!("{}{}", pre, col); + fn try_get_from_json(res: &QueryResult, idx: I) -> Result { match &res.row { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(row) => { use sqlx::Row; - row.try_get::>, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column)).map(|json| json.0)) - } - #[cfg(feature = "sqlx-postgres")] - QueryResultRow::SqlxPostgres(row) => { - use sqlx::Row; - row.try_get::>, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column)).map(|json| json.0)) - } - #[cfg(feature = "sqlx-sqlite")] - QueryResultRow::SqlxSqlite(row) => { - use sqlx::Row; - row.try_get::>, _>(column.as_str()) - .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) - .and_then(|opt| opt.ok_or(TryGetError::Null(column)).map(|json| json.0)) - } - #[cfg(feature = "mock")] - QueryResultRow::Mock(row) => row - .try_get::(column.as_str()) - .map_err(|e| { - debug_print!("{:#?}", e.to_string()); - TryGetError::Null(column) - }) - .and_then(|json| { - serde_json::from_value(json) - .map_err(|e| TryGetError::DbErr(DbErr::Json(e.to_string()))) - }), - #[allow(unreachable_patterns)] - _ => unreachable!(), - } - } - - /// Get a JSON from the query result based on the order in the select expressions - #[allow(unused_variables)] - fn try_get_from_json_by_index(res: &QueryResult, idx: usize) -> Result { - match &res.row { - #[cfg(feature = "sqlx-mysql")] - QueryResultRow::SqlxMySql(row) => { - use sqlx::Row; - row.try_get::>, _>(idx) + row.try_get::>, _>(idx.as_sqlx_mysql_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx)).map(|json| json.0)) } #[cfg(feature = "sqlx-postgres")] QueryResultRow::SqlxPostgres(row) => { use sqlx::Row; - row.try_get::>, _>(idx) + row.try_get::>, _>(idx.as_sqlx_postgres_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx)).map(|json| json.0)) } #[cfg(feature = "sqlx-sqlite")] QueryResultRow::SqlxSqlite(row) => { use sqlx::Row; - row.try_get::>, _>(idx) + row.try_get::>, _>(idx.as_sqlx_sqlite_index()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(err_null_idx_col(idx)).map(|json| json.0)) } #[cfg(feature = "mock")] QueryResultRow::Mock(row) => row - .try_get_by_index::(idx) + .try_get_by::(idx) .map_err(|e| { debug_print!("{:#?}", e.to_string()); err_null_idx_col(idx) @@ -1282,12 +984,8 @@ impl TryGetable for T where T: TryGetableFromJson, { - fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - T::try_get_from_json(res, pre, col) - } - - fn try_get_by_index(res: &QueryResult, idx: usize) -> Result { - T::try_get_from_json_by_index(res, idx) + fn try_get_by(res: &QueryResult, index: I) -> Result { + T::try_get_from_json(res, index) } }