1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
use crate::{
ActiveModelBehavior, ActiveModelTrait, ConnectionTrait, DbErr, DeleteResult, EntityTrait,
IntoActiveModel, Linked, QueryFilter, QueryResult, Related, Select, SelectModel, SelectorRaw,
Statement,
};
use async_trait::async_trait;
pub use sea_query::Value;
use std::fmt::Debug;
/// A Trait for a Model
#[async_trait]
pub trait ModelTrait: Clone + Send + Debug {
#[allow(missing_docs)]
type Entity: EntityTrait;
/// Get the [Value] of a column from an Entity
fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> Value;
/// Set the [Value] of a column in an Entity
fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value);
/// Find related Models
fn find_related<R>(&self, _: R) -> Select<R>
where
R: EntityTrait,
Self::Entity: Related<R>,
{
<Self::Entity as Related<R>>::find_related().belongs_to(self)
}
/// Find linked Models
fn find_linked<L>(&self, l: L) -> Select<L::ToEntity>
where
L: Linked<FromEntity = Self::Entity>,
{
let tbl_alias = &format!("r{}", l.link().len() - 1);
l.find_linked().belongs_to_tbl_alias(self, tbl_alias)
}
/// Delete an model
async fn delete<'a, A, C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
where
Self: IntoActiveModel<A>,
C: ConnectionTrait<'a>,
A: ActiveModelTrait<Entity = Self::Entity> + ActiveModelBehavior + Send + 'a,
{
self.into_active_model().delete(db).await
}
}
/// A Trait for implementing a [QueryResult]
pub trait FromQueryResult: Sized {
/// Instantiate a Model from a [QueryResult]
fn from_query_result(res: &QueryResult, pre: &str) -> Result<Self, DbErr>;
/// Transform the error from instantiating a Model from a [QueryResult]
/// and converting it to an [Option]
fn from_query_result_optional(res: &QueryResult, pre: &str) -> Result<Option<Self>, DbErr> {
Ok(Self::from_query_result(res, pre).ok())
}
/// ```
/// # use sea_orm::{error::*, tests_cfg::*, *};
/// #
/// # #[smol_potat::main]
/// # #[cfg(feature = "mock")]
/// # pub async fn main() -> Result<(), DbErr> {
/// #
/// # 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(2),
/// # },
/// # ]])
/// # .into_connection();
/// #
/// use sea_orm::{query::*, FromQueryResult};
///
/// #[derive(Debug, PartialEq, FromQueryResult)]
/// struct SelectResult {
/// name: String,
/// num_of_cakes: i32,
/// }
///
/// let res: Vec<SelectResult> = SelectResult::find_by_statement(Statement::from_sql_and_values(
/// DbBackend::Postgres,
/// r#"SELECT "name", COUNT(*) AS "num_of_cakes" FROM "cake" GROUP BY("name")"#,
/// vec![],
/// ))
/// .all(&db)
/// .await?;
///
/// assert_eq!(
/// res,
/// vec![SelectResult {
/// name: "Chocolate Forest".to_owned(),
/// num_of_cakes: 2,
/// },]
/// );
/// #
/// # assert_eq!(
/// # db.into_transaction_log(),
/// # vec![Transaction::from_sql_and_values(
/// # DbBackend::Postgres,
/// # r#"SELECT "name", COUNT(*) AS "num_of_cakes" FROM "cake" GROUP BY("name")"#,
/// # vec![]
/// # ),]
/// # );
/// #
/// # Ok(())
/// # }
/// ```
fn find_by_statement(stmt: Statement) -> SelectorRaw<SelectModel<Self>> {
SelectorRaw::<SelectModel<Self>>::from_statement(stmt)
}
}