sea_orm/entity/
model.rs

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