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")]
|
#[cfg(feature = "mock")]
|
||||||
use crate::debug_print;
|
use crate::debug_print;
|
||||||
use crate::DbErr;
|
use crate::{DbErr, SelectGetableValue, SelectorRaw, Statement};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -302,6 +302,79 @@ try_getable_all!(uuid::Uuid);
|
|||||||
|
|
||||||
pub trait TryGetableMany: Sized {
|
pub trait TryGetableMany: Sized {
|
||||||
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
|
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
|
impl<T> TryGetableMany for T
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::*, DatabaseConnection, EntityTrait, FromQueryResult, IdenStatic, Iterable, JsonValue,
|
error::*, DatabaseConnection, EntityTrait, FromQueryResult, IdenStatic, Iterable, JsonValue,
|
||||||
ModelTrait, Paginator, PrimaryKeyToColumn, QueryResult, Select, SelectA, SelectB, SelectTwo,
|
ModelTrait, Paginator, PrimaryKeyToColumn, QueryResult, Select, SelectA, SelectB, SelectTwo,
|
||||||
SelectTwoMany, Statement,
|
SelectTwoMany, Statement, TryGetableMany,
|
||||||
};
|
};
|
||||||
use sea_query::SelectStatement;
|
use sea_query::SelectStatement;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
@ -30,6 +30,16 @@ pub trait SelectorTrait {
|
|||||||
fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr>;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct SelectModel<M>
|
pub struct SelectModel<M>
|
||||||
where
|
where
|
||||||
@ -47,6 +57,19 @@ where
|
|||||||
model: PhantomData<(M, N)>,
|
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>
|
impl<M> SelectorTrait for SelectModel<M>
|
||||||
where
|
where
|
||||||
M: FromQueryResult + Sized,
|
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> {
|
pub async fn one(self, db: &DatabaseConnection) -> Result<Option<E::Model>, DbErr> {
|
||||||
self.into_model().one(db).await
|
self.into_model().one(db).await
|
||||||
}
|
}
|
||||||
@ -228,6 +318,22 @@ impl<S> Selector<S>
|
|||||||
where
|
where
|
||||||
S: SelectorTrait,
|
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> {
|
pub async fn one(mut self, db: &DatabaseConnection) -> Result<Option<S::Item>, DbErr> {
|
||||||
let builder = db.get_database_backend();
|
let builder = db.get_database_backend();
|
||||||
self.query.limit(1);
|
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")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user