Remove PrimaryKeyValue trait

This commit is contained in:
Billy Chan 2021-10-08 18:04:42 +08:00
parent ade06b4240
commit 2f90207d64
No known key found for this signature in database
GPG Key ID: A2D690CAC7DF3CC7
8 changed files with 65 additions and 63 deletions

View File

@ -30,7 +30,7 @@ futures-util = { version = "^0.3" }
log = { version = "^0.4", optional = true } log = { version = "^0.4", optional = true }
rust_decimal = { version = "^1", optional = true } rust_decimal = { version = "^1", optional = true }
sea-orm-macros = { version = "^0.2.5", path = "sea-orm-macros", optional = true } sea-orm-macros = { version = "^0.2.5", path = "sea-orm-macros", optional = true }
sea-query = { version = "^0.17.0", features = ["thread-safe"] } sea-query = { version = "^0.17.0", git = "https://github.com/SeaQL/sea-query.git", branch = "from-value-tuple", features = ["thread-safe"] }
sea-strum = { version = "^0.21", features = ["derive", "sea-orm"] } sea-strum = { version = "^0.21", features = ["derive", "sea-orm"] }
serde = { version = "^1.0", features = ["derive"] } serde = { version = "^1.0", features = ["derive"] }
serde_json = { version = "^1", optional = true } serde_json = { version = "^1", optional = true }

View File

@ -1,7 +1,7 @@
use heck::SnakeCase; use heck::SnakeCase;
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{quote, quote_spanned, ToTokens}; use quote::{quote, quote_spanned};
use syn::{punctuated::Punctuated, token::Comma, Data, DataEnum, Fields, Variant}; use syn::{Data, DataEnum, Fields, Variant};
pub fn expand_derive_primary_key(ident: Ident, data: Data) -> syn::Result<TokenStream> { pub fn expand_derive_primary_key(ident: Ident, data: Data) -> syn::Result<TokenStream> {
let variants = match data { let variants = match data {
@ -30,21 +30,6 @@ pub fn expand_derive_primary_key(ident: Ident, data: Data) -> syn::Result<TokenS
}) })
.collect(); .collect();
let primary_key_value: Punctuated<_, Comma> =
variants.iter().fold(Punctuated::new(), |mut acc, v| {
let variant = &v.ident;
acc.push(
quote! { active_model.take(#ident::#variant.into_column()).unwrap().unwrap() },
);
acc
});
let mut primary_key_value = primary_key_value.to_token_stream();
if variants.len() > 1 {
primary_key_value = quote! {
(#primary_key_value)
};
}
Ok(quote!( Ok(quote!(
impl sea_orm::Iden for #ident { impl sea_orm::Iden for #ident {
fn unquoted(&self, s: &mut dyn std::fmt::Write) { fn unquoted(&self, s: &mut dyn std::fmt::Write) {
@ -76,16 +61,5 @@ pub fn expand_derive_primary_key(ident: Ident, data: Data) -> syn::Result<TokenS
} }
} }
} }
impl PrimaryKeyValue<Entity> for #ident {
fn get_primary_key_value<A>(
mut active_model: A,
) -> <<Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType
where
A: ActiveModelTrait<Entity = Entity>,
{
#primary_key_value
}
}
)) ))
} }

View File

@ -2,6 +2,7 @@ use crate::{
error::*, DatabaseConnection, DeleteResult, EntityTrait, Iterable, PrimaryKeyToColumn, Value, error::*, DatabaseConnection, DeleteResult, EntityTrait, Iterable, PrimaryKeyToColumn, Value,
}; };
use async_trait::async_trait; use async_trait::async_trait;
use sea_query::ValueTuple;
use std::fmt::Debug; use std::fmt::Debug;
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
@ -9,7 +10,8 @@ pub struct ActiveValue<V>
where where
V: Into<Value>, V: Into<Value>,
{ {
value: Option<V>, // Don't want to call ActiveValue::unwrap() and cause panic
pub(self) value: Option<V>,
state: ActiveValueState, state: ActiveValueState,
} }
@ -66,6 +68,41 @@ pub trait ActiveModelTrait: Clone + Debug {
fn default() -> Self; fn default() -> Self;
fn get_primary_key_value(&self) -> Option<ValueTuple> {
let mut cols = <Self::Entity as EntityTrait>::PrimaryKey::iter();
macro_rules! next {
() => {
if let Some(col) = cols.next() {
if let Some(val) = self.get(col.into_column()).value {
val
} else {
return None;
}
} else {
return None;
}
};
}
match <Self::Entity as EntityTrait>::PrimaryKey::iter().count() {
1 => {
let s1 = next!();
Some(ValueTuple::One(s1))
}
2 => {
let s1 = next!();
let s2 = next!();
Some(ValueTuple::Two(s1, s2))
}
3 => {
let s1 = next!();
let s2 = next!();
let s3 = next!();
Some(ValueTuple::Three(s1, s2, s3))
}
_ => panic!("The arity cannot be larger than 3"),
}
}
async fn insert(self, db: &DatabaseConnection) -> Result<Self, DbErr> async fn insert(self, db: &DatabaseConnection) -> Result<Self, DbErr>
where where
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>, <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
ActiveModelTrait, ColumnTrait, Delete, DeleteMany, DeleteOne, FromQueryResult, Insert, ActiveModelTrait, ColumnTrait, Delete, DeleteMany, DeleteOne, FromQueryResult, Insert,
ModelTrait, PrimaryKeyToColumn, PrimaryKeyTrait, PrimaryKeyValue, QueryFilter, Related, ModelTrait, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, Related, RelationBuilder,
RelationBuilder, RelationTrait, RelationType, Select, Update, UpdateMany, UpdateOne, RelationTrait, RelationType, Select, Update, UpdateMany, UpdateOne,
}; };
use sea_query::{Alias, Iden, IntoIden, IntoTableRef, IntoValueTuple, TableRef}; use sea_query::{Alias, Iden, IntoIden, IntoTableRef, IntoValueTuple, TableRef};
pub use sea_strum::IntoEnumIterator as Iterable; pub use sea_strum::IntoEnumIterator as Iterable;
@ -49,9 +49,7 @@ pub trait EntityTrait: EntityName {
type Relation: RelationTrait; type Relation: RelationTrait;
type PrimaryKey: PrimaryKeyTrait type PrimaryKey: PrimaryKeyTrait + PrimaryKeyToColumn<Column = Self::Column>;
+ PrimaryKeyToColumn<Column = Self::Column>
+ PrimaryKeyValue<Self>;
fn belongs_to<R>(related: R) -> RelationBuilder<Self, R> fn belongs_to<R>(related: R) -> RelationBuilder<Self, R>
where where

View File

@ -1,8 +1,8 @@
pub use crate::{ pub use crate::{
error::*, ActiveModelBehavior, ActiveModelTrait, ColumnDef, ColumnTrait, ColumnType, error::*, ActiveModelBehavior, ActiveModelTrait, ColumnDef, ColumnTrait, ColumnType,
EntityName, EntityTrait, EnumIter, ForeignKeyAction, Iden, IdenStatic, Linked, ModelTrait, EntityName, EntityTrait, EnumIter, ForeignKeyAction, Iden, IdenStatic, Linked, ModelTrait,
PrimaryKeyToColumn, PrimaryKeyTrait, PrimaryKeyValue, QueryFilter, QueryResult, Related, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef,
RelationDef, RelationTrait, Select, Value, RelationTrait, Select, Value,
}; };
#[cfg(feature = "macros")] #[cfg(feature = "macros")]

View File

@ -1,11 +1,18 @@
use super::{ColumnTrait, IdenStatic, Iterable}; use super::{ColumnTrait, IdenStatic, Iterable};
use crate::{ActiveModelTrait, EntityTrait, TryFromU64, TryGetableMany}; use crate::{TryFromU64, TryGetableMany};
use sea_query::IntoValueTuple; use sea_query::{FromValueTuple, IntoValueTuple};
use std::fmt::Debug; use std::fmt::Debug;
//LINT: composite primary key cannot auto increment //LINT: composite primary key cannot auto increment
pub trait PrimaryKeyTrait: IdenStatic + Iterable { pub trait PrimaryKeyTrait: IdenStatic + Iterable {
type ValueType: Sized + Send + Debug + PartialEq + IntoValueTuple + TryGetableMany + TryFromU64; type ValueType: Sized
+ Send
+ Debug
+ PartialEq
+ IntoValueTuple
+ FromValueTuple
+ TryGetableMany
+ TryFromU64;
fn auto_increment() -> bool; fn auto_increment() -> bool;
} }
@ -19,12 +26,3 @@ pub trait PrimaryKeyToColumn {
where where
Self: Sized; Self: Sized;
} }
pub trait PrimaryKeyValue<E>
where
E: EntityTrait,
{
fn get_primary_key_value<A>(active_model: A) -> <E::PrimaryKey as PrimaryKeyTrait>::ValueType
where
A: ActiveModelTrait<Entity = E>;
}

View File

@ -2,7 +2,7 @@ use crate::{
error::*, ActiveModelTrait, DatabaseConnection, DbBackend, EntityTrait, Insert, error::*, ActiveModelTrait, DatabaseConnection, DbBackend, EntityTrait, Insert,
PrimaryKeyTrait, Statement, TryFromU64, PrimaryKeyTrait, Statement, TryFromU64,
}; };
use sea_query::InsertStatement; use sea_query::{FromValueTuple, InsertStatement, ValueTuple};
use std::{future::Future, marker::PhantomData}; use std::{future::Future, marker::PhantomData};
#[derive(Debug)] #[derive(Debug)]
@ -10,7 +10,7 @@ pub struct Inserter<A>
where where
A: ActiveModelTrait, A: ActiveModelTrait,
{ {
primary_key: Option<<<<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType>, primary_key: Option<ValueTuple>,
query: InsertStatement, query: InsertStatement,
model: PhantomData<A>, model: PhantomData<A>,
} }
@ -35,7 +35,6 @@ where
where where
A: 'a, A: 'a,
{ {
// TODO: extract primary key's value from query
// so that self is dropped before entering await // so that self is dropped before entering await
let mut query = self.query; let mut query = self.query;
if db.get_database_backend() == DbBackend::Postgres { if db.get_database_backend() == DbBackend::Postgres {
@ -49,7 +48,6 @@ where
} }
} }
Inserter::<A>::new(self.primary_key, query).exec(db) Inserter::<A>::new(self.primary_key, query).exec(db)
// TODO: return primary key if extracted before, otherwise use InsertResult
} }
} }
@ -57,10 +55,7 @@ impl<A> Inserter<A>
where where
A: ActiveModelTrait, A: ActiveModelTrait,
{ {
pub fn new( pub fn new(primary_key: Option<ValueTuple>, query: InsertStatement) -> Self {
primary_key: Option<<<<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType>,
query: InsertStatement,
) -> Self {
Self { Self {
primary_key, primary_key,
query, query,
@ -82,7 +77,7 @@ where
// Only Statement impl Send // Only Statement impl Send
async fn exec_insert<A>( async fn exec_insert<A>(
primary_key: Option<<<<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType>, primary_key: Option<ValueTuple>,
statement: Statement, statement: Statement,
db: &DatabaseConnection, db: &DatabaseConnection,
) -> Result<InsertResult<A>, DbErr> ) -> Result<InsertResult<A>, DbErr>
@ -108,7 +103,7 @@ where
let last_insert_id = match last_insert_id_opt { let last_insert_id = match last_insert_id_opt {
Some(last_insert_id) => last_insert_id, Some(last_insert_id) => last_insert_id,
None => match primary_key { None => match primary_key {
Some(primary_key) => primary_key, Some(value_tuple) => FromValueTuple::from_value_tuple(value_tuple),
None => return Err(DbErr::Exec("Fail to unpack last_insert_id".to_owned())), None => return Err(DbErr::Exec("Fail to unpack last_insert_id".to_owned())),
}, },
}; };

View File

@ -1,9 +1,9 @@
use crate::{ use crate::{
ActiveModelTrait, EntityName, EntityTrait, IntoActiveModel, Iterable, PrimaryKeyTrait, ActiveModelTrait, EntityName, EntityTrait, IntoActiveModel, Iterable, PrimaryKeyTrait,
PrimaryKeyValue, QueryTrait, QueryTrait,
}; };
use core::marker::PhantomData; use core::marker::PhantomData;
use sea_query::InsertStatement; use sea_query::{InsertStatement, ValueTuple};
#[derive(Debug)] #[derive(Debug)]
pub struct Insert<A> pub struct Insert<A>
@ -12,7 +12,7 @@ where
{ {
pub(crate) query: InsertStatement, pub(crate) query: InsertStatement,
pub(crate) columns: Vec<bool>, pub(crate) columns: Vec<bool>,
pub(crate) primary_key: Option<<<<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType>, pub(crate) primary_key: Option<ValueTuple>,
pub(crate) model: PhantomData<A>, pub(crate) model: PhantomData<A>,
} }
@ -114,7 +114,7 @@ where
let mut am: A = m.into_active_model(); let mut am: A = m.into_active_model();
self.primary_key = self.primary_key =
if !<<A::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::auto_increment() { if !<<A::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::auto_increment() {
Some(<<A::Entity as EntityTrait>::PrimaryKey as PrimaryKeyValue<A::Entity>>::get_primary_key_value::<A>(am.clone())) am.get_primary_key_value()
} else { } else {
None None
}; };