MySQL insert on conflict do nothing (#2244)
* MySQL insert on conflict do nothing * on_conflict_do_nothing * clippy
This commit is contained in:
parent
ad9f3c4112
commit
b4506c0647
@ -1,6 +1,7 @@
|
||||
use crate::{
|
||||
error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, Insert, IntoActiveModel,
|
||||
Iterable, PrimaryKeyToColumn, PrimaryKeyTrait, SelectModel, SelectorRaw, TryFromU64, TryInsert,
|
||||
error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, DbBackend, EntityTrait, Insert,
|
||||
IntoActiveModel, Iterable, PrimaryKeyToColumn, PrimaryKeyTrait, SelectModel, SelectorRaw,
|
||||
TryFromU64, TryInsert,
|
||||
};
|
||||
use sea_query::{FromValueTuple, Iden, InsertStatement, Query, ValueTuple};
|
||||
use std::{future::Future, marker::PhantomData};
|
||||
@ -245,6 +246,14 @@ where
|
||||
return Err(DbErr::RecordNotInserted);
|
||||
}
|
||||
let last_insert_id = res.last_insert_id();
|
||||
// For MySQL, the affected-rows number:
|
||||
// - The affected-rows value per row is `1` if the row is inserted as a new row,
|
||||
// - `2` if an existing row is updated,
|
||||
// - and `0` if an existing row is set to its current values.
|
||||
// Reference: https://dev.mysql.com/doc/refman/8.4/en/insert-on-duplicate.html
|
||||
if db_backend == DbBackend::MySql && last_insert_id == 0 {
|
||||
return Err(DbErr::RecordNotInserted);
|
||||
}
|
||||
ValueTypeOf::<A>::try_from_u64(last_insert_id).map_err(|_| DbErr::UnpackInsertId)?
|
||||
}
|
||||
};
|
||||
|
@ -225,6 +225,21 @@ where
|
||||
{
|
||||
TryInsert::from_insert(self)
|
||||
}
|
||||
|
||||
/// On conflict do nothing
|
||||
pub fn on_conflict_do_nothing(mut self) -> TryInsert<A>
|
||||
where
|
||||
A: ActiveModelTrait,
|
||||
{
|
||||
let primary_keys = <A::Entity as EntityTrait>::PrimaryKey::iter();
|
||||
self.query.on_conflict(
|
||||
OnConflict::columns(primary_keys.clone())
|
||||
.do_nothing_on(primary_keys)
|
||||
.to_owned(),
|
||||
);
|
||||
|
||||
TryInsert::from_insert(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> QueryTrait for Insert<A>
|
||||
|
@ -34,12 +34,19 @@ pub async fn test(db: &DbConn) {
|
||||
|
||||
assert!(matches!(res, Ok(TryInsertResult::Inserted(_))));
|
||||
|
||||
let _double_seaside_bakery = bakery::ActiveModel {
|
||||
let double_seaside_bakery = bakery::ActiveModel {
|
||||
name: Set("SeaSide Bakery".to_owned()),
|
||||
profit_margin: Set(10.4),
|
||||
id: Set(1),
|
||||
};
|
||||
|
||||
let conflict_insert = Bakery::insert_many([double_seaside_bakery])
|
||||
.on_conflict_do_nothing()
|
||||
.exec(db)
|
||||
.await;
|
||||
|
||||
assert!(matches!(conflict_insert, Ok(TryInsertResult::Conflicted)));
|
||||
|
||||
let empty_insert = Bakery::insert_many(std::iter::empty::<bakery::ActiveModel>())
|
||||
.on_empty_do_nothing()
|
||||
.exec(db)
|
||||
|
@ -9,7 +9,6 @@ use sea_orm::TryInsertResult;
|
||||
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?;
|
||||
@ -22,7 +21,9 @@ async fn main() -> Result<(), DbErr> {
|
||||
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 on_conflict = OnConflict::column(Column::Id)
|
||||
.do_nothing_on([Column::Id])
|
||||
.to_owned();
|
||||
|
||||
let res = Entity::insert_many([
|
||||
ActiveModel { id: Set(1) },
|
||||
|
Loading…
x
Reference in New Issue
Block a user