Add find_by_statement
for T: TryGetableMany
Add `into_values` for `Select<T>`
This commit is contained in:
parent
7742eb2cec
commit
5379a23630
@ -1,6 +1,6 @@
|
||||
#[cfg(feature = "mock")]
|
||||
use crate::debug_print;
|
||||
use crate::DbErr;
|
||||
use crate::{DbErr, SelectGetableValue, SelectorRaw, Statement};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -302,6 +302,79 @@ try_getable_all!(uuid::Uuid);
|
||||
|
||||
pub trait TryGetableMany: Sized {
|
||||
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
|
||||
|
||||
/// ```
|
||||
/// # #[cfg(feature = "mock")]
|
||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
||||
/// #
|
||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||
/// # .append_query_results(vec![vec![
|
||||
/// # maplit::btreemap! {
|
||||
/// # "name" => Into::<Value>::into("Chocolate Forest"),
|
||||
/// # "num_of_cakes" => Into::<Value>::into(1),
|
||||
/// # },
|
||||
/// # maplit::btreemap! {
|
||||
/// # "name" => Into::<Value>::into("New York Cheese"),
|
||||
/// # "num_of_cakes" => Into::<Value>::into(1),
|
||||
/// # },
|
||||
/// # ]])
|
||||
/// # .into_connection();
|
||||
/// #
|
||||
/// use sea_orm::{entity::*, query::*, tests_cfg::cake, EnumIter, TryGetableMany};
|
||||
///
|
||||
/// #[derive(EnumIter)]
|
||||
/// enum ResultCol {
|
||||
/// Name,
|
||||
/// NumOfCakes,
|
||||
/// }
|
||||
///
|
||||
/// // this can be derived using derive_more crate
|
||||
/// impl std::fmt::Display for ResultCol {
|
||||
/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
/// match self {
|
||||
/// Self::Name => write!(f, "name"),
|
||||
/// Self::NumOfCakes => write!(f, "num_of_cakes"),
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
||||
/// #
|
||||
/// let res: Vec<(String, i32)> =
|
||||
/// <(String, i32)>::find_by_statement::<ResultCol>(Statement::from_sql_and_values(
|
||||
/// DbBackend::Postgres,
|
||||
/// r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
|
||||
/// vec![],
|
||||
/// ))
|
||||
/// .all(&db)
|
||||
/// .await?;
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// res,
|
||||
/// vec![
|
||||
/// ("Chocolate Forest".to_owned(), 1),
|
||||
/// ("New York Cheese".to_owned(), 1),
|
||||
/// ]
|
||||
/// );
|
||||
/// #
|
||||
/// # Ok(())
|
||||
/// # });
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// db.into_transaction_log(),
|
||||
/// vec![Transaction::from_sql_and_values(
|
||||
/// DbBackend::Postgres,
|
||||
/// r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
|
||||
/// vec![]
|
||||
/// ),]
|
||||
/// );
|
||||
/// ```
|
||||
fn find_by_statement<C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<Self, C>>
|
||||
where
|
||||
C: sea_strum::IntoEnumIterator + ToString,
|
||||
{
|
||||
SelectorRaw::<SelectGetableValue<Self, C>>::with_columns(stmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TryGetableMany for T
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
error::*, DatabaseConnection, EntityTrait, FromQueryResult, IdenStatic, Iterable, JsonValue,
|
||||
ModelTrait, Paginator, PrimaryKeyToColumn, QueryResult, Select, SelectA, SelectB, SelectTwo,
|
||||
SelectTwoMany, Statement,
|
||||
SelectTwoMany, Statement, TryGetableMany,
|
||||
};
|
||||
use sea_query::SelectStatement;
|
||||
use std::marker::PhantomData;
|
||||
@ -30,6 +30,16 @@ pub trait SelectorTrait {
|
||||
fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SelectGetableValue<T, C>
|
||||
where
|
||||
T: TryGetableMany,
|
||||
C: sea_strum::IntoEnumIterator + ToString,
|
||||
{
|
||||
columns: PhantomData<C>,
|
||||
model: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SelectModel<M>
|
||||
where
|
||||
@ -47,6 +57,19 @@ where
|
||||
model: PhantomData<(M, N)>,
|
||||
}
|
||||
|
||||
impl<T, C> SelectorTrait for SelectGetableValue<T, C>
|
||||
where
|
||||
T: TryGetableMany,
|
||||
C: sea_strum::IntoEnumIterator + ToString,
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
|
||||
let cols: Vec<String> = C::iter().map(|col| col.to_string()).collect();
|
||||
T::try_get_many(&res, "", &cols).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> SelectorTrait for SelectModel<M>
|
||||
where
|
||||
M: FromQueryResult + Sized,
|
||||
@ -103,6 +126,73 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// ```
|
||||
/// # #[cfg(feature = "mock")]
|
||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
||||
/// #
|
||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||
/// # .append_query_results(vec![vec![
|
||||
/// # maplit::btreemap! {
|
||||
/// # "name" => Into::<Value>::into("Chocolate Forest"),
|
||||
/// # "num_of_cakes" => Into::<Value>::into(1),
|
||||
/// # },
|
||||
/// # maplit::btreemap! {
|
||||
/// # "name" => Into::<Value>::into("New York Cheese"),
|
||||
/// # "num_of_cakes" => Into::<Value>::into(1),
|
||||
/// # },
|
||||
/// # ]])
|
||||
/// # .into_connection();
|
||||
/// #
|
||||
/// use sea_orm::{entity::*, query::*, tests_cfg::cake, EnumIter, TryGetableMany};
|
||||
///
|
||||
/// #[derive(EnumIter)]
|
||||
/// enum ResultCol {
|
||||
/// Name,
|
||||
/// }
|
||||
///
|
||||
/// // this can be derived using derive_more crate
|
||||
/// impl std::fmt::Display for ResultCol {
|
||||
/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
/// match self {
|
||||
/// Self::Name => write!(f, "name"),
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
||||
/// #
|
||||
/// let res: Vec<String> = cake::Entity::find()
|
||||
/// .select_only()
|
||||
/// .column(cake::Column::Name)
|
||||
/// .into_values::<_, ResultCol>()
|
||||
/// .all(&db)
|
||||
/// .await?;
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// res,
|
||||
/// vec!["Chocolate Forest".to_owned(), "New York Cheese".to_owned(),]
|
||||
/// );
|
||||
/// #
|
||||
/// # Ok(())
|
||||
/// # });
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// db.into_transaction_log(),
|
||||
/// vec![Transaction::from_sql_and_values(
|
||||
/// DbBackend::Postgres,
|
||||
/// r#"SELECT "cake"."name" FROM "cake""#,
|
||||
/// vec![]
|
||||
/// ),]
|
||||
/// );
|
||||
/// ```
|
||||
pub fn into_values<T, C>(self) -> Selector<SelectGetableValue<T, C>>
|
||||
where
|
||||
T: TryGetableMany,
|
||||
C: sea_strum::IntoEnumIterator + ToString,
|
||||
{
|
||||
Selector::<SelectGetableValue<T, C>>::with_columns(self.query)
|
||||
}
|
||||
|
||||
pub async fn one(self, db: &DatabaseConnection) -> Result<Option<E::Model>, DbErr> {
|
||||
self.into_model().one(db).await
|
||||
}
|
||||
@ -228,6 +318,22 @@ impl<S> Selector<S>
|
||||
where
|
||||
S: SelectorTrait,
|
||||
{
|
||||
/// Create `Selector` from Statment 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
|
||||
T: TryGetableMany,
|
||||
C: sea_strum::IntoEnumIterator + ToString,
|
||||
{
|
||||
Selector {
|
||||
query,
|
||||
selector: SelectGetableValue {
|
||||
columns: PhantomData,
|
||||
model: PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn one(mut self, db: &DatabaseConnection) -> Result<Option<S::Item>, DbErr> {
|
||||
let builder = db.get_database_backend();
|
||||
self.query.limit(1);
|
||||
@ -275,6 +381,22 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Create `SelectorRaw` from Statment and columns. Executing this `SelectorRaw` will
|
||||
/// return a type `T` which implement `TryGetableMany`.
|
||||
pub fn with_columns<T, C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<T, C>>
|
||||
where
|
||||
T: TryGetableMany,
|
||||
C: sea_strum::IntoEnumIterator + ToString,
|
||||
{
|
||||
SelectorRaw {
|
||||
stmt,
|
||||
selector: SelectGetableValue {
|
||||
columns: PhantomData,
|
||||
model: PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// ```
|
||||
/// # #[cfg(feature = "mock")]
|
||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
||||
|
Loading…
x
Reference in New Issue
Block a user