From d3ee74cbe52e81516b9d0698d30acaac1ad91001 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Fri, 28 May 2021 00:33:04 +0800 Subject: [PATCH] Insert POC --- sea-orm-macros/src/derives/active_model.rs | 12 ++- src/entity/active_model.rs | 15 ++- src/entity/base.rs | 6 +- src/entity/column.rs | 4 +- src/entity/primary_key.rs | 4 +- src/entity/relation.rs | 4 +- src/lib.rs | 2 + src/operation/insert.rs | 120 +++++++++++++++++++++ src/operation/mod.rs | 3 + src/query/mod.rs | 2 +- 10 files changed, 153 insertions(+), 19 deletions(-) create mode 100644 src/operation/insert.rs create mode 100644 src/operation/mod.rs diff --git a/sea-orm-macros/src/derives/active_model.rs b/sea-orm-macros/src/derives/active_model.rs index 25f7d4f7..374270aa 100644 --- a/sea-orm-macros/src/derives/active_model.rs +++ b/sea-orm-macros/src/derives/active_model.rs @@ -36,11 +36,7 @@ pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result),* } - impl sea_orm::ActiveModelOf<#ident> for ActiveModel { - fn from_model(m: #ident) -> Self { - Self::from(m) - } - } + impl sea_orm::ActiveModelOf for ActiveModel {} impl From<#ident> for ActiveModel { fn from(m: #ident) -> Self { @@ -53,6 +49,12 @@ pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result sea_orm::Action { + match c { + #(Self::Column::#name => std::mem::take(&mut self.#field).into_action_value()),* + } + } + fn get(&self, c: Self::Column) -> sea_orm::Action { match c { #(Self::Column::#name => self.#field.clone().into_action_value()),* diff --git a/src/entity/active_model.rs b/src/entity/active_model.rs index 369a185a..c0e87bf8 100644 --- a/src/entity/active_model.rs +++ b/src/entity/active_model.rs @@ -1,4 +1,4 @@ -use crate::{ColumnTrait, ModelTrait, Value}; +use crate::{ColumnTrait, EntityTrait, Value}; use std::fmt::Debug; #[derive(Clone, Debug)] @@ -7,6 +7,12 @@ pub enum Action { Unset, } +impl Default for Action { + fn default() -> Self { + Self::Unset + } +} + impl Action where V: Into, @@ -19,16 +25,17 @@ where } } -pub trait ActiveModelOf +pub trait ActiveModelOf where - M: ModelTrait, + E: EntityTrait, { - fn from_model(m: M) -> Self; } pub trait ActiveModelTrait: Clone + Debug { type Column: ColumnTrait; + fn take(&mut self, c: Self::Column) -> Action; + fn get(&self, c: Self::Column) -> Action; fn set(&mut self, c: Self::Column, v: Value); diff --git a/src/entity/base.rs b/src/entity/base.rs index 4283a27f..b0058194 100644 --- a/src/entity/base.rs +++ b/src/entity/base.rs @@ -15,11 +15,11 @@ pub trait EntityName: IdenStatic + Default {} pub trait EntityTrait: EntityName { type Model: ModelTrait; - type Column: ColumnTrait + Iterable; + type Column: ColumnTrait; - type Relation: RelationTrait + Iterable; + type Relation: RelationTrait; - type PrimaryKey: PrimaryKeyTrait + Iterable; + type PrimaryKey: PrimaryKeyTrait; fn has_one(entity: R) -> RelationBuilder where diff --git a/src/entity/column.rs b/src/entity/column.rs index b1e8a679..b680565f 100644 --- a/src/entity/column.rs +++ b/src/entity/column.rs @@ -1,4 +1,4 @@ -use crate::{EntityName, IdenStatic}; +use crate::{EntityName, IdenStatic, Iterable}; pub use sea_query::ColumnType; use sea_query::{Expr, Iden, SimpleExpr, Value}; @@ -36,7 +36,7 @@ macro_rules! bind_vec_func { }; } -pub trait ColumnTrait: IdenStatic { +pub trait ColumnTrait: IdenStatic + Iterable { type EntityName: EntityName; fn def(&self) -> ColumnType; diff --git a/src/entity/primary_key.rs b/src/entity/primary_key.rs index fc9641e5..30f2ed0b 100644 --- a/src/entity/primary_key.rs +++ b/src/entity/primary_key.rs @@ -1,6 +1,6 @@ -use super::{IdenStatic, ModelTrait}; +use super::{IdenStatic, Iterable, ModelTrait}; -pub trait PrimaryKeyTrait: IdenStatic {} +pub trait PrimaryKeyTrait: IdenStatic + Iterable {} pub trait PrimaryKeyOfModel where diff --git a/src/entity/relation.rs b/src/entity/relation.rs index 1626f2cc..6cee53a3 100644 --- a/src/entity/relation.rs +++ b/src/entity/relation.rs @@ -1,4 +1,4 @@ -use crate::{EntityTrait, Identity, IntoIdentity, QueryHelper, Select}; +use crate::{EntityTrait, Identity, IntoIdentity, Iterable, QueryHelper, Select}; use core::marker::PhantomData; use sea_query::{Iden, IntoIden, JoinType}; use std::fmt::Debug; @@ -10,7 +10,7 @@ pub enum RelationType { HasMany, } -pub trait RelationTrait: Debug + 'static { +pub trait RelationTrait: Iterable + Debug + 'static { fn def(&self) -> RelationDef; } diff --git a/src/lib.rs b/src/lib.rs index b44ee556..c11817bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ mod connector; mod database; mod driver; pub mod entity; +mod operation; mod query; pub mod tests_cfg; mod util; @@ -10,6 +11,7 @@ pub use connector::*; pub use database::*; pub use driver::*; pub use entity::*; +pub use operation::*; pub use query::*; pub use sea_orm_macros::{ diff --git a/src/operation/insert.rs b/src/operation/insert.rs new file mode 100644 index 00000000..7adf40d9 --- /dev/null +++ b/src/operation/insert.rs @@ -0,0 +1,120 @@ +use crate::{Action, ActiveModelOf, ActiveModelTrait, EntityTrait, Iterable, Statement}; +use core::marker::PhantomData; +use sea_query::{InsertStatement, IntoIden, QueryBuilder}; + +#[derive(Clone, Debug)] +pub struct Insert +where + A: ActiveModelTrait, +{ + pub(crate) query: InsertStatement, + pub(crate) model: PhantomData, +} + +impl Insert +where + A: ActiveModelTrait, +{ + pub fn new() -> Self + where + E: EntityTrait, + A: ActiveModelOf, + { + Self { + query: InsertStatement::new() + .into_table(E::default().into_iden()) + .to_owned(), + model: PhantomData, + } + } + + pub fn one(mut self, m: M) -> Self + where + M: Into, + { + let mut am: A = m.into(); + let mut columns = Vec::new(); + let mut values = Vec::new(); + for col in A::Column::iter() { + if let Action::Set(val) = am.take(col) { + columns.push(col); + values.push(val); + } + } + self.query.columns(columns); + self.query.values_panic(values); + self + } + + /// Get a mutable ref to the query builder + pub fn query(&mut self) -> &mut InsertStatement { + &mut self.query + } + + /// Get an immutable ref to the query builder + pub fn as_query(&self) -> &InsertStatement { + &self.query + } + + /// Take ownership of the query builder + pub fn into_query(self) -> InsertStatement { + self.query + } + + /// Build the query as [`Statement`] + pub fn build(&self, builder: B) -> Statement + where + B: QueryBuilder, + { + self.as_query().build(builder).into() + } +} + +#[cfg(test)] +mod tests { + use crate::tests_cfg::cake; + use crate::{Action, Insert}; + use sea_query::PostgresQueryBuilder; + + #[test] + fn insert_1() { + assert_eq!( + Insert::::new() + .one(cake::ActiveModel { + id: Action::Unset, + name: Action::Set("Apple Pie".to_owned()), + }) + .build(PostgresQueryBuilder) + .to_string(), + r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie')"#, + ); + } + + #[test] + fn insert_2() { + assert_eq!( + Insert::::new() + .one(cake::ActiveModel { + id: Action::Set(1), + name: Action::Set("Apple Pie".to_owned()), + }) + .build(PostgresQueryBuilder) + .to_string(), + r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#, + ); + } + + #[test] + fn insert_3() { + assert_eq!( + Insert::::new() + .one(cake::Model { + id: 1, + name: "Apple Pie".to_owned(), + }) + .build(PostgresQueryBuilder) + .to_string(), + r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#, + ); + } +} diff --git a/src/operation/mod.rs b/src/operation/mod.rs new file mode 100644 index 00000000..1871a479 --- /dev/null +++ b/src/operation/mod.rs @@ -0,0 +1,3 @@ +mod insert; + +pub use insert::*; diff --git a/src/query/mod.rs b/src/query/mod.rs index c894f4bf..ec033948 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -6,7 +6,7 @@ mod json; mod result; mod select; -pub use combine::*; +// pub use combine::*; pub use helper::*; pub use join::*; #[cfg(feature = "with-json")]