sea_orm/entity/
base_entity.rs

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