1use crate::{
2 ActiveModelTrait, ActiveValue, ColumnTrait, EntityName, EntityTrait, IntoActiveModel, Iterable,
3 PrimaryKeyTrait, QueryTrait,
4};
5use core::marker::PhantomData;
6use sea_query::{Expr, InsertStatement, Keyword, OnConflict, SimpleExpr, Value, ValueTuple};
7
8#[derive(Debug)]
13pub struct Insert<A>
14where
15 A: ActiveModelTrait,
16{
17 pub(crate) query: InsertStatement,
18 pub(crate) primary_key: Option<ValueTuple>,
19 pub(crate) model: PhantomData<A>,
20}
21
22#[derive(Debug)]
27pub struct InsertMany<A>
28where
29 A: ActiveModelTrait,
30{
31 pub(crate) query: InsertStatement,
32 pub(crate) primary_key: Option<ValueTuple>,
33 pub(crate) empty: bool,
34 pub(crate) model: PhantomData<A>,
35}
36
37#[derive(Debug)]
46pub struct TryInsert<A>
47where
48 A: ActiveModelTrait,
49{
50 pub(crate) insert_struct: Insert<A>,
51 pub(crate) empty: bool,
52}
53
54impl<A> Insert<A>
55where
56 A: ActiveModelTrait,
57{
58 pub fn one<M>(m: M) -> Self
89 where
90 M: IntoActiveModel<A>,
91 {
92 let mut query = InsertStatement::new();
93 query
94 .into_table(A::Entity::default().table_ref())
95 .or_default_values();
96
97 let mut am: A = m.into_active_model();
98 let primary_key =
99 if !<<A::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::auto_increment() {
100 am.get_primary_key_value()
101 } else {
102 None
103 };
104 let mut columns = Vec::new();
105 let mut values = Vec::new();
106
107 for col in <A::Entity as EntityTrait>::Column::iter() {
108 let av = am.take(col);
109
110 match av {
111 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => {
112 columns.push(col);
113 values.push(col.save_as(Expr::val(value)));
114 }
115 ActiveValue::NotSet => {}
116 }
117 }
118
119 query.columns(columns);
120 query.values_panic(values);
121
122 Self {
123 query,
124 primary_key,
125 model: PhantomData,
126 }
127 }
128
129 pub fn many<M, I>(models: I) -> InsertMany<A>
152 where
153 M: IntoActiveModel<A>,
154 I: IntoIterator<Item = M>,
155 {
156 InsertMany::many(models)
157 }
158
159 pub fn on_conflict(mut self, on_conflict: OnConflict) -> Self {
216 self.query.on_conflict(on_conflict);
217 self
218 }
219
220 pub fn on_conflict_do_nothing_on<I>(mut self, columns: I) -> TryInsert<A>
222 where
223 I: IntoIterator<Item = <A::Entity as EntityTrait>::Column>,
224 {
225 let primary_keys = <A::Entity as EntityTrait>::PrimaryKey::iter();
226 let mut on_conflict = OnConflict::columns(columns);
227 on_conflict.do_nothing_on(primary_keys);
228 self.query.on_conflict(on_conflict);
229 TryInsert::from_one(self)
230 }
231
232 #[deprecated(
234 since = "2.0.0",
235 note = "Please use [`TryInsert::one`] or `on_conflict_do_nothing*` methods that return [`TryInsert`], or [`Insert::try_insert`]."
236 )]
237 pub fn do_nothing(self) -> TryInsert<A>
238 where
239 A: ActiveModelTrait,
240 {
241 TryInsert::from_one(self)
242 }
243
244 pub fn try_insert(self) -> TryInsert<A>
246 where
247 A: ActiveModelTrait,
248 {
249 TryInsert::from_one(self)
250 }
251
252 #[deprecated(
254 since = "2.0.0",
255 note = "Please use [`TryInsert::one`] or `on_conflict_do_nothing*` methods that return [`TryInsert`]"
256 )]
257 pub fn on_empty_do_nothing(self) -> TryInsert<A>
258 where
259 A: ActiveModelTrait,
260 {
261 TryInsert::from_one(self)
262 }
263
264 pub fn on_conflict_do_nothing(mut self) -> TryInsert<A>
297 where
298 A: ActiveModelTrait,
299 {
300 self.query.on_conflict(on_conflict_primary_key::<A>());
301
302 TryInsert::from_one(self)
303 }
304}
305
306impl<A> InsertMany<A>
307where
308 A: ActiveModelTrait,
309{
310 pub fn many<M, I>(models: I) -> Self
312 where
313 M: IntoActiveModel<A>,
314 I: IntoIterator<Item = M>,
315 {
316 let mut query = InsertStatement::new();
317 query.into_table(A::Entity::default().table_ref());
318
319 let mut columns: Vec<_> = <A::Entity as EntityTrait>::Column::iter()
320 .map(|_| None)
321 .collect();
322 let mut null_value: Vec<Option<Value>> = std::iter::repeat_n(None, columns.len()).collect();
323 let mut all_values: Vec<Vec<SimpleExpr>> = Vec::new();
324 let mut primary_key = None;
325
326 for model in models.into_iter() {
327 let mut am: A = model.into_active_model();
328 primary_key =
329 if !<<A::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::auto_increment() {
330 am.get_primary_key_value()
331 } else {
332 None
333 };
334 let mut values = Vec::with_capacity(columns.len());
335 for (idx, col) in <A::Entity as EntityTrait>::Column::iter().enumerate() {
336 let av = am.take(col);
337 match av {
338 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => {
339 columns[idx] = Some(col); null_value[idx] = Some(value.as_null()); values.push(col.save_as(Expr::val(value))); }
343 ActiveValue::NotSet => {
344 values.push(SimpleExpr::Keyword(Keyword::Null)); }
346 }
347 }
348 all_values.push(values);
349 }
350
351 let empty = all_values.is_empty();
352
353 if !all_values.is_empty() {
354 query.columns(columns.iter().cloned().flatten());
356 }
357
358 for values in all_values {
359 query.values_panic(values.into_iter().enumerate().filter_map(|(i, v)| {
361 if columns[i].is_some() {
362 if !matches!(v, SimpleExpr::Keyword(Keyword::Null)) {
364 Some(v)
366 } else {
367 null_value[i].clone().map(SimpleExpr::Value)
369 }
370 } else {
371 None
372 }
373 }));
374 }
375
376 Self {
377 query,
378 primary_key,
379 empty,
380 model: PhantomData,
381 }
382 }
383
384 pub fn on_conflict(mut self, on_conflict: OnConflict) -> Self {
386 self.query.on_conflict(on_conflict);
387 self
388 }
389
390 pub fn on_conflict_do_nothing_on<I>(mut self, columns: I) -> TryInsert<A>
413 where
414 I: IntoIterator<Item = <A::Entity as EntityTrait>::Column>,
415 {
416 let primary_keys = <A::Entity as EntityTrait>::PrimaryKey::iter();
417 let mut on_conflict = OnConflict::columns(columns);
418 on_conflict.do_nothing_on(primary_keys);
419 self.query.on_conflict(on_conflict);
420 TryInsert::from_many(self)
421 }
422
423 #[deprecated(
425 since = "2.0.0",
426 note = "Please use [`TryInsert::many`] or `on_conflict_do_nothing*` methods that return [`TryInsert`], or [`InsertMany::try_insert`]"
427 )]
428 pub fn do_nothing(self) -> TryInsert<A>
429 where
430 A: ActiveModelTrait,
431 {
432 TryInsert::from_many(self)
433 }
434
435 pub fn try_insert(self) -> TryInsert<A>
437 where
438 A: ActiveModelTrait,
439 {
440 TryInsert::from_many(self)
441 }
442
443 #[deprecated(
445 since = "2.0.0",
446 note = "Empty input is already handled by [`InsertMany::exec`] (no SQL executed). For conflict handling, use [`InsertMany::on_conflict_do_nothing`] or [`InsertMany::on_conflict_do_nothing_on`]."
447 )]
448 pub fn on_empty_do_nothing(self) -> TryInsert<A>
449 where
450 A: ActiveModelTrait,
451 {
452 TryInsert::from_many(self)
453 }
454
455 pub fn on_conflict_do_nothing(mut self) -> TryInsert<A>
458 where
459 A: ActiveModelTrait,
460 {
461 self.query.on_conflict(on_conflict_primary_key::<A>());
462
463 TryInsert::from_many(self)
464 }
465
466 pub(crate) fn into_one(self) -> Insert<A> {
468 assert!(!self.empty);
469
470 let Self {
471 query,
472 primary_key,
473 empty: _,
474 model,
475 } = self;
476
477 Insert {
478 query,
479 primary_key,
480 model,
481 }
482 }
483}
484
485impl<A> QueryTrait for Insert<A>
486where
487 A: ActiveModelTrait,
488{
489 type QueryStatement = InsertStatement;
490
491 fn query(&mut self) -> &mut InsertStatement {
492 &mut self.query
493 }
494
495 fn as_query(&self) -> &InsertStatement {
496 &self.query
497 }
498
499 fn into_query(self) -> InsertStatement {
500 self.query
501 }
502}
503
504impl<A> QueryTrait for InsertMany<A>
505where
506 A: ActiveModelTrait,
507{
508 type QueryStatement = InsertStatement;
509
510 fn query(&mut self) -> &mut InsertStatement {
511 &mut self.query
512 }
513
514 fn as_query(&self) -> &InsertStatement {
515 &self.query
516 }
517
518 fn into_query(self) -> InsertStatement {
519 self.query
520 }
521}
522
523impl<A> TryInsert<A>
524where
525 A: ActiveModelTrait,
526{
527 fn from_one(insert: Insert<A>) -> Self {
528 Self {
529 insert_struct: insert,
530 empty: false,
531 }
532 }
533
534 fn from_many(insert: InsertMany<A>) -> Self {
535 let InsertMany {
536 query,
537 primary_key,
538 empty,
539 model,
540 } = insert;
541
542 Self {
543 insert_struct: Insert {
544 query,
545 primary_key,
546 model,
547 },
548 empty,
549 }
550 }
551
552 pub fn one<M>(m: M) -> Self
554 where
555 M: IntoActiveModel<A>,
556 {
557 Self::from_one(Insert::one(m))
558 }
559
560 pub fn many<M, I>(models: I) -> Self
562 where
563 M: IntoActiveModel<A>,
564 I: IntoIterator<Item = M>,
565 {
566 Self::from_many(Insert::many(models))
567 }
568
569 pub fn on_conflict(mut self, on_conflict: OnConflict) -> Insert<A> {
571 self.insert_struct.query.on_conflict(on_conflict);
572 self.insert_struct
573 }
574
575 pub fn on_conflict_do_nothing(mut self) -> Self {
577 self.insert_struct
578 .query
579 .on_conflict(on_conflict_primary_key::<A>());
580
581 self
582 }
583
584 pub fn on_conflict_do_nothing_on<I>(mut self, columns: I) -> Self
586 where
587 I: IntoIterator<Item = <A::Entity as EntityTrait>::Column>,
588 {
589 let primary_keys = <A::Entity as EntityTrait>::PrimaryKey::iter();
590 let mut on_conflict = OnConflict::columns(columns);
591 on_conflict.do_nothing_on(primary_keys);
592 self.insert_struct.query.on_conflict(on_conflict);
593 self
594 }
595}
596
597impl<A> QueryTrait for TryInsert<A>
598where
599 A: ActiveModelTrait,
600{
601 type QueryStatement = InsertStatement;
602
603 fn query(&mut self) -> &mut InsertStatement {
604 &mut self.insert_struct.query
605 }
606
607 fn as_query(&self) -> &InsertStatement {
608 &self.insert_struct.query
609 }
610
611 fn into_query(self) -> InsertStatement {
612 self.insert_struct.query
613 }
614}
615
616fn on_conflict_primary_key<A: ActiveModelTrait>() -> OnConflict {
617 let primary_keys = <A::Entity as EntityTrait>::PrimaryKey::iter();
618 let mut on_conflict = OnConflict::columns(primary_keys.clone());
619 on_conflict.do_nothing_on(primary_keys);
620 on_conflict
621}
622
623#[cfg(test)]
624mod tests {
625 use sea_query::OnConflict;
626
627 use crate::tests_cfg::{cake, cake_filling};
628 use crate::{
629 ActiveValue, DbBackend, DbErr, EntityTrait, Insert, IntoActiveModel, NotSet, QueryTrait,
630 Set,
631 };
632
633 #[test]
634 fn insert_1() {
635 assert_eq!(
636 Insert::<cake::ActiveModel>::one(cake::ActiveModel {
637 id: ActiveValue::not_set(),
638 name: ActiveValue::set("Apple Pie".to_owned()),
639 })
640 .build(DbBackend::Postgres)
641 .to_string(),
642 r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie')"#,
643 );
644 }
645
646 #[test]
647 fn insert_2() {
648 assert_eq!(
649 Insert::<cake::ActiveModel>::one(cake::ActiveModel {
650 id: ActiveValue::set(1),
651 name: ActiveValue::set("Apple Pie".to_owned()),
652 })
653 .build(DbBackend::Postgres)
654 .to_string(),
655 r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#,
656 );
657 }
658
659 #[test]
660 fn insert_3() {
661 assert_eq!(
662 Insert::<cake::ActiveModel>::one(cake::Model {
663 id: 1,
664 name: "Apple Pie".to_owned(),
665 })
666 .build(DbBackend::Postgres)
667 .to_string(),
668 r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#,
669 );
670 }
671
672 #[test]
673 fn insert_many_1() {
674 assert_eq!(
675 Insert::<cake::ActiveModel>::many([
676 cake::Model {
677 id: 1,
678 name: "Apple Pie".to_owned(),
679 },
680 cake::Model {
681 id: 2,
682 name: "Orange Scone".to_owned(),
683 }
684 ])
685 .build(DbBackend::Postgres)
686 .to_string(),
687 r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie'), (2, 'Orange Scone')"#,
688 );
689 }
690
691 #[test]
692 fn insert_many_2() {
693 assert_eq!(
694 Insert::<cake::ActiveModel>::many([
695 cake::ActiveModel {
696 id: NotSet,
697 name: Set("Apple Pie".to_owned()),
698 },
699 cake::ActiveModel {
700 id: NotSet,
701 name: Set("Orange Scone".to_owned()),
702 }
703 ])
704 .build(DbBackend::Postgres)
705 .to_string(),
706 r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie'), ('Orange Scone')"#,
707 );
708 }
709
710 #[test]
711 fn insert_many_3() {
712 let apple = cake_filling::ActiveModel {
713 cake_id: ActiveValue::set(2),
714 filling_id: ActiveValue::NotSet,
715 };
716 let orange = cake_filling::ActiveModel {
717 cake_id: ActiveValue::NotSet,
718 filling_id: ActiveValue::set(3),
719 };
720 assert_eq!(
721 Insert::<cake_filling::ActiveModel>::many([apple, orange])
722 .build(DbBackend::Postgres)
723 .to_string(),
724 r#"INSERT INTO "cake_filling" ("cake_id", "filling_id") VALUES (2, NULL), (NULL, 3)"#,
725 );
726 }
727
728 #[test]
729 fn insert_6() {
730 let orange = cake::ActiveModel {
731 id: ActiveValue::set(2),
732 name: ActiveValue::set("Orange".to_owned()),
733 };
734
735 assert_eq!(
736 cake::Entity::insert(orange)
737 .on_conflict(
738 OnConflict::column(cake::Column::Name)
739 .do_nothing()
740 .to_owned()
741 )
742 .build(DbBackend::Postgres)
743 .to_string(),
744 r#"INSERT INTO "cake" ("id", "name") VALUES (2, 'Orange') ON CONFLICT ("name") DO NOTHING"#,
745 );
746 }
747
748 #[test]
749 fn insert_7() {
750 let orange = cake::ActiveModel {
751 id: ActiveValue::set(2),
752 name: ActiveValue::set("Orange".to_owned()),
753 };
754
755 assert_eq!(
756 cake::Entity::insert(orange)
757 .on_conflict(
758 OnConflict::column(cake::Column::Name)
759 .update_column(cake::Column::Name)
760 .to_owned()
761 )
762 .build(DbBackend::Postgres)
763 .to_string(),
764 r#"INSERT INTO "cake" ("id", "name") VALUES (2, 'Orange') ON CONFLICT ("name") DO UPDATE SET "name" = "excluded"."name""#,
765 );
766 }
767
768 #[test]
769 fn test_on_conflict_do_nothing_on() {
770 let orange = cake::ActiveModel {
771 id: ActiveValue::set(2),
772 name: ActiveValue::set("Orange".to_owned()),
773 };
774
775 assert_eq!(
776 cake::Entity::insert(orange.clone())
777 .on_conflict_do_nothing_on([cake::Column::Name])
778 .build(DbBackend::Postgres)
779 .to_string(),
780 r#"INSERT INTO "cake" ("id", "name") VALUES (2, 'Orange') ON CONFLICT ("name") DO NOTHING"#,
781 );
782 assert_eq!(
783 cake::Entity::insert(orange)
784 .on_conflict_do_nothing_on([cake::Column::Name])
785 .build(DbBackend::MySql)
786 .to_string(),
787 r#"INSERT INTO `cake` (`id`, `name`) VALUES (2, 'Orange') ON DUPLICATE KEY UPDATE `id` = `id`"#,
788 );
789 }
790
791 #[test]
792 fn insert_8() -> Result<(), DbErr> {
793 use crate::{DbBackend, MockDatabase, Statement, Transaction};
794
795 mod post {
796 use crate as sea_orm;
797 use crate::entity::prelude::*;
798
799 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
800 #[sea_orm(table_name = "posts")]
801 pub struct Model {
802 #[sea_orm(primary_key, select_as = "INTEGER", save_as = "TEXT")]
803 pub id: i32,
804 pub title: String,
805 pub text: String,
806 }
807
808 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
809 pub enum Relation {}
810
811 impl ActiveModelBehavior for ActiveModel {}
812 }
813
814 let model = post::Model {
815 id: 1,
816 title: "News wrap up 2022".into(),
817 text: "brbrbrrrbrbrbrr...".into(),
818 };
819
820 let db = MockDatabase::new(DbBackend::Postgres)
821 .append_query_results([[model.clone()]])
822 .into_connection();
823
824 post::Entity::insert(model.into_active_model()).exec(&db)?;
825
826 assert_eq!(
827 db.into_transaction_log(),
828 [Transaction::many([Statement::from_sql_and_values(
829 DbBackend::Postgres,
830 r#"INSERT INTO "posts" ("id", "title", "text") VALUES (CAST($1 AS TEXT), $2, $3) RETURNING CAST("id" AS INTEGER)"#,
831 [
832 1.into(),
833 "News wrap up 2022".into(),
834 "brbrbrrrbrbrbrr...".into(),
835 ]
836 )])]
837 );
838
839 Ok(())
840 }
841
842 #[test]
843 fn insert_9() -> Result<(), DbErr> {
844 use crate::{DbBackend, MockDatabase, MockExecResult, Statement, Transaction};
845
846 mod post {
847 use crate as sea_orm;
848 use crate::entity::prelude::*;
849
850 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
851 #[sea_orm(table_name = "posts")]
852 pub struct Model {
853 #[sea_orm(
854 primary_key,
855 auto_increment = false,
856 select_as = "INTEGER",
857 save_as = "TEXT"
858 )]
859 pub id_primary: i32,
860 #[sea_orm(
861 primary_key,
862 auto_increment = false,
863 select_as = "INTEGER",
864 save_as = "TEXT"
865 )]
866 pub id_secondary: i32,
867 pub title: String,
868 pub text: String,
869 }
870
871 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
872 pub enum Relation {}
873
874 impl ActiveModelBehavior for ActiveModel {}
875 }
876
877 let model = post::Model {
878 id_primary: 1,
879 id_secondary: 1001,
880 title: "News wrap up 2022".into(),
881 text: "brbrbrrrbrbrbrr...".into(),
882 };
883
884 let db = MockDatabase::new(DbBackend::Postgres)
885 .append_query_results([[model.clone()]])
886 .into_connection();
887
888 post::Entity::insert(model.into_active_model()).exec(&db)?;
889
890 assert_eq!(
891 db.into_transaction_log(),
892 [Transaction::many([Statement::from_sql_and_values(
893 DbBackend::Postgres,
894 r#"INSERT INTO "posts" ("id_primary", "id_secondary", "title", "text") VALUES (CAST($1 AS TEXT), CAST($2 AS TEXT), $3, $4) RETURNING CAST("id_primary" AS INTEGER), CAST("id_secondary" AS INTEGER)"#,
895 [
896 1.into(),
897 1001.into(),
898 "News wrap up 2022".into(),
899 "brbrbrrrbrbrbrr...".into(),
900 ]
901 )])]
902 );
903
904 Ok(())
905 }
906}