Skip to main content

sea_orm/entity/
base_entity.rs

1use crate::{
2    ActiveModelBehavior, ActiveModelTrait, ColumnTrait, Delete, DeleteMany, DeleteOne,
3    FromQueryResult, Identity, Insert, InsertMany, ModelTrait, PrimaryKeyArity, PrimaryKeyToColumn,
4    PrimaryKeyTrait, QueryFilter, Related, RelationBuilder, RelationTrait, RelationType, Select,
5    Update, UpdateMany, UpdateOne, ValidatedDeleteOne,
6};
7use sea_query::{Iden, IntoIden, IntoTableRef, IntoValueTuple, TableRef};
8use std::fmt::Debug;
9pub use strum::IntoEnumIterator as Iterable;
10
11/// Ensure the identifier for an Entity can be converted to a static str
12pub trait IdenStatic: Iden + Copy + Debug + Send + Sync + 'static {
13    /// Method to call to get the static string identity
14    fn as_str(&self) -> &'static str;
15}
16
17/// A Trait for mapping an Entity to a database table
18pub trait EntityName: IdenStatic + Default {
19    /// Method to get the name for the schema, defaults to [Option::None] if not set
20    fn schema_name(&self) -> Option<&str> {
21        None
22    }
23
24    /// Method to get the comment for the schema, defaults to [Option::None] if not set
25    fn comment(&self) -> Option<&str> {
26        None
27    }
28
29    /// Get the name of the table
30    fn table_name(&self) -> &'static str;
31
32    /// Get the [TableRef] from invoking the `self.schema_name()`
33    fn table_ref(&self) -> TableRef {
34        match self.schema_name() {
35            Some(schema) => (schema.to_owned(), self.into_iden()).into_table_ref(),
36            None => self.into_table_ref(),
37        }
38    }
39}
40
41/// An abstract base class for defining Entities.
42///
43/// This trait provides an API for you to inspect it's properties
44/// - Column (implemented [`ColumnTrait`])
45/// - Relation (implemented [`RelationTrait`])
46/// - Primary Key (implemented [`PrimaryKeyTrait`] and [`PrimaryKeyToColumn`])
47///
48/// This trait also provides an API for CRUD actions
49/// - Select: `find`, `find_*`
50/// - Insert: `insert`, `insert_*`
51/// - Update: `update`, `update_*`
52/// - Delete: `delete`, `delete_*`
53pub trait EntityTrait: EntityName {
54    #[allow(missing_docs)]
55    type Model: ModelTrait<Entity = Self> + FromQueryResult;
56
57    #[allow(missing_docs)]
58    type ModelEx: ModelTrait<Entity = Self>;
59
60    #[allow(missing_docs)]
61    type ActiveModel: ActiveModelBehavior<Entity = Self>;
62
63    #[allow(missing_docs)]
64    type ActiveModelEx: ActiveModelTrait<Entity = Self>;
65
66    #[allow(missing_docs)]
67    type Column: ColumnTrait;
68
69    #[allow(missing_docs)]
70    type Relation: RelationTrait;
71
72    #[allow(missing_docs)]
73    type PrimaryKey: PrimaryKeyTrait + PrimaryKeyToColumn<Column = Self::Column>;
74
75    /// Construct a belongs to relation, where this table has a foreign key to
76    /// another table.
77    fn belongs_to<R>(related: R) -> RelationBuilder<Self, R>
78    where
79        R: EntityTrait,
80    {
81        RelationBuilder::new(RelationType::HasOne, Self::default(), related, false)
82    }
83
84    /// Construct a has one relation
85    fn has_one<R>(_: R) -> RelationBuilder<Self, R>
86    where
87        R: EntityTrait + Related<Self>,
88    {
89        RelationBuilder::from_rel(RelationType::HasOne, R::to().rev(), true)
90    }
91
92    /// Construct a has many relation
93    fn has_many<R>(_: R) -> RelationBuilder<Self, R>
94    where
95        R: EntityTrait + Related<Self>,
96    {
97        RelationBuilder::from_rel(RelationType::HasMany, R::to().rev(), true)
98    }
99
100    /// Construct a has many relation, with the Relation provided.
101    /// This is for the case where `Related<Self>` is not possible.
102    fn has_many_via<R, T>(_: R, rel: T) -> RelationBuilder<Self, R>
103    where
104        R: EntityTrait,
105        T: RelationTrait,
106    {
107        RelationBuilder::from_rel(RelationType::HasMany, rel.def().rev(), true)
108    }
109
110    /// Construct select statement to find one / all models
111    ///
112    /// - To select columns, join tables and group by expressions, see [`QuerySelect`](crate::query::QuerySelect)
113    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
114    /// - To apply order by expressions, see [`QueryOrder`](crate::query::QueryOrder)
115    ///
116    /// # Example
117    ///
118    /// ```
119    /// # use sea_orm::{error::*, tests_cfg::*, *};
120    /// #
121    /// # #[smol_potat::main]
122    /// # #[cfg(feature = "mock")]
123    /// # pub async fn main() -> Result<(), DbErr> {
124    /// #
125    /// # let db = MockDatabase::new(DbBackend::Postgres)
126    /// #     .append_query_results([
127    /// #         vec![
128    /// #             cake::Model {
129    /// #                 id: 1,
130    /// #                 name: "New York Cheese".to_owned(),
131    /// #             },
132    /// #         ],
133    /// #         vec![
134    /// #             cake::Model {
135    /// #                 id: 1,
136    /// #                 name: "New York Cheese".to_owned(),
137    /// #             },
138    /// #             cake::Model {
139    /// #                 id: 2,
140    /// #                 name: "Chocolate Forest".to_owned(),
141    /// #             },
142    /// #         ],
143    /// #     ])
144    /// #     .into_connection();
145    /// #
146    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
147    ///
148    /// assert_eq!(
149    ///     cake::Entity::find().one(&db).await?,
150    ///     Some(cake::Model {
151    ///         id: 1,
152    ///         name: "New York Cheese".to_owned(),
153    ///     })
154    /// );
155    ///
156    /// assert_eq!(
157    ///     cake::Entity::find().all(&db).await?,
158    ///     [
159    ///         cake::Model {
160    ///             id: 1,
161    ///             name: "New York Cheese".to_owned(),
162    ///         },
163    ///         cake::Model {
164    ///             id: 2,
165    ///             name: "Chocolate Forest".to_owned(),
166    ///         },
167    ///     ]
168    /// );
169    ///
170    /// assert_eq!(
171    ///     db.into_transaction_log(),
172    ///     [
173    ///         Transaction::from_sql_and_values(
174    ///             DbBackend::Postgres,
175    ///             r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#,
176    ///             [1u64.into()]
177    ///         ),
178    ///         Transaction::from_sql_and_values(
179    ///             DbBackend::Postgres,
180    ///             r#"SELECT "cake"."id", "cake"."name" FROM "cake""#,
181    ///             []
182    ///         ),
183    ///     ]
184    /// );
185    /// #
186    /// # Ok(())
187    /// # }
188    /// ```
189    fn find() -> Select<Self> {
190        Select::new()
191    }
192
193    /// Same as `find_related`, but using the other Entity's relation definition.
194    /// Not stable.
195    #[doc(hidden)]
196    fn find_related_rev<R>() -> Select<R>
197    where
198        R: EntityTrait,
199        R: Related<Self>,
200    {
201        use crate::{JoinType, QuerySelect};
202        Select::<R>::new().join_join(JoinType::InnerJoin, R::to(), R::via())
203    }
204
205    /// Find a model by primary key
206    ///
207    /// # Example
208    ///
209    /// ```
210    /// # use sea_orm::{error::*, tests_cfg::*, *};
211    /// #
212    /// # #[smol_potat::main]
213    /// # #[cfg(feature = "mock")]
214    /// # pub async fn main() -> Result<(), DbErr> {
215    /// #
216    /// # let db = MockDatabase::new(DbBackend::Postgres)
217    /// #     .append_query_results([
218    /// #         [
219    /// #             cake::Model {
220    /// #                 id: 11,
221    /// #                 name: "Sponge Cake".to_owned(),
222    /// #             },
223    /// #         ],
224    /// #     ])
225    /// #     .into_connection();
226    /// #
227    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
228    ///
229    /// assert_eq!(
230    ///     cake::Entity::find_by_id(11).all(&db).await?,
231    ///     [cake::Model {
232    ///         id: 11,
233    ///         name: "Sponge Cake".to_owned(),
234    ///     }]
235    /// );
236    ///
237    /// assert_eq!(
238    ///     db.into_transaction_log(),
239    ///     [Transaction::from_sql_and_values(
240    ///         DbBackend::Postgres,
241    ///         r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "cake"."id" = $1"#,
242    ///         [11i32.into()]
243    ///     )]
244    /// );
245    /// #
246    /// # Ok(())
247    /// # }
248    /// ```
249    /// Find by composite key
250    /// ```
251    /// # use sea_orm::{error::*, tests_cfg::*, *};
252    /// #
253    /// # #[smol_potat::main]
254    /// # #[cfg(feature = "mock")]
255    /// # pub async fn main() -> Result<(), DbErr> {
256    /// #
257    /// # let db = MockDatabase::new(DbBackend::Postgres)
258    /// #     .append_query_results([
259    /// #         [
260    /// #             cake_filling::Model {
261    /// #                 cake_id: 2,
262    /// #                 filling_id: 3,
263    /// #             },
264    /// #         ],
265    /// #     ])
266    /// #     .into_connection();
267    /// #
268    /// use sea_orm::{entity::*, query::*, tests_cfg::cake_filling};
269    ///
270    /// assert_eq!(
271    ///     cake_filling::Entity::find_by_id((2, 3)).all(&db).await?,
272    ///     [cake_filling::Model {
273    ///         cake_id: 2,
274    ///         filling_id: 3,
275    ///     }]
276    /// );
277    ///
278    /// assert_eq!(
279    ///     db.into_transaction_log(),
280    ///     [Transaction::from_sql_and_values(
281    ///         DbBackend::Postgres,
282    ///         [
283    ///             r#"SELECT "cake_filling"."cake_id", "cake_filling"."filling_id" FROM "cake_filling""#,
284    ///             r#"WHERE "cake_filling"."cake_id" = $1 AND "cake_filling"."filling_id" = $2"#,
285    ///         ].join(" ").as_str(),
286    ///         [2i32.into(), 3i32.into()]
287    ///     )]);
288    /// #
289    /// # Ok(())
290    /// # }
291    /// ```
292    fn find_by_id<T>(values: T) -> Select<Self>
293    where
294        T: Into<<Self::PrimaryKey as PrimaryKeyTrait>::ValueType>,
295    {
296        let mut select = Self::find();
297        let mut keys = Self::PrimaryKey::iter();
298        for v in values.into().into_value_tuple() {
299            if let Some(key) = keys.next() {
300                let col = key.into_column();
301                select = select.filter(col.eq(v));
302            } else {
303                unreachable!("primary key arity mismatch");
304            }
305        }
306        select
307    }
308
309    /// Get primary key as Identity
310    fn primary_key_identity() -> Identity {
311        let mut cols = Self::PrimaryKey::iter();
312        macro_rules! next {
313            () => {
314                cols.next()
315                    .expect("Already checked arity")
316                    .into_column()
317                    .as_column_ref()
318                    .1
319            };
320        }
321        match <<Self::PrimaryKey as PrimaryKeyTrait>::ValueType as PrimaryKeyArity>::ARITY {
322            1 => {
323                let s1 = next!();
324                Identity::Unary(s1)
325            }
326            2 => {
327                let s1 = next!();
328                let s2 = next!();
329                Identity::Binary(s1, s2)
330            }
331            3 => {
332                let s1 = next!();
333                let s2 = next!();
334                let s3 = next!();
335                Identity::Ternary(s1, s2, s3)
336            }
337            len => {
338                let mut vec = Vec::with_capacity(len);
339                for _ in 0..len {
340                    let s = next!();
341                    vec.push(s);
342                }
343                Identity::Many(vec)
344            }
345        }
346    }
347
348    /// Insert a model into database
349    ///
350    /// # Example (Postgres)
351    ///
352    /// ```
353    /// # use sea_orm::{error::*, tests_cfg::*, *};
354    /// #
355    /// # #[smol_potat::main]
356    /// # #[cfg(feature = "mock")]
357    /// # pub async fn main() -> Result<(), DbErr> {
358    /// #
359    /// # let db = MockDatabase::new(DbBackend::Postgres)
360    /// #     .append_query_results([[maplit::btreemap! {
361    /// #         "id" => Into::<Value>::into(15),
362    /// #     }]])
363    /// #     .into_connection();
364    /// #
365    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
366    ///
367    /// let apple = cake::ActiveModel {
368    ///     name: Set("Apple Pie".to_owned()),
369    ///     ..Default::default()
370    /// };
371    ///
372    /// let insert_result = cake::Entity::insert(apple).exec(&db).await?;
373    ///
374    /// assert_eq!(dbg!(insert_result.last_insert_id), 15);
375    ///
376    /// assert_eq!(
377    ///     db.into_transaction_log(),
378    ///     [Transaction::from_sql_and_values(
379    ///         DbBackend::Postgres,
380    ///         r#"INSERT INTO "cake" ("name") VALUES ($1) RETURNING "id""#,
381    ///         ["Apple Pie".into()]
382    ///     )]
383    /// );
384    /// #
385    /// # Ok(())
386    /// # }
387    /// ```
388    ///
389    /// # Example (MySQL)
390    ///
391    /// ```
392    /// # use sea_orm::{error::*, tests_cfg::*, *};
393    /// #
394    /// # #[smol_potat::main]
395    /// # #[cfg(feature = "mock")]
396    /// # pub async fn main() -> Result<(), DbErr> {
397    /// #
398    /// # let db = MockDatabase::new(DbBackend::MySql)
399    /// #     .append_exec_results([
400    /// #         MockExecResult {
401    /// #             last_insert_id: 15,
402    /// #             rows_affected: 1,
403    /// #         },
404    /// #     ])
405    /// #     .into_connection();
406    /// #
407    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
408    ///
409    /// let apple = cake::ActiveModel {
410    ///     name: Set("Apple Pie".to_owned()),
411    ///     ..Default::default()
412    /// };
413    ///
414    /// let insert_result = cake::Entity::insert(apple).exec(&db).await?;
415    ///
416    /// assert_eq!(insert_result.last_insert_id, 15);
417    ///
418    /// assert_eq!(
419    ///     db.into_transaction_log(),
420    ///     [Transaction::from_sql_and_values(
421    ///         DbBackend::MySql,
422    ///         r#"INSERT INTO `cake` (`name`) VALUES (?)"#,
423    ///         ["Apple Pie".into()]
424    ///     )]
425    /// );
426    /// #
427    /// # Ok(())
428    /// # }
429    /// ```
430    ///
431    /// To get back inserted Model
432    ///
433    /// ```
434    /// # use sea_orm::{error::*, tests_cfg::*, *};
435    /// #
436    /// # #[smol_potat::main]
437    /// # #[cfg(feature = "mock")]
438    /// # pub async fn main() -> Result<(), DbErr> {
439    /// #
440    /// # let db = MockDatabase::new(DbBackend::Postgres)
441    /// #     .append_query_results([
442    /// #         [cake::Model {
443    /// #             id: 1,
444    /// #             name: "Apple Pie".to_owned(),
445    /// #         }],
446    /// #     ])
447    /// #     .into_connection();
448    /// #
449    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
450    ///
451    /// assert_eq!(
452    ///     cake::Entity::insert(cake::ActiveModel {
453    ///         id: NotSet,
454    ///         name: Set("Apple Pie".to_owned()),
455    ///     })
456    ///     .exec_with_returning(&db)
457    ///     .await?,
458    ///     cake::Model {
459    ///         id: 1,
460    ///         name: "Apple Pie".to_owned(),
461    ///     }
462    /// );
463    ///
464    /// assert_eq!(
465    ///     db.into_transaction_log()[0].statements()[0].sql,
466    ///     r#"INSERT INTO "cake" ("name") VALUES ($1) RETURNING "id", "name""#
467    /// );
468    /// #
469    /// # Ok(())
470    /// # }
471    /// ```
472    fn insert<A>(model: A) -> Insert<A>
473    where
474        A: ActiveModelTrait<Entity = Self>,
475    {
476        Insert::one(model)
477    }
478
479    /// Insert many models into database
480    ///
481    /// # Example (Postgres)
482    ///
483    /// ```
484    /// # use sea_orm::{error::*, tests_cfg::*, *};
485    /// #
486    /// # #[smol_potat::main]
487    /// # #[cfg(feature = "mock")]
488    /// # pub async fn main() -> Result<(), DbErr> {
489    /// #
490    /// # let db = MockDatabase::new(DbBackend::Postgres)
491    /// #     .append_query_results([[maplit::btreemap! {
492    /// #         "id" => Into::<Value>::into(28),
493    /// #     }]])
494    /// #     .into_connection();
495    /// #
496    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
497    ///
498    /// let apple = cake::ActiveModel {
499    ///     name: Set("Apple Pie".to_owned()),
500    ///     ..Default::default()
501    /// };
502    /// let orange = cake::ActiveModel {
503    ///     name: Set("Orange Scone".to_owned()),
504    ///     ..Default::default()
505    /// };
506    ///
507    /// let insert_result = cake::Entity::insert_many::<cake::ActiveModel, _>([])
508    ///     .exec(&db)
509    ///     .await?;
510    ///
511    /// assert_eq!(insert_result.last_insert_id, None);
512    ///
513    /// let insert_result = cake::Entity::insert_many([apple, orange]).exec(&db).await?;
514    ///
515    /// assert_eq!(insert_result.last_insert_id, Some(28));
516    ///
517    /// assert_eq!(
518    ///     db.into_transaction_log(),
519    ///     [Transaction::from_sql_and_values(
520    ///         DbBackend::Postgres,
521    ///         r#"INSERT INTO "cake" ("name") VALUES ($1), ($2) RETURNING "id""#,
522    ///         ["Apple Pie".into(), "Orange Scone".into()]
523    ///     )]
524    /// );
525    /// #
526    /// # Ok(())
527    /// # }
528    /// ```
529    ///
530    /// # Example (MySQL)
531    ///
532    /// ```
533    /// # use sea_orm::{error::*, tests_cfg::*, *};
534    /// #
535    /// # #[smol_potat::main]
536    /// # #[cfg(feature = "mock")]
537    /// # pub async fn main() -> Result<(), DbErr> {
538    /// #
539    /// # let db = MockDatabase::new(DbBackend::MySql)
540    /// #     .append_exec_results([
541    /// #         MockExecResult {
542    /// #             last_insert_id: 28,
543    /// #             rows_affected: 2,
544    /// #         },
545    /// #     ])
546    /// #     .into_connection();
547    /// #
548    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
549    ///
550    /// let apple = cake::ActiveModel {
551    ///     name: Set("Apple Pie".to_owned()),
552    ///     ..Default::default()
553    /// };
554    /// let orange = cake::ActiveModel {
555    ///     name: Set("Orange Scone".to_owned()),
556    ///     ..Default::default()
557    /// };
558    ///
559    /// let insert_result = cake::Entity::insert_many([apple, orange]).exec(&db).await?;
560    ///
561    /// assert_eq!(insert_result.last_insert_id, Some(28));
562    ///
563    /// assert_eq!(
564    ///     db.into_transaction_log(),
565    ///     [Transaction::from_sql_and_values(
566    ///         DbBackend::MySql,
567    ///         r#"INSERT INTO `cake` (`name`) VALUES (?), (?)"#,
568    ///         ["Apple Pie".into(), "Orange Scone".into()]
569    ///     )]
570    /// );
571    /// #
572    /// # Ok(())
573    /// # }
574    /// ```
575    ///
576    /// Before 1.1.3, if the active models have different column set, this method would panic.
577    /// Now, it'd attempt to fill in the missing columns with null
578    /// (which may or may not be correct, depending on whether the column is nullable):
579    ///
580    /// ```
581    /// use sea_orm::{
582    ///     DbBackend,
583    ///     entity::*,
584    ///     query::*,
585    ///     tests_cfg::{cake, cake_filling},
586    /// };
587    ///
588    /// assert_eq!(
589    ///     cake::Entity::insert_many([
590    ///         cake::ActiveModel {
591    ///             id: NotSet,
592    ///             name: Set("Apple Pie".to_owned()),
593    ///         },
594    ///         cake::ActiveModel {
595    ///             id: NotSet,
596    ///             name: Set("Orange Scone".to_owned()),
597    ///         }
598    ///     ])
599    ///     .build(DbBackend::Postgres)
600    ///     .to_string(),
601    ///     r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie'), ('Orange Scone')"#,
602    /// );
603    ///
604    /// assert_eq!(
605    ///     cake_filling::Entity::insert_many([
606    ///         cake_filling::ActiveModel {
607    ///             cake_id: ActiveValue::set(2),
608    ///             filling_id: ActiveValue::NotSet,
609    ///         },
610    ///         cake_filling::ActiveModel {
611    ///             cake_id: ActiveValue::NotSet,
612    ///             filling_id: ActiveValue::set(3),
613    ///         }
614    ///     ])
615    ///     .build(DbBackend::Postgres)
616    ///     .to_string(),
617    ///     r#"INSERT INTO "cake_filling" ("cake_id", "filling_id") VALUES (2, NULL), (NULL, 3)"#,
618    /// );
619    /// ```
620    ///
621    /// To get back inserted Models
622    ///
623    /// ```
624    /// # use sea_orm::{error::*, tests_cfg::*, *};
625    /// #
626    /// # #[smol_potat::main]
627    /// # #[cfg(feature = "mock")]
628    /// # pub async fn main() -> Result<(), DbErr> {
629    /// #
630    /// # let db = MockDatabase::new(DbBackend::Postgres)
631    /// #     .append_query_results([
632    /// #         [cake::Model {
633    /// #             id: 1,
634    /// #             name: "Apple Pie".to_owned(),
635    /// #         }, cake::Model {
636    /// #             id: 2,
637    /// #             name: "Choco Pie".to_owned(),
638    /// #         }],
639    /// #     ])
640    /// #     .into_connection();
641    /// #
642    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
643    ///
644    /// assert_eq!(
645    ///     cake::Entity::insert_many([
646    ///         cake::ActiveModel {
647    ///             id: NotSet,
648    ///             name: Set("Apple Pie".to_owned()),
649    ///         },
650    ///         cake::ActiveModel {
651    ///             id: NotSet,
652    ///             name: Set("Choco Pie".to_owned()),
653    ///         },
654    ///     ])
655    ///     .exec_with_returning(&db)
656    ///     .await?,
657    ///     [
658    ///         cake::Model {
659    ///             id: 1,
660    ///             name: "Apple Pie".to_owned(),
661    ///         },
662    ///         cake::Model {
663    ///             id: 2,
664    ///             name: "Choco Pie".to_owned(),
665    ///         }
666    ///     ]
667    /// );
668    ///
669    /// assert_eq!(
670    ///     db.into_transaction_log()[0].statements()[0].sql,
671    ///     r#"INSERT INTO "cake" ("name") VALUES ($1), ($2) RETURNING "id", "name""#
672    /// );
673    /// #
674    /// # Ok(())
675    /// # }
676    /// ```
677    fn insert_many<A, I>(models: I) -> InsertMany<A>
678    where
679        A: ActiveModelTrait<Entity = Self>,
680        I: IntoIterator<Item = A>,
681    {
682        InsertMany::many(models)
683    }
684
685    /// Update a model in database
686    ///
687    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
688    ///
689    /// # Example (Postgres)
690    ///
691    /// ```
692    /// # use sea_orm::{error::*, tests_cfg::*, *};
693    /// #
694    /// # #[smol_potat::main]
695    /// # #[cfg(feature = "mock")]
696    /// # pub async fn main() -> Result<(), DbErr> {
697    /// #
698    /// # let db = MockDatabase::new(DbBackend::Postgres)
699    /// #     .append_query_results([
700    /// #         [fruit::Model {
701    /// #             id: 1,
702    /// #             name: "Orange".to_owned(),
703    /// #             cake_id: None,
704    /// #         }],
705    /// #     ])
706    /// #     .into_connection();
707    /// #
708    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
709    ///
710    /// let orange = fruit::ActiveModel {
711    ///     id: Set(1),
712    ///     name: Set("Orange".to_owned()),
713    ///     ..Default::default()
714    /// };
715    ///
716    /// assert_eq!(
717    ///     fruit::Entity::update(orange.clone())
718    ///         .validate()?
719    ///         .filter(fruit::Column::Name.contains("orange"))
720    ///         .exec(&db)
721    ///         .await?,
722    ///     fruit::Model {
723    ///         id: 1,
724    ///         name: "Orange".to_owned(),
725    ///         cake_id: None,
726    ///     }
727    /// );
728    ///
729    /// assert_eq!(
730    ///     db.into_transaction_log(),
731    ///     [Transaction::from_sql_and_values(
732    ///         DbBackend::Postgres,
733    ///         r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2 AND "fruit"."name" LIKE $3 RETURNING "id", "name", "cake_id""#,
734    ///         ["Orange".into(), 1i32.into(), "%orange%".into()]
735    ///     )]);
736    /// #
737    /// # Ok(())
738    /// # }
739    /// ```
740    ///
741    /// # Example (MySQL)
742    ///
743    /// ```
744    /// # use sea_orm::{error::*, tests_cfg::*, *};
745    /// #
746    /// # #[smol_potat::main]
747    /// # #[cfg(feature = "mock")]
748    /// # pub async fn main() -> Result<(), DbErr> {
749    /// #
750    /// # let db = MockDatabase::new(DbBackend::MySql)
751    /// #     .append_exec_results([
752    /// #         MockExecResult {
753    /// #             last_insert_id: 0,
754    /// #             rows_affected: 1,
755    /// #         },
756    /// #     ])
757    /// #     .append_query_results([
758    /// #         [fruit::Model {
759    /// #             id: 1,
760    /// #             name: "Orange".to_owned(),
761    /// #             cake_id: None,
762    /// #         }],
763    /// #     ])
764    /// #     .into_connection();
765    /// #
766    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
767    ///
768    /// let orange = fruit::ActiveModel {
769    ///     id: Set(1),
770    ///     name: Set("Orange".to_owned()),
771    ///     ..Default::default()
772    /// };
773    ///
774    /// assert_eq!(
775    ///     fruit::Entity::update(orange.clone())
776    ///         .validate()?
777    ///         .filter(fruit::Column::Name.contains("orange"))
778    ///         .exec(&db)
779    ///         .await?,
780    ///     fruit::Model {
781    ///         id: 1,
782    ///         name: "Orange".to_owned(),
783    ///         cake_id: None,
784    ///     }
785    /// );
786    ///
787    /// assert_eq!(
788    ///     db.into_transaction_log(),
789    ///     [
790    ///         Transaction::from_sql_and_values(
791    ///             DbBackend::MySql,
792    ///             r#"UPDATE `fruit` SET `name` = ? WHERE `fruit`.`id` = ? AND `fruit`.`name` LIKE ?"#,
793    ///             ["Orange".into(), 1i32.into(), "%orange%".into()]
794    ///         ),
795    ///         Transaction::from_sql_and_values(
796    ///             DbBackend::MySql,
797    ///             r#"SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit` WHERE `fruit`.`id` = ? LIMIT ?"#,
798    ///             [1i32.into(), 1u64.into()]
799    ///         )]);
800    /// #
801    /// # Ok(())
802    /// # }
803    /// ```
804    fn update<A>(model: A) -> UpdateOne<A>
805    where
806        A: ActiveModelTrait<Entity = Self>,
807    {
808        Update::one(model)
809    }
810
811    /// Update many models in database
812    ///
813    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
814    ///
815    /// # Example
816    ///
817    /// ```
818    /// # use sea_orm::{error::*, tests_cfg::*, *};
819    /// #
820    /// # #[smol_potat::main]
821    /// # #[cfg(feature = "mock")]
822    /// # pub async fn main() -> Result<(), DbErr> {
823    /// #
824    /// # let db = MockDatabase::new(DbBackend::Postgres)
825    /// #     .append_exec_results([
826    /// #         MockExecResult {
827    /// #             last_insert_id: 0,
828    /// #             rows_affected: 5,
829    /// #         },
830    /// #     ])
831    /// #     .into_connection();
832    /// #
833    /// use sea_orm::{
834    ///     entity::*,
835    ///     query::*,
836    ///     sea_query::{Expr, Value},
837    ///     tests_cfg::fruit,
838    /// };
839    ///
840    /// let update_result = fruit::Entity::update_many()
841    ///     .col_expr(fruit::Column::CakeId, Expr::value(Value::Int(None)))
842    ///     .filter(fruit::Column::Name.contains("Apple"))
843    ///     .exec(&db)
844    ///     .await?;
845    ///
846    /// assert_eq!(update_result.rows_affected, 5);
847    ///
848    /// assert_eq!(
849    ///     db.into_transaction_log(),
850    ///     [Transaction::from_sql_and_values(
851    ///         DbBackend::Postgres,
852    ///         r#"UPDATE "fruit" SET "cake_id" = $1 WHERE "fruit"."name" LIKE $2"#,
853    ///         [Value::Int(None), "%Apple%".into()]
854    ///     )]
855    /// );
856    /// #
857    /// # Ok(())
858    /// # }
859    /// ```
860    fn update_many() -> UpdateMany<Self> {
861        Update::many(Self::default())
862    }
863
864    /// Delete a model from database
865    ///
866    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
867    ///
868    /// # Example
869    ///
870    /// ```
871    /// # use sea_orm::{error::*, tests_cfg::*, *};
872    /// #
873    /// # #[smol_potat::main]
874    /// # #[cfg(feature = "mock")]
875    /// # pub async fn main() -> Result<(), DbErr> {
876    /// #
877    /// # let db = MockDatabase::new(DbBackend::Postgres)
878    /// #     .append_exec_results([
879    /// #         MockExecResult {
880    /// #             last_insert_id: 0,
881    /// #             rows_affected: 1,
882    /// #         },
883    /// #     ])
884    /// #     .into_connection();
885    /// #
886    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
887    ///
888    /// let orange = fruit::ActiveModel {
889    ///     id: Set(3),
890    ///     ..Default::default()
891    /// };
892    ///
893    /// let delete_result = fruit::Entity::delete(orange).exec(&db).await?;
894    ///
895    /// assert_eq!(delete_result.rows_affected, 1);
896    ///
897    /// assert_eq!(
898    ///     db.into_transaction_log(),
899    ///     [Transaction::from_sql_and_values(
900    ///         DbBackend::Postgres,
901    ///         r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#,
902    ///         [3i32.into()]
903    ///     )]
904    /// );
905    /// #
906    /// # Ok(())
907    /// # }
908    /// ```
909    fn delete<A>(model: A) -> DeleteOne<Self>
910    where
911        A: ActiveModelTrait<Entity = Self>,
912    {
913        Delete::one(model)
914    }
915
916    /// Delete many models from database
917    ///
918    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
919    ///
920    /// # Example
921    ///
922    /// ```
923    /// # use sea_orm::{error::*, tests_cfg::*, *};
924    /// #
925    /// # #[smol_potat::main]
926    /// # #[cfg(feature = "mock")]
927    /// # pub async fn main() -> Result<(), DbErr> {
928    /// #
929    /// # let db = MockDatabase::new(DbBackend::Postgres)
930    /// #     .append_exec_results([
931    /// #         MockExecResult {
932    /// #             last_insert_id: 0,
933    /// #             rows_affected: 5,
934    /// #         },
935    /// #     ])
936    /// #     .append_query_results([
937    /// #         [cake::Model {
938    /// #             id: 15,
939    /// #             name: "Apple Pie".to_owned(),
940    /// #         }],
941    /// #     ])
942    /// #     .into_connection();
943    /// #
944    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
945    ///
946    /// let delete_result = fruit::Entity::delete_many()
947    ///     .filter(fruit::Column::Name.contains("Apple"))
948    ///     .exec(&db)
949    ///     .await?;
950    ///
951    /// assert_eq!(delete_result.rows_affected, 5);
952    ///
953    /// assert_eq!(
954    ///     db.into_transaction_log(),
955    ///     [Transaction::from_sql_and_values(
956    ///         DbBackend::Postgres,
957    ///         r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE $1"#,
958    ///         ["%Apple%".into()]
959    ///     )]
960    /// );
961    /// #
962    /// # Ok(())
963    /// # }
964    /// ```
965    fn delete_many() -> DeleteMany<Self> {
966        Delete::many(Self::default())
967    }
968
969    /// Delete a model based on primary key
970    ///
971    /// # Example
972    ///
973    /// ```
974    /// # use sea_orm::{error::*, tests_cfg::*, *};
975    /// #
976    /// # #[smol_potat::main]
977    /// # #[cfg(feature = "mock")]
978    /// # pub async fn main() -> Result<(), DbErr> {
979    /// #
980    /// # let db = MockDatabase::new(DbBackend::Postgres)
981    /// #     .append_exec_results([
982    /// #         MockExecResult {
983    /// #             last_insert_id: 0,
984    /// #             rows_affected: 1,
985    /// #         },
986    /// #     ])
987    /// #     .into_connection();
988    /// #
989    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
990    ///
991    /// let delete_result = fruit::Entity::delete_by_id(1).exec(&db).await?;
992    ///
993    /// assert_eq!(delete_result.rows_affected, 1);
994    ///
995    /// assert_eq!(
996    ///     db.into_transaction_log(),
997    ///     [Transaction::from_sql_and_values(
998    ///         DbBackend::Postgres,
999    ///         r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#,
1000    ///         [1i32.into()]
1001    ///     )]
1002    /// );
1003    /// #
1004    /// # Ok(())
1005    /// # }
1006    /// ```
1007    /// Delete by composite key
1008    /// ```
1009    /// # use sea_orm::{error::*, tests_cfg::*, *};
1010    /// #
1011    /// # #[smol_potat::main]
1012    /// # #[cfg(feature = "mock")]
1013    /// # pub async fn main() -> Result<(), DbErr> {
1014    ///
1015    /// # let db = MockDatabase::new(DbBackend::Postgres)
1016    /// #     .append_exec_results([
1017    /// #         MockExecResult {
1018    /// #             last_insert_id: 0,
1019    /// #             rows_affected: 1,
1020    /// #         },
1021    /// #     ])
1022    /// #     .into_connection();
1023    /// #
1024    /// use sea_orm::{entity::*, query::*, tests_cfg::cake_filling};
1025    ///
1026    /// let delete_result = cake_filling::Entity::delete_by_id((2, 3)).exec(&db).await?;
1027    ///
1028    /// assert_eq!(delete_result.rows_affected, 1);
1029    ///
1030    /// assert_eq!(
1031    ///     db.into_transaction_log(),
1032    ///     [Transaction::from_sql_and_values(
1033    ///         DbBackend::Postgres,
1034    ///         r#"DELETE FROM "cake_filling" WHERE "cake_filling"."cake_id" = $1 AND "cake_filling"."filling_id" = $2"#,
1035    ///         [2i32.into(), 3i32.into()]
1036    ///     )]
1037    /// );
1038    /// #
1039    /// # Ok(())
1040    /// # }
1041    /// ```
1042    fn delete_by_id<T>(values: T) -> ValidatedDeleteOne<Self>
1043    where
1044        T: Into<<Self::PrimaryKey as PrimaryKeyTrait>::ValueType>,
1045    {
1046        let mut am = Self::ActiveModel::default();
1047        let mut keys = Self::PrimaryKey::iter();
1048        for v in values.into().into_value_tuple() {
1049            if let Some(key) = keys.next() {
1050                let col = key.into_column();
1051                am.set(col, v);
1052            } else {
1053                unreachable!("primary key arity mismatch");
1054            }
1055        }
1056        Delete::one(am).validate().expect("Must be valid")
1057    }
1058}
1059
1060#[cfg(test)]
1061mod tests {
1062    #[test]
1063    fn test_delete_by_id_1() {
1064        use crate::tests_cfg::cake;
1065        use crate::{DbBackend, entity::*, query::*};
1066        assert_eq!(
1067            cake::Entity::delete_by_id(1)
1068                .build(DbBackend::Sqlite)
1069                .to_string(),
1070            r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#,
1071        );
1072    }
1073
1074    #[test]
1075    fn test_delete_by_id_2() {
1076        use crate::tests_cfg::cake_filling_price;
1077        use crate::{DbBackend, entity::*, query::*};
1078        assert_eq!(
1079            cake_filling_price::Entity::delete_by_id((1, 2))
1080                .build(DbBackend::Sqlite)
1081                .to_string(),
1082            r#"DELETE FROM "public"."cake_filling_price" WHERE "cake_filling_price"."cake_id" = 1 AND "cake_filling_price"."filling_id" = 2"#,
1083        );
1084    }
1085
1086    #[test]
1087    #[cfg(feature = "macros")]
1088    fn entity_model_1() {
1089        use crate::entity::*;
1090
1091        mod hello {
1092            use crate as sea_orm;
1093            use crate::entity::prelude::*;
1094
1095            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1096            #[sea_orm(table_name = "hello")]
1097            pub struct Model {
1098                #[sea_orm(primary_key)]
1099                pub id: i32,
1100            }
1101
1102            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1103            pub enum Relation {}
1104
1105            impl ActiveModelBehavior for ActiveModel {}
1106        }
1107
1108        assert_eq!(hello::Entity.table_name(), "hello");
1109        assert_eq!(hello::Entity.schema_name(), None);
1110    }
1111
1112    #[test]
1113    #[cfg(feature = "macros")]
1114    fn entity_model_2() {
1115        use crate::entity::*;
1116
1117        mod hello {
1118            use crate as sea_orm;
1119            use crate::entity::prelude::*;
1120
1121            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1122            #[sea_orm(table_name = "hello", schema_name = "world")]
1123            pub struct Model {
1124                #[sea_orm(primary_key)]
1125                pub id: i32,
1126            }
1127
1128            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1129            pub enum Relation {}
1130
1131            impl ActiveModelBehavior for ActiveModel {}
1132        }
1133
1134        assert_eq!(hello::Entity.table_name(), "hello");
1135        assert_eq!(hello::Entity.schema_name(), Some("world"));
1136    }
1137
1138    #[test]
1139    #[cfg(feature = "macros")]
1140    fn entity_model_3() {
1141        use crate::{DbBackend, entity::*, query::*};
1142        use std::borrow::Cow;
1143
1144        mod hello {
1145            use crate as sea_orm;
1146            use crate::entity::prelude::*;
1147
1148            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1149            #[sea_orm(table_name = "hello", schema_name = "world")]
1150            pub struct Model {
1151                #[sea_orm(primary_key, auto_increment = false)]
1152                pub id: String,
1153            }
1154
1155            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1156            pub enum Relation {}
1157
1158            impl ActiveModelBehavior for ActiveModel {}
1159        }
1160
1161        fn delete_by_id<T>(value: T)
1162        where
1163            T: Into<<<hello::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType>,
1164        {
1165            assert_eq!(
1166                hello::Entity::delete_by_id(value)
1167                    .build(DbBackend::Sqlite)
1168                    .to_string(),
1169                r#"DELETE FROM "world"."hello" WHERE "hello"."id" = 'UUID'"#
1170            );
1171        }
1172
1173        delete_by_id("UUID".to_string());
1174        delete_by_id("UUID");
1175        delete_by_id(Cow::from("UUID"));
1176    }
1177
1178    #[smol_potat::test]
1179    async fn test_find_by_id() {
1180        use crate::tests_cfg::{cake, cake_filling};
1181        use crate::{DbBackend, EntityTrait, MockDatabase};
1182
1183        let db = MockDatabase::new(DbBackend::MySql).into_connection();
1184
1185        cake::Entity::find_by_id(1).all(&db).await.ok();
1186        cake_filling::Entity::find_by_id((2, 3)).all(&db).await.ok();
1187
1188        // below does not compile:
1189
1190        // cake::Entity::find_by_id((1, 2)).all(&db).await.ok();
1191        // cake_filling::Entity::find_by_id(1).all(&db).await.ok();
1192        // cake_filling::Entity::find_by_id((1, 2, 3))
1193        //     .all(&db)
1194        //     .await
1195        //     .ok();
1196    }
1197
1198    #[test]
1199    fn test_triangle() {
1200        mod triangle {
1201            use crate as sea_orm;
1202            use sea_orm::entity::prelude::*;
1203            use serde::{Deserialize, Serialize};
1204
1205            #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
1206            #[sea_orm(table_name = "triangle")]
1207            pub struct Model {
1208                #[sea_orm(primary_key)]
1209                pub id: i32,
1210                pub p1: Point,
1211                pub p2: Point,
1212                pub p3: Point,
1213            }
1214
1215            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1216            pub enum Relation {}
1217
1218            impl ActiveModelBehavior for ActiveModel {}
1219
1220            #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, FromJsonQueryResult)]
1221            pub struct Point {
1222                pub x: f64,
1223                pub y: f64,
1224            }
1225        }
1226        use triangle::{Model as Triangle, Point};
1227
1228        impl Triangle {
1229            fn area(&self) -> f64 {
1230                let a = self.p1.distance_to(&self.p2);
1231                let b = self.p2.distance_to(&self.p3);
1232                let c = self.p3.distance_to(&self.p1);
1233                let s = (a + b + c) / 2.0;
1234                (s * (s - a) * (s - b) * (s - c)).sqrt()
1235            }
1236        }
1237
1238        impl Point {
1239            fn distance_to(&self, p: &Point) -> f64 {
1240                let dx = self.x - p.x;
1241                let dy = self.y - p.y;
1242                (dx * dx + dy * dy).sqrt()
1243            }
1244        }
1245
1246        assert!(
1247            (Triangle {
1248                id: 1,
1249                p1: Point { x: 0., y: 0. },
1250                p2: Point { x: 2., y: 0. },
1251                p3: Point { x: 0., y: 2. },
1252            }
1253            .area()
1254                - 2.)
1255                .abs()
1256                < 0.00000001
1257        );
1258    }
1259}