impl selectlist for foreign key

This commit is contained in:
manuel 2022-08-20 21:44:24 +02:00
parent b56bdf8984
commit a6edbc0f56
6 changed files with 67 additions and 34 deletions

View File

@ -12,14 +12,19 @@ use struct_fields::{
}; };
mod selectlist_fields; mod selectlist_fields;
use selectlist_fields::{get_select_list, get_select_lists}; use selectlist_fields::{get_select_list_from_enum, get_select_list_from_model, get_select_lists};
mod attributes; mod attributes;
mod model_fields; mod model_fields;
#[proc_macro_derive(DeriveActixAdminSelectList, attributes(actix_admin))] #[proc_macro_derive(DeriveActixAdminEnumSelectList, attributes(actix_admin))]
pub fn derive_actix_admin_select_list(input: proc_macro::TokenStream) -> proc_macro::TokenStream { pub fn derive_actix_admin_enum_select_list(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
get_select_list(input) get_select_list_from_enum(input)
}
#[proc_macro_derive(DeriveActixAdminModelSelectList, attributes(actix_admin))]
pub fn derive_actix_admin_model_select_list(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
get_select_list_from_model(input)
} }
#[proc_macro_derive(DeriveActixAdmin, attributes(actix_admin))] #[proc_macro_derive(DeriveActixAdmin, attributes(actix_admin))]
@ -70,15 +75,16 @@ pub fn derive_actix_admin_view_model(input: proc_macro::TokenStream) -> proc_mac
entities entities
} }
async fn create_entity(db: &DatabaseConnection, mut model: ActixAdminModel) -> ActixAdminModel { fn validate_entity(model: &mut ActixAdminModel) {
let mut validation_errs = Entity::validate_model(&model); Entity::validate_model(model);
//model.errors.append(&mut validation_errs);
model.errors = validation_errs;
if !model.has_errors() { let custom_errors = Entity::validate(&model);
model.custom_errors = custom_errors;
}
async fn create_entity(db: &DatabaseConnection, mut model: ActixAdminModel) -> ActixAdminModel {
let new_model = ActiveModel::from(model.clone()); let new_model = ActiveModel::from(model.clone());
let insert_operation = Entity::insert(new_model).exec(db).await; let insert_operation = Entity::insert(new_model).exec(db).await;
}
model model
} }
@ -91,17 +97,12 @@ pub fn derive_actix_admin_view_model(input: proc_macro::TokenStream) -> proc_mac
} }
async fn edit_entity(db: &DatabaseConnection, id: i32, mut model: ActixAdminModel) -> ActixAdminModel { async fn edit_entity(db: &DatabaseConnection, id: i32, mut model: ActixAdminModel) -> ActixAdminModel {
let mut validation_errs = Entity::validate_model(&model);
//model.errors.append(&mut validation_errs);
model.errors=validation_errs;
if !model.has_errors() {
let entity: Option<Model> = Entity::find_by_id(id).one(db).await.unwrap(); let entity: Option<Model> = Entity::find_by_id(id).one(db).await.unwrap();
let mut entity: ActiveModel = entity.unwrap().into(); let mut entity: ActiveModel = entity.unwrap().into();
#(#fields_for_edit_model);*; #(#fields_for_edit_model);*;
let entity: Model = entity.update(db).await.unwrap(); let entity: Model = entity.update(db).await.unwrap();
}
model model
} }
@ -152,7 +153,8 @@ pub fn derive_actix_admin_model(input: proc_macro::TokenStream) -> proc_macro::T
values: hashmap![ values: hashmap![
#(#fields_for_from_model),* #(#fields_for_from_model),*
], ],
errors: HashMap::new() errors: HashMap::new(),
custom_errors: HashMap::new(),
} }
} }
} }
@ -194,12 +196,11 @@ pub fn derive_actix_admin_model(input: proc_macro::TokenStream) -> proc_macro::T
(num_pages, model_entities) (num_pages, model_entities)
} }
fn validate_model(model: &ActixAdminModel) -> HashMap<String, String> { fn validate_model(model: &mut ActixAdminModel) {
let mut errors = HashMap::<String, String>::new(); let mut errors = HashMap::<String, String>::new();
#(#fields_for_validate_model);*; #(#fields_for_validate_model);*;
//let mut custom_errors = Entity.validate();
//errors.append(&mut custom_errors); model.errors = errors;
errors
} }
fn get_fields() -> Vec<ActixAdminViewModelField> { fn get_fields() -> Vec<ActixAdminViewModelField> {

View File

@ -5,13 +5,37 @@ use quote::quote;
use crate::model_fields::{ ModelField }; use crate::model_fields::{ ModelField };
use proc_macro2::{Span}; use proc_macro2::{Span};
pub fn get_select_list(input: proc_macro::TokenStream) -> proc_macro::TokenStream { pub fn get_select_list_from_model(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
//let ast: DeriveInput = syn::parse(input).unwrap();
//let (_vis, _ty, _generics) = (&ast.vis, &ast.ident, &ast.generics);
let expanded = quote! {
#[async_trait]
impl ActixAdminSelectListTrait for Entity {
async fn get_key_value(db: &DatabaseConnection) -> Vec<(String, String)> {
let entities = Entity::find().order_by_asc(Column::Id).all(db).await;
let mut key_value = Vec::new();
for entity in entities.unwrap() {
key_value.push((entity.id.to_string(), entity.to_string()));
};
key_value.sort_by(|a, b| a.1.cmp(&b.1));
key_value
}
}
};
proc_macro::TokenStream::from(expanded)
}
pub fn get_select_list_from_enum(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast: DeriveInput = syn::parse(input).unwrap(); let ast: DeriveInput = syn::parse(input).unwrap();
let (_vis, ty, _generics) = (&ast.vis, &ast.ident, &ast.generics); let (_vis, ty, _generics) = (&ast.vis, &ast.ident, &ast.generics);
let expanded = quote! { let expanded = quote! {
#[async_trait]
impl ActixAdminSelectListTrait for #ty { impl ActixAdminSelectListTrait for #ty {
fn get_key_value() -> Vec<(String, String)> { async fn get_key_value(db: &DatabaseConnection) -> Vec<(String, String)> {
let mut fields = Vec::new(); let mut fields = Vec::new();
for field in #ty::iter() { for field in #ty::iter() {
fields.push((field.to_string(), field.to_string())); fields.push((field.to_string(), field.to_string()));
@ -20,6 +44,7 @@ pub fn get_select_list(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
} }
} }
}; };
proc_macro::TokenStream::from(expanded) proc_macro::TokenStream::from(expanded)
} }
@ -31,7 +56,7 @@ pub fn get_select_lists(fields: &Vec<ModelField>) -> Vec<proc_macro2::TokenStrea
let ident_name = model_field.ident.to_string(); let ident_name = model_field.ident.to_string();
let select_list_ident = Ident::new(&(model_field.select_list), Span::call_site()); let select_list_ident = Ident::new(&(model_field.select_list), Span::call_site());
quote! { quote! {
#ident_name => #select_list_ident::get_key_value() #ident_name => #select_list_ident::get_key_value(db).await
} }
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()

View File

@ -4,6 +4,7 @@ use std::collections::HashMap;
use tera::{Tera, Result, to_value, try_get_value }; use tera::{Tera, Result, to_value, try_get_value };
use std::{ hash::BuildHasher}; use std::{ hash::BuildHasher};
use actix_session::{Session}; use actix_session::{Session};
use async_trait::async_trait;
pub mod view_model; pub mod view_model;
pub mod model; pub mod model;
@ -14,7 +15,7 @@ pub mod prelude {
pub use crate::builder::{ ActixAdminBuilder, ActixAdminBuilderTrait}; pub use crate::builder::{ ActixAdminBuilder, ActixAdminBuilderTrait};
pub use crate::model::{ ActixAdminModel, ActixAdminModelTrait}; pub use crate::model::{ ActixAdminModel, ActixAdminModelTrait};
pub use crate::view_model::{ ActixAdminViewModel, ActixAdminViewModelTrait, ActixAdminViewModelField, ActixAdminViewModelSerializable, ActixAdminViewModelFieldType }; pub use crate::view_model::{ ActixAdminViewModel, ActixAdminViewModelTrait, ActixAdminViewModelField, ActixAdminViewModelSerializable, ActixAdminViewModelFieldType };
pub use actix_admin_macros::{ DeriveActixAdmin, DeriveActixAdminModel, DeriveActixAdminViewModel, DeriveActixAdminSelectList }; pub use actix_admin_macros::{ DeriveActixAdmin, DeriveActixAdminModel, DeriveActixAdminViewModel, DeriveActixAdminEnumSelectList, DeriveActixAdminModelSelectList };
pub use crate::{ ActixAdminAppDataTrait, ActixAdmin, ActixAdminConfiguration }; pub use crate::{ ActixAdminAppDataTrait, ActixAdmin, ActixAdminConfiguration };
pub use crate::{ hashmap, ActixAdminSelectListTrait }; pub use crate::{ hashmap, ActixAdminSelectListTrait };
} }
@ -88,8 +89,9 @@ pub trait ActixAdminAppDataTrait {
} }
// SelectListTrait // SelectListTrait
#[async_trait]
pub trait ActixAdminSelectListTrait { pub trait ActixAdminSelectListTrait {
fn get_key_value() -> Vec<(String, String)>; async fn get_key_value(db: &DatabaseConnection) -> Vec<(String, String)>;
} }

View File

@ -16,9 +16,9 @@ pub trait ActixAdminModelTrait {
search: &String search: &String
) -> (usize, Vec<ActixAdminModel>); ) -> (usize, Vec<ActixAdminModel>);
fn get_fields() -> Vec<ActixAdminViewModelField>; fn get_fields() -> Vec<ActixAdminViewModelField>;
fn validate_model(model: &ActixAdminModel) -> HashMap<String, String>; fn validate_model(model: &mut ActixAdminModel);
// function to be overridable for custom error handling // function to be overridable for custom error handling
fn validate(&self) -> HashMap<String, String> { fn validate(_model: &ActixAdminModel) -> HashMap<String, String> {
return HashMap::new(); return HashMap::new();
} }
} }
@ -28,6 +28,7 @@ pub struct ActixAdminModel {
pub primary_key: Option<String>, pub primary_key: Option<String>,
pub values: HashMap<String, String>, pub values: HashMap<String, String>,
pub errors: HashMap<String, String>, pub errors: HashMap<String, String>,
pub custom_errors: HashMap<String, String>
} }
@ -37,6 +38,7 @@ impl ActixAdminModel {
primary_key: None, primary_key: None,
values: HashMap::new(), values: HashMap::new(),
errors: HashMap::new(), errors: HashMap::new(),
custom_errors: HashMap::new(),
} }
} }
@ -63,6 +65,7 @@ impl ActixAdminModel {
primary_key: None, primary_key: None,
values: hashmap, values: hashmap,
errors: HashMap::new(), errors: HashMap::new(),
custom_errors: HashMap::new(),
}) })
} }

View File

@ -37,7 +37,8 @@ async fn create_or_edit_post<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTr
} }
let db = &data.get_db(); let db = &data.get_db();
let model = ActixAdminModel::create_from_payload(payload).await.unwrap(); let mut model = ActixAdminModel::create_from_payload(payload).await.unwrap();
E::validate_entity(&mut model);
if model.has_errors() { if model.has_errors() {
let mut ctx = Context::new(); let mut ctx = Context::new();

View File

@ -21,6 +21,7 @@ pub trait ActixAdminViewModelTrait {
async fn get_entity(db: &DatabaseConnection, id: i32) -> ActixAdminModel; async fn get_entity(db: &DatabaseConnection, id: i32) -> ActixAdminModel;
async fn edit_entity(db: &DatabaseConnection, id: i32, model: ActixAdminModel) -> ActixAdminModel; async fn edit_entity(db: &DatabaseConnection, id: i32, model: ActixAdminModel) -> ActixAdminModel;
async fn get_select_lists(db: &DatabaseConnection) -> HashMap<String, Vec<(String, String)>>; async fn get_select_lists(db: &DatabaseConnection) -> HashMap<String, Vec<(String, String)>>;
fn validate_entity(model: &mut ActixAdminModel);
fn get_entity_name() -> String; fn get_entity_name() -> String;