Skip to content

Commit

Permalink
FEAT: impl Increment
Browse files Browse the repository at this point in the history
  • Loading branch information
wuyuedefeng committed Sep 4, 2023
1 parent 375fbe9 commit 18f3ed9
Show file tree
Hide file tree
Showing 12 changed files with 321 additions and 38 deletions.
42 changes: 34 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ active_user.name.set("n-1");
let ret = active_user.save().await?;
println!("{}", ret.rows_affected());

// delete
// destroy
let ret = active_user.destroy().await?;
println!("{}", ret.rows_affected());
```
Expand Down Expand Up @@ -144,23 +144,49 @@ let sql = User::query().paginate(1, 10).to_sql();

</details>

---

### Insert

<details>
<summary>transaction</summary>

```rust
User::with_transaction(|tx| {
Box::pin(async move {
for entry in 1i32..=100 {
sqlx::query("INSERT INTO user (name) VALUES ($1)")
.bind(format!("name-{}", entry))
.bind("Admin")
.execute(tx.as_mut())
.await?;
}
// for entry in 1i32..=100 {
// sqlx::query("INSERT INTO user (name) VALUES ($1)")
// .bind(format!("name-{}", entry))
// .bind("Admin")
// .execute(tx.as_mut())
// .await?;
// }
let mut active_user = ArelActiveUser {
name: Set("n1"),
r#type: Set("ADMIN"),
..Default::default()
};
active_user.save_exec(tx.as_mut()).await?;
Ok(None)
})
})
.await?;
```

</details>

### Update

<details>
<summary>increment</summary>

```rust
let user: User = User::query().r#where("id", 1).fetch_one_as().await?;
let mut active_user: ArelActiveUser = user.into();
active_user.increment("lock_version", 5, |active_model, step| {
let value = active_model.lock_version.try_get_i32().unwrap_or(0) + step;
active_model.lock_version.set_unchanged(value);
}).await?;
```

</details>
156 changes: 128 additions & 28 deletions arel-macros/src/arel/arel_active_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub(crate) fn create_arel_active_model(input: &crate::ItemInput) -> syn::Result<
let impl_trait_to_destroy_sql = impl_trait_to_destroy_sql(input)?;
let impl_trait_save_exec = impl_trait_save_exec(input)?;
let impl_trait_destroy_exec = impl_trait_destroy_exec(input)?;
let impl_trait_increment_exec = impl_trait_increment_exec(input)?;

let vis = input.vis()?;
ret_token_stream.extend(quote::quote!(
Expand All @@ -58,6 +59,7 @@ pub(crate) fn create_arel_active_model(input: &crate::ItemInput) -> syn::Result<
self.__persisted__
}
}

#impl_from_model
#impl_from_arel_model

Expand All @@ -73,9 +75,13 @@ pub(crate) fn create_arel_active_model(input: &crate::ItemInput) -> syn::Result<
self.save_exec(Self::Model::pool()?).await
}
#impl_trait_destroy_exec
async fn destroy(&mut self) -> anyhow::Result<arel::DatabaseQueryResult> {
async fn destroy(&mut self) -> arel::anyhow::Result<arel::DatabaseQueryResult> {
self.destroy_exec(Self::Model::pool()?).await
}
#impl_trait_increment_exec
async fn increment<K: ToString + Send, F: Send>(&mut self, key: K, step: i32, update_self_cb: F) -> arel::anyhow::Result<arel::DatabaseQueryResult> where F: FnOnce(&mut Self, i32) -> () {
self.increment_exec(key, step, update_self_cb, Self::Model::pool()?).await
}
}
));

Expand All @@ -84,7 +90,6 @@ pub(crate) fn create_arel_active_model(input: &crate::ItemInput) -> syn::Result<

fn impl_from_model(input: &crate::ItemInput) -> syn::Result<proc_macro2::TokenStream> {
let struct_ident = input.ident()?;
let model_name_ident = struct_ident;
let fields = input.struct_fields()?;
let generics = input.generics()?;
let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
Expand All @@ -106,8 +111,8 @@ fn impl_from_model(input: &crate::ItemInput) -> syn::Result<proc_macro2::TokenSt

let mut ret_token_stream = proc_macro2::TokenStream::new();
ret_token_stream.extend(quote::quote!(
impl #impl_generics From<#model_name_ident #type_generics> for ArelActiveUser #type_generics #where_clause {
fn from(value: #model_name_ident #type_generics) -> ArelActiveUser #type_generics {
impl #impl_generics From<#struct_ident #type_generics> for ArelActiveUser #type_generics #where_clause {
fn from(value: #struct_ident #type_generics) -> ArelActiveUser #type_generics {
let mut arel_active_model = Self::default();
#(#init_clauses)*
arel_active_model
Expand Down Expand Up @@ -165,8 +170,7 @@ fn impl_from_arel_model(input: &crate::ItemInput) -> syn::Result<proc_macro2::To
}

fn impl_trait_to_insert_sql(input: &crate::ItemInput) -> syn::Result<proc_macro2::TokenStream> {
let struct_ident = input.ident()?;
let model_ident = struct_ident;
// let struct_ident = input.ident()?;
let fields = input.struct_fields()?;

let mut insert_fields_init_clause = proc_macro2::TokenStream::new();
Expand Down Expand Up @@ -200,26 +204,26 @@ fn impl_trait_to_insert_sql(input: &crate::ItemInput) -> syn::Result<proc_macro2
Ok(quote::quote!(
fn to_insert_sql(&self) -> arel::anyhow::Result<arel::Sql> {
let primary_keys = {
if let Some(keys) = #model_ident::primary_keys() {
if let Some(keys) = Self::Model::primary_keys() {
keys
} else if let Some(key) = #model_ident::primary_key() {
} else if let Some(key) = Self::Model::primary_key() {
vec![key]
} else {
vec![]
}
};
if primary_keys.len() == 0 {
return Err(anyhow::anyhow!("primary key/keys MUST SET"));
return Err(arel::anyhow::anyhow!("primary key/keys MUST SET"));
}

let table_name = #model_ident::table_name();
let table_name = Self::Model::table_name();
let mut final_sql = arel::Sql::new("");

let mut insert_fields: Vec<&'static str> = vec![];
let mut insert_values: Vec<arel::Value> = vec![];
#insert_fields_init_clause

if let Some(sql) = arel::statements::insert::Insert::<#model_ident>::new(insert_fields, insert_values).to_sql() {
if let Some(sql) = arel::statements::insert::Insert::<Self::Model>::new(insert_fields, insert_values).to_sql() {
final_sql = sql;
}
Ok(final_sql)
Expand All @@ -228,8 +232,7 @@ fn impl_trait_to_insert_sql(input: &crate::ItemInput) -> syn::Result<proc_macro2
}

fn impl_trait_to_update_sql(input: &crate::ItemInput) -> syn::Result<proc_macro2::TokenStream> {
let struct_ident = input.ident()?;
let model_ident = struct_ident;
// let struct_ident = input.ident()?;
let fields = input.struct_fields()?;

let mut update_fields_init_clause = proc_macro2::TokenStream::new();
Expand Down Expand Up @@ -279,19 +282,19 @@ fn impl_trait_to_update_sql(input: &crate::ItemInput) -> syn::Result<proc_macro2
Ok(quote::quote!(
fn to_update_sql(&self) -> arel::anyhow::Result<arel::Sql> {
let primary_keys = {
if let Some(keys) = #model_ident::primary_keys() {
if let Some(keys) = Self::Model::primary_keys() {
keys
} else if let Some(key) = #model_ident::primary_key() {
} else if let Some(key) = Self::Model::primary_key() {
vec![key]
} else {
vec![]
}
};
if primary_keys.len() == 0 {
return Err(anyhow::anyhow!("primary key/keys MUST SET"));
return Err(arel::anyhow::anyhow!("primary key/keys MUST SET"));
}

let table_name = #model_ident::table_name();
let table_name = Self::Model::table_name();
let mut final_sql = arel::Sql::new("");

let mut update_fields: Vec<&'static str> = vec![];
Expand All @@ -301,9 +304,9 @@ fn impl_trait_to_update_sql(input: &crate::ItemInput) -> syn::Result<proc_macro2
#update_fields_init_clause

if update_where_fields.len() == 0 {
return Err(anyhow::anyhow!("Update where statement is blank!"));
return Err(arel::anyhow::anyhow!("Update where statement is blank!"));
}
if let Some(sql) = arel::statements::update::Update::<#model_ident>::new(update_fields, update_values, update_where_fields, update_where_values).to_sql() {
if let Some(sql) = arel::statements::update::Update::<Self::Model>::new(update_fields, update_values, update_where_fields, update_where_values).to_sql() {
final_sql = sql;
}

Expand All @@ -313,8 +316,7 @@ fn impl_trait_to_update_sql(input: &crate::ItemInput) -> syn::Result<proc_macro2
}

fn impl_trait_to_destroy_sql(input: &crate::ItemInput) -> syn::Result<proc_macro2::TokenStream> {
let struct_ident = input.ident()?;
let model_ident = struct_ident;
// let struct_ident = input.ident()?;
let fields = input.struct_fields()?;

let mut delete_fields_init_clause = proc_macro2::TokenStream::new();
Expand Down Expand Up @@ -362,33 +364,33 @@ fn impl_trait_to_destroy_sql(input: &crate::ItemInput) -> syn::Result<proc_macro
Ok(quote::quote!(
fn to_destroy_sql(&self) -> arel::anyhow::Result<arel::Sql> {
let primary_keys = {
if let Some(keys) = #model_ident::primary_keys() {
if let Some(keys) = Self::Model::primary_keys() {
keys
} else if let Some(key) = #model_ident::primary_key() {
} else if let Some(key) = Self::Model::primary_key() {
vec![key]
} else {
vec![]
}
};
if primary_keys.len() == 0 {
return Err(anyhow::anyhow!("Primary key/keys MUST SET"));
return Err(arel::anyhow::anyhow!("Primary key/keys MUST SET"));
}

let table_name = #model_ident::table_name();
let table_name = Self::Model::table_name();
let mut final_sql = arel::Sql::new("");
if self.__persisted__ {
let mut delete_where_fields: Vec<&'static str> = vec![];
let mut delete_where_values: Vec<arel::Value> = vec![];
#delete_fields_init_clause

if delete_where_fields.len() == 0 {
return Err(anyhow::anyhow!("Update where statement is blank!"));
return Err(arel::anyhow::anyhow!("Update where statement is blank!"));
}
if let Some(sql) = arel::statements::delete::Delete::<#model_ident>::new(delete_where_fields, delete_where_values).to_sql() {
if let Some(sql) = arel::statements::delete::Delete::<Self::Model>::new(delete_where_fields, delete_where_values).to_sql() {
final_sql = sql;
}
} else {
return Err(anyhow::anyhow!("Model is Not Persisted"));
return Err(arel::anyhow::anyhow!("Model is Not Persisted"));
}
Ok(final_sql)
}
Expand Down Expand Up @@ -463,3 +465,101 @@ fn impl_trait_destroy_exec(input: &crate::ItemInput) -> syn::Result<proc_macro2:
}
))
}

fn impl_trait_increment_exec(input: &crate::ItemInput) -> syn::Result<proc_macro2::TokenStream> {
// let struct_ident = input.ident()?;
let fields = input.struct_fields()?;

let mut update_fields_init_clause = proc_macro2::TokenStream::new();
for field in fields.iter() {
let ident = &field.ident;
// let r#type = &field.ty;
let field_name = {
if let Some((rename, _)) = crate::ItemInput::get_field_path_value(field, vec!["arel"], "rename", None)? {
rename
} else {
match ident {
Some(ident) => ident.to_string().trim_start_matches("r#").to_string(),
_ => return Err(syn::Error::new_spanned(field, "Field name can not Blank!")),
}
}
};
update_fields_init_clause.extend(quote::quote!(
let field_name = #field_name;
match &self.#ident {
arel::ActiveValue::Changed(nv, ov) => {
if primary_keys.contains(&field_name.into()) {
match ov.as_ref() {
arel::ActiveValue::Unchanged(v) => {
update_where_fields.push(field_name);
update_where_values.push(v.into());
},
_ => ()
}

}
},
arel::ActiveValue::Unchanged(v) => {
if primary_keys.contains(&field_name.into()) {
update_where_fields.push(field_name);
update_where_values.push(v.into());
}
}
_ => ()
}
));
}

Ok(quote::quote!(
async fn increment_exec<'a, K: ToString + Send, F: Send, E>(&mut self, key: K, step: i32, update_self_cb: F, executor: E) -> arel::anyhow::Result<arel::DatabaseQueryResult>
where
F: FnOnce(&mut Self, i32) -> (),
E: arel::sqlx::Executor<'a, Database = arel::Database>,
{
let key = key.to_string();
let primary_keys = {
if let Some(keys) = Self::Model::primary_keys() {
keys
} else if let Some(key) = Self::Model::primary_key() {
vec![key]
} else {
vec![]
}
};
if primary_keys.len() == 0 {
return Err(arel::anyhow::anyhow!("primary key/keys MUST SET"));
}
let column_name = {
if let Some(column_name) = Self::Model::table_column_name(&key) {
column_name.to_string()
} else {
return Err(arel::anyhow::anyhow!("Key: {}, Column name Can not found!", key));
}
};


let mut update_where_fields: Vec<&'static str> = vec![];
let mut update_where_values: Vec<arel::Value> = vec![];
#update_fields_init_clause

let increment_statement = arel::statements::increment::Increment::<Self::Model>::new(column_name, step, update_where_fields, update_where_values);
if let Some(increment_sql) =increment_statement.to_sql() {
if self.__persisted__ {
match increment_sql.exec(executor).await {
Ok(val) => {
if val.rows_affected() >= 1 {
update_self_cb(self, step);
}
Ok(val)
}
Err(err) => Err(err),
}
} else {
return Err(arel::anyhow::anyhow!("Model is Not Persisted"));
}
} else {
return Err(arel::anyhow::anyhow!("Increment sql error!"));
}
}
))
}
31 changes: 31 additions & 0 deletions arel-macros/src/arel/arel_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,34 @@ pub(crate) fn impl_primary_key_or_primary_keys(input: &crate::ItemInput) -> syn:

Ok(ret_token_stream)
}

pub(crate) fn impl_table_column_name(input: &crate::ItemInput) -> syn::Result<proc_macro2::TokenStream> {
let fields = input.struct_fields()?;

let mut get_column_name_clauses = vec![];
for field in fields.iter() {
let ident = &field.ident;

let field_name = {
if let Some((rename, _)) = crate::ItemInput::get_field_path_value(field, vec!["arel"], "rename", None)? {
rename
} else {
match ident {
Some(ident) => ident.to_string().trim_start_matches("r#").to_string(),
_ => return Err(syn::Error::new_spanned(field, "Field name can not Blank!")),
}
}
};

get_column_name_clauses.push(quote::quote!(if struct_key.as_ref() == stringify!(#ident) {
return std::option::Option::Some(std::borrow::Cow::Borrowed(#field_name))
}));
}

Ok(quote::quote!(
fn _table_column_name<K: AsRef<str>>(struct_key: K) -> Option<std::borrow::Cow<'static, str>> {
#(#get_column_name_clauses)*
None
}
))
}

0 comments on commit 18f3ed9

Please sign in to comment.