diff --git a/src/entity/model.rs b/src/entity/model.rs index 25a437539..25b46719c 100644 --- a/src/entity/model.rs +++ b/src/entity/model.rs @@ -1,4 +1,7 @@ -use crate::{DbErr, EntityTrait, Linked, QueryFilter, QueryResult, Related, Select}; +use crate::{ + DbErr, EntityTrait, Linked, QueryFilter, QueryResult, Related, Select, SelectModel, + SelectorRaw, Statement, +}; pub use sea_query::Value; use std::fmt::Debug; @@ -37,3 +40,72 @@ pub trait FromQueryResult { Ok(Self::from_query_result(res, pre).ok()) } } + +pub trait FromQueryResultExt: FromQueryResult + Sized { + /// ``` + /// # #[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::::into("Chocolate Forest"), + /// # "num_of_cakes" => Into::::into(1), + /// # }, + /// # maplit::btreemap! { + /// # "name" => Into::::into("New York Cheese"), + /// # "num_of_cakes" => Into::::into(1), + /// # }, + /// # ]]) + /// # .into_connection(); + /// # + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, FromQueryResult}; + /// + /// #[derive(Debug, PartialEq, FromQueryResult)] + /// struct SelectResult { + /// name: String, + /// num_of_cakes: i32, + /// } + /// + /// # let _: Result<(), DbErr> = smol::block_on(async { + /// # + /// let res: Vec = SelectResult::find_by_statement(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![ + /// SelectResult { + /// name: "Chocolate Forest".to_owned(), + /// num_of_cakes: 1, + /// }, + /// SelectResult { + /// name: "New York Cheese".to_owned(), + /// num_of_cakes: 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(stmt: Statement) -> SelectorRaw> { + SelectorRaw::>::from_statement(stmt) + } +} + +impl FromQueryResultExt for T {} diff --git a/src/entity/prelude.rs b/src/entity/prelude.rs index 8d87a4b20..22cfeeb05 100644 --- a/src/entity/prelude.rs +++ b/src/entity/prelude.rs @@ -2,8 +2,9 @@ pub use crate::{ error::*, ActiveModelBehavior, ActiveModelTrait, ColumnDef, ColumnTrait, ColumnType, DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveCustomColumn, DeriveEntity, DeriveEntityModel, DeriveModel, DerivePrimaryKey, DeriveRelation, EntityName, EntityTrait, - EnumIter, ForeignKeyAction, Iden, IdenStatic, Linked, ModelTrait, PrimaryKeyToColumn, - PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef, RelationTrait, Select, Value, + EnumIter, ForeignKeyAction, FromQueryResultExt, Iden, IdenStatic, Linked, ModelTrait, + PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef, + RelationTrait, Select, Value, }; #[cfg(feature = "with-json")] diff --git a/src/executor/select.rs b/src/executor/select.rs index ef30bb3d1..959091c01 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -263,6 +263,18 @@ impl SelectorRaw where S: SelectorTrait, { + /// Create `SelectorRaw` from Statment. Executing this `SelectorRaw` will + /// return a type `M` which implement `FromQueryResult`. + pub fn from_statement(stmt: Statement) -> SelectorRaw> + where + M: FromQueryResult, + { + SelectorRaw { + stmt, + selector: SelectModel { model: PhantomData }, + } + } + /// ``` /// # #[cfg(feature = "mock")] /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};