diff --git a/README-zh.md b/README-zh.md index 5d5266c7fe..78039a1368 100644 --- a/README-zh.md +++ b/README-zh.md @@ -303,7 +303,7 @@ let result = Fruit::insert_many([apple, pear]) .exec(db) .await?; -matches!(result, TryInsertResult::Conflicted); +result.last_insert_id.is_none(); ``` ### 更新 diff --git a/README.md b/README.md index 84f8d47e0c..6bfee25b97 100644 --- a/README.md +++ b/README.md @@ -304,7 +304,7 @@ let result = Fruit::insert_many([apple, pear]) .exec(db) .await?; -matches!(result, TryInsertResult::Conflicted); +result.last_insert_id.is_none(); ``` ### Update diff --git a/sea-orm-sync/README.md b/sea-orm-sync/README.md index 3e2df1622b..6132275c7f 100644 --- a/sea-orm-sync/README.md +++ b/sea-orm-sync/README.md @@ -296,7 +296,7 @@ let result = Fruit::insert_many([apple, pear]) .on_conflict_do_nothing() .exec(db)?; -matches!(result, TryInsertResult::Conflicted); +result.last_insert_id.is_none(); ``` ### Update diff --git a/sea-orm-sync/src/entity/active_model.rs b/sea-orm-sync/src/entity/active_model.rs index 685d482c5d..63effc4fca 100644 --- a/sea-orm-sync/src/entity/active_model.rs +++ b/sea-orm-sync/src/entity/active_model.rs @@ -1333,14 +1333,12 @@ where // insert new junctions if db.support_returning() { // use the returned value if it is supported - let res = J::insert_many(via_models_res) + let inserted = J::insert_many(via_models_res) .on_conflict_do_nothing() - .exec_with_returning_many(db)?; + .exec_with_returning(db)?; // run after_save hooks - if let TryInsertResult::Inserted(inserted) = res { - for model in inserted { - let _ = J::ActiveModel::after_save(model, db, true)?; - } + for model in inserted { + let _ = J::ActiveModel::after_save(model, db, true)?; } } else { // fall back to individual inserts if returning is not supported diff --git a/sea-orm-sync/src/executor/insert.rs b/sea-orm-sync/src/executor/insert.rs index 8eafed9800..ef3729a13b 100644 --- a/sea-orm-sync/src/executor/insert.rs +++ b/sea-orm-sync/src/executor/insert.rs @@ -37,7 +37,7 @@ where } /// Result of inserting many ActiveModels: the primary key of the last row -/// inserted, or `None` if the iterator was empty. +/// inserted, or `None` if the iterator was empty or the last insert id is unavailable. #[derive(Debug)] #[non_exhaustive] pub struct InsertManyResult @@ -54,10 +54,6 @@ where /// them as errors. #[derive(Debug)] pub enum TryInsertResult { - /// There was nothing to insert, so no SQL was executed. - /// - /// This typically happens when creating a [`crate::TryInsert`] from an empty iterator or None. - Empty, /// The statement was executed, but SeaORM could not get the inserted row / insert id. /// /// This is commonly caused by `ON CONFLICT ... DO NOTHING` (Postgres / SQLite) or the MySQL @@ -79,15 +75,13 @@ where { /// Extract the last inserted id. /// - /// - [`TryInsertResult::Empty`] => `Ok(None)` - /// - [`TryInsertResult::Inserted`] => `Ok(Some(last_insert_id))` + /// - [`TryInsertResult::Inserted`] => `Ok(last_insert_id)` /// - [`TryInsertResult::Conflicted`] => `Err(DbErr::RecordNotInserted)` pub fn last_insert_id( self, - ) -> Result as PrimaryKeyTrait>::ValueType>, DbErr> { + ) -> Result< as PrimaryKeyTrait>::ValueType, DbErr> { match self { - Self::Empty => Ok(None), - Self::Inserted(v) => Ok(Some(v.last_insert_id)), + Self::Inserted(v) => Ok(v.last_insert_id), Self::Conflicted => Err(DbErr::RecordNotInserted), } } @@ -102,9 +96,6 @@ where where C: ConnectionTrait, { - if self.empty { - return Ok(TryInsertResult::Empty); - } let res = self.insert_struct.exec(db); match res { Ok(res) => Ok(TryInsertResult::Inserted(res)), @@ -119,9 +110,6 @@ where where C: ConnectionTrait, { - if self.empty { - return Ok(TryInsertResult::Empty); - } let res = self.insert_struct.exec_without_returning(db); match res { Ok(res) => Ok(TryInsertResult::Inserted(res)), @@ -139,9 +127,6 @@ where ::Model: IntoActiveModel, C: ConnectionTrait, { - if self.empty { - return Ok(TryInsertResult::Empty); - } let res = self.insert_struct.exec_with_returning(db); match res { Ok(res) => Ok(TryInsertResult::Inserted(res)), @@ -159,10 +144,6 @@ where ::Model: IntoActiveModel, C: ConnectionTrait, { - if self.empty { - return Ok(TryInsertResult::Empty); - } - let res = self.insert_struct.exec_with_returning_keys(db); match res { Ok(res) => Ok(TryInsertResult::Inserted(res)), @@ -180,10 +161,6 @@ where ::Model: IntoActiveModel, C: ConnectionTrait, { - if self.empty { - return Ok(TryInsertResult::Empty); - } - let res = self.insert_struct.exec_with_returning_many(db); match res { Ok(res) => Ok(TryInsertResult::Inserted(res)), @@ -269,7 +246,10 @@ impl InsertMany where A: ActiveModelTrait, { - /// Execute an insert operation + /// Execute an insert operation. + /// + /// The returned [`InsertManyResult::last_insert_id`] is `None` if the + /// iterator was empty or the last insert id is unavailable. pub fn exec(self, db: &C) -> Result, DbErr> where C: ConnectionTrait, @@ -284,6 +264,9 @@ where Ok(r) => Ok(InsertManyResult { last_insert_id: Some(r.last_insert_id), }), + Err(DbErr::RecordNotInserted) => Ok(InsertManyResult { + last_insert_id: None, + }), Err(err) => Err(err), } } diff --git a/sea-orm-sync/src/lib.rs b/sea-orm-sync/src/lib.rs index 13869c3edf..47e8e9b591 100644 --- a/sea-orm-sync/src/lib.rs +++ b/sea-orm-sync/src/lib.rs @@ -386,7 +386,7 @@ //! ### Insert (advanced) //! You can take advantage of database specific features to perform upsert and idempotent insert. //! ``` -//! # use sea_orm::{DbConn, TryInsertResult, DbErr, entity::*, query::*, tests_cfg::*}; +//! # use sea_orm::{DbConn, DbErr, entity::*, query::*, tests_cfg::*}; //! # fn function_1(db: &DbConn) -> Result<(), DbErr> { //! # let apple = fruit::ActiveModel { //! # name: Set("Apple".to_owned()), @@ -421,7 +421,7 @@ //! .on_conflict_do_nothing() //! .exec(db)?; //! -//! matches!(result, TryInsertResult::Conflicted); +//! result.last_insert_id.is_none(); //! # Ok(()) //! # } //! ``` diff --git a/sea-orm-sync/src/query/insert.rs b/sea-orm-sync/src/query/insert.rs index 6a0883c908..810b08ff6c 100644 --- a/sea-orm-sync/src/query/insert.rs +++ b/sea-orm-sync/src/query/insert.rs @@ -34,11 +34,10 @@ where pub(crate) model: PhantomData, } -/// Wrapper of [`Insert`] / [`InsertMany`], treats "no row inserted/id returned" as a normal outcome. +/// Wrapper of [`Insert`], treats "no row inserted/id returned" as a normal outcome. /// /// Its `exec*` methods return [`crate::TryInsertResult`]. -/// Mapping empty input to [`crate::TryInsertResult::Empty`] (no SQL executed) and -/// `DbErr::RecordNotInserted` to [`crate::TryInsertResult::Conflicted`]. +/// Mapping `DbErr::RecordNotInserted` to [`crate::TryInsertResult::Conflicted`]. /// /// Useful for idempotent inserts such as `ON CONFLICT ... DO NOTHING` (Postgres / SQLite) or the /// MySQL polyfill (`ON DUPLICATE KEY UPDATE pk = pk`). @@ -48,7 +47,6 @@ where A: ActiveModelTrait, { pub(crate) insert_struct: Insert, - pub(crate) empty: bool, } impl Insert @@ -229,7 +227,7 @@ where TryInsert::from_one(self) } - /// Allow insert statement to return without error if nothing's been inserted. + /// Deprecated alias to [`Insert::try_insert`]. #[deprecated( since = "2.0.0", note = "Please use [`TryInsert::one`] or `on_conflict_do_nothing*` methods that return [`TryInsert`], or [`Insert::try_insert`]." @@ -409,7 +407,7 @@ where /// r#"INSERT INTO `cake` (`id`, `name`) VALUES (2, 'Orange') ON DUPLICATE KEY UPDATE `id` = `id`"#, /// ); /// ``` - pub fn on_conflict_do_nothing_on(mut self, columns: I) -> TryInsert + pub fn on_conflict_do_nothing_on(mut self, columns: I) -> Self where I: IntoIterator::Column>, { @@ -417,50 +415,60 @@ where let mut on_conflict = OnConflict::columns(columns); on_conflict.do_nothing_on(primary_keys); self.query.on_conflict(on_conflict); - TryInsert::from_many(self) + self } - /// Allow insert statement to return without error if nothing's been inserted. + /// Deprecated no-op. + /// + /// [`InsertMany::exec`] already handles empty input and inserts that affect no rows. #[deprecated( since = "2.0.0", - note = "Please use [`TryInsert::many`] or `on_conflict_do_nothing*` methods that return [`TryInsert`], or [`InsertMany::try_insert`]" + note = "Deprecated no-op. Use [`InsertMany::exec`] directly." )] - pub fn do_nothing(self) -> TryInsert + pub fn do_nothing(self) -> Self where A: ActiveModelTrait, { - TryInsert::from_many(self) + self } - /// Convert self into a `TryInsert`. It is just a wrapper for converting `DbErr::RecordNotInserted` -> `TryInsertResult::Conflicted`. - pub fn try_insert(self) -> TryInsert + /// Deprecated no-op. + /// + /// [`InsertMany::exec`] already handles empty input and inserts that affect no rows. + #[deprecated( + since = "2.0.0", + note = "Deprecated no-op. Use [`InsertMany::exec`] directly." + )] + pub fn try_insert(self) -> Self where A: ActiveModelTrait, { - TryInsert::from_many(self) + self } - /// Alias to [`InsertMany::do_nothing`]. + /// Deprecated no-op. + /// + /// [`InsertMany::exec`] already handles empty input and inserts that affect no rows. #[deprecated( since = "2.0.0", - 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`]." + note = "Deprecated no-op. Use [`InsertMany::exec`] directly." )] - pub fn on_empty_do_nothing(self) -> TryInsert + pub fn on_empty_do_nothing(self) -> Self where A: ActiveModelTrait, { - TryInsert::from_many(self) + self } /// Set ON CONFLICT on primary key do nothing, but with MySQL specific polyfill. /// See also [`Insert::on_conflict_do_nothing`]. - pub fn on_conflict_do_nothing(mut self) -> TryInsert + pub fn on_conflict_do_nothing(mut self) -> Self where A: ActiveModelTrait, { self.query.on_conflict(on_conflict_primary_key::()); - TryInsert::from_many(self) + self } /// panic when self is empty @@ -527,25 +535,6 @@ where fn from_one(insert: Insert) -> Self { Self { insert_struct: insert, - empty: false, - } - } - - fn from_many(insert: InsertMany) -> Self { - let InsertMany { - query, - primary_key, - empty, - model, - } = insert; - - Self { - insert_struct: Insert { - query, - primary_key, - model, - }, - empty, } } @@ -557,15 +546,6 @@ where Self::from_one(Insert::one(m)) } - /// Try insert many items - pub fn many(models: I) -> Self - where - M: IntoActiveModel, - I: IntoIterator, - { - Self::from_many(Insert::many(models)) - } - /// Set ON CONFLICT logic pub fn on_conflict(mut self, on_conflict: OnConflict) -> Insert { self.insert_struct.query.on_conflict(on_conflict); diff --git a/sea-orm-sync/src/rbac/context.rs b/sea-orm-sync/src/rbac/context.rs index 909c5ccc70..169ec9d14c 100644 --- a/sea-orm-sync/src/rbac/context.rs +++ b/sea-orm-sync/src/rbac/context.rs @@ -81,16 +81,14 @@ impl RbacContext { let txn = db.begin()?; for table_name in tables { - if let Some(table_id) = resource::Entity::insert(Resource { + let table_id = resource::Entity::insert(Resource { table: Set(table_name.to_string()), ..Default::default() }) .on_conflict_do_nothing() .exec(&txn)? - .last_insert_id()? - { - self.tables.insert(table_name.to_string(), table_id); - } + .last_insert_id()?; + self.tables.insert(table_name.to_string(), table_id); } txn.commit() @@ -106,17 +104,15 @@ impl RbacContext { AccessType::Update, AccessType::Delete, ] { - if let Some(permission_id) = permission::Entity::insert(Permission { + let permission_id = permission::Entity::insert(Permission { action: Set(action.as_str().to_owned()), ..Default::default() }) .on_conflict_do_nothing() .exec(&txn)? - .last_insert_id()? - { - self.permissions - .insert(action.as_str().to_owned(), permission_id); - } + .last_insert_id()?; + self.permissions + .insert(action.as_str().to_owned(), permission_id); } txn.commit() @@ -131,16 +127,14 @@ impl RbacContext { let txn = db.begin()?; for role in roles { - if let Some(role_id) = role::Entity::insert(Role { + let role_id = role::Entity::insert(Role { role: Set(role.to_string()), ..Default::default() }) .on_conflict_do_nothing() .exec(&txn)? - .last_insert_id()? - { - self.roles.insert(role.to_string(), role_id); - } + .last_insert_id()?; + self.roles.insert(role.to_string(), role_id); } txn.commit() diff --git a/sea-orm-sync/tests/empty_insert_tests.rs b/sea-orm-sync/tests/empty_insert_tests.rs index fc9b7d20f1..b047c86bf4 100644 --- a/sea-orm-sync/tests/empty_insert_tests.rs +++ b/sea-orm-sync/tests/empty_insert_tests.rs @@ -10,7 +10,7 @@ pub use sea_orm::{ pub use crud::*; // use common::bakery_chain::*; -use sea_orm::{DbConn, TryInsertResult}; +use sea_orm::DbConn; #[sea_orm_macros::test] fn main() { @@ -42,7 +42,7 @@ pub fn test(db: &DbConn) { .on_conflict_do_nothing() .exec(db); - assert!(matches!(conflict_insert, Ok(TryInsertResult::Conflicted))); + assert!(conflict_insert.unwrap().last_insert_id.is_none()); let empty_insert = Bakery::insert_many(std::iter::empty::()) .exec(db) diff --git a/sea-orm-sync/tests/string_primary_key_tests.rs b/sea-orm-sync/tests/string_primary_key_tests.rs index 716db5351d..52c0342a1c 100644 --- a/sea-orm-sync/tests/string_primary_key_tests.rs +++ b/sea-orm-sync/tests/string_primary_key_tests.rs @@ -4,7 +4,7 @@ pub mod common; pub use common::{TestContext, features::*, setup::*}; use pretty_assertions::assert_eq; -use sea_orm::{DatabaseConnection, TryInsertResult, entity::prelude::*, entity::*}; +use sea_orm::{DatabaseConnection, entity::prelude::*, entity::*}; use serde_json::json; #[sea_orm_macros::test] @@ -119,15 +119,10 @@ pub fn insert_and_delete_repository(db: &DatabaseConnection) -> Result<(), DbErr .into_active_model(), ]) .on_conflict_do_nothing() - .exec_with_returning_many(db)?; + .exec_with_returning(db)?; - match result { - TryInsertResult::Inserted(inserted) => { - assert_eq!(inserted.len(), 1); - assert_eq!(inserted[0].id, "unique-id-003"); - } - _ => panic!("{result:?}"), - } + assert_eq!(result.len(), 1); + assert_eq!(result[0].id, "unique-id-003"); } Ok(()) diff --git a/sea-orm-sync/tests/upsert_tests.rs b/sea-orm-sync/tests/upsert_tests.rs index d91b85e8da..8251a3a609 100644 --- a/sea-orm-sync/tests/upsert_tests.rs +++ b/sea-orm-sync/tests/upsert_tests.rs @@ -4,7 +4,6 @@ pub mod common; pub use common::{TestContext, features::*, setup::*}; use pretty_assertions::assert_eq; -use sea_orm::TryInsertResult; use sea_orm::entity::prelude::*; use sea_orm::{Set, sea_query::OnConflict}; @@ -64,13 +63,13 @@ pub fn create_insert_default(db: &DatabaseConnection) -> Result<(), DbErr> { .on_conflict(on_conflict.clone()) .exec(db); - assert!(matches!(res, Err(DbErr::RecordNotInserted))); + assert_eq!(res?.last_insert_id, None); let res = Entity::insert_many([ActiveModel { id: Set(3) }, ActiveModel { id: Set(4) }]) .on_conflict_do_nothing_on([Column::Id]) .exec(db); - assert!(matches!(res, Ok(TryInsertResult::Conflicted))); + assert_eq!(res?.last_insert_id, None); Ok(()) } diff --git a/src/entity/active_model.rs b/src/entity/active_model.rs index 3eb8ef5d56..5be2281b3a 100644 --- a/src/entity/active_model.rs +++ b/src/entity/active_model.rs @@ -1347,15 +1347,13 @@ where // insert new junctions if db.support_returning() { // use the returned value if it is supported - let res = J::insert_many(via_models_res) + let inserted = J::insert_many(via_models_res) .on_conflict_do_nothing() - .exec_with_returning_many(db) + .exec_with_returning(db) .await?; // run after_save hooks - if let TryInsertResult::Inserted(inserted) = res { - for model in inserted { - let _ = J::ActiveModel::after_save(model, db, true).await?; - } + for model in inserted { + let _ = J::ActiveModel::after_save(model, db, true).await?; } } else { // fall back to individual inserts if returning is not supported diff --git a/src/executor/insert.rs b/src/executor/insert.rs index df5f67281b..dec0eee3f8 100644 --- a/src/executor/insert.rs +++ b/src/executor/insert.rs @@ -37,7 +37,7 @@ where } /// Result of inserting many ActiveModels: the primary key of the last row -/// inserted, or `None` if the iterator was empty. +/// inserted, or `None` if the iterator was empty or the last insert id is unavailable. #[derive(Debug)] #[non_exhaustive] pub struct InsertManyResult @@ -54,10 +54,6 @@ where /// them as errors. #[derive(Debug)] pub enum TryInsertResult { - /// There was nothing to insert, so no SQL was executed. - /// - /// This typically happens when creating a [`crate::TryInsert`] from an empty iterator or None. - Empty, /// The statement was executed, but SeaORM could not get the inserted row / insert id. /// /// This is commonly caused by `ON CONFLICT ... DO NOTHING` (Postgres / SQLite) or the MySQL @@ -79,15 +75,11 @@ where { /// Extract the last inserted id. /// - /// - [`TryInsertResult::Empty`] => `Ok(None)` - /// - [`TryInsertResult::Inserted`] => `Ok(Some(last_insert_id))` + /// - [`TryInsertResult::Inserted`] => `Ok(last_insert_id)` /// - [`TryInsertResult::Conflicted`] => `Err(DbErr::RecordNotInserted)` - pub fn last_insert_id( - self, - ) -> Result as PrimaryKeyTrait>::ValueType>, DbErr> { + pub fn last_insert_id(self) -> Result< as PrimaryKeyTrait>::ValueType, DbErr> { match self { - Self::Empty => Ok(None), - Self::Inserted(v) => Ok(Some(v.last_insert_id)), + Self::Inserted(v) => Ok(v.last_insert_id), Self::Conflicted => Err(DbErr::RecordNotInserted), } } @@ -102,9 +94,6 @@ where where C: ConnectionTrait, { - if self.empty { - return Ok(TryInsertResult::Empty); - } let res = self.insert_struct.exec(db).await; match res { Ok(res) => Ok(TryInsertResult::Inserted(res)), @@ -119,9 +108,6 @@ where where C: ConnectionTrait, { - if self.empty { - return Ok(TryInsertResult::Empty); - } let res = self.insert_struct.exec_without_returning(db).await; match res { Ok(res) => Ok(TryInsertResult::Inserted(res)), @@ -139,9 +125,6 @@ where ::Model: IntoActiveModel, C: ConnectionTrait, { - if self.empty { - return Ok(TryInsertResult::Empty); - } let res = self.insert_struct.exec_with_returning(db).await; match res { Ok(res) => Ok(TryInsertResult::Inserted(res)), @@ -159,10 +142,6 @@ where ::Model: IntoActiveModel, C: ConnectionTrait, { - if self.empty { - return Ok(TryInsertResult::Empty); - } - let res = self.insert_struct.exec_with_returning_keys(db).await; match res { Ok(res) => Ok(TryInsertResult::Inserted(res)), @@ -180,10 +159,6 @@ where ::Model: IntoActiveModel, C: ConnectionTrait, { - if self.empty { - return Ok(TryInsertResult::Empty); - } - let res = self.insert_struct.exec_with_returning_many(db).await; match res { Ok(res) => Ok(TryInsertResult::Inserted(res)), @@ -277,7 +252,10 @@ impl InsertMany where A: ActiveModelTrait, { - /// Execute an insert operation + /// Execute an insert operation. + /// + /// The returned [`InsertManyResult::last_insert_id`] is `None` if the + /// iterator was empty or the last insert id is unavailable. pub async fn exec(self, db: &C) -> Result, DbErr> where C: ConnectionTrait, @@ -292,6 +270,9 @@ where Ok(r) => Ok(InsertManyResult { last_insert_id: Some(r.last_insert_id), }), + Err(DbErr::RecordNotInserted) => Ok(InsertManyResult { + last_insert_id: None, + }), Err(err) => Err(err), } } diff --git a/src/lib.rs b/src/lib.rs index 5e7dbe0a9d..370b2fd135 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -391,7 +391,7 @@ //! ### Insert (advanced) //! You can take advantage of database specific features to perform upsert and idempotent insert. //! ``` -//! # use sea_orm::{DbConn, TryInsertResult, DbErr, entity::*, query::*, tests_cfg::*}; +//! # use sea_orm::{DbConn, DbErr, entity::*, query::*, tests_cfg::*}; //! # async fn function_1(db: &DbConn) -> Result<(), DbErr> { //! # let apple = fruit::ActiveModel { //! # name: Set("Apple".to_owned()), @@ -429,7 +429,7 @@ //! .exec(db) //! .await?; //! -//! matches!(result, TryInsertResult::Conflicted); +//! result.last_insert_id.is_none(); //! # Ok(()) //! # } //! ``` diff --git a/src/query/insert.rs b/src/query/insert.rs index 405997cac2..465e433674 100644 --- a/src/query/insert.rs +++ b/src/query/insert.rs @@ -34,11 +34,10 @@ where pub(crate) model: PhantomData, } -/// Wrapper of [`Insert`] / [`InsertMany`], treats "no row inserted/id returned" as a normal outcome. +/// Wrapper of [`Insert`], treats "no row inserted/id returned" as a normal outcome. /// /// Its `exec*` methods return [`crate::TryInsertResult`]. -/// Mapping empty input to [`crate::TryInsertResult::Empty`] (no SQL executed) and -/// `DbErr::RecordNotInserted` to [`crate::TryInsertResult::Conflicted`]. +/// Mapping `DbErr::RecordNotInserted` to [`crate::TryInsertResult::Conflicted`]. /// /// Useful for idempotent inserts such as `ON CONFLICT ... DO NOTHING` (Postgres / SQLite) or the /// MySQL polyfill (`ON DUPLICATE KEY UPDATE pk = pk`). @@ -48,7 +47,6 @@ where A: ActiveModelTrait, { pub(crate) insert_struct: Insert, - pub(crate) empty: bool, } impl Insert @@ -229,7 +227,7 @@ where TryInsert::from_one(self) } - /// Allow insert statement to return without error if nothing's been inserted. + /// Deprecated alias to [`Insert::try_insert`]. #[deprecated( since = "2.0.0", note = "Please use [`TryInsert::one`] or `on_conflict_do_nothing*` methods that return [`TryInsert`], or [`Insert::try_insert`]." @@ -409,7 +407,7 @@ where /// r#"INSERT INTO `cake` (`id`, `name`) VALUES (2, 'Orange') ON DUPLICATE KEY UPDATE `id` = `id`"#, /// ); /// ``` - pub fn on_conflict_do_nothing_on(mut self, columns: I) -> TryInsert + pub fn on_conflict_do_nothing_on(mut self, columns: I) -> Self where I: IntoIterator::Column>, { @@ -417,50 +415,60 @@ where let mut on_conflict = OnConflict::columns(columns); on_conflict.do_nothing_on(primary_keys); self.query.on_conflict(on_conflict); - TryInsert::from_many(self) + self } - /// Allow insert statement to return without error if nothing's been inserted. + /// Deprecated no-op. + /// + /// [`InsertMany::exec`] already handles empty input and inserts that affect no rows. #[deprecated( since = "2.0.0", - note = "Please use [`TryInsert::many`] or `on_conflict_do_nothing*` methods that return [`TryInsert`], or [`InsertMany::try_insert`]" + note = "Deprecated no-op. Use [`InsertMany::exec`] directly." )] - pub fn do_nothing(self) -> TryInsert + pub fn do_nothing(self) -> Self where A: ActiveModelTrait, { - TryInsert::from_many(self) + self } - /// Convert self into a `TryInsert`. It is just a wrapper for converting `DbErr::RecordNotInserted` -> `TryInsertResult::Conflicted`. - pub fn try_insert(self) -> TryInsert + /// Deprecated no-op. + /// + /// [`InsertMany::exec`] already handles empty input and inserts that affect no rows. + #[deprecated( + since = "2.0.0", + note = "Deprecated no-op. Use [`InsertMany::exec`] directly." + )] + pub fn try_insert(self) -> Self where A: ActiveModelTrait, { - TryInsert::from_many(self) + self } - /// Alias to [`InsertMany::do_nothing`]. + /// Deprecated no-op. + /// + /// [`InsertMany::exec`] already handles empty input and inserts that affect no rows. #[deprecated( since = "2.0.0", - 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`]." + note = "Deprecated no-op. Use [`InsertMany::exec`] directly." )] - pub fn on_empty_do_nothing(self) -> TryInsert + pub fn on_empty_do_nothing(self) -> Self where A: ActiveModelTrait, { - TryInsert::from_many(self) + self } /// Set ON CONFLICT on primary key do nothing, but with MySQL specific polyfill. /// See also [`Insert::on_conflict_do_nothing`]. - pub fn on_conflict_do_nothing(mut self) -> TryInsert + pub fn on_conflict_do_nothing(mut self) -> Self where A: ActiveModelTrait, { self.query.on_conflict(on_conflict_primary_key::()); - TryInsert::from_many(self) + self } /// panic when self is empty @@ -527,25 +535,6 @@ where fn from_one(insert: Insert) -> Self { Self { insert_struct: insert, - empty: false, - } - } - - fn from_many(insert: InsertMany) -> Self { - let InsertMany { - query, - primary_key, - empty, - model, - } = insert; - - Self { - insert_struct: Insert { - query, - primary_key, - model, - }, - empty, } } @@ -557,15 +546,6 @@ where Self::from_one(Insert::one(m)) } - /// Try insert many items - pub fn many(models: I) -> Self - where - M: IntoActiveModel, - I: IntoIterator, - { - Self::from_many(Insert::many(models)) - } - /// Set ON CONFLICT logic pub fn on_conflict(mut self, on_conflict: OnConflict) -> Insert { self.insert_struct.query.on_conflict(on_conflict); diff --git a/src/rbac/context.rs b/src/rbac/context.rs index 690bcf16d6..1494681a49 100644 --- a/src/rbac/context.rs +++ b/src/rbac/context.rs @@ -86,17 +86,15 @@ impl RbacContext { let txn = db.begin().await?; for table_name in tables { - if let Some(table_id) = resource::Entity::insert(Resource { + let table_id = resource::Entity::insert(Resource { table: Set(table_name.to_string()), ..Default::default() }) .on_conflict_do_nothing() .exec(&txn) .await? - .last_insert_id()? - { - self.tables.insert(table_name.to_string(), table_id); - } + .last_insert_id()?; + self.tables.insert(table_name.to_string(), table_id); } txn.commit().await @@ -112,18 +110,16 @@ impl RbacContext { AccessType::Update, AccessType::Delete, ] { - if let Some(permission_id) = permission::Entity::insert(Permission { + let permission_id = permission::Entity::insert(Permission { action: Set(action.as_str().to_owned()), ..Default::default() }) .on_conflict_do_nothing() .exec(&txn) .await? - .last_insert_id()? - { - self.permissions - .insert(action.as_str().to_owned(), permission_id); - } + .last_insert_id()?; + self.permissions + .insert(action.as_str().to_owned(), permission_id); } txn.commit().await @@ -138,17 +134,15 @@ impl RbacContext { let txn = db.begin().await?; for role in roles { - if let Some(role_id) = role::Entity::insert(Role { + let role_id = role::Entity::insert(Role { role: Set(role.to_string()), ..Default::default() }) .on_conflict_do_nothing() .exec(&txn) .await? - .last_insert_id()? - { - self.roles.insert(role.to_string(), role_id); - } + .last_insert_id()?; + self.roles.insert(role.to_string(), role_id); } txn.commit().await diff --git a/tests/empty_insert_tests.rs b/tests/empty_insert_tests.rs index 0fc57d2933..e723191675 100644 --- a/tests/empty_insert_tests.rs +++ b/tests/empty_insert_tests.rs @@ -10,7 +10,7 @@ pub use sea_orm::{ pub use crud::*; // use common::bakery_chain::*; -use sea_orm::{DbConn, TryInsertResult}; +use sea_orm::DbConn; #[sea_orm_macros::test] async fn main() { @@ -43,7 +43,7 @@ pub async fn test(db: &DbConn) { .exec(db) .await; - assert!(matches!(conflict_insert, Ok(TryInsertResult::Conflicted))); + assert!(conflict_insert.unwrap().last_insert_id.is_none()); let empty_insert = Bakery::insert_many(std::iter::empty::()) .exec(db) diff --git a/tests/string_primary_key_tests.rs b/tests/string_primary_key_tests.rs index 51176b0ecb..1b7a1038f2 100644 --- a/tests/string_primary_key_tests.rs +++ b/tests/string_primary_key_tests.rs @@ -4,7 +4,7 @@ pub mod common; pub use common::{TestContext, features::*, setup::*}; use pretty_assertions::assert_eq; -use sea_orm::{DatabaseConnection, TryInsertResult, entity::prelude::*, entity::*}; +use sea_orm::{DatabaseConnection, entity::prelude::*, entity::*}; use serde_json::json; #[sea_orm_macros::test] @@ -120,16 +120,11 @@ pub async fn insert_and_delete_repository(db: &DatabaseConnection) -> Result<(), .into_active_model(), ]) .on_conflict_do_nothing() - .exec_with_returning_many(db) + .exec_with_returning(db) .await?; - match result { - TryInsertResult::Inserted(inserted) => { - assert_eq!(inserted.len(), 1); - assert_eq!(inserted[0].id, "unique-id-003"); - } - _ => panic!("{result:?}"), - } + assert_eq!(result.len(), 1); + assert_eq!(result[0].id, "unique-id-003"); } Ok(()) diff --git a/tests/upsert_tests.rs b/tests/upsert_tests.rs index 76f630f6c1..94dae9bff7 100644 --- a/tests/upsert_tests.rs +++ b/tests/upsert_tests.rs @@ -4,7 +4,6 @@ pub mod common; pub use common::{TestContext, features::*, setup::*}; use pretty_assertions::assert_eq; -use sea_orm::TryInsertResult; use sea_orm::entity::prelude::*; use sea_orm::{Set, sea_query::OnConflict}; @@ -69,14 +68,14 @@ pub async fn create_insert_default(db: &DatabaseConnection) -> Result<(), DbErr> .exec(db) .await; - assert!(matches!(res, Err(DbErr::RecordNotInserted))); + assert_eq!(res?.last_insert_id, None); let res = Entity::insert_many([ActiveModel { id: Set(3) }, ActiveModel { id: Set(4) }]) .on_conflict_do_nothing_on([Column::Id]) .exec(db) .await; - assert!(matches!(res, Ok(TryInsertResult::Conflicted))); + assert_eq!(res?.last_insert_id, None); Ok(()) }