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::{Alias, 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) => (Alias::new(schema).into_iden(), 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    ///         .filter(fruit::Column::Name.contains("orange"))
666    ///         .exec(&db)
667    ///         .await?,
668    ///     fruit::Model {
669    ///         id: 1,
670    ///         name: "Orange".to_owned(),
671    ///         cake_id: None,
672    ///     }
673    /// );
674    ///
675    /// assert_eq!(
676    ///     db.into_transaction_log(),
677    ///     [Transaction::from_sql_and_values(
678    ///         DbBackend::Postgres,
679    ///         r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2 AND "fruit"."name" LIKE $3 RETURNING "id", "name", "cake_id""#,
680    ///         ["Orange".into(), 1i32.into(), "%orange%".into()]
681    ///     )]);
682    /// #
683    /// # Ok(())
684    /// # }
685    /// ```
686    ///
687    /// # Example (MySQL)
688    ///
689    /// ```
690    /// # use sea_orm::{error::*, tests_cfg::*, *};
691    /// #
692    /// # #[smol_potat::main]
693    /// # #[cfg(feature = "mock")]
694    /// # pub async fn main() -> Result<(), DbErr> {
695    /// #
696    /// # let db = MockDatabase::new(DbBackend::MySql)
697    /// #     .append_exec_results([
698    /// #         MockExecResult {
699    /// #             last_insert_id: 0,
700    /// #             rows_affected: 1,
701    /// #         },
702    /// #     ])
703    /// #     .append_query_results([
704    /// #         [fruit::Model {
705    /// #             id: 1,
706    /// #             name: "Orange".to_owned(),
707    /// #             cake_id: None,
708    /// #         }],
709    /// #     ])
710    /// #     .into_connection();
711    /// #
712    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
713    ///
714    /// let orange = fruit::ActiveModel {
715    ///     id: Set(1),
716    ///     name: Set("Orange".to_owned()),
717    ///     ..Default::default()
718    /// };
719    ///
720    /// assert_eq!(
721    ///     fruit::Entity::update(orange.clone())
722    ///         .filter(fruit::Column::Name.contains("orange"))
723    ///         .exec(&db)
724    ///         .await?,
725    ///     fruit::Model {
726    ///         id: 1,
727    ///         name: "Orange".to_owned(),
728    ///         cake_id: None,
729    ///     }
730    /// );
731    ///
732    /// assert_eq!(
733    ///     db.into_transaction_log(),
734    ///     [
735    ///         Transaction::from_sql_and_values(
736    ///             DbBackend::MySql,
737    ///             r#"UPDATE `fruit` SET `name` = ? WHERE `fruit`.`id` = ? AND `fruit`.`name` LIKE ?"#,
738    ///             ["Orange".into(), 1i32.into(), "%orange%".into()]
739    ///         ),
740    ///         Transaction::from_sql_and_values(
741    ///             DbBackend::MySql,
742    ///             r#"SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit` WHERE `fruit`.`id` = ? LIMIT ?"#,
743    ///             [1i32.into(), 1u64.into()]
744    ///         )]);
745    /// #
746    /// # Ok(())
747    /// # }
748    /// ```
749    fn update<A>(model: A) -> UpdateOne<A>
750    where
751        A: ActiveModelTrait<Entity = Self>,
752    {
753        Update::one(model)
754    }
755
756    /// Update many models in database
757    ///
758    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
759    ///
760    /// # Example
761    ///
762    /// ```
763    /// # use sea_orm::{error::*, tests_cfg::*, *};
764    /// #
765    /// # #[smol_potat::main]
766    /// # #[cfg(feature = "mock")]
767    /// # pub async fn main() -> Result<(), DbErr> {
768    /// #
769    /// # let db = MockDatabase::new(DbBackend::Postgres)
770    /// #     .append_exec_results([
771    /// #         MockExecResult {
772    /// #             last_insert_id: 0,
773    /// #             rows_affected: 5,
774    /// #         },
775    /// #     ])
776    /// #     .into_connection();
777    /// #
778    /// use sea_orm::{
779    ///     entity::*,
780    ///     query::*,
781    ///     sea_query::{Expr, Value},
782    ///     tests_cfg::fruit,
783    /// };
784    ///
785    /// let update_result = fruit::Entity::update_many()
786    ///     .col_expr(fruit::Column::CakeId, Expr::value(Value::Int(None)))
787    ///     .filter(fruit::Column::Name.contains("Apple"))
788    ///     .exec(&db)
789    ///     .await?;
790    ///
791    /// assert_eq!(update_result.rows_affected, 5);
792    ///
793    /// assert_eq!(
794    ///     db.into_transaction_log(),
795    ///     [Transaction::from_sql_and_values(
796    ///         DbBackend::Postgres,
797    ///         r#"UPDATE "fruit" SET "cake_id" = $1 WHERE "fruit"."name" LIKE $2"#,
798    ///         [Value::Int(None), "%Apple%".into()]
799    ///     )]
800    /// );
801    /// #
802    /// # Ok(())
803    /// # }
804    /// ```
805    fn update_many() -> UpdateMany<Self> {
806        Update::many(Self::default())
807    }
808
809    /// Delete a model from database
810    ///
811    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
812    ///
813    /// # Example
814    ///
815    /// ```
816    /// # use sea_orm::{error::*, tests_cfg::*, *};
817    /// #
818    /// # #[smol_potat::main]
819    /// # #[cfg(feature = "mock")]
820    /// # pub async fn main() -> Result<(), DbErr> {
821    /// #
822    /// # let db = MockDatabase::new(DbBackend::Postgres)
823    /// #     .append_exec_results([
824    /// #         MockExecResult {
825    /// #             last_insert_id: 0,
826    /// #             rows_affected: 1,
827    /// #         },
828    /// #     ])
829    /// #     .into_connection();
830    /// #
831    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
832    ///
833    /// let orange = fruit::ActiveModel {
834    ///     id: Set(3),
835    ///     ..Default::default()
836    /// };
837    ///
838    /// let delete_result = fruit::Entity::delete(orange).exec(&db).await?;
839    ///
840    /// assert_eq!(delete_result.rows_affected, 1);
841    ///
842    /// assert_eq!(
843    ///     db.into_transaction_log(),
844    ///     [Transaction::from_sql_and_values(
845    ///         DbBackend::Postgres,
846    ///         r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#,
847    ///         [3i32.into()]
848    ///     )]
849    /// );
850    /// #
851    /// # Ok(())
852    /// # }
853    /// ```
854    fn delete<A>(model: A) -> DeleteOne<A>
855    where
856        A: ActiveModelTrait<Entity = Self>,
857    {
858        Delete::one(model)
859    }
860
861    /// Delete many models from database
862    ///
863    /// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
864    ///
865    /// # Example
866    ///
867    /// ```
868    /// # use sea_orm::{error::*, tests_cfg::*, *};
869    /// #
870    /// # #[smol_potat::main]
871    /// # #[cfg(feature = "mock")]
872    /// # pub async fn main() -> Result<(), DbErr> {
873    /// #
874    /// # let db = MockDatabase::new(DbBackend::Postgres)
875    /// #     .append_exec_results([
876    /// #         MockExecResult {
877    /// #             last_insert_id: 0,
878    /// #             rows_affected: 5,
879    /// #         },
880    /// #     ])
881    /// #     .append_query_results([
882    /// #         [cake::Model {
883    /// #             id: 15,
884    /// #             name: "Apple Pie".to_owned(),
885    /// #         }],
886    /// #     ])
887    /// #     .into_connection();
888    /// #
889    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
890    ///
891    /// let delete_result = fruit::Entity::delete_many()
892    ///     .filter(fruit::Column::Name.contains("Apple"))
893    ///     .exec(&db)
894    ///     .await?;
895    ///
896    /// assert_eq!(delete_result.rows_affected, 5);
897    ///
898    /// assert_eq!(
899    ///     db.into_transaction_log(),
900    ///     [Transaction::from_sql_and_values(
901    ///         DbBackend::Postgres,
902    ///         r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE $1"#,
903    ///         ["%Apple%".into()]
904    ///     )]
905    /// );
906    /// #
907    /// # Ok(())
908    /// # }
909    /// ```
910    fn delete_many() -> DeleteMany<Self> {
911        Delete::many(Self::default())
912    }
913
914    /// Delete a model based on primary key
915    ///
916    /// # Example
917    ///
918    /// ```
919    /// # use sea_orm::{error::*, tests_cfg::*, *};
920    /// #
921    /// # #[smol_potat::main]
922    /// # #[cfg(feature = "mock")]
923    /// # pub async fn main() -> Result<(), DbErr> {
924    /// #
925    /// # let db = MockDatabase::new(DbBackend::Postgres)
926    /// #     .append_exec_results([
927    /// #         MockExecResult {
928    /// #             last_insert_id: 0,
929    /// #             rows_affected: 1,
930    /// #         },
931    /// #     ])
932    /// #     .into_connection();
933    /// #
934    /// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
935    ///
936    /// let delete_result = fruit::Entity::delete_by_id(1).exec(&db).await?;
937    ///
938    /// assert_eq!(delete_result.rows_affected, 1);
939    ///
940    /// assert_eq!(
941    ///     db.into_transaction_log(),
942    ///     [Transaction::from_sql_and_values(
943    ///         DbBackend::Postgres,
944    ///         r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#,
945    ///         [1i32.into()]
946    ///     )]
947    /// );
948    /// #
949    /// # Ok(())
950    /// # }
951    /// ```
952    /// Delete by composite key
953    /// ```
954    /// # use sea_orm::{error::*, tests_cfg::*, *};
955    /// #
956    /// # #[smol_potat::main]
957    /// # #[cfg(feature = "mock")]
958    /// # pub async fn main() -> Result<(), DbErr> {
959    ///
960    /// # let db = MockDatabase::new(DbBackend::Postgres)
961    /// #     .append_exec_results([
962    /// #         MockExecResult {
963    /// #             last_insert_id: 0,
964    /// #             rows_affected: 1,
965    /// #         },
966    /// #     ])
967    /// #     .into_connection();
968    /// #
969    /// use sea_orm::{entity::*, query::*, tests_cfg::cake_filling};
970    ///
971    /// let delete_result = cake_filling::Entity::delete_by_id((2, 3)).exec(&db).await?;
972    ///
973    /// assert_eq!(delete_result.rows_affected, 1);
974    ///
975    /// assert_eq!(
976    ///     db.into_transaction_log(),
977    ///     [Transaction::from_sql_and_values(
978    ///         DbBackend::Postgres,
979    ///         r#"DELETE FROM "cake_filling" WHERE "cake_filling"."cake_id" = $1 AND "cake_filling"."filling_id" = $2"#,
980    ///         [2i32.into(), 3i32.into()]
981    ///     )]
982    /// );
983    /// #
984    /// # Ok(())
985    /// # }
986    /// ```
987    ///
988    /// # Panics
989    ///
990    /// Panics if arity of input values don't match arity of primary key
991    fn delete_by_id<T>(values: T) -> DeleteMany<Self>
992    where
993        T: Into<<Self::PrimaryKey as PrimaryKeyTrait>::ValueType>,
994    {
995        let mut delete = Self::delete_many();
996        let mut keys = Self::PrimaryKey::iter();
997        for v in values.into().into_value_tuple() {
998            if let Some(key) = keys.next() {
999                let col = key.into_column();
1000                delete = delete.filter(col.eq(v));
1001            } else {
1002                unreachable!("primary key arity mismatch");
1003            }
1004        }
1005        delete
1006    }
1007}
1008
1009#[cfg(test)]
1010mod tests {
1011    #[test]
1012    fn test_delete_by_id_1() {
1013        use crate::tests_cfg::cake;
1014        use crate::{DbBackend, entity::*, query::*};
1015        assert_eq!(
1016            cake::Entity::delete_by_id(1)
1017                .build(DbBackend::Sqlite)
1018                .to_string(),
1019            r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#,
1020        );
1021    }
1022
1023    #[test]
1024    fn test_delete_by_id_2() {
1025        use crate::tests_cfg::cake_filling_price;
1026        use crate::{DbBackend, entity::*, query::*};
1027        assert_eq!(
1028            cake_filling_price::Entity::delete_by_id((1, 2))
1029                .build(DbBackend::Sqlite)
1030                .to_string(),
1031            r#"DELETE FROM "public"."cake_filling_price" WHERE "cake_filling_price"."cake_id" = 1 AND "cake_filling_price"."filling_id" = 2"#,
1032        );
1033    }
1034
1035    #[test]
1036    #[cfg(feature = "macros")]
1037    fn entity_model_1() {
1038        use crate::entity::*;
1039
1040        mod hello {
1041            use crate as sea_orm;
1042            use crate::entity::prelude::*;
1043
1044            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1045            #[sea_orm(table_name = "hello")]
1046            pub struct Model {
1047                #[sea_orm(primary_key)]
1048                pub id: i32,
1049            }
1050
1051            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1052            pub enum Relation {}
1053
1054            impl ActiveModelBehavior for ActiveModel {}
1055        }
1056
1057        assert_eq!(hello::Entity.table_name(), "hello");
1058        assert_eq!(hello::Entity.schema_name(), None);
1059    }
1060
1061    #[test]
1062    #[cfg(feature = "macros")]
1063    fn entity_model_2() {
1064        use crate::entity::*;
1065
1066        mod hello {
1067            use crate as sea_orm;
1068            use crate::entity::prelude::*;
1069
1070            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1071            #[sea_orm(table_name = "hello", schema_name = "world")]
1072            pub struct Model {
1073                #[sea_orm(primary_key)]
1074                pub id: i32,
1075            }
1076
1077            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1078            pub enum Relation {}
1079
1080            impl ActiveModelBehavior for ActiveModel {}
1081        }
1082
1083        assert_eq!(hello::Entity.table_name(), "hello");
1084        assert_eq!(hello::Entity.schema_name(), Some("world"));
1085    }
1086
1087    #[test]
1088    #[cfg(feature = "macros")]
1089    fn entity_model_3() {
1090        use crate::{DbBackend, entity::*, query::*};
1091        use std::borrow::Cow;
1092
1093        mod hello {
1094            use crate as sea_orm;
1095            use crate::entity::prelude::*;
1096
1097            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1098            #[sea_orm(table_name = "hello", schema_name = "world")]
1099            pub struct Model {
1100                #[sea_orm(primary_key, auto_increment = false)]
1101                pub id: String,
1102            }
1103
1104            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1105            pub enum Relation {}
1106
1107            impl ActiveModelBehavior for ActiveModel {}
1108        }
1109
1110        fn delete_by_id<T>(value: T)
1111        where
1112            T: Into<<<hello::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType>,
1113        {
1114            assert_eq!(
1115                hello::Entity::delete_by_id(value)
1116                    .build(DbBackend::Sqlite)
1117                    .to_string(),
1118                r#"DELETE FROM "world"."hello" WHERE "hello"."id" = 'UUID'"#
1119            );
1120        }
1121
1122        delete_by_id("UUID".to_string());
1123        delete_by_id("UUID");
1124        delete_by_id(Cow::from("UUID"));
1125    }
1126
1127    #[smol_potat::test]
1128    async fn test_find_by_id() {
1129        use crate::tests_cfg::{cake, cake_filling};
1130        use crate::{DbBackend, EntityTrait, MockDatabase};
1131
1132        let db = MockDatabase::new(DbBackend::MySql).into_connection();
1133
1134        cake::Entity::find_by_id(1).all(&db).await.ok();
1135        cake_filling::Entity::find_by_id((2, 3)).all(&db).await.ok();
1136
1137        // below does not compile:
1138
1139        // cake::Entity::find_by_id((1, 2)).all(&db).await.ok();
1140        // cake_filling::Entity::find_by_id(1).all(&db).await.ok();
1141        // cake_filling::Entity::find_by_id((1, 2, 3))
1142        //     .all(&db)
1143        //     .await
1144        //     .ok();
1145    }
1146}