Skip to content

Commit

Permalink
Improve working with raw SQL
Browse files Browse the repository at this point in the history
- Add `find_by_statement` to `T: FromQueryResult`
- Add `SelectorRaw::from_statement` constructor
  • Loading branch information
MuhannadAlrusayni committed Sep 16, 2021
1 parent 9107c90 commit e71a74b
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 78 deletions.
71 changes: 1 addition & 70 deletions src/database/statement.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{DbBackend, FromQueryResult, SelectModel, SelectorRaw};
use crate::DbBackend;
use sea_query::{inject_parameters, MysqlQueryBuilder, PostgresQueryBuilder, SqliteQueryBuilder};
pub use sea_query::{Value, Values};
use std::fmt;
Expand Down Expand Up @@ -43,75 +43,6 @@ impl Statement {
db_backend,
}
}

/// ```
/// # #[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, FromQueryResult};
///
/// #[derive(Debug, PartialEq, FromQueryResult)]
/// struct SelectResult {
/// name: String,
/// num_of_cakes: i32,
/// }
///
/// # let _: Result<(), DbErr> = smol::block_on(async {
/// #
/// let res: Vec<SelectResult> = Statement::from_sql_and_values(
/// DbBackend::Postgres,
/// r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
/// vec![],
/// )
/// .into_model::<SelectResult>()
/// .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![]
/// ),]
/// );
/// ```
pub fn into_model<M>(self) -> SelectorRaw<SelectModel<M>>
where
M: FromQueryResult,
{
SelectorRaw::<SelectModel<M>>::from_statement(self)
}
}

impl fmt::Display for Statement {
Expand Down
74 changes: 73 additions & 1 deletion src/entity/model.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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::<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, FromQueryResult};
///
/// #[derive(Debug, PartialEq, FromQueryResult)]
/// struct SelectResult {
/// name: String,
/// num_of_cakes: i32,
/// }
///
/// # let _: Result<(), DbErr> = smol::block_on(async {
/// #
/// let res: Vec<SelectResult> = 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<SelectModel<Self>> {
SelectorRaw::<SelectModel<Self>>::from_statement(stmt)
}
}

impl<T: FromQueryResult> FromQueryResultExt for T {}
5 changes: 3 additions & 2 deletions src/entity/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
8 changes: 3 additions & 5 deletions src/executor/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,9 @@ impl<S> SelectorRaw<S>
where
S: SelectorTrait,
{
// Create `SelectorRaw` from Statment. Executing this `SelectorRaw` will
// return a type `M` which implement `FromQueryResult`.
//
// Helper function used by `Statment.into_model()`
pub(crate) fn from_statement<M>(stmt: Statement) -> SelectorRaw<SelectModel<M>>
/// Create `SelectorRaw` from Statment. Executing this `SelectorRaw` will
/// return a type `M` which implement `FromQueryResult`.
pub fn from_statement<M>(stmt: Statement) -> SelectorRaw<SelectModel<M>>
where
M: FromQueryResult,
{
Expand Down

0 comments on commit e71a74b

Please sign in to comment.