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 a 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    ///
374    /// To get back inserted Model
375    ///
376    /// ```
377    /// # use sea_orm::{error::*, tests_cfg::*, *};
378    /// #
379    /// # #[smol_potat::main]
380    /// # #[cfg(feature = "mock")]
381    /// # pub async fn main() -> Result<(), DbErr> {
382    /// #
383    /// # let db = MockDatabase::new(DbBackend::Postgres)
384    /// #     .append_query_results([
385    /// #         [cake::Model {
386    /// #             id: 1,
387    /// #             name: "Apple Pie".to_owned(),
388    /// #         }],
389    /// #     ])
390    /// #     .into_connection();
391    /// #
392    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
393    ///
394    /// assert_eq!(
395    ///     cake::Entity::insert(cake::ActiveModel {
396    ///         id: NotSet,
397    ///         name: Set("Apple Pie".to_owned()),
398    ///     })
399    ///     .exec_with_returning(&db)
400    ///     .await?,
401    ///     cake::Model {
402    ///         id: 1,
403    ///         name: "Apple Pie".to_owned(),
404    ///     }
405    /// );
406    ///
407    /// assert_eq!(
408    ///     db.into_transaction_log()[0].statements()[0].sql,
409    ///     r#"INSERT INTO "cake" ("name") VALUES ($1) RETURNING "id", "name""#
410    /// );
411    /// #
412    /// # Ok(())
413    /// # }
414    /// ```
415    fn insert<A>(model: A) -> Insert<A>
416    where
417        A: ActiveModelTrait<Entity = Self>,
418    {
419        Insert::one(model)
420    }
421
422    /// Insert many models into database
423    ///
424    /// # Example (Postgres)
425    ///
426    /// ```
427    /// # use sea_orm::{error::*, tests_cfg::*, *};
428    /// #
429    /// # #[smol_potat::main]
430    /// # #[cfg(feature = "mock")]
431    /// # pub async fn main() -> Result<(), DbErr> {
432    /// #
433    /// # let db = MockDatabase::new(DbBackend::Postgres)
434    /// #     .append_query_results([[maplit::btreemap! {
435    /// #         "id" => Into::<Value>::into(28),
436    /// #     }]])
437    /// #     .into_connection();
438    /// #
439    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
440    ///
441    /// let apple = cake::ActiveModel {
442    ///     name: Set("Apple Pie".to_owned()),
443    ///     ..Default::default()
444    /// };
445    /// let orange = cake::ActiveModel {
446    ///     name: Set("Orange Scone".to_owned()),
447    ///     ..Default::default()
448    /// };
449    ///
450    /// let insert_result = cake::Entity::insert_many([apple, orange]).exec(&db).await?;
451    ///
452    /// assert_eq!(insert_result.last_insert_id, 28);
453    ///
454    /// assert_eq!(
455    ///     db.into_transaction_log(),
456    ///     [Transaction::from_sql_and_values(
457    ///         DbBackend::Postgres,
458    ///         r#"INSERT INTO "cake" ("name") VALUES ($1), ($2) RETURNING "id""#,
459    ///         ["Apple Pie".into(), "Orange Scone".into()]
460    ///     )]
461    /// );
462    /// #
463    /// # Ok(())
464    /// # }
465    /// ```
466    ///
467    /// # Example (MySQL)
468    ///
469    /// ```
470    /// # use sea_orm::{error::*, tests_cfg::*, *};
471    /// #
472    /// # #[smol_potat::main]
473    /// # #[cfg(feature = "mock")]
474    /// # pub async fn main() -> Result<(), DbErr> {
475    /// #
476    /// # let db = MockDatabase::new(DbBackend::MySql)
477    /// #     .append_exec_results([
478    /// #         MockExecResult {
479    /// #             last_insert_id: 28,
480    /// #             rows_affected: 2,
481    /// #         },
482    /// #     ])
483    /// #     .into_connection();
484    /// #
485    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
486    ///
487    /// let apple = cake::ActiveModel {
488    ///     name: Set("Apple Pie".to_owned()),
489    ///     ..Default::default()
490    /// };
491    /// let orange = cake::ActiveModel {
492    ///     name: Set("Orange Scone".to_owned()),
493    ///     ..Default::default()
494    /// };
495    ///
496    /// let insert_result = cake::Entity::insert_many([apple, orange]).exec(&db).await?;
497    ///
498    /// assert_eq!(insert_result.last_insert_id, 28);
499    ///
500    /// assert_eq!(
501    ///     db.into_transaction_log(),
502    ///     [Transaction::from_sql_and_values(
503    ///         DbBackend::MySql,
504    ///         r#"INSERT INTO `cake` (`name`) VALUES (?), (?)"#,
505    ///         ["Apple Pie".into(), "Orange Scone".into()]
506    ///     )]
507    /// );
508    /// #
509    /// # Ok(())
510    /// # }
511    /// ```
512    ///
513    /// Before 1.1.3, if the active models have different column set, this method would panic.
514    /// Now, it'd attempt to fill in the missing columns with null
515    /// (which may or may not be correct, depending on whether the column is nullable):
516    ///
517    /// ```
518    /// use sea_orm::{
519    ///     entity::*,
520    ///     query::*,
521    ///     tests_cfg::{cake, cake_filling},
522    ///     DbBackend,
523    /// };
524    ///
525    /// assert_eq!(
526    ///     cake::Entity::insert_many([
527    ///         cake::ActiveModel {
528    ///             id: NotSet,
529    ///             name: Set("Apple Pie".to_owned()),
530    ///         },
531    ///         cake::ActiveModel {
532    ///             id: NotSet,
533    ///             name: Set("Orange Scone".to_owned()),
534    ///         }
535    ///     ])
536    ///     .build(DbBackend::Postgres)
537    ///     .to_string(),
538    ///     r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie'), ('Orange Scone')"#,
539    /// );
540    ///
541    /// assert_eq!(
542    ///     cake_filling::Entity::insert_many([
543    ///         cake_filling::ActiveModel {
544    ///             cake_id: ActiveValue::set(2),
545    ///             filling_id: ActiveValue::NotSet,
546    ///         },
547    ///         cake_filling::ActiveModel {
548    ///             cake_id: ActiveValue::NotSet,
549    ///             filling_id: ActiveValue::set(3),
550    ///         }
551    ///     ])
552    ///     .build(DbBackend::Postgres)
553    ///     .to_string(),
554    ///     r#"INSERT INTO "cake_filling" ("cake_id", "filling_id") VALUES (2, NULL), (NULL, 3)"#,
555    /// );
556    /// ```
557    ///
558    /// To get back inserted Models
559    ///
560    /// ```
561    /// # use sea_orm::{error::*, tests_cfg::*, *};
562    /// #
563    /// # #[smol_potat::main]
564    /// # #[cfg(feature = "mock")]
565    /// # pub async fn main() -> Result<(), DbErr> {
566    /// #
567    /// # let db = MockDatabase::new(DbBackend::Postgres)
568    /// #     .append_query_results([
569    /// #         [cake::Model {
570    /// #             id: 1,
571    /// #             name: "Apple Pie".to_owned(),
572    /// #         }, cake::Model {
573    /// #             id: 2,
574    /// #             name: "Choco Pie".to_owned(),
575    /// #         }],
576    /// #     ])
577    /// #     .into_connection();
578    /// #
579    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
580    ///
581    /// assert_eq!(
582    ///     cake::Entity::insert_many([
583    ///         cake::ActiveModel {
584    ///             id: NotSet,
585    ///             name: Set("Apple Pie".to_owned()),
586    ///         },
587    ///         cake::ActiveModel {
588    ///             id: NotSet,
589    ///             name: Set("Choco Pie".to_owned()),
590    ///         },
591    ///     ])
592    ///     .exec_with_returning_many(&db)
593    ///     .await?,
594    ///     [
595    ///         cake::Model {
596    ///             id: 1,
597    ///             name: "Apple Pie".to_owned(),
598    ///         },
599    ///         cake::Model {
600    ///             id: 2,
601    ///             name: "Choco Pie".to_owned(),
602    ///         }
603    ///     ]
604    /// );
605    ///
606    /// assert_eq!(
607    ///     db.into_transaction_log()[0].statements()[0].sql,
608    ///     r#"INSERT INTO "cake" ("name") VALUES ($1), ($2) RETURNING "id", "name""#
609    /// );
610    /// #
611    /// # Ok(())
612    /// # }
613    /// ```
614    fn insert_many<A, I>(models: I) -> Insert<A>
615    where
616        A: ActiveModelTrait<Entity = Self>,
617        I: IntoIterator<Item = A>,
618    {
619        Insert::many(models)
620    }
621
622    /// Update a model in database
623    ///
624    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
625    ///
626    /// # Example (Postgres)
627    ///
628    /// ```
629    /// # use sea_orm::{error::*, tests_cfg::*, *};
630    /// #
631    /// # #[smol_potat::main]
632    /// # #[cfg(feature = "mock")]
633    /// # pub async fn main() -> Result<(), DbErr> {
634    /// #
635    /// # let db = MockDatabase::new(DbBackend::Postgres)
636    /// #     .append_query_results([
637    /// #         [fruit::Model {
638    /// #             id: 1,
639    /// #             name: "Orange".to_owned(),
640    /// #             cake_id: None,
641    /// #         }],
642    /// #     ])
643    /// #     .into_connection();
644    /// #
645    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
646    ///
647    /// let orange = fruit::ActiveModel {
648    ///     id: Set(1),
649    ///     name: Set("Orange".to_owned()),
650    ///     ..Default::default()
651    /// };
652    ///
653    /// assert_eq!(
654    ///     fruit::Entity::update(orange.clone())
655    ///         .filter(fruit::Column::Name.contains("orange"))
656    ///         .exec(&db)
657    ///         .await?,
658    ///     fruit::Model {
659    ///         id: 1,
660    ///         name: "Orange".to_owned(),
661    ///         cake_id: None,
662    ///     }
663    /// );
664    ///
665    /// assert_eq!(
666    ///     db.into_transaction_log(),
667    ///     [Transaction::from_sql_and_values(
668    ///         DbBackend::Postgres,
669    ///         r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2 AND "fruit"."name" LIKE $3 RETURNING "id", "name", "cake_id""#,
670    ///         ["Orange".into(), 1i32.into(), "%orange%".into()]
671    ///     )]);
672    /// #
673    /// # Ok(())
674    /// # }
675    /// ```
676    ///
677    /// # Example (MySQL)
678    ///
679    /// ```
680    /// # use sea_orm::{error::*, tests_cfg::*, *};
681    /// #
682    /// # #[smol_potat::main]
683    /// # #[cfg(feature = "mock")]
684    /// # pub async fn main() -> Result<(), DbErr> {
685    /// #
686    /// # let db = MockDatabase::new(DbBackend::MySql)
687    /// #     .append_exec_results([
688    /// #         MockExecResult {
689    /// #             last_insert_id: 0,
690    /// #             rows_affected: 1,
691    /// #         },
692    /// #     ])
693    /// #     .append_query_results([
694    /// #         [fruit::Model {
695    /// #             id: 1,
696    /// #             name: "Orange".to_owned(),
697    /// #             cake_id: None,
698    /// #         }],
699    /// #     ])
700    /// #     .into_connection();
701    /// #
702    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
703    ///
704    /// let orange = fruit::ActiveModel {
705    ///     id: Set(1),
706    ///     name: Set("Orange".to_owned()),
707    ///     ..Default::default()
708    /// };
709    ///
710    /// assert_eq!(
711    ///     fruit::Entity::update(orange.clone())
712    ///         .filter(fruit::Column::Name.contains("orange"))
713    ///         .exec(&db)
714    ///         .await?,
715    ///     fruit::Model {
716    ///         id: 1,
717    ///         name: "Orange".to_owned(),
718    ///         cake_id: None,
719    ///     }
720    /// );
721    ///
722    /// assert_eq!(
723    ///     db.into_transaction_log(),
724    ///     [
725    ///         Transaction::from_sql_and_values(
726    ///             DbBackend::MySql,
727    ///             r#"UPDATE `fruit` SET `name` = ? WHERE `fruit`.`id` = ? AND `fruit`.`name` LIKE ?"#,
728    ///             ["Orange".into(), 1i32.into(), "%orange%".into()]
729    ///         ),
730    ///         Transaction::from_sql_and_values(
731    ///             DbBackend::MySql,
732    ///             r#"SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit` WHERE `fruit`.`id` = ? LIMIT ?"#,
733    ///             [1i32.into(), 1u64.into()]
734    ///         )]);
735    /// #
736    /// # Ok(())
737    /// # }
738    /// ```
739    fn update<A>(model: A) -> UpdateOne<A>
740    where
741        A: ActiveModelTrait<Entity = Self>,
742    {
743        Update::one(model)
744    }
745
746    /// Update many models in database
747    ///
748    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
749    ///
750    /// # Example
751    ///
752    /// ```
753    /// # use sea_orm::{error::*, tests_cfg::*, *};
754    /// #
755    /// # #[smol_potat::main]
756    /// # #[cfg(feature = "mock")]
757    /// # pub async fn main() -> Result<(), DbErr> {
758    /// #
759    /// # let db = MockDatabase::new(DbBackend::Postgres)
760    /// #     .append_exec_results([
761    /// #         MockExecResult {
762    /// #             last_insert_id: 0,
763    /// #             rows_affected: 5,
764    /// #         },
765    /// #     ])
766    /// #     .into_connection();
767    /// #
768    /// use sea_orm::{
769    ///     entity::*,
770    ///     query::*,
771    ///     sea_query::{Expr, Value},
772    ///     tests_cfg::fruit,
773    /// };
774    ///
775    /// let update_result = fruit::Entity::update_many()
776    ///     .col_expr(fruit::Column::CakeId, Expr::value(Value::Int(None)))
777    ///     .filter(fruit::Column::Name.contains("Apple"))
778    ///     .exec(&db)
779    ///     .await?;
780    ///
781    /// assert_eq!(update_result.rows_affected, 5);
782    ///
783    /// assert_eq!(
784    ///     db.into_transaction_log(),
785    ///     [Transaction::from_sql_and_values(
786    ///         DbBackend::Postgres,
787    ///         r#"UPDATE "fruit" SET "cake_id" = $1 WHERE "fruit"."name" LIKE $2"#,
788    ///         [Value::Int(None), "%Apple%".into()]
789    ///     )]
790    /// );
791    /// #
792    /// # Ok(())
793    /// # }
794    /// ```
795    fn update_many() -> UpdateMany<Self> {
796        Update::many(Self::default())
797    }
798
799    /// Delete a model from database
800    ///
801    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
802    ///
803    /// # Example
804    ///
805    /// ```
806    /// # use sea_orm::{error::*, tests_cfg::*, *};
807    /// #
808    /// # #[smol_potat::main]
809    /// # #[cfg(feature = "mock")]
810    /// # pub async fn main() -> Result<(), DbErr> {
811    /// #
812    /// # let db = MockDatabase::new(DbBackend::Postgres)
813    /// #     .append_exec_results([
814    /// #         MockExecResult {
815    /// #             last_insert_id: 0,
816    /// #             rows_affected: 1,
817    /// #         },
818    /// #     ])
819    /// #     .into_connection();
820    /// #
821    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
822    ///
823    /// let orange = fruit::ActiveModel {
824    ///     id: Set(3),
825    ///     ..Default::default()
826    /// };
827    ///
828    /// let delete_result = fruit::Entity::delete(orange).exec(&db).await?;
829    ///
830    /// assert_eq!(delete_result.rows_affected, 1);
831    ///
832    /// assert_eq!(
833    ///     db.into_transaction_log(),
834    ///     [Transaction::from_sql_and_values(
835    ///         DbBackend::Postgres,
836    ///         r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#,
837    ///         [3i32.into()]
838    ///     )]
839    /// );
840    /// #
841    /// # Ok(())
842    /// # }
843    /// ```
844    fn delete<A>(model: A) -> DeleteOne<A>
845    where
846        A: ActiveModelTrait<Entity = Self>,
847    {
848        Delete::one(model)
849    }
850
851    /// Delete many models from database
852    ///
853    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
854    ///
855    /// # Example
856    ///
857    /// ```
858    /// # use sea_orm::{error::*, tests_cfg::*, *};
859    /// #
860    /// # #[smol_potat::main]
861    /// # #[cfg(feature = "mock")]
862    /// # pub async fn main() -> Result<(), DbErr> {
863    /// #
864    /// # let db = MockDatabase::new(DbBackend::Postgres)
865    /// #     .append_exec_results([
866    /// #         MockExecResult {
867    /// #             last_insert_id: 0,
868    /// #             rows_affected: 5,
869    /// #         },
870    /// #     ])
871    /// #     .append_query_results([
872    /// #         [cake::Model {
873    /// #             id: 15,
874    /// #             name: "Apple Pie".to_owned(),
875    /// #         }],
876    /// #     ])
877    /// #     .into_connection();
878    /// #
879    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
880    ///
881    /// let delete_result = fruit::Entity::delete_many()
882    ///     .filter(fruit::Column::Name.contains("Apple"))
883    ///     .exec(&db)
884    ///     .await?;
885    ///
886    /// assert_eq!(delete_result.rows_affected, 5);
887    ///
888    /// assert_eq!(
889    ///     db.into_transaction_log(),
890    ///     [Transaction::from_sql_and_values(
891    ///         DbBackend::Postgres,
892    ///         r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE $1"#,
893    ///         ["%Apple%".into()]
894    ///     )]
895    /// );
896    /// #
897    /// # Ok(())
898    /// # }
899    /// ```
900    fn delete_many() -> DeleteMany<Self> {
901        Delete::many(Self::default())
902    }
903
904    /// Delete a model based on primary key
905    ///
906    /// # Example
907    ///
908    /// ```
909    /// # use sea_orm::{error::*, tests_cfg::*, *};
910    /// #
911    /// # #[smol_potat::main]
912    /// # #[cfg(feature = "mock")]
913    /// # pub async fn main() -> Result<(), DbErr> {
914    /// #
915    /// # let db = MockDatabase::new(DbBackend::Postgres)
916    /// #     .append_exec_results([
917    /// #         MockExecResult {
918    /// #             last_insert_id: 0,
919    /// #             rows_affected: 1,
920    /// #         },
921    /// #     ])
922    /// #     .into_connection();
923    /// #
924    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
925    ///
926    /// let delete_result = fruit::Entity::delete_by_id(1).exec(&db).await?;
927    ///
928    /// assert_eq!(delete_result.rows_affected, 1);
929    ///
930    /// assert_eq!(
931    ///     db.into_transaction_log(),
932    ///     [Transaction::from_sql_and_values(
933    ///         DbBackend::Postgres,
934    ///         r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#,
935    ///         [1i32.into()]
936    ///     )]
937    /// );
938    /// #
939    /// # Ok(())
940    /// # }
941    /// ```
942    /// Delete by composite key
943    /// ```
944    /// # use sea_orm::{error::*, tests_cfg::*, *};
945    /// #
946    /// # #[smol_potat::main]
947    /// # #[cfg(feature = "mock")]
948    /// # pub async fn main() -> Result<(), DbErr> {
949    ///
950    /// # let db = MockDatabase::new(DbBackend::Postgres)
951    /// #     .append_exec_results([
952    /// #         MockExecResult {
953    /// #             last_insert_id: 0,
954    /// #             rows_affected: 1,
955    /// #         },
956    /// #     ])
957    /// #     .into_connection();
958    /// #
959    /// use sea_orm::{entity::*, query::*, tests_cfg::cake_filling};
960    ///
961    /// let delete_result = cake_filling::Entity::delete_by_id((2, 3)).exec(&db).await?;
962    ///
963    /// assert_eq!(delete_result.rows_affected, 1);
964    ///
965    /// assert_eq!(
966    ///     db.into_transaction_log(),
967    ///     [Transaction::from_sql_and_values(
968    ///         DbBackend::Postgres,
969    ///         r#"DELETE FROM "cake_filling" WHERE "cake_filling"."cake_id" = $1 AND "cake_filling"."filling_id" = $2"#,
970    ///         [2i32.into(), 3i32.into()]
971    ///     )]
972    /// );
973    /// #
974    /// # Ok(())
975    /// # }
976    /// ```
977    ///
978    /// # Panics
979    ///
980    /// Panics if arity of input values don't match arity of primary key
981    fn delete_by_id<T>(values: T) -> DeleteMany<Self>
982    where
983        T: Into<<Self::PrimaryKey as PrimaryKeyTrait>::ValueType>,
984    {
985        let mut delete = Self::delete_many();
986        let mut keys = Self::PrimaryKey::iter();
987        for v in values.into().into_value_tuple() {
988            if let Some(key) = keys.next() {
989                let col = key.into_column();
990                delete = delete.filter(col.eq(v));
991            } else {
992                panic!("primary key arity mismatch");
993            }
994        }
995        if keys.next().is_some() {
996            panic!("primary key arity mismatch");
997        }
998        delete
999    }
1000}
1001
1002#[cfg(test)]
1003mod tests {
1004    #[test]
1005    fn test_delete_by_id_1() {
1006        use crate::tests_cfg::cake;
1007        use crate::{entity::*, query::*, DbBackend};
1008        assert_eq!(
1009            cake::Entity::delete_by_id(1)
1010                .build(DbBackend::Sqlite)
1011                .to_string(),
1012            r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#,
1013        );
1014    }
1015
1016    #[test]
1017    fn test_delete_by_id_2() {
1018        use crate::tests_cfg::cake_filling_price;
1019        use crate::{entity::*, query::*, DbBackend};
1020        assert_eq!(
1021            cake_filling_price::Entity::delete_by_id((1, 2))
1022                .build(DbBackend::Sqlite)
1023                .to_string(),
1024            r#"DELETE FROM "public"."cake_filling_price" WHERE "cake_filling_price"."cake_id" = 1 AND "cake_filling_price"."filling_id" = 2"#,
1025        );
1026    }
1027
1028    #[test]
1029    #[cfg(feature = "macros")]
1030    fn entity_model_1() {
1031        use crate::entity::*;
1032
1033        mod hello {
1034            use crate as sea_orm;
1035            use crate::entity::prelude::*;
1036
1037            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1038            #[sea_orm(table_name = "hello")]
1039            pub struct Model {
1040                #[sea_orm(primary_key)]
1041                pub id: i32,
1042            }
1043
1044            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1045            pub enum Relation {}
1046
1047            impl ActiveModelBehavior for ActiveModel {}
1048        }
1049
1050        assert_eq!(hello::Entity.table_name(), "hello");
1051        assert_eq!(hello::Entity.schema_name(), None);
1052    }
1053
1054    #[test]
1055    #[cfg(feature = "macros")]
1056    fn entity_model_2() {
1057        use crate::entity::*;
1058
1059        mod hello {
1060            use crate as sea_orm;
1061            use crate::entity::prelude::*;
1062
1063            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1064            #[sea_orm(table_name = "hello", schema_name = "world")]
1065            pub struct Model {
1066                #[sea_orm(primary_key)]
1067                pub id: i32,
1068            }
1069
1070            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1071            pub enum Relation {}
1072
1073            impl ActiveModelBehavior for ActiveModel {}
1074        }
1075
1076        assert_eq!(hello::Entity.table_name(), "hello");
1077        assert_eq!(hello::Entity.schema_name(), Some("world"));
1078    }
1079
1080    #[test]
1081    #[cfg(feature = "macros")]
1082    fn entity_model_3() {
1083        use crate::{entity::*, query::*, DbBackend};
1084        use std::borrow::Cow;
1085
1086        mod hello {
1087            use crate as sea_orm;
1088            use crate::entity::prelude::*;
1089
1090            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1091            #[sea_orm(table_name = "hello", schema_name = "world")]
1092            pub struct Model {
1093                #[sea_orm(primary_key, auto_increment = false)]
1094                pub id: String,
1095            }
1096
1097            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1098            pub enum Relation {}
1099
1100            impl ActiveModelBehavior for ActiveModel {}
1101        }
1102
1103        fn delete_by_id<T>(value: T)
1104        where
1105            T: Into<<<hello::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType>,
1106        {
1107            assert_eq!(
1108                hello::Entity::delete_by_id(value)
1109                    .build(DbBackend::Sqlite)
1110                    .to_string(),
1111                r#"DELETE FROM "world"."hello" WHERE "hello"."id" = 'UUID'"#
1112            );
1113        }
1114
1115        delete_by_id("UUID".to_string());
1116        delete_by_id("UUID");
1117        delete_by_id(Cow::from("UUID"));
1118    }
1119}