diff --git a/issues/1357/Cargo.toml b/issues/1357/Cargo.toml
new file mode 100644
index 000000000..55e7bfc33
--- /dev/null
+++ b/issues/1357/Cargo.toml
@@ -0,0 +1,18 @@
+[workspace]
+# A separate workspace
+
+[package]
+name = "sea-orm-issues-1357"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[dependencies]
+anyhow = "1"
+serde = "1"
+tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }
+
+[dependencies.sea-orm]
+path = "../../"
+default-features = false
+features = ["macros", "runtime-tokio-native-tls", "sqlx-sqlite"]
diff --git a/issues/1357/src/entity.rs b/issues/1357/src/entity.rs
new file mode 100644
index 000000000..3ad25f9ff
--- /dev/null
+++ b/issues/1357/src/entity.rs
@@ -0,0 +1,14 @@
+use sea_orm::entity::prelude::*;
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[sea_orm(table_name = "pool")]
+pub struct Model {
+ #[sea_orm(primary_key, auto_increment = false)]
+ pub id: i64,
+ pub name: String,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
+
+impl ActiveModelBehavior for ActiveModel {}
diff --git a/issues/1357/src/main.rs b/issues/1357/src/main.rs
new file mode 100644
index 000000000..f7488beb4
--- /dev/null
+++ b/issues/1357/src/main.rs
@@ -0,0 +1,42 @@
+use anyhow::Result;
+use sea_orm::{ConnectionTrait, Database, EntityTrait, IntoActiveModel, Schema};
+
+mod entity;
+
+use entity::*;
+
+#[tokio::main]
+async fn main() -> Result<()> {
+ let db = Database::connect("sqlite::memory:").await.unwrap();
+
+ let builder = db.get_database_backend();
+ let schema = Schema::new(builder);
+ let stmt = schema.create_table_from_entity(Entity);
+ db.execute(builder.build(&stmt)).await?;
+
+ let model = Model {
+ id: 100,
+ name: "Hello".to_owned(),
+ };
+
+ let res = Entity::insert(model.clone().into_active_model())
+ .exec(&db)
+ .await?;
+
+ assert_eq!(Entity::find().one(&db).await?, Some(model.clone()));
+ assert_eq!(res.last_insert_id, model.id);
+
+ let model = Model {
+ id: -10,
+ name: "World".to_owned(),
+ };
+
+ let res = Entity::insert(model.clone().into_active_model())
+ .exec(&db)
+ .await?;
+
+ assert_eq!(Entity::find().one(&db).await?, Some(model.clone()));
+ assert_eq!(res.last_insert_id, model.id);
+
+ Ok(())
+}
diff --git a/src/error.rs b/src/error.rs
index 7988bd1b8..2ed87ffdc 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -58,8 +58,8 @@ pub enum DbErr {
/// 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),
+ #[error("None of the records are being inserted")]
+ RecordNotInserted,
}
/// Runtime error
diff --git a/src/executor/execute.rs b/src/executor/execute.rs
index 3da4ec8a3..f3a7150de 100644
--- a/src/executor/execute.rs
+++ b/src/executor/execute.rs
@@ -52,7 +52,7 @@ impl ExecResult {
}
}
- /// Get the number of rows affedted by the operation
+ /// Get the number of rows affected by the operation
pub fn rows_affected(&self) -> u64 {
match &self.result {
#[cfg(feature = "sqlx-mysql")]
diff --git a/src/executor/insert.rs b/src/executor/insert.rs
index 796cd3629..c4c988ba9 100644
--- a/src/executor/insert.rs
+++ b/src/executor/insert.rs
@@ -137,29 +137,37 @@ where
{
type PrimaryKey = <::Entity as EntityTrait>::PrimaryKey;
type ValueTypeOf = as PrimaryKeyTrait>::ValueType;
- let last_insert_id_opt = match db.support_returning() {
- true => {
+
+ let last_insert_id = match (primary_key, db.support_returning()) {
+ (Some(value_tuple), _) => {
+ let res = db.execute(statement).await?;
+ if res.rows_affected() == 0 {
+ return Err(DbErr::RecordNotInserted);
+ }
+ FromValueTuple::from_value_tuple(value_tuple)
+ }
+ (None, true) => {
+ let mut rows = db.query_all(statement).await?;
+ let row = match rows.pop() {
+ Some(row) => row,
+ None => return Err(DbErr::RecordNotInserted),
+ };
let cols = PrimaryKey::::iter()
.map(|col| col.to_string())
.collect::>();
- 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()
+ row.try_get_many("", cols.as_ref())
+ .map_err(|_| DbErr::UnpackInsertId)?
}
- false => {
- let last_insert_id = db.execute(statement).await?.last_insert_id();
- ValueTypeOf::::try_from_u64(last_insert_id).ok()
+ (None, false) => {
+ let res = db.execute(statement).await?;
+ if res.rows_affected() == 0 {
+ return Err(DbErr::RecordNotInserted);
+ }
+ let last_insert_id = res.last_insert_id();
+ ValueTypeOf::::try_from_u64(last_insert_id).map_err(|_| DbErr::UnpackInsertId)?
}
};
- let last_insert_id = match primary_key {
- Some(value_tuple) => FromValueTuple::from_value_tuple(value_tuple),
- None => match last_insert_id_opt {
- Some(last_insert_id) => last_insert_id,
- None => return Err(DbErr::UnpackInsertId),
- },
- };
+
Ok(InsertResult { last_insert_id })
}
diff --git a/tests/string_primary_key_tests.rs b/tests/string_primary_key_tests.rs
index 94d1ae554..9ed4df476 100644
--- a/tests/string_primary_key_tests.rs
+++ b/tests/string_primary_key_tests.rs
@@ -2,7 +2,7 @@ pub mod common;
pub use common::{features::*, setup::*, TestContext};
use pretty_assertions::assert_eq;
-use sea_orm::{entity::prelude::*, entity::*, DatabaseConnection};
+use sea_orm::{entity::prelude::*, entity::*, sea_query::OnConflict, DatabaseConnection};
use serde_json::json;
#[sea_orm_macros::test]
@@ -30,7 +30,7 @@ pub async fn insert_and_delete_repository(db: &DatabaseConnection) -> Result<(),
}
.into_active_model();
- let result = repository.insert(db).await?;
+ let result = repository.clone().insert(db).await?;
assert_eq!(
result,
@@ -42,6 +42,17 @@ pub async fn insert_and_delete_repository(db: &DatabaseConnection) -> Result<(),
}
);
+ #[cfg(any(feature = "sqlx-sqlite", feature = "sqlx-postgres"))]
+ {
+ let err = Repository::insert(repository)
+ // MySQL does not support DO NOTHING, we might workaround that later
+ .on_conflict(OnConflict::new().do_nothing().to_owned())
+ .exec(db)
+ .await;
+
+ assert_eq!(err.err(), Some(DbErr::RecordNotInserted));
+ }
+
result.delete(db).await?;
assert_eq!(
diff --git a/tests/upsert_tests.rs b/tests/upsert_tests.rs
index ad874e79c..748d5b0a3 100644
--- a/tests/upsert_tests.rs
+++ b/tests/upsert_tests.rs
@@ -54,12 +54,7 @@ pub async fn create_insert_default(db: &DatabaseConnection) -> Result<(), DbErr>
.exec(db)
.await;
- assert_eq!(
- res.err(),
- Some(DbErr::RecordNotInserted(
- "None of the records are being inserted".to_owned()
- ))
- );
+ assert_eq!(res.err(), Some(DbErr::RecordNotInserted));
Ok(())
}