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;
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 model_fields;
#[proc_macro_derive(DeriveActixAdminSelectList, attributes(actix_admin))]
pub fn derive_actix_admin_select_list(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
get_select_list(input)
#[proc_macro_derive(DeriveActixAdminEnumSelectList, attributes(actix_admin))]
pub fn derive_actix_admin_enum_select_list(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
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))]
@ -70,15 +75,16 @@ pub fn derive_actix_admin_view_model(input: proc_macro::TokenStream) -> proc_mac
entities
}
async fn create_entity(db: &DatabaseConnection, mut model: ActixAdminModel) -> ActixAdminModel {
let mut validation_errs = Entity::validate_model(&model);
//model.errors.append(&mut validation_errs);
model.errors = validation_errs;
fn validate_entity(model: &mut ActixAdminModel) {
Entity::validate_model(model);
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 insert_operation = Entity::insert(new_model).exec(db).await;
}
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 {
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 mut entity: ActiveModel = entity.unwrap().into();
#(#fields_for_edit_model);*;
let entity: Model = entity.update(db).await.unwrap();
}
model
}
@ -152,7 +153,8 @@ pub fn derive_actix_admin_model(input: proc_macro::TokenStream) -> proc_macro::T
values: hashmap![
#(#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)
}
fn validate_model(model: &ActixAdminModel) -> HashMap<String, String> {
fn validate_model(model: &mut ActixAdminModel) {
let mut errors = HashMap::<String, String>::new();
#(#fields_for_validate_model);*;
//let mut custom_errors = Entity.validate();
//errors.append(&mut custom_errors);
errors
model.errors = errors;
}
fn get_fields() -> Vec<ActixAdminViewModelField> {

View File

@ -5,13 +5,37 @@ use quote::quote;
use crate::model_fields::{ ModelField };
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 (_vis, ty, _generics) = (&ast.vis, &ast.ident, &ast.generics);
let expanded = quote! {
#[async_trait]
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();
for field in #ty::iter() {
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)
}
@ -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 select_list_ident = Ident::new(&(model_field.select_list), Span::call_site());
quote! {
#ident_name => #select_list_ident::get_key_value()
#ident_name => #select_list_ident::get_key_value(db).await
}
})
.collect::<Vec<_>>()

View File

@ -4,6 +4,7 @@ use std::collections::HashMap;
use tera::{Tera, Result, to_value, try_get_value };
use std::{ hash::BuildHasher};
use actix_session::{Session};
use async_trait::async_trait;
pub mod view_model;
pub mod model;
@ -14,7 +15,7 @@ pub mod prelude {
pub use crate::builder::{ ActixAdminBuilder, ActixAdminBuilderTrait};
pub use crate::model::{ ActixAdminModel, ActixAdminModelTrait};
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::{ hashmap, ActixAdminSelectListTrait };
}
@ -88,8 +89,9 @@ pub trait ActixAdminAppDataTrait {
}
// SelectListTrait
#[async_trait]
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
) -> (usize, Vec<ActixAdminModel>);
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
fn validate(&self) -> HashMap<String, String> {
fn validate(_model: &ActixAdminModel) -> HashMap<String, String> {
return HashMap::new();
}
}
@ -28,6 +28,7 @@ pub struct ActixAdminModel {
pub primary_key: Option<String>,
pub values: HashMap<String, String>,
pub errors: HashMap<String, String>,
pub custom_errors: HashMap<String, String>
}
@ -37,6 +38,7 @@ impl ActixAdminModel {
primary_key: None,
values: HashMap::new(),
errors: HashMap::new(),
custom_errors: HashMap::new(),
}
}
@ -63,6 +65,7 @@ impl ActixAdminModel {
primary_key: None,
values: hashmap,
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 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() {
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 edit_entity(db: &DatabaseConnection, id: i32, model: ActixAdminModel) -> ActixAdminModel;
async fn get_select_lists(db: &DatabaseConnection) -> HashMap<String, Vec<(String, String)>>;
fn validate_entity(model: &mut ActixAdminModel);
fn get_entity_name() -> String;