From f79a4171503dbcd6f86187b6263e7c345bd173be Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Mon, 27 Sep 2021 18:01:38 +0800 Subject: [PATCH] Remove `ValueType: Default` --- src/entity/active_model.rs | 25 +++++++++++-------------- src/entity/base_entity.rs | 8 ++++++-- src/entity/prelude.rs | 5 +++-- src/entity/primary_key.rs | 20 +++++++++++--------- src/executor/insert.rs | 29 ++++++++++++++++++++--------- src/query/insert.rs | 23 +++++++++++++++++++++-- 6 files changed, 72 insertions(+), 38 deletions(-) diff --git a/src/entity/active_model.rs b/src/entity/active_model.rs index cfcb0bbd..c69e5b01 100644 --- a/src/entity/active_model.rs +++ b/src/entity/active_model.rs @@ -1,6 +1,6 @@ use crate::{ error::*, DatabaseConnection, DeleteResult, EntityTrait, Iterable, PrimaryKeyToColumn, - PrimaryKeyTrait, Value, + PrimaryKeyValue, Value, }; use async_trait::async_trait; use std::fmt::Debug; @@ -70,23 +70,18 @@ pub trait ActiveModelTrait: Clone + Debug { async fn insert(self, db: &DatabaseConnection) -> Result where ::Model: IntoActiveModel, + <::Entity as EntityTrait>::PrimaryKey: + PrimaryKeyValue<::Entity>, { let am = self; let exec = ::insert(am).exec(db); let res = exec.await?; - // Assume valid last_insert_id is not equals to Default::default() - if res.last_insert_id - != <::PrimaryKey as PrimaryKeyTrait>::ValueType::default() - { - let found = ::find_by_id(res.last_insert_id) - .one(db) - .await?; - match found { - Some(model) => Ok(model.into_active_model()), - None => Err(DbErr::Exec("Failed to find inserted item".to_owned())), - } - } else { - Ok(Self::default()) + let found = ::find_by_id(res.last_insert_id) + .one(db) + .await?; + match found { + Some(model) => Ok(model.into_active_model()), + None => Err(DbErr::Exec("Failed to find inserted item".to_owned())), } } @@ -101,6 +96,8 @@ pub trait ActiveModelTrait: Clone + Debug { where Self: ActiveModelBehavior, ::Model: IntoActiveModel, + <::Entity as EntityTrait>::PrimaryKey: + PrimaryKeyValue<::Entity>, { let mut am = self; am = ActiveModelBehavior::before_save(am); diff --git a/src/entity/base_entity.rs b/src/entity/base_entity.rs index 7ba1e965..0c9813f7 100644 --- a/src/entity/base_entity.rs +++ b/src/entity/base_entity.rs @@ -1,7 +1,7 @@ use crate::{ ActiveModelTrait, ColumnTrait, Delete, DeleteMany, DeleteOne, FromQueryResult, Insert, - ModelTrait, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, Related, RelationBuilder, - RelationTrait, RelationType, Select, Update, UpdateMany, UpdateOne, + ModelTrait, PrimaryKeyToColumn, PrimaryKeyTrait, PrimaryKeyValue, QueryFilter, Related, + RelationBuilder, RelationTrait, RelationType, Select, Update, UpdateMany, UpdateOne, }; use sea_query::{Alias, Iden, IntoIden, IntoTableRef, IntoValueTuple, TableRef}; pub use sea_strum::IntoEnumIterator as Iterable; @@ -299,6 +299,8 @@ pub trait EntityTrait: EntityName { fn insert(model: A) -> Insert where A: ActiveModelTrait, + <::Entity as EntityTrait>::PrimaryKey: + PrimaryKeyValue<::Entity>, { Insert::one(model) } @@ -352,6 +354,8 @@ pub trait EntityTrait: EntityName { where A: ActiveModelTrait, I: IntoIterator, + <::Entity as EntityTrait>::PrimaryKey: + PrimaryKeyValue<::Entity>, { Insert::many(models) } diff --git a/src/entity/prelude.rs b/src/entity/prelude.rs index 8d87a4b2..be630567 100644 --- a/src/entity/prelude.rs +++ b/src/entity/prelude.rs @@ -2,8 +2,9 @@ pub use crate::{ error::*, ActiveModelBehavior, ActiveModelTrait, ColumnDef, ColumnTrait, ColumnType, DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveCustomColumn, DeriveEntity, DeriveEntityModel, DeriveModel, DerivePrimaryKey, DeriveRelation, EntityName, EntityTrait, - EnumIter, ForeignKeyAction, Iden, IdenStatic, Linked, ModelTrait, PrimaryKeyToColumn, - PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef, RelationTrait, Select, Value, + EnumIter, ForeignKeyAction, Iden, IdenStatic, IntoActiveModel, Linked, ModelTrait, + PrimaryKeyToColumn, PrimaryKeyTrait, PrimaryKeyValue, QueryFilter, QueryResult, Related, + RelationDef, RelationTrait, Select, Value, }; #[cfg(feature = "with-json")] diff --git a/src/entity/primary_key.rs b/src/entity/primary_key.rs index 463f1482..530eba30 100644 --- a/src/entity/primary_key.rs +++ b/src/entity/primary_key.rs @@ -1,18 +1,11 @@ use super::{ColumnTrait, IdenStatic, Iterable}; -use crate::{TryFromU64, TryGetableMany}; +use crate::{ActiveModelTrait, EntityTrait, TryFromU64, TryGetableMany}; use sea_query::IntoValueTuple; use std::fmt::Debug; //LINT: composite primary key cannot auto increment pub trait PrimaryKeyTrait: IdenStatic + Iterable { - type ValueType: Sized - + Send - + Default - + Debug - + PartialEq - + IntoValueTuple - + TryGetableMany - + TryFromU64; + type ValueType: Sized + Send + Debug + PartialEq + IntoValueTuple + TryGetableMany + TryFromU64; fn auto_increment() -> bool; } @@ -26,3 +19,12 @@ pub trait PrimaryKeyToColumn { where Self: Sized; } + +pub trait PrimaryKeyValue +where + E: EntityTrait, +{ + fn get_primary_key_value(active_model: A) -> ::ValueType + where + A: ActiveModelTrait; +} diff --git a/src/executor/insert.rs b/src/executor/insert.rs index 1f4936ba..cb7e5555 100644 --- a/src/executor/insert.rs +++ b/src/executor/insert.rs @@ -5,11 +5,12 @@ use crate::{ use sea_query::InsertStatement; use std::{future::Future, marker::PhantomData}; -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct Inserter where A: ActiveModelTrait, { + primary_key: Option<<<::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType>, query: InsertStatement, model: PhantomData, } @@ -48,7 +49,7 @@ where ); } } - Inserter::::new(query).exec(db) + Inserter::::new(self.primary_key, query).exec(db) // TODO: return primary key if extracted before, otherwise use InsertResult } } @@ -57,8 +58,12 @@ impl Inserter where A: ActiveModelTrait, { - pub fn new(query: InsertStatement) -> Self { + pub fn new( + primary_key: Option<<<::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType>, + query: InsertStatement, + ) -> Self { Self { + primary_key, query, model: PhantomData, } @@ -72,12 +77,13 @@ where A: 'a, { let builder = db.get_database_backend(); - exec_insert(builder.build(&self.query), db) + exec_insert(self.primary_key, builder.build(&self.query), db) } } // Only Statement impl Send async fn exec_insert( + primary_key: Option<<<::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType>, statement: Statement, db: &DatabaseConnection, ) -> Result, DbErr> @@ -86,7 +92,7 @@ where { type PrimaryKey = <::Entity as EntityTrait>::PrimaryKey; type ValueTypeOf = as PrimaryKeyTrait>::ValueType; - let last_insert_id = match db { + let last_insert_id_opt = match db { #[cfg(feature = "sqlx-postgres")] DatabaseConnection::SqlxPostgresPoolConnection(conn) => { use crate::{sea_query::Iden, Iterable}; @@ -94,14 +100,19 @@ where .map(|col| col.to_string()) .collect::>(); let res = conn.query_one(statement).await?.unwrap(); - res.try_get_many("", cols.as_ref()).unwrap_or_default() + Some(res.try_get_many("", cols.as_ref()).unwrap_or_default()) } _ => { let last_insert_id = db.execute(statement).await?.last_insert_id(); - ValueTypeOf::::try_from_u64(last_insert_id) - .ok() - .unwrap_or_default() + ValueTypeOf::::try_from_u64(last_insert_id).ok() } }; + let last_insert_id = match last_insert_id_opt { + Some(last_insert_id) => last_insert_id, + None => match primary_key { + Some(primary_key) => primary_key, + None => return Err(DbErr::Exec("Fail to unpack last_insert_id".to_owned())), + }, + }; Ok(InsertResult { last_insert_id }) } diff --git a/src/query/insert.rs b/src/query/insert.rs index a65071e1..418d2b70 100644 --- a/src/query/insert.rs +++ b/src/query/insert.rs @@ -1,14 +1,18 @@ -use crate::{ActiveModelTrait, EntityName, EntityTrait, IntoActiveModel, Iterable, QueryTrait}; +use crate::{ + ActiveModelTrait, EntityName, EntityTrait, IntoActiveModel, Iterable, PrimaryKeyTrait, + PrimaryKeyValue, QueryTrait, +}; use core::marker::PhantomData; use sea_query::InsertStatement; -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct Insert where A: ActiveModelTrait, { pub(crate) query: InsertStatement, pub(crate) columns: Vec, + pub(crate) primary_key: Option<<<::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType>, pub(crate) model: PhantomData, } @@ -31,6 +35,7 @@ where .into_table(A::Entity::default().table_ref()) .to_owned(), columns: Vec::new(), + primary_key: None, model: PhantomData, } } @@ -68,6 +73,8 @@ where pub fn one(m: M) -> Insert where M: IntoActiveModel, + <::Entity as EntityTrait>::PrimaryKey: + PrimaryKeyValue<::Entity>, { Self::new().add(m) } @@ -97,6 +104,8 @@ where where M: IntoActiveModel, I: IntoIterator, + <::Entity as EntityTrait>::PrimaryKey: + PrimaryKeyValue<::Entity>, { Self::new().add_many(models) } @@ -105,8 +114,16 @@ where pub fn add(mut self, m: M) -> Self where M: IntoActiveModel, + <::Entity as EntityTrait>::PrimaryKey: + PrimaryKeyValue<::Entity>, { let mut am: A = m.into_active_model(); + self.primary_key = + if !<::PrimaryKey as PrimaryKeyTrait>::auto_increment() { + Some(<::PrimaryKey as PrimaryKeyValue>::get_primary_key_value::(am.clone())) + } else { + None + }; let mut columns = Vec::new(); let mut values = Vec::new(); let columns_empty = self.columns.is_empty(); @@ -132,6 +149,8 @@ where where M: IntoActiveModel, I: IntoIterator, + <::Entity as EntityTrait>::PrimaryKey: + PrimaryKeyValue<::Entity>, { for model in models.into_iter() { self = self.add(model);