sea_orm/entity/
base_entity.rs

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