sea_orm/entity/
model.rs

1use crate::{
2    ActiveModelBehavior, ActiveModelTrait, ColumnTrait, ConnectionTrait, DbErr, DeleteResult,
3    EntityTrait, IntoActiveModel, Linked, QueryFilter, QueryResult, Related, Select, SelectModel,
4    SelectorRaw, Statement, TryGetError,
5};
6use async_trait::async_trait;
7use sea_query::ArrayType;
8pub use sea_query::Value;
9use std::fmt::Debug;
10
11/// The interface for Model, implemented by data structs
12#[async_trait]
13pub trait ModelTrait: Clone + Send + Debug {
14    #[allow(missing_docs)]
15    type Entity: EntityTrait;
16
17    /// Get the [Value] of a column from a Model
18    fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> Value;
19
20    /// Get the Value Type of a column from the Model
21    fn get_value_type(c: <Self::Entity as EntityTrait>::Column) -> ArrayType;
22
23    /// Set the Value of a Model field, panic if failed
24    fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) {
25        self.try_set(c, v)
26            .unwrap_or_else(|e| panic!("Failed to set value for {:?}: {e:?}", c.as_column_ref()))
27    }
28
29    /// Set the Value of a Model field, return error if failed
30    fn try_set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) -> Result<(), DbErr>;
31
32    /// Find related Models
33    fn find_related<R>(&self, _: R) -> Select<R>
34    where
35        R: EntityTrait,
36        Self::Entity: Related<R>,
37    {
38        <Self::Entity as Related<R>>::find_related().belongs_to(self)
39    }
40
41    /// Find linked Models
42    fn find_linked<L>(&self, l: L) -> Select<L::ToEntity>
43    where
44        L: Linked<FromEntity = Self::Entity>,
45    {
46        let tbl_alias = &format!("r{}", l.link().len() - 1);
47        l.find_linked().belongs_to_tbl_alias(self, tbl_alias)
48    }
49
50    /// Delete a model
51    async fn delete<'a, A, C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
52    where
53        Self: IntoActiveModel<A>,
54        C: ConnectionTrait,
55        A: ActiveModelTrait<Entity = Self::Entity> + ActiveModelBehavior + Send + 'a,
56    {
57        self.into_active_model().delete(db).await
58    }
59}
60
61/// A Trait for implementing a [QueryResult]
62pub trait FromQueryResult: Sized {
63    /// Instantiate a Model from a [QueryResult]
64    ///
65    /// NOTE: Please also override `from_query_result_nullable` when manually implementing.
66    ///       The future default implementation will be along the lines of:
67    ///
68    /// ```rust,ignore
69    /// fn from_query_result(res: &QueryResult, pre: &str) -> Result<Self, DbErr> {
70    ///     (Self::from_query_result_nullable(res, pre)?)
71    /// }
72    /// ```
73    fn from_query_result(res: &QueryResult, pre: &str) -> Result<Self, DbErr>;
74
75    /// Transform the error from instantiating a Model from a [QueryResult]
76    /// and converting it to an [Option]
77    fn from_query_result_optional(res: &QueryResult, pre: &str) -> Result<Option<Self>, DbErr> {
78        Ok(Self::from_query_result(res, pre).ok())
79
80        // would really like to do the following, but can't without version bump:
81        // match Self::from_query_result_nullable(res, pre) {
82        //     Ok(v) => Ok(Some(v)),
83        //     Err(TryGetError::Null(_)) => Ok(None),
84        //     Err(TryGetError::DbErr(err)) => Err(err),
85        // }
86    }
87
88    /// Transform the error from instantiating a Model from a [QueryResult]
89    /// and converting it to an [Option]
90    ///
91    /// NOTE: This will most likely stop being a provided method in the next major version!
92    fn from_query_result_nullable(res: &QueryResult, pre: &str) -> Result<Self, TryGetError> {
93        Self::from_query_result(res, pre).map_err(TryGetError::DbErr)
94    }
95
96    /// ```
97    /// # use sea_orm::{error::*, tests_cfg::*, *};
98    /// #
99    /// # #[smol_potat::main]
100    /// # #[cfg(feature = "mock")]
101    /// # pub async fn main() -> Result<(), DbErr> {
102    /// #
103    /// # let db = MockDatabase::new(DbBackend::Postgres)
104    /// #     .append_query_results([[
105    /// #         maplit::btreemap! {
106    /// #             "name" => Into::<Value>::into("Chocolate Forest"),
107    /// #             "num_of_cakes" => Into::<Value>::into(2),
108    /// #         },
109    /// #     ]])
110    /// #     .into_connection();
111    /// #
112    /// use sea_orm::{FromQueryResult, query::*};
113    ///
114    /// #[derive(Debug, PartialEq, FromQueryResult)]
115    /// struct SelectResult {
116    ///     name: String,
117    ///     num_of_cakes: i32,
118    /// }
119    ///
120    /// let res: Vec<SelectResult> = SelectResult::find_by_statement(Statement::from_sql_and_values(
121    ///     DbBackend::Postgres,
122    ///     r#"SELECT "name", COUNT(*) AS "num_of_cakes" FROM "cake" GROUP BY("name")"#,
123    ///     [],
124    /// ))
125    /// .all(&db)
126    /// .await?;
127    ///
128    /// assert_eq!(
129    ///     res,
130    ///     [SelectResult {
131    ///         name: "Chocolate Forest".to_owned(),
132    ///         num_of_cakes: 2,
133    ///     },]
134    /// );
135    /// #
136    /// # assert_eq!(
137    /// #     db.into_transaction_log(),
138    /// #     [Transaction::from_sql_and_values(
139    /// #         DbBackend::Postgres,
140    /// #         r#"SELECT "name", COUNT(*) AS "num_of_cakes" FROM "cake" GROUP BY("name")"#,
141    /// #         []
142    /// #     ),]
143    /// # );
144    /// #
145    /// # Ok(())
146    /// # }
147    /// ```
148    fn find_by_statement(stmt: Statement) -> SelectorRaw<SelectModel<Self>> {
149        SelectorRaw::<SelectModel<Self>>::from_statement(stmt)
150    }
151}
152
153impl<T: FromQueryResult> FromQueryResult for Option<T> {
154    fn from_query_result(res: &QueryResult, pre: &str) -> Result<Self, DbErr> {
155        Ok(Self::from_query_result_nullable(res, pre)?)
156    }
157
158    fn from_query_result_optional(res: &QueryResult, pre: &str) -> Result<Option<Self>, DbErr> {
159        match Self::from_query_result_nullable(res, pre) {
160            Ok(v) => Ok(Some(v)),
161            Err(TryGetError::Null(_)) => Ok(None),
162            Err(TryGetError::DbErr(err)) => Err(err),
163        }
164    }
165
166    fn from_query_result_nullable(res: &QueryResult, pre: &str) -> Result<Self, TryGetError> {
167        match T::from_query_result_nullable(res, pre) {
168            Ok(v) => Ok(Some(v)),
169            Err(TryGetError::Null(_)) => Ok(None),
170            Err(err @ TryGetError::DbErr(_)) => Err(err),
171        }
172    }
173}
174
175/// A Trait for any type that can be converted into an Model
176pub trait TryIntoModel<M>
177where
178    M: ModelTrait,
179{
180    /// Method to call to perform the conversion
181    fn try_into_model(self) -> Result<M, DbErr>;
182}
183
184impl<M> TryIntoModel<M> for M
185where
186    M: ModelTrait,
187{
188    fn try_into_model(self) -> Result<M, DbErr> {
189        Ok(self)
190    }
191}