sea_orm/entity/
base_entity.rs

1use crate::{
2    ActiveModelBehavior, ActiveModelTrait, ColumnTrait, Delete, DeleteMany, DeleteOne,
3    FromQueryResult, Insert, ModelTrait, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, Related,
4    RelationBuilder, RelationTrait, RelationType, Select, Update, UpdateMany, UpdateOne,
5};
6use sea_query::{Alias, Iden, IntoIden, IntoTableRef, IntoValueTuple, TableRef};
7use std::fmt::Debug;
8pub use strum::IntoEnumIterator as Iterable;
9
10/// Ensure the identifier for an Entity can be converted to a static str
11pub trait IdenStatic: Iden + Copy + Debug + 'static {
12    /// Method to call to get the static string identity
13    fn as_str(&self) -> &str;
14}
15
16/// A Trait for mapping an Entity to a database table
17pub trait EntityName: IdenStatic + Default {
18    /// Method to get the name for the schema, defaults to [Option::None] if not set
19    fn schema_name(&self) -> Option<&str> {
20        None
21    }
22
23    /// Method to get the comment for the schema, defaults to [Option::None] if not set
24    fn comment(&self) -> Option<&str> {
25        None
26    }
27
28    /// Get the name of the table
29    fn table_name(&self) -> &str;
30
31    /// Get the name of the module from the invoking `self.table_name()`
32    fn module_name(&self) -> &str {
33        self.table_name()
34    }
35
36    /// Get the [TableRef] from invoking the `self.schema_name()`
37    fn table_ref(&self) -> TableRef {
38        match self.schema_name() {
39            Some(schema) => (Alias::new(schema).into_iden(), self.into_iden()).into_table_ref(),
40            None => self.into_table_ref(),
41        }
42    }
43}
44
45/// An abstract base class for defining Entities.
46///
47/// This trait provides an API for you to inspect it's properties
48/// - Column (implemented [`ColumnTrait`])
49/// - Relation (implemented [`RelationTrait`])
50/// - Primary Key (implemented [`PrimaryKeyTrait`] and [`PrimaryKeyToColumn`])
51///
52/// This trait also provides an API for CRUD actions
53/// - Select: `find`, `find_*`
54/// - Insert: `insert`, `insert_*`
55/// - Update: `update`, `update_*`
56/// - Delete: `delete`, `delete_*`
57pub trait EntityTrait: EntityName {
58    #[allow(missing_docs)]
59    type Model: ModelTrait<Entity = Self> + FromQueryResult;
60
61    #[allow(missing_docs)]
62    type ActiveModel: ActiveModelBehavior<Entity = Self>;
63
64    #[allow(missing_docs)]
65    type Column: ColumnTrait;
66
67    #[allow(missing_docs)]
68    type Relation: RelationTrait;
69
70    #[allow(missing_docs)]
71    type PrimaryKey: PrimaryKeyTrait + PrimaryKeyToColumn<Column = Self::Column>;
72
73    /// Construct a belongs to relation
74    fn belongs_to<R>(related: R) -> RelationBuilder<Self, R>
75    where
76        R: EntityTrait,
77    {
78        RelationBuilder::new(RelationType::HasOne, Self::default(), related, false)
79    }
80
81    /// Construct a has one relation
82    fn has_one<R>(_: R) -> RelationBuilder<Self, R>
83    where
84        R: EntityTrait + Related<Self>,
85    {
86        RelationBuilder::from_rel(RelationType::HasOne, R::to().rev(), true)
87    }
88
89    /// Construct a has many relation
90    fn has_many<R>(_: R) -> RelationBuilder<Self, R>
91    where
92        R: EntityTrait + Related<Self>,
93    {
94        RelationBuilder::from_rel(RelationType::HasMany, R::to().rev(), true)
95    }
96
97    /// Construct select statement to find one / all models
98    ///
99    /// - To select columns, join tables and group by expressions, see [`QuerySelect`](crate::query::QuerySelect)
100    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
101    /// - To apply order by expressions, see [`QueryOrder`](crate::query::QueryOrder)
102    ///
103    /// # Example
104    ///
105    /// ```
106    /// # use sea_orm::{error::*, tests_cfg::*, *};
107    /// #
108    /// # #[smol_potat::main]
109    /// # #[cfg(feature = "mock")]
110    /// # pub async fn main() -> Result<(), DbErr> {
111    /// #
112    /// # let db = MockDatabase::new(DbBackend::Postgres)
113    /// #     .append_query_results([
114    /// #         vec![
115    /// #             cake::Model {
116    /// #                 id: 1,
117    /// #                 name: "New York Cheese".to_owned(),
118    /// #             },
119    /// #         ],
120    /// #         vec![
121    /// #             cake::Model {
122    /// #                 id: 1,
123    /// #                 name: "New York Cheese".to_owned(),
124    /// #             },
125    /// #             cake::Model {
126    /// #                 id: 2,
127    /// #                 name: "Chocolate Forest".to_owned(),
128    /// #             },
129    /// #         ],
130    /// #     ])
131    /// #     .into_connection();
132    /// #
133    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
134    ///
135    /// assert_eq!(
136    ///     cake::Entity::find().one(&db).await?,
137    ///     Some(cake::Model {
138    ///         id: 1,
139    ///         name: "New York Cheese".to_owned(),
140    ///     })
141    /// );
142    ///
143    /// assert_eq!(
144    ///     cake::Entity::find().all(&db).await?,
145    ///     [
146    ///         cake::Model {
147    ///             id: 1,
148    ///             name: "New York Cheese".to_owned(),
149    ///         },
150    ///         cake::Model {
151    ///             id: 2,
152    ///             name: "Chocolate Forest".to_owned(),
153    ///         },
154    ///     ]
155    /// );
156    ///
157    /// assert_eq!(
158    ///     db.into_transaction_log(),
159    ///     [
160    ///         Transaction::from_sql_and_values(
161    ///             DbBackend::Postgres,
162    ///             r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#,
163    ///             [1u64.into()]
164    ///         ),
165    ///         Transaction::from_sql_and_values(
166    ///             DbBackend::Postgres,
167    ///             r#"SELECT "cake"."id", "cake"."name" FROM "cake""#,
168    ///             []
169    ///         ),
170    ///     ]
171    /// );
172    /// #
173    /// # Ok(())
174    /// # }
175    /// ```
176    fn find() -> Select<Self> {
177        Select::new()
178    }
179
180    /// Find a model by primary key
181    ///
182    /// # Example
183    ///
184    /// ```
185    /// # use sea_orm::{error::*, tests_cfg::*, *};
186    /// #
187    /// # #[smol_potat::main]
188    /// # #[cfg(feature = "mock")]
189    /// # pub async fn main() -> Result<(), DbErr> {
190    /// #
191    /// # let db = MockDatabase::new(DbBackend::Postgres)
192    /// #     .append_query_results([
193    /// #         [
194    /// #             cake::Model {
195    /// #                 id: 11,
196    /// #                 name: "Sponge Cake".to_owned(),
197    /// #             },
198    /// #         ],
199    /// #     ])
200    /// #     .into_connection();
201    /// #
202    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
203    ///
204    /// assert_eq!(
205    ///     cake::Entity::find_by_id(11).all(&db).await?,
206    ///     [cake::Model {
207    ///         id: 11,
208    ///         name: "Sponge Cake".to_owned(),
209    ///     }]
210    /// );
211    ///
212    /// assert_eq!(
213    ///     db.into_transaction_log(),
214    ///     [Transaction::from_sql_and_values(
215    ///         DbBackend::Postgres,
216    ///         r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "cake"."id" = $1"#,
217    ///         [11i32.into()]
218    ///     )]
219    /// );
220    /// #
221    /// # Ok(())
222    /// # }
223    /// ```
224    /// Find by composite key
225    /// ```
226    /// # use sea_orm::{error::*, tests_cfg::*, *};
227    /// #
228    /// # #[smol_potat::main]
229    /// # #[cfg(feature = "mock")]
230    /// # pub async fn main() -> Result<(), DbErr> {
231    /// #
232    /// # let db = MockDatabase::new(DbBackend::Postgres)
233    /// #     .append_query_results([
234    /// #         [
235    /// #             cake_filling::Model {
236    /// #                 cake_id: 2,
237    /// #                 filling_id: 3,
238    /// #             },
239    /// #         ],
240    /// #     ])
241    /// #     .into_connection();
242    /// #
243    /// use sea_orm::{entity::*, query::*, tests_cfg::cake_filling};
244    ///
245    /// assert_eq!(
246    ///     cake_filling::Entity::find_by_id((2, 3)).all(&db).await?,
247    ///     [cake_filling::Model {
248    ///         cake_id: 2,
249    ///         filling_id: 3,
250    ///     }]
251    /// );
252    ///
253    /// assert_eq!(
254    ///     db.into_transaction_log(),
255    ///     [Transaction::from_sql_and_values(
256    ///         DbBackend::Postgres,
257    ///         [
258    ///             r#"SELECT "cake_filling"."cake_id", "cake_filling"."filling_id" FROM "cake_filling""#,
259    ///             r#"WHERE "cake_filling"."cake_id" = $1 AND "cake_filling"."filling_id" = $2"#,
260    ///         ].join(" ").as_str(),
261    ///         [2i32.into(), 3i32.into()]
262    ///     )]);
263    /// #
264    /// # Ok(())
265    /// # }
266    /// ```
267    ///
268    /// # Panics
269    ///
270    /// Panics if arity of input values don't match arity of primary key
271    fn find_by_id<T>(values: T) -> Select<Self>
272    where
273        T: Into<<Self::PrimaryKey as PrimaryKeyTrait>::ValueType>,
274    {
275        let mut select = Self::find();
276        let mut keys = Self::PrimaryKey::iter();
277        for v in values.into().into_value_tuple() {
278            if let Some(key) = keys.next() {
279                let col = key.into_column();
280                select = select.filter(col.eq(v));
281            } else {
282                panic!("primary key arity mismatch");
283            }
284        }
285        if keys.next().is_some() {
286            panic!("primary key arity mismatch");
287        }
288        select
289    }
290
291    /// Insert an model into database
292    ///
293    /// # Example (Postgres)
294    ///
295    /// ```
296    /// # use sea_orm::{error::*, tests_cfg::*, *};
297    /// #
298    /// # #[smol_potat::main]
299    /// # #[cfg(feature = "mock")]
300    /// # pub async fn main() -> Result<(), DbErr> {
301    /// #
302    /// # let db = MockDatabase::new(DbBackend::Postgres)
303    /// #     .append_query_results([[maplit::btreemap! {
304    /// #         "id" => Into::<Value>::into(15),
305    /// #     }]])
306    /// #     .into_connection();
307    /// #
308    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
309    ///
310    /// let apple = cake::ActiveModel {
311    ///     name: Set("Apple Pie".to_owned()),
312    ///     ..Default::default()
313    /// };
314    ///
315    /// let insert_result = cake::Entity::insert(apple).exec(&db).await?;
316    ///
317    /// assert_eq!(dbg!(insert_result.last_insert_id), 15);
318    ///
319    /// assert_eq!(
320    ///     db.into_transaction_log(),
321    ///     [Transaction::from_sql_and_values(
322    ///         DbBackend::Postgres,
323    ///         r#"INSERT INTO "cake" ("name") VALUES ($1) RETURNING "id""#,
324    ///         ["Apple Pie".into()]
325    ///     )]
326    /// );
327    /// #
328    /// # Ok(())
329    /// # }
330    /// ```
331    ///
332    /// # Example (MySQL)
333    ///
334    /// ```
335    /// # use sea_orm::{error::*, tests_cfg::*, *};
336    /// #
337    /// # #[smol_potat::main]
338    /// # #[cfg(feature = "mock")]
339    /// # pub async fn main() -> Result<(), DbErr> {
340    /// #
341    /// # let db = MockDatabase::new(DbBackend::MySql)
342    /// #     .append_exec_results([
343    /// #         MockExecResult {
344    /// #             last_insert_id: 15,
345    /// #             rows_affected: 1,
346    /// #         },
347    /// #     ])
348    /// #     .into_connection();
349    /// #
350    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
351    ///
352    /// let apple = cake::ActiveModel {
353    ///     name: Set("Apple Pie".to_owned()),
354    ///     ..Default::default()
355    /// };
356    ///
357    /// let insert_result = cake::Entity::insert(apple).exec(&db).await?;
358    ///
359    /// assert_eq!(insert_result.last_insert_id, 15);
360    ///
361    /// assert_eq!(
362    ///     db.into_transaction_log(),
363    ///     [Transaction::from_sql_and_values(
364    ///         DbBackend::MySql,
365    ///         r#"INSERT INTO `cake` (`name`) VALUES (?)"#,
366    ///         ["Apple Pie".into()]
367    ///     )]
368    /// );
369    /// #
370    /// # Ok(())
371    /// # }
372    /// ```
373    fn insert<A>(model: A) -> Insert<A>
374    where
375        A: ActiveModelTrait<Entity = Self>,
376    {
377        Insert::one(model)
378    }
379
380    /// Insert many models into database
381    ///
382    /// # Example (Postgres)
383    ///
384    /// ```
385    /// # use sea_orm::{error::*, tests_cfg::*, *};
386    /// #
387    /// # #[smol_potat::main]
388    /// # #[cfg(feature = "mock")]
389    /// # pub async fn main() -> Result<(), DbErr> {
390    /// #
391    /// # let db = MockDatabase::new(DbBackend::Postgres)
392    /// #     .append_query_results([[maplit::btreemap! {
393    /// #         "id" => Into::<Value>::into(28),
394    /// #     }]])
395    /// #     .into_connection();
396    /// #
397    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
398    ///
399    /// let apple = cake::ActiveModel {
400    ///     name: Set("Apple Pie".to_owned()),
401    ///     ..Default::default()
402    /// };
403    /// let orange = cake::ActiveModel {
404    ///     name: Set("Orange Scone".to_owned()),
405    ///     ..Default::default()
406    /// };
407    ///
408    /// let insert_result = cake::Entity::insert_many([apple, orange]).exec(&db).await?;
409    ///
410    /// assert_eq!(insert_result.last_insert_id, 28);
411    ///
412    /// assert_eq!(
413    ///     db.into_transaction_log(),
414    ///     [Transaction::from_sql_and_values(
415    ///         DbBackend::Postgres,
416    ///         r#"INSERT INTO "cake" ("name") VALUES ($1), ($2) RETURNING "id""#,
417    ///         ["Apple Pie".into(), "Orange Scone".into()]
418    ///     )]
419    /// );
420    /// #
421    /// # Ok(())
422    /// # }
423    /// ```
424    ///
425    /// # Example (MySQL)
426    ///
427    /// ```
428    /// # use sea_orm::{error::*, tests_cfg::*, *};
429    /// #
430    /// # #[smol_potat::main]
431    /// # #[cfg(feature = "mock")]
432    /// # pub async fn main() -> Result<(), DbErr> {
433    /// #
434    /// # let db = MockDatabase::new(DbBackend::MySql)
435    /// #     .append_exec_results([
436    /// #         MockExecResult {
437    /// #             last_insert_id: 28,
438    /// #             rows_affected: 2,
439    /// #         },
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([apple, orange]).exec(&db).await?;
455    ///
456    /// assert_eq!(insert_result.last_insert_id, 28);
457    ///
458    /// assert_eq!(
459    ///     db.into_transaction_log(),
460    ///     [Transaction::from_sql_and_values(
461    ///         DbBackend::MySql,
462    ///         r#"INSERT INTO `cake` (`name`) VALUES (?), (?)"#,
463    ///         ["Apple Pie".into(), "Orange Scone".into()]
464    ///     )]
465    /// );
466    /// #
467    /// # Ok(())
468    /// # }
469    /// ```
470    ///
471    /// Before 1.1.3, if the active models have different column set, this method would panic.
472    /// Now, it'd attempt to fill in the missing columns with null
473    /// (which may or may not be correct, depending on whether the column is nullable):
474    ///
475    /// ```
476    /// use sea_orm::{
477    ///     entity::*,
478    ///     query::*,
479    ///     tests_cfg::{cake, cake_filling},
480    ///     DbBackend,
481    /// };
482    ///
483    /// assert_eq!(
484    ///     cake::Entity::insert_many([
485    ///         cake::ActiveModel {
486    ///             id: NotSet,
487    ///             name: Set("Apple Pie".to_owned()),
488    ///         },
489    ///         cake::ActiveModel {
490    ///             id: NotSet,
491    ///             name: Set("Orange Scone".to_owned()),
492    ///         }
493    ///     ])
494    ///     .build(DbBackend::Postgres)
495    ///     .to_string(),
496    ///     r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie'), ('Orange Scone')"#,
497    /// );
498    ///
499    /// assert_eq!(
500    ///     cake_filling::Entity::insert_many([
501    ///         cake_filling::ActiveModel {
502    ///             cake_id: ActiveValue::set(2),
503    ///             filling_id: ActiveValue::NotSet,
504    ///         },
505    ///         cake_filling::ActiveModel {
506    ///             cake_id: ActiveValue::NotSet,
507    ///             filling_id: ActiveValue::set(3),
508    ///         }
509    ///     ])
510    ///     .build(DbBackend::Postgres)
511    ///     .to_string(),
512    ///     r#"INSERT INTO "cake_filling" ("cake_id", "filling_id") VALUES (2, NULL), (NULL, 3)"#,
513    /// );
514    /// ```
515    fn insert_many<A, I>(models: I) -> Insert<A>
516    where
517        A: ActiveModelTrait<Entity = Self>,
518        I: IntoIterator<Item = A>,
519    {
520        Insert::many(models)
521    }
522
523    /// Update an model in database
524    ///
525    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
526    ///
527    /// # Example (Postgres)
528    ///
529    /// ```
530    /// # use sea_orm::{error::*, tests_cfg::*, *};
531    /// #
532    /// # #[smol_potat::main]
533    /// # #[cfg(feature = "mock")]
534    /// # pub async fn main() -> Result<(), DbErr> {
535    /// #
536    /// # let db = MockDatabase::new(DbBackend::Postgres)
537    /// #     .append_query_results([
538    /// #         [fruit::Model {
539    /// #             id: 1,
540    /// #             name: "Orange".to_owned(),
541    /// #             cake_id: None,
542    /// #         }],
543    /// #     ])
544    /// #     .into_connection();
545    /// #
546    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
547    ///
548    /// let orange = fruit::ActiveModel {
549    ///     id: Set(1),
550    ///     name: Set("Orange".to_owned()),
551    ///     ..Default::default()
552    /// };
553    ///
554    /// assert_eq!(
555    ///     fruit::Entity::update(orange.clone())
556    ///         .filter(fruit::Column::Name.contains("orange"))
557    ///         .exec(&db)
558    ///         .await?,
559    ///     fruit::Model {
560    ///         id: 1,
561    ///         name: "Orange".to_owned(),
562    ///         cake_id: None,
563    ///     }
564    /// );
565    ///
566    /// assert_eq!(
567    ///     db.into_transaction_log(),
568    ///     [Transaction::from_sql_and_values(
569    ///         DbBackend::Postgres,
570    ///         r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2 AND "fruit"."name" LIKE $3 RETURNING "id", "name", "cake_id""#,
571    ///         ["Orange".into(), 1i32.into(), "%orange%".into()]
572    ///     )]);
573    /// #
574    /// # Ok(())
575    /// # }
576    /// ```
577    ///
578    /// # Example (MySQL)
579    ///
580    /// ```
581    /// # use sea_orm::{error::*, tests_cfg::*, *};
582    /// #
583    /// # #[smol_potat::main]
584    /// # #[cfg(feature = "mock")]
585    /// # pub async fn main() -> Result<(), DbErr> {
586    /// #
587    /// # let db = MockDatabase::new(DbBackend::MySql)
588    /// #     .append_exec_results([
589    /// #         MockExecResult {
590    /// #             last_insert_id: 0,
591    /// #             rows_affected: 1,
592    /// #         },
593    /// #     ])
594    /// #     .append_query_results([
595    /// #         [fruit::Model {
596    /// #             id: 1,
597    /// #             name: "Orange".to_owned(),
598    /// #             cake_id: None,
599    /// #         }],
600    /// #     ])
601    /// #     .into_connection();
602    /// #
603    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
604    ///
605    /// let orange = fruit::ActiveModel {
606    ///     id: Set(1),
607    ///     name: Set("Orange".to_owned()),
608    ///     ..Default::default()
609    /// };
610    ///
611    /// assert_eq!(
612    ///     fruit::Entity::update(orange.clone())
613    ///         .filter(fruit::Column::Name.contains("orange"))
614    ///         .exec(&db)
615    ///         .await?,
616    ///     fruit::Model {
617    ///         id: 1,
618    ///         name: "Orange".to_owned(),
619    ///         cake_id: None,
620    ///     }
621    /// );
622    ///
623    /// assert_eq!(
624    ///     db.into_transaction_log(),
625    ///     [
626    ///         Transaction::from_sql_and_values(
627    ///             DbBackend::MySql,
628    ///             r#"UPDATE `fruit` SET `name` = ? WHERE `fruit`.`id` = ? AND `fruit`.`name` LIKE ?"#,
629    ///             ["Orange".into(), 1i32.into(), "%orange%".into()]
630    ///         ),
631    ///         Transaction::from_sql_and_values(
632    ///             DbBackend::MySql,
633    ///             r#"SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit` WHERE `fruit`.`id` = ? LIMIT ?"#,
634    ///             [1i32.into(), 1u64.into()]
635    ///         )]);
636    /// #
637    /// # Ok(())
638    /// # }
639    /// ```
640    fn update<A>(model: A) -> UpdateOne<A>
641    where
642        A: ActiveModelTrait<Entity = Self>,
643    {
644        Update::one(model)
645    }
646
647    /// Update many models in database
648    ///
649    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
650    ///
651    /// # Example
652    ///
653    /// ```
654    /// # use sea_orm::{error::*, tests_cfg::*, *};
655    /// #
656    /// # #[smol_potat::main]
657    /// # #[cfg(feature = "mock")]
658    /// # pub async fn main() -> Result<(), DbErr> {
659    /// #
660    /// # let db = MockDatabase::new(DbBackend::Postgres)
661    /// #     .append_exec_results([
662    /// #         MockExecResult {
663    /// #             last_insert_id: 0,
664    /// #             rows_affected: 5,
665    /// #         },
666    /// #     ])
667    /// #     .into_connection();
668    /// #
669    /// use sea_orm::{
670    ///     entity::*,
671    ///     query::*,
672    ///     sea_query::{Expr, Value},
673    ///     tests_cfg::fruit,
674    /// };
675    ///
676    /// let update_result = fruit::Entity::update_many()
677    ///     .col_expr(fruit::Column::CakeId, Expr::value(Value::Int(None)))
678    ///     .filter(fruit::Column::Name.contains("Apple"))
679    ///     .exec(&db)
680    ///     .await?;
681    ///
682    /// assert_eq!(update_result.rows_affected, 5);
683    ///
684    /// assert_eq!(
685    ///     db.into_transaction_log(),
686    ///     [Transaction::from_sql_and_values(
687    ///         DbBackend::Postgres,
688    ///         r#"UPDATE "fruit" SET "cake_id" = $1 WHERE "fruit"."name" LIKE $2"#,
689    ///         [Value::Int(None), "%Apple%".into()]
690    ///     )]
691    /// );
692    /// #
693    /// # Ok(())
694    /// # }
695    /// ```
696    fn update_many() -> UpdateMany<Self> {
697        Update::many(Self::default())
698    }
699
700    /// Delete an model from database
701    ///
702    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
703    ///
704    /// # Example
705    ///
706    /// ```
707    /// # use sea_orm::{error::*, tests_cfg::*, *};
708    /// #
709    /// # #[smol_potat::main]
710    /// # #[cfg(feature = "mock")]
711    /// # pub async fn main() -> Result<(), DbErr> {
712    /// #
713    /// # let db = MockDatabase::new(DbBackend::Postgres)
714    /// #     .append_exec_results([
715    /// #         MockExecResult {
716    /// #             last_insert_id: 0,
717    /// #             rows_affected: 1,
718    /// #         },
719    /// #     ])
720    /// #     .into_connection();
721    /// #
722    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
723    ///
724    /// let orange = fruit::ActiveModel {
725    ///     id: Set(3),
726    ///     ..Default::default()
727    /// };
728    ///
729    /// let delete_result = fruit::Entity::delete(orange).exec(&db).await?;
730    ///
731    /// assert_eq!(delete_result.rows_affected, 1);
732    ///
733    /// assert_eq!(
734    ///     db.into_transaction_log(),
735    ///     [Transaction::from_sql_and_values(
736    ///         DbBackend::Postgres,
737    ///         r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#,
738    ///         [3i32.into()]
739    ///     )]
740    /// );
741    /// #
742    /// # Ok(())
743    /// # }
744    /// ```
745    fn delete<A>(model: A) -> DeleteOne<A>
746    where
747        A: ActiveModelTrait<Entity = Self>,
748    {
749        Delete::one(model)
750    }
751
752    /// Delete many models from database
753    ///
754    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
755    ///
756    /// # Example
757    ///
758    /// ```
759    /// # use sea_orm::{error::*, tests_cfg::*, *};
760    /// #
761    /// # #[smol_potat::main]
762    /// # #[cfg(feature = "mock")]
763    /// # pub async fn main() -> Result<(), DbErr> {
764    /// #
765    /// # let db = MockDatabase::new(DbBackend::Postgres)
766    /// #     .append_exec_results([
767    /// #         MockExecResult {
768    /// #             last_insert_id: 0,
769    /// #             rows_affected: 5,
770    /// #         },
771    /// #     ])
772    /// #     .append_query_results([
773    /// #         [cake::Model {
774    /// #             id: 15,
775    /// #             name: "Apple Pie".to_owned(),
776    /// #         }],
777    /// #     ])
778    /// #     .into_connection();
779    /// #
780    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
781    ///
782    /// let delete_result = fruit::Entity::delete_many()
783    ///     .filter(fruit::Column::Name.contains("Apple"))
784    ///     .exec(&db)
785    ///     .await?;
786    ///
787    /// assert_eq!(delete_result.rows_affected, 5);
788    ///
789    /// assert_eq!(
790    ///     db.into_transaction_log(),
791    ///     [Transaction::from_sql_and_values(
792    ///         DbBackend::Postgres,
793    ///         r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE $1"#,
794    ///         ["%Apple%".into()]
795    ///     )]
796    /// );
797    /// #
798    /// # Ok(())
799    /// # }
800    /// ```
801    fn delete_many() -> DeleteMany<Self> {
802        Delete::many(Self::default())
803    }
804
805    /// Delete a model based on primary key
806    ///
807    /// # Example
808    ///
809    /// ```
810    /// # use sea_orm::{error::*, tests_cfg::*, *};
811    /// #
812    /// # #[smol_potat::main]
813    /// # #[cfg(feature = "mock")]
814    /// # pub async fn main() -> Result<(), DbErr> {
815    /// #
816    /// # let db = MockDatabase::new(DbBackend::Postgres)
817    /// #     .append_exec_results([
818    /// #         MockExecResult {
819    /// #             last_insert_id: 0,
820    /// #             rows_affected: 1,
821    /// #         },
822    /// #     ])
823    /// #     .into_connection();
824    /// #
825    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
826    ///
827    /// let delete_result = fruit::Entity::delete_by_id(1).exec(&db).await?;
828    ///
829    /// assert_eq!(delete_result.rows_affected, 1);
830    ///
831    /// assert_eq!(
832    ///     db.into_transaction_log(),
833    ///     [Transaction::from_sql_and_values(
834    ///         DbBackend::Postgres,
835    ///         r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#,
836    ///         [1i32.into()]
837    ///     )]
838    /// );
839    /// #
840    /// # Ok(())
841    /// # }
842    /// ```
843    /// Delete by composite key
844    /// ```
845    /// # use sea_orm::{error::*, tests_cfg::*, *};
846    /// #
847    /// # #[smol_potat::main]
848    /// # #[cfg(feature = "mock")]
849    /// # pub async fn main() -> Result<(), DbErr> {
850    ///
851    /// # let db = MockDatabase::new(DbBackend::Postgres)
852    /// #     .append_exec_results([
853    /// #         MockExecResult {
854    /// #             last_insert_id: 0,
855    /// #             rows_affected: 1,
856    /// #         },
857    /// #     ])
858    /// #     .into_connection();
859    /// #
860    /// use sea_orm::{entity::*, query::*, tests_cfg::cake_filling};
861    ///
862    /// let delete_result = cake_filling::Entity::delete_by_id((2, 3)).exec(&db).await?;
863    ///
864    /// assert_eq!(delete_result.rows_affected, 1);
865    ///
866    /// assert_eq!(
867    ///     db.into_transaction_log(),
868    ///     [Transaction::from_sql_and_values(
869    ///         DbBackend::Postgres,
870    ///         r#"DELETE FROM "cake_filling" WHERE "cake_filling"."cake_id" = $1 AND "cake_filling"."filling_id" = $2"#,
871    ///         [2i32.into(), 3i32.into()]
872    ///     )]
873    /// );
874    /// #
875    /// # Ok(())
876    /// # }
877    /// ```
878    ///
879    /// # Panics
880    ///
881    /// Panics if arity of input values don't match arity of primary key
882    fn delete_by_id<T>(values: T) -> DeleteMany<Self>
883    where
884        T: Into<<Self::PrimaryKey as PrimaryKeyTrait>::ValueType>,
885    {
886        let mut delete = Self::delete_many();
887        let mut keys = Self::PrimaryKey::iter();
888        for v in values.into().into_value_tuple() {
889            if let Some(key) = keys.next() {
890                let col = key.into_column();
891                delete = delete.filter(col.eq(v));
892            } else {
893                panic!("primary key arity mismatch");
894            }
895        }
896        if keys.next().is_some() {
897            panic!("primary key arity mismatch");
898        }
899        delete
900    }
901}
902
903#[cfg(test)]
904mod tests {
905    #[test]
906    fn test_delete_by_id_1() {
907        use crate::tests_cfg::cake;
908        use crate::{entity::*, query::*, DbBackend};
909        assert_eq!(
910            cake::Entity::delete_by_id(1)
911                .build(DbBackend::Sqlite)
912                .to_string(),
913            r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#,
914        );
915    }
916
917    #[test]
918    fn test_delete_by_id_2() {
919        use crate::tests_cfg::cake_filling_price;
920        use crate::{entity::*, query::*, DbBackend};
921        assert_eq!(
922            cake_filling_price::Entity::delete_by_id((1, 2))
923                .build(DbBackend::Sqlite)
924                .to_string(),
925            r#"DELETE FROM "public"."cake_filling_price" WHERE "cake_filling_price"."cake_id" = 1 AND "cake_filling_price"."filling_id" = 2"#,
926        );
927    }
928
929    #[test]
930    #[cfg(feature = "macros")]
931    fn entity_model_1() {
932        use crate::entity::*;
933
934        mod hello {
935            use crate as sea_orm;
936            use crate::entity::prelude::*;
937
938            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
939            #[sea_orm(table_name = "hello")]
940            pub struct Model {
941                #[sea_orm(primary_key)]
942                pub id: i32,
943            }
944
945            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
946            pub enum Relation {}
947
948            impl ActiveModelBehavior for ActiveModel {}
949        }
950
951        assert_eq!(hello::Entity.table_name(), "hello");
952        assert_eq!(hello::Entity.schema_name(), None);
953    }
954
955    #[test]
956    #[cfg(feature = "macros")]
957    fn entity_model_2() {
958        use crate::entity::*;
959
960        mod hello {
961            use crate as sea_orm;
962            use crate::entity::prelude::*;
963
964            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
965            #[sea_orm(table_name = "hello", schema_name = "world")]
966            pub struct Model {
967                #[sea_orm(primary_key)]
968                pub id: i32,
969            }
970
971            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
972            pub enum Relation {}
973
974            impl ActiveModelBehavior for ActiveModel {}
975        }
976
977        assert_eq!(hello::Entity.table_name(), "hello");
978        assert_eq!(hello::Entity.schema_name(), Some("world"));
979    }
980
981    #[test]
982    #[cfg(feature = "macros")]
983    fn entity_model_3() {
984        use crate::{entity::*, query::*, DbBackend};
985        use std::borrow::Cow;
986
987        mod hello {
988            use crate as sea_orm;
989            use crate::entity::prelude::*;
990
991            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
992            #[sea_orm(table_name = "hello", schema_name = "world")]
993            pub struct Model {
994                #[sea_orm(primary_key, auto_increment = false)]
995                pub id: String,
996            }
997
998            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
999            pub enum Relation {}
1000
1001            impl ActiveModelBehavior for ActiveModel {}
1002        }
1003
1004        fn delete_by_id<T>(value: T)
1005        where
1006            T: Into<<<hello::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType>,
1007        {
1008            assert_eq!(
1009                hello::Entity::delete_by_id(value)
1010                    .build(DbBackend::Sqlite)
1011                    .to_string(),
1012                r#"DELETE FROM "world"."hello" WHERE "hello"."id" = 'UUID'"#
1013            );
1014        }
1015
1016        delete_by_id("UUID".to_string());
1017        delete_by_id("UUID");
1018        delete_by_id(Cow::from("UUID"));
1019    }
1020}