Select into tuple
This commit is contained in:
parent
5b9c49a9a0
commit
70c4a3a23e
@ -356,6 +356,11 @@ impl ActiveEnum {
|
||||
let value = <<Self as sea_orm::ActiveEnum>::Value as sea_orm::TryGetable>::try_get(res, pre, col)?;
|
||||
<Self as sea_orm::ActiveEnum>::try_from_value(&value).map_err(sea_orm::TryGetError::DbErr)
|
||||
}
|
||||
|
||||
fn try_get_by_index(res: &sea_orm::QueryResult, idx: usize) -> std::result::Result<Self, sea_orm::TryGetError> {
|
||||
let value = <<Self as sea_orm::ActiveEnum>::Value as sea_orm::TryGetable>::try_get_by_index(res, idx)?;
|
||||
<Self as sea_orm::ActiveEnum>::try_from_value(&value).map_err(sea_orm::TryGetError::DbErr)
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
|
@ -211,6 +211,21 @@ impl MockRow {
|
||||
T::try_from(self.values.get(col).unwrap().clone()).map_err(|e| DbErr::Type(e.to_string()))
|
||||
}
|
||||
|
||||
pub fn try_get_by_index<T>(&self, idx: usize) -> Result<T, DbErr>
|
||||
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()))
|
||||
}
|
||||
|
||||
/// An iterator over the keys and values of a mock row
|
||||
pub fn into_column_value_tuples(self) -> impl Iterator<Item = (String, Value)> {
|
||||
self.values.into_iter()
|
||||
|
@ -158,6 +158,13 @@ where
|
||||
.map(|value| T::try_from_value(&value).map_err(TryGetError::DbErr))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn try_get_by_index(res: &QueryResult, idx: usize) -> Result<Self, TryGetError> {
|
||||
<T::ValueVec as TryGetable>::try_get_by_index(res, idx)?
|
||||
.into_iter()
|
||||
.map(|value| T::try_from_value(&value).map_err(TryGetError::DbErr))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -21,10 +21,13 @@ pub(crate) enum QueryResultRow {
|
||||
Mock(crate::MockRow),
|
||||
}
|
||||
|
||||
/// Constrain any type trying to get a Row in a database
|
||||
/// An interface to get a value from the query result
|
||||
pub trait TryGetable: Sized {
|
||||
/// Ensure the type implements this method
|
||||
/// Get a value from the query result with prefixed column name
|
||||
fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError>;
|
||||
|
||||
/// 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<Self, TryGetError>;
|
||||
}
|
||||
|
||||
/// An error from trying to get a row from a Model
|
||||
@ -58,6 +61,13 @@ impl QueryResult {
|
||||
Ok(T::try_get(self, pre, col)?)
|
||||
}
|
||||
|
||||
pub fn try_get_by_index<T>(&self, idx: usize) -> Result<T, DbErr>
|
||||
where
|
||||
T: TryGetable,
|
||||
{
|
||||
Ok(T::try_get_by_index(self, idx)?)
|
||||
}
|
||||
|
||||
/// Perform query operations on multiple Columns
|
||||
pub fn try_get_many<T>(&self, pre: &str, cols: &[String]) -> Result<T, DbErr>
|
||||
where
|
||||
@ -65,6 +75,13 @@ impl QueryResult {
|
||||
{
|
||||
Ok(T::try_get_many(self, pre, cols)?)
|
||||
}
|
||||
|
||||
pub fn try_get_many_by_index<T>(&self) -> Result<T, DbErr>
|
||||
where
|
||||
T: TryGetableMany,
|
||||
{
|
||||
Ok(T::try_get_many_by_index(self)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
@ -95,6 +112,14 @@ impl<T: TryGetable> TryGetable for Option<T> {
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_by_index(res: &QueryResult, idx: usize) -> Result<Self, TryGetError> {
|
||||
match T::try_get_by_index(res, idx) {
|
||||
Ok(v) => Ok(Some(v)),
|
||||
Err(TryGetError::Null(_)) => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! try_getable_all {
|
||||
@ -135,6 +160,40 @@ macro_rules! try_getable_all {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_by_index(res: &QueryResult, idx: usize) -> Result<Self, TryGetError> {
|
||||
match &res.row {
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
QueryResultRow::SqlxMySql(row) => {
|
||||
use sqlx::Row;
|
||||
row.try_get::<Option<$type>, _>(idx)
|
||||
.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::<Option<$type>, _>(idx)
|
||||
.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::<Option<$type>, _>(idx)
|
||||
.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| {
|
||||
debug_print!("{:#?}", e.to_string());
|
||||
TryGetError::Null(idx.to_string())
|
||||
}),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -174,6 +233,37 @@ macro_rules! try_getable_unsigned {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_by_index(res: &QueryResult, idx: usize) -> Result<Self, TryGetError> {
|
||||
match &res.row {
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
QueryResultRow::SqlxMySql(row) => {
|
||||
use sqlx::Row;
|
||||
row.try_get::<Option<$type>, _>(idx)
|
||||
.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(_) => {
|
||||
panic!("{} unsupported by sqlx-postgres", stringify!($type))
|
||||
}
|
||||
#[cfg(feature = "sqlx-sqlite")]
|
||||
QueryResultRow::SqlxSqlite(row) => {
|
||||
use sqlx::Row;
|
||||
row.try_get::<Option<$type>, _>(idx)
|
||||
.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| {
|
||||
debug_print!("{:#?}", e.to_string());
|
||||
err_null_idx_col(idx)
|
||||
}),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -210,6 +300,34 @@ macro_rules! try_getable_mysql {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_by_index(res: &QueryResult, idx: usize) -> Result<Self, TryGetError> {
|
||||
match &res.row {
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
QueryResultRow::SqlxMySql(row) => {
|
||||
use sqlx::Row;
|
||||
row.try_get::<Option<$type>, _>(idx)
|
||||
.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(_) => {
|
||||
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_by_index(idx).map_err(|e| {
|
||||
debug_print!("{:#?}", e.to_string());
|
||||
err_null_idx_col(idx)
|
||||
}),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -257,6 +375,44 @@ macro_rules! try_getable_date_time {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_by_index(res: &QueryResult, idx: usize) -> Result<Self, TryGetError> {
|
||||
match &res.row {
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
QueryResultRow::SqlxMySql(row) => {
|
||||
use chrono::{DateTime, Utc};
|
||||
use sqlx::Row;
|
||||
row.try_get::<Option<DateTime<Utc>>, _>(idx)
|
||||
.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 = "sqlx-postgres")]
|
||||
QueryResultRow::SqlxPostgres(row) => {
|
||||
use sqlx::Row;
|
||||
row.try_get::<Option<$type>, _>(idx)
|
||||
.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 chrono::{DateTime, Utc};
|
||||
use sqlx::Row;
|
||||
row.try_get::<Option<DateTime<Utc>>, _>(idx)
|
||||
.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| {
|
||||
debug_print!("{:#?}", e.to_string());
|
||||
err_null_idx_col(idx)
|
||||
}),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -357,6 +513,50 @@ impl TryGetable for Decimal {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_by_index(res: &QueryResult, idx: usize) -> Result<Self, TryGetError> {
|
||||
match &res.row {
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
QueryResultRow::SqlxMySql(row) => {
|
||||
use sqlx::Row;
|
||||
row.try_get::<Option<Decimal>, _>(idx)
|
||||
.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::<Option<Decimal>, _>(idx)
|
||||
.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;
|
||||
let val: Option<f64> = row
|
||||
.try_get(idx)
|
||||
.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(err_null_idx_col(idx)),
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "mock")]
|
||||
#[allow(unused_variables)]
|
||||
QueryResultRow::Mock(row) => row.try_get_by_index(idx).map_err(|e| {
|
||||
debug_print!("{:#?}", e.to_string());
|
||||
err_null_idx_col(idx)
|
||||
}),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "with-bigdecimal")]
|
||||
@ -409,6 +609,50 @@ impl TryGetable for BigDecimal {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_by_index(res: &QueryResult, idx: usize) -> Result<Self, TryGetError> {
|
||||
match &res.row {
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
QueryResultRow::SqlxMySql(row) => {
|
||||
use sqlx::Row;
|
||||
row.try_get::<Option<BigDecimal>, _>(idx)
|
||||
.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::<Option<BigDecimal>, _>(idx)
|
||||
.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;
|
||||
let val: Option<f64> = row
|
||||
.try_get(idx)
|
||||
.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(err_null_idx_col(idx)),
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "mock")]
|
||||
#[allow(unused_variables)]
|
||||
QueryResultRow::Mock(row) => row.try_get_by_index(idx).map_err(|e| {
|
||||
debug_print!("{:#?}", e.to_string());
|
||||
err_null_idx_col(idx)
|
||||
}),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "with-uuid")]
|
||||
@ -454,6 +698,48 @@ impl TryGetable for u32 {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_by_index(res: &QueryResult, idx: usize) -> Result<Self, TryGetError> {
|
||||
match &res.row {
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
QueryResultRow::SqlxMySql(row) => {
|
||||
use sqlx::Row;
|
||||
row.try_get::<Option<u32>, _>(idx)
|
||||
.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::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::<Option<Oid>, _>(idx)
|
||||
.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)
|
||||
}
|
||||
#[cfg(feature = "sqlx-sqlite")]
|
||||
QueryResultRow::SqlxSqlite(row) => {
|
||||
use sqlx::Row;
|
||||
row.try_get::<Option<u32>, _>(idx)
|
||||
.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| {
|
||||
debug_print!("{:#?}", e.to_string());
|
||||
err_null_idx_col(idx)
|
||||
}),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn err_null_idx_col(idx: usize) -> TryGetError {
|
||||
TryGetError::Null(format!("column at index {}", idx))
|
||||
}
|
||||
|
||||
#[cfg(feature = "postgres-array")]
|
||||
@ -469,7 +755,7 @@ mod postgres_array {
|
||||
let column = format!("{}{}", pre, col);
|
||||
match &res.row {
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
QueryResultRow::SqlxMySql(row) => {
|
||||
QueryResultRow::SqlxMySql(_) => {
|
||||
panic!("{} unsupported by sqlx-mysql", stringify!($type))
|
||||
}
|
||||
#[cfg(feature = "sqlx-postgres")]
|
||||
@ -492,6 +778,33 @@ mod postgres_array {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_by_index(res: &QueryResult, idx: usize) -> Result<Self, TryGetError> {
|
||||
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::<Option<Vec<$type>>, _>(idx)
|
||||
.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(_) => {
|
||||
panic!("{} unsupported by sqlx-sqlite", stringify!($type))
|
||||
}
|
||||
#[cfg(feature = "mock")]
|
||||
QueryResultRow::Mock(row) => row.try_get_by_index(idx).map_err(|e| {
|
||||
debug_print!("{:#?}", e.to_string());
|
||||
err_null_idx_col(idx)
|
||||
}),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -553,7 +866,7 @@ mod postgres_array {
|
||||
let column = format!("{}{}", pre, col);
|
||||
match &res.row {
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
QueryResultRow::SqlxMySql(row) => {
|
||||
QueryResultRow::SqlxMySql(_) => {
|
||||
panic!("{} unsupported by sqlx-mysql", stringify!($type))
|
||||
}
|
||||
#[cfg(feature = "sqlx-postgres")]
|
||||
@ -580,16 +893,50 @@ mod postgres_array {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_by_index(res: &QueryResult, idx: usize) -> Result<Self, TryGetError> {
|
||||
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::<Option<Vec<Oid>>, _>(idx)
|
||||
.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())
|
||||
}
|
||||
#[cfg(feature = "sqlx-sqlite")]
|
||||
QueryResultRow::SqlxSqlite(_) => {
|
||||
panic!("{} unsupported by sqlx-sqlite", stringify!($type))
|
||||
}
|
||||
#[cfg(feature = "mock")]
|
||||
QueryResultRow::Mock(row) => row.try_get_by_index(idx).map_err(|e| {
|
||||
debug_print!("{:#?}", e.to_string());
|
||||
err_null_idx_col(idx)
|
||||
}),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TryGetableMany //
|
||||
|
||||
/// Perform a query on multiple columns
|
||||
/// An interface to get a tuple value from the query result
|
||||
pub trait TryGetableMany: Sized {
|
||||
/// THe method to perform a query on multiple columns
|
||||
/// Get a tuple value from the query result with prefixed column name
|
||||
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
|
||||
|
||||
/// Get a tuple value from the query result based on the order in the select expressions
|
||||
fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError>;
|
||||
|
||||
/// ```
|
||||
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||
/// #
|
||||
@ -663,6 +1010,10 @@ where
|
||||
try_get_many_with_slice_len_of(1, cols)?;
|
||||
T::try_get(res, pre, &cols[0])
|
||||
}
|
||||
|
||||
fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
|
||||
T::try_get_by_index(res, 0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TryGetableMany for (T,)
|
||||
@ -672,6 +1023,10 @@ where
|
||||
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
|
||||
T::try_get_many(res, pre, cols).map(|r| (r,))
|
||||
}
|
||||
|
||||
fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
|
||||
T::try_get_many_by_index(res).map(|r| (r,))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> TryGetableMany for (A, B)
|
||||
@ -686,6 +1041,10 @@ where
|
||||
B::try_get(res, pre, &cols[1])?,
|
||||
))
|
||||
}
|
||||
|
||||
fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
|
||||
Ok((A::try_get_by_index(res, 0)?, B::try_get_by_index(res, 1)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, C> TryGetableMany for (A, B, C)
|
||||
@ -702,6 +1061,14 @@ where
|
||||
C::try_get(res, pre, &cols[2])?,
|
||||
))
|
||||
}
|
||||
|
||||
fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
|
||||
Ok((
|
||||
A::try_get_by_index(res, 0)?,
|
||||
B::try_get_by_index(res, 1)?,
|
||||
C::try_get_by_index(res, 2)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, C, D> TryGetableMany for (A, B, C, D)
|
||||
@ -720,6 +1087,15 @@ where
|
||||
D::try_get(res, pre, &cols[3])?,
|
||||
))
|
||||
}
|
||||
|
||||
fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
|
||||
Ok((
|
||||
A::try_get_by_index(res, 0)?,
|
||||
B::try_get_by_index(res, 1)?,
|
||||
C::try_get_by_index(res, 2)?,
|
||||
D::try_get_by_index(res, 3)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, C, D, E> TryGetableMany for (A, B, C, D, E)
|
||||
@ -740,6 +1116,16 @@ where
|
||||
E::try_get(res, pre, &cols[4])?,
|
||||
))
|
||||
}
|
||||
|
||||
fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
|
||||
Ok((
|
||||
A::try_get_by_index(res, 0)?,
|
||||
B::try_get_by_index(res, 1)?,
|
||||
C::try_get_by_index(res, 2)?,
|
||||
D::try_get_by_index(res, 3)?,
|
||||
E::try_get_by_index(res, 4)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, C, D, E, F> TryGetableMany for (A, B, C, D, E, F)
|
||||
@ -762,6 +1148,17 @@ where
|
||||
F::try_get(res, pre, &cols[5])?,
|
||||
))
|
||||
}
|
||||
|
||||
fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
|
||||
Ok((
|
||||
A::try_get_by_index(res, 0)?,
|
||||
B::try_get_by_index(res, 1)?,
|
||||
C::try_get_by_index(res, 2)?,
|
||||
D::try_get_by_index(res, 3)?,
|
||||
E::try_get_by_index(res, 4)?,
|
||||
F::try_get_by_index(res, 5)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), TryGetError> {
|
||||
@ -825,6 +1222,45 @@ where
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_from_json_by_index(res: &QueryResult, idx: usize) -> Result<Self, TryGetError> {
|
||||
match &res.row {
|
||||
#[cfg(feature = "sqlx-mysql")]
|
||||
QueryResultRow::SqlxMySql(row) => {
|
||||
use sqlx::Row;
|
||||
row.try_get::<Option<sqlx::types::Json<Self>>, _>(idx)
|
||||
.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::<Option<sqlx::types::Json<Self>>, _>(idx)
|
||||
.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::<Option<sqlx::types::Json<Self>>, _>(idx)
|
||||
.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::<serde_json::Value>(idx)
|
||||
.map_err(|e| {
|
||||
debug_print!("{:#?}", e.to_string());
|
||||
err_null_idx_col(idx)
|
||||
})
|
||||
.and_then(|json| {
|
||||
serde_json::from_value(json)
|
||||
.map_err(|e| TryGetError::DbErr(DbErr::Json(e.to_string())))
|
||||
}),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "with-json")]
|
||||
@ -835,6 +1271,10 @@ where
|
||||
fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError> {
|
||||
T::try_get_from_json(res, pre, col)
|
||||
}
|
||||
|
||||
fn try_get_by_index(res: &QueryResult, idx: usize) -> Result<Self, TryGetError> {
|
||||
T::try_get_from_json_by_index(res, idx)
|
||||
}
|
||||
}
|
||||
|
||||
// TryFromU64 //
|
||||
|
@ -52,6 +52,14 @@ where
|
||||
model: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SelectGetableTuple<T>
|
||||
where
|
||||
T: TryGetableMany,
|
||||
{
|
||||
model: PhantomData<T>,
|
||||
}
|
||||
|
||||
/// Defines a type to get a Model
|
||||
#[derive(Debug)]
|
||||
pub struct SelectModel<M>
|
||||
@ -84,6 +92,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SelectorTrait for SelectGetableTuple<T>
|
||||
where
|
||||
T: TryGetableMany,
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
|
||||
T::try_get_many_by_index(&res).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> SelectorTrait for SelectModel<M>
|
||||
where
|
||||
M: FromQueryResult + Sized,
|
||||
@ -253,6 +272,104 @@ where
|
||||
Selector::<SelectGetableValue<T, C>>::with_columns(self.query)
|
||||
}
|
||||
|
||||
/// ```
|
||||
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||
/// #
|
||||
/// # #[smol_potat::main]
|
||||
/// # #[cfg(all(feature = "mock", feature = "macros"))]
|
||||
/// # pub async fn main() -> Result<(), DbErr> {
|
||||
/// #
|
||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||
/// # .append_query_results(vec![vec![
|
||||
/// # maplit::btreemap! {
|
||||
/// # "cake_name" => Into::<Value>::into("Chocolate Forest"),
|
||||
/// # },
|
||||
/// # maplit::btreemap! {
|
||||
/// # "cake_name" => Into::<Value>::into("New York Cheese"),
|
||||
/// # },
|
||||
/// # ]])
|
||||
/// # .into_connection();
|
||||
/// #
|
||||
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
||||
///
|
||||
/// let res: Vec<String> = cake::Entity::find()
|
||||
/// .select_only()
|
||||
/// .column(cake::Column::Name)
|
||||
/// .into_tuple()
|
||||
/// .all(&db)
|
||||
/// .await?;
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// res,
|
||||
/// vec!["Chocolate Forest".to_owned(), "New York Cheese".to_owned()]
|
||||
/// );
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// db.into_transaction_log(),
|
||||
/// vec![Transaction::from_sql_and_values(
|
||||
/// DbBackend::Postgres,
|
||||
/// r#"SELECT "cake"."name" FROM "cake""#,
|
||||
/// vec![]
|
||||
/// )]
|
||||
/// );
|
||||
/// #
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||
/// #
|
||||
/// # #[smol_potat::main]
|
||||
/// # #[cfg(all(feature = "mock", feature = "macros"))]
|
||||
/// # pub async fn main() -> Result<(), DbErr> {
|
||||
/// #
|
||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||
/// # .append_query_results(vec![vec![
|
||||
/// # maplit::btreemap! {
|
||||
/// # "cake_name" => Into::<Value>::into("Chocolate Forest"),
|
||||
/// # "num_of_cakes" => Into::<Value>::into(2i64),
|
||||
/// # },
|
||||
/// # ]])
|
||||
/// # .into_connection();
|
||||
/// #
|
||||
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
||||
///
|
||||
/// let res: Vec<(String, i64)> = cake::Entity::find()
|
||||
/// .select_only()
|
||||
/// .column(cake::Column::Name)
|
||||
/// .column(cake::Column::Id)
|
||||
/// .group_by(cake::Column::Name)
|
||||
/// .into_tuple()
|
||||
/// .all(&db)
|
||||
/// .await?;
|
||||
///
|
||||
/// assert_eq!(res, vec![("Chocolate Forest".to_owned(), 2i64)]);
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// db.into_transaction_log(),
|
||||
/// vec![Transaction::from_sql_and_values(
|
||||
/// DbBackend::Postgres,
|
||||
/// vec![
|
||||
/// r#"SELECT "cake"."name", "cake"."id""#,
|
||||
/// r#"FROM "cake" GROUP BY "cake"."name""#,
|
||||
/// ]
|
||||
/// .join(" ")
|
||||
/// .as_str(),
|
||||
/// vec![]
|
||||
/// )]
|
||||
/// );
|
||||
/// #
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn into_tuple<T>(self) -> Selector<SelectGetableTuple<T>>
|
||||
where
|
||||
T: TryGetableMany,
|
||||
{
|
||||
Selector::<SelectGetableTuple<T>>::into_tuple(self.query)
|
||||
}
|
||||
|
||||
/// Get one Model from the SELECT query
|
||||
pub async fn one<'a, C>(self, db: &C) -> Result<Option<E::Model>, DbErr>
|
||||
where
|
||||
@ -402,7 +519,7 @@ impl<S> Selector<S>
|
||||
where
|
||||
S: SelectorTrait,
|
||||
{
|
||||
/// Create `Selector` from Statment and columns. Executing this `Selector`
|
||||
/// Create `Selector` from Statement and columns. Executing this `Selector`
|
||||
/// will return a type `T` which implement `TryGetableMany`.
|
||||
pub fn with_columns<T, C>(query: SelectStatement) -> Selector<SelectGetableValue<T, C>>
|
||||
where
|
||||
@ -418,6 +535,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_tuple<T>(query: SelectStatement) -> Selector<SelectGetableTuple<T>>
|
||||
where
|
||||
T: TryGetableMany,
|
||||
{
|
||||
Selector {
|
||||
query,
|
||||
selector: SelectGetableTuple { model: PhantomData },
|
||||
}
|
||||
}
|
||||
|
||||
fn into_selector_raw<C>(self, db: &C) -> SelectorRaw<S>
|
||||
where
|
||||
C: ConnectionTrait,
|
||||
|
@ -29,6 +29,11 @@ impl TryGetable for StringVec {
|
||||
let json_str: String = res.try_get(pre, col).map_err(TryGetError::DbErr)?;
|
||||
serde_json::from_str(&json_str).map_err(|e| TryGetError::DbErr(DbErr::Json(e.to_string())))
|
||||
}
|
||||
|
||||
fn try_get_by_index(res: &QueryResult, idx: usize) -> Result<Self, TryGetError> {
|
||||
let json_str: String = res.try_get_by_index(idx).map_err(TryGetError::DbErr)?;
|
||||
serde_json::from_str(&json_str).map_err(|e| TryGetError::DbErr(DbErr::Json(e.to_string())))
|
||||
}
|
||||
}
|
||||
|
||||
impl sea_query::ValueType for StringVec {
|
||||
|
Loading…
x
Reference in New Issue
Block a user