Update Statement

This commit is contained in:
Chris Tsang 2021-06-02 23:46:08 +08:00
parent 2169d1284f
commit f706eb261d
8 changed files with 157 additions and 12 deletions

View File

@ -50,7 +50,14 @@ pub fn expand_derive_primary_key(ident: Ident, data: Data) -> syn::Result<TokenS
impl sea_orm::PrimaryKeyToColumn<Entity> for #ident {
fn into_column(self) -> <Entity as EntityTrait>::Column {
match self {
#(Self::#variant => Column::#variant),*
#(Self::#variant => Column::#variant,)*
}
}
fn from_column(col: <Entity as EntityTrait>::Column) -> Option<Self> {
match col {
#(Column::#variant => Some(Self::#variant),)*
_ => None,
}
}
}

View File

@ -78,6 +78,10 @@ where
}
}
pub fn is_unchanged(&self) -> bool {
matches!(self.state, ActiveValueState::Unchanged)
}
pub fn unset() -> Self {
Self {
value: V::default(),

View File

@ -1,7 +1,7 @@
use crate::{
ActiveModelTrait, ColumnTrait, FromQueryResult, Insert, ModelTrait,
OneOrManyActiveModel, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, RelationBuilder,
RelationTrait, RelationType, Select,
ActiveModelTrait, ColumnTrait, FromQueryResult, Insert, ModelTrait, OneOrManyActiveModel,
PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, RelationBuilder, RelationTrait, RelationType,
Select,
};
use sea_query::{Iden, IntoValueTuple};
use std::fmt::Debug;

View File

@ -1,6 +1,6 @@
pub use crate::{
ActiveModelTrait, ColumnTrait, ColumnType, DeriveActiveModel, DeriveColumn,
DeriveEntity, DeriveModel, DerivePrimaryKey, EntityName, EntityTrait, EnumIter, Iden,
IdenStatic, ModelTrait, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, QueryResult, Related,
RelationDef, RelationTrait, Select, TypeErr, Value,
ActiveModelTrait, ColumnTrait, ColumnType, DeriveActiveModel, DeriveColumn, DeriveEntity,
DeriveModel, DerivePrimaryKey, EntityName, EntityTrait, EnumIter, Iden, IdenStatic, ModelTrait,
PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef,
RelationTrait, Select, TypeErr, Value,
};

View File

@ -7,4 +7,6 @@ where
E: EntityTrait,
{
fn into_column(self) -> E::Column;
fn from_column(col: E::Column) -> Option<Self> where Self: std::marker::Sized;
}

View File

@ -14,7 +14,7 @@ where
impl<A> Default for Insert<A>
where
A: ActiveModelTrait
A: ActiveModelTrait,
{
fn default() -> Self {
Self::new()
@ -50,7 +50,7 @@ where
} else if self.columns[idx] != av.is_set() {
panic!("columns mismatch");
}
if !av.is_unset() {
if av.is_set() {
columns.push(col);
values.push(av.into_value());
}

View File

@ -7,7 +7,7 @@ mod json;
mod result;
mod select;
mod traits;
// mod update;
mod update;
// pub use combine::*;
pub use helper::*;
@ -18,4 +18,4 @@ pub use json::*;
pub use result::*;
pub use select::*;
pub use traits::*;
// pub use update::*;
pub use update::*;

132
src/query/update.rs Normal file
View File

@ -0,0 +1,132 @@
use crate::{
ActiveModelTrait, ColumnTrait, EntityTrait, Iterable, PrimaryKeyToColumn, QueryFilter,
QueryTrait,
};
use sea_query::{IntoIden, UpdateStatement};
#[derive(Clone, Debug)]
pub struct Update<A>
where
A: ActiveModelTrait,
{
pub(crate) query: UpdateStatement,
pub(crate) model: A,
}
impl<A> Update<A>
where
A: ActiveModelTrait,
{
pub fn new<M>(model: M) -> Self
where
M: Into<A>,
{
let myself = Self {
query: UpdateStatement::new()
.table(A::Entity::default().into_iden())
.to_owned(),
model: model.into(),
};
myself.prepare()
}
pub(crate) fn prepare(mut self) -> Self {
for key in <A::Entity as EntityTrait>::PrimaryKey::iter() {
let col = key.into_column();
let av = self.model.get(col);
if av.is_set() || av.is_unchanged() {
self = self.filter(col.eq(av.unwrap()));
} else {
panic!("PrimaryKey is not set");
}
}
for col in <A::Entity as EntityTrait>::Column::iter() {
if <A::Entity as EntityTrait>::PrimaryKey::from_column(col).is_some() {
continue;
}
let av = self.model.get(col);
if av.is_set() {
self.query.value(col, av.unwrap());
}
}
self
}
}
impl<A> QueryFilter for Update<A>
where
A: ActiveModelTrait,
{
type QueryStatement = UpdateStatement;
fn query(&mut self) -> &mut UpdateStatement {
&mut self.query
}
}
impl<A> QueryTrait for Update<A>
where
A: ActiveModelTrait,
{
type QueryStatement = UpdateStatement;
fn query(&mut self) -> &mut UpdateStatement {
&mut self.query
}
fn as_query(&self) -> &UpdateStatement {
&self.query
}
fn into_query(self) -> UpdateStatement {
self.query
}
}
#[cfg(test)]
mod tests {
use crate::tests_cfg::{cake, fruit};
use crate::{Update, QueryTrait, Val};
use sea_query::PostgresQueryBuilder;
#[test]
fn update_1() {
assert_eq!(
Update::<cake::ActiveModel>::new(cake::ActiveModel {
id: Val::set(1),
name: Val::set("Apple Pie".to_owned()),
})
.build(PostgresQueryBuilder)
.to_string(),
r#"UPDATE "cake" SET "name" = 'Apple Pie' WHERE "cake"."id" = 1"#,
);
}
#[test]
fn update_2() {
assert_eq!(
Update::<fruit::ActiveModel>::new(fruit::ActiveModel {
id: Val::set(1),
name: Val::set("Orange".to_owned()),
cake_id: Val::unset(),
})
.build(PostgresQueryBuilder)
.to_string(),
r#"UPDATE "fruit" SET "name" = 'Orange' WHERE "fruit"."id" = 1"#,
);
}
#[test]
fn update_3() {
assert_eq!(
Update::<fruit::ActiveModel>::new(fruit::ActiveModel {
id: Val::set(2),
name: Val::unset(),
cake_id: Val::set(Some(3)),
})
.build(PostgresQueryBuilder)
.to_string(),
r#"UPDATE "fruit" SET "cake_id" = 3 WHERE "fruit"."id" = 2"#,
);
}
}