From 18fdbef9ccd80e6e5272a39db0ad9e742c5dd3e9 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 11 Jan 2023 14:16:35 +0800 Subject: [PATCH] Postgres insert many will throw RecordNotInserted error if non of them are being inserted (#1021) --- src/error.rs | 5 ++++ src/executor/insert.rs | 5 +++- tests/upsert_tests.rs | 65 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 tests/upsert_tests.rs diff --git a/src/error.rs b/src/error.rs index 099c62f4c0..7988bd1b8a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -55,6 +55,11 @@ pub enum DbErr { /// A migration error #[error("Migration Error: {0}")] Migration(String), + /// None of the records are being inserted into the database, + /// if you insert with upsert expression that means + /// all of them conflict with existing records in the database + #[error("RecordNotInserted Error: {0}")] + RecordNotInserted(String), } /// Runtime error diff --git a/src/executor/insert.rs b/src/executor/insert.rs index 29ab6b440d..b990bf5ea7 100644 --- a/src/executor/insert.rs +++ b/src/executor/insert.rs @@ -142,7 +142,10 @@ where let cols = PrimaryKey::::iter() .map(|col| col.to_string()) .collect::>(); - let res = db.query_one(statement).await?.unwrap(); + let rows = db.query_all(statement).await?; + let res = rows.last().ok_or_else(|| { + DbErr::RecordNotInserted("None of the records are being inserted".to_owned()) + })?; res.try_get_many("", cols.as_ref()).ok() } false => { diff --git a/tests/upsert_tests.rs b/tests/upsert_tests.rs new file mode 100644 index 0000000000..ad874e79c8 --- /dev/null +++ b/tests/upsert_tests.rs @@ -0,0 +1,65 @@ +pub mod common; + +pub use common::{features::*, setup::*, TestContext}; +use pretty_assertions::assert_eq; +use sea_orm::entity::prelude::*; +use sea_orm::{sea_query::OnConflict, Set}; + +#[sea_orm_macros::test] +#[cfg(feature = "sqlx-postgres")] +async fn main() -> Result<(), DbErr> { + let ctx = TestContext::new("upsert_tests").await; + create_tables(&ctx.db).await?; + create_insert_default(&ctx.db).await?; + ctx.delete().await; + + Ok(()) +} + +pub async fn create_insert_default(db: &DatabaseConnection) -> Result<(), DbErr> { + use insert_default::*; + + let on_conflict = OnConflict::column(Column::Id).do_nothing().to_owned(); + + let res = Entity::insert_many([ + ActiveModel { id: Set(1) }, + ActiveModel { id: Set(2) }, + ActiveModel { id: Set(3) }, + ]) + .on_conflict(on_conflict.clone()) + .exec(db) + .await; + + assert_eq!(res?.last_insert_id, 3); + + let res = Entity::insert_many([ + ActiveModel { id: Set(1) }, + ActiveModel { id: Set(2) }, + ActiveModel { id: Set(3) }, + ActiveModel { id: Set(4) }, + ]) + .on_conflict(on_conflict.clone()) + .exec(db) + .await; + + assert_eq!(res?.last_insert_id, 4); + + let res = Entity::insert_many([ + ActiveModel { id: Set(1) }, + ActiveModel { id: Set(2) }, + ActiveModel { id: Set(3) }, + ActiveModel { id: Set(4) }, + ]) + .on_conflict(on_conflict) + .exec(db) + .await; + + assert_eq!( + res.err(), + Some(DbErr::RecordNotInserted( + "None of the records are being inserted".to_owned() + )) + ); + + Ok(()) +}