separate primary_key from other field values
This commit is contained in:
parent
244d1f9e01
commit
96b069042e
@ -9,7 +9,8 @@ pub mod derive_attr {
|
|||||||
Default
|
Default
|
||||||
)]
|
)]
|
||||||
pub struct ActixAdmin {
|
pub struct ActixAdmin {
|
||||||
pub inner_type: Option<syn::Type>,
|
pub primary_key: Option<()>
|
||||||
|
//pub inner_type: Option<syn::Type>,
|
||||||
|
|
||||||
// Anything that implements `syn::parse::Parse` is supported.
|
// Anything that implements `syn::parse::Parse` is supported.
|
||||||
//mandatory_type: syn::Type,
|
//mandatory_type: syn::Type,
|
||||||
|
@ -2,7 +2,9 @@ use proc_macro;
|
|||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
||||||
mod struct_fields;
|
mod struct_fields;
|
||||||
use struct_fields::get_fields_for_tokenstream;
|
use struct_fields::{ get_fields_for_tokenstream, get_fields_for_edit_model, get_fields_for_from_model, get_fields_for_create_model, get_field_names, get_field_for_primary_key, get_primary_key_field_name};
|
||||||
|
|
||||||
|
mod model_fields;
|
||||||
|
|
||||||
mod attributes;
|
mod attributes;
|
||||||
|
|
||||||
@ -10,82 +12,12 @@ mod attributes;
|
|||||||
pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
let fields = get_fields_for_tokenstream(input);
|
let fields = get_fields_for_tokenstream(input);
|
||||||
|
|
||||||
let names_const_fields_str = fields
|
let names_const_fields_str = get_field_names(&fields);
|
||||||
.iter()
|
let name_primary_field_str = get_primary_key_field_name(&fields);
|
||||||
.map(|(_vis, ident, _ty, _is_option)| {
|
let fields_for_create_model = get_fields_for_create_model(&fields);
|
||||||
let ident_name = ident.to_string();
|
let fields_for_edit_model = get_fields_for_edit_model(&fields);
|
||||||
quote! {
|
let fields_for_from_model = get_fields_for_from_model(&fields);
|
||||||
#ident_name
|
let field_for_primary_key = get_field_for_primary_key(&fields);
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let fields_for_create_model = fields
|
|
||||||
.iter()
|
|
||||||
// TODO: filter id attr based on struct attr or sea_orm primary_key attr
|
|
||||||
.filter(|(_vis, ident, _ty, _is_option)| !ident.to_string().eq("id"))
|
|
||||||
.map(|(_vis, ident, ty, is_option)| {
|
|
||||||
let ident_name = ident.to_string();
|
|
||||||
match is_option {
|
|
||||||
true => {
|
|
||||||
quote! {
|
|
||||||
#ident: Set(model.get_value::<#ty>(#ident_name))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false => {
|
|
||||||
quote! {
|
|
||||||
#ident: Set(model.get_value::<#ty>(#ident_name).unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let fields_for_edit_model = fields
|
|
||||||
.iter()
|
|
||||||
// TODO: filter id attr based on struct attr or sea_orm primary_key attr
|
|
||||||
.filter(|(_vis, ident, _ty, _is_option)| !ident.to_string().eq("id"))
|
|
||||||
.map(|(_vis, ident, ty, is_option)| {
|
|
||||||
let ident_name = ident.to_string();
|
|
||||||
println!("edit {} {:?}", &ident_name, ty);
|
|
||||||
match is_option {
|
|
||||||
true => {
|
|
||||||
quote! {
|
|
||||||
entity.#ident = Set(model.get_value::<#ty>(#ident_name))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false => {
|
|
||||||
quote! {
|
|
||||||
entity.#ident = Set(model.get_value::<#ty>(#ident_name).unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let fields_for_from_model = fields
|
|
||||||
.iter()
|
|
||||||
.map(|(_vis, ident, _ty, is_option)| {
|
|
||||||
let ident_name = ident.to_string();
|
|
||||||
println!("from {} {:?}", &ident_name, _ty);
|
|
||||||
|
|
||||||
match is_option {
|
|
||||||
true => {
|
|
||||||
quote! {
|
|
||||||
#ident_name => match model.#ident {
|
|
||||||
Some(val) => val.to_string(),
|
|
||||||
None => "".to_owned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false => {
|
|
||||||
quote! {
|
|
||||||
#ident_name => model.#ident.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
@ -102,6 +34,7 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
|
|||||||
impl From<Entity> for ActixAdminViewModel {
|
impl From<Entity> for ActixAdminViewModel {
|
||||||
fn from(entity: Entity) -> Self {
|
fn from(entity: Entity) -> Self {
|
||||||
ActixAdminViewModel {
|
ActixAdminViewModel {
|
||||||
|
primary_key: #name_primary_field_str.to_string(),
|
||||||
entity_name: entity.table_name().to_string(),
|
entity_name: entity.table_name().to_string(),
|
||||||
fields: Entity::get_fields()
|
fields: Entity::get_fields()
|
||||||
}
|
}
|
||||||
@ -111,6 +44,7 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
|
|||||||
impl From<Model> for ActixAdminModel {
|
impl From<Model> for ActixAdminModel {
|
||||||
fn from(model: Model) -> Self {
|
fn from(model: Model) -> Self {
|
||||||
ActixAdminModel {
|
ActixAdminModel {
|
||||||
|
#field_for_primary_key,
|
||||||
values: hashmap![
|
values: hashmap![
|
||||||
#(#fields_for_from_model),*
|
#(#fields_for_from_model),*
|
||||||
]
|
]
|
||||||
@ -139,8 +73,6 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
|
|||||||
async fn create_entity(db: &DatabaseConnection, mut model: ActixAdminModel) -> ActixAdminModel {
|
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;
|
||||||
println!("creating {:?}", model);
|
|
||||||
println!("operation {:?}", insert_operation);
|
|
||||||
|
|
||||||
model
|
model
|
||||||
}
|
}
|
||||||
|
18
actix_admin/actix_admin_macros/src/model_fields.rs
Normal file
18
actix_admin/actix_admin_macros/src/model_fields.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use syn::{
|
||||||
|
Visibility, Type
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct ModelField {
|
||||||
|
pub visibility: Visibility,
|
||||||
|
pub ident: proc_macro2::Ident,
|
||||||
|
pub ty: Type,
|
||||||
|
// struct field is option<>
|
||||||
|
pub inner_type: Option<Type>,
|
||||||
|
pub primary_key: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModelField {
|
||||||
|
pub fn is_option(&self) -> bool {
|
||||||
|
self.inner_type.is_some()
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,12 @@
|
|||||||
use proc_macro2::{Span, Ident};
|
use proc_macro2::{Span, Ident, TokenStream};
|
||||||
use syn::{
|
use syn::{
|
||||||
Attribute, Fields, Meta, NestedMeta, Visibility, DeriveInput, Type
|
Fields, DeriveInput
|
||||||
};
|
};
|
||||||
|
use quote::quote;
|
||||||
use crate::attributes::derive_attr;
|
use crate::attributes::derive_attr;
|
||||||
|
use crate::model_fields::{ ModelField };
|
||||||
|
|
||||||
const ACTIX_ADMIN: &'static str = "actix_admin";
|
pub fn get_fields_for_tokenstream(input: proc_macro::TokenStream) -> std::vec::Vec<ModelField> {
|
||||||
|
|
||||||
pub fn get_fields_for_tokenstream(input: proc_macro::TokenStream) -> std::vec::Vec<(syn::Visibility, proc_macro2::Ident, Type, bool)> {
|
|
||||||
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 _names_struct_ident = Ident::new(&(ty.to_string() + "FieldStaticStr"), Span::call_site());
|
let _names_struct_ident = Ident::new(&(ty.to_string() + "FieldStaticStr"), Span::call_site());
|
||||||
@ -19,58 +18,29 @@ pub fn get_fields_for_tokenstream(input: proc_macro::TokenStream) -> std::vec::V
|
|||||||
fields
|
fields
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_skip_attr(attr: &Attribute, path: &'static str) -> bool {
|
pub fn filter_fields(fields: &Fields) -> Vec<ModelField> {
|
||||||
if let Ok(Meta::List(meta_list)) = attr.parse_meta() {
|
|
||||||
//println!("1");
|
|
||||||
//println!("{:?}", meta_list.path);
|
|
||||||
//println!("{}", path);
|
|
||||||
if meta_list.path.is_ident(path) {
|
|
||||||
//println!("2");
|
|
||||||
for nested_item in meta_list.nested.iter() {
|
|
||||||
if let NestedMeta::Meta(Meta::Path(path)) = nested_item {
|
|
||||||
//println!("3");
|
|
||||||
if path.is_ident(ACTIX_ADMIN) {
|
|
||||||
//println!("true");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_field_type<'a>(actix_admin_attr: &'a Option<derive_attr::ActixAdmin>, field: &'a syn::Field) -> &'a syn::Type {
|
|
||||||
match actix_admin_attr {
|
|
||||||
Some(attr) => {
|
|
||||||
match &attr.inner_type {
|
|
||||||
Some(inner_type) => &inner_type,
|
|
||||||
None => &field.ty
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => &field.ty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn filter_fields(fields: &Fields) -> Vec<(Visibility, Ident, Type, bool)> {
|
|
||||||
fields
|
fields
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|field| {
|
.filter_map(|field| {
|
||||||
let actix_admin_attr = derive_attr::ActixAdmin::try_from_attributes(&field.attrs).unwrap_or_default();
|
let actix_admin_attr = derive_attr::ActixAdmin::try_from_attributes(&field.attrs).unwrap_or_default();
|
||||||
|
|
||||||
if field
|
if field.ident.is_some()
|
||||||
.attrs
|
|
||||||
.iter()
|
|
||||||
.find(|attr| has_skip_attr(attr, ACTIX_ADMIN))
|
|
||||||
.is_none()
|
|
||||||
&& field.ident.is_some()
|
|
||||||
{
|
{
|
||||||
let field_vis = field.vis.clone();
|
let field_vis = field.vis.clone();
|
||||||
let field_ident = field.ident.as_ref().unwrap().clone();
|
let field_ident = field.ident.as_ref().unwrap().clone();
|
||||||
println!("{}", field_ident.to_string());
|
let inner_type = extract_type_from_option(&field.ty);
|
||||||
let is_option = extract_type_from_option(&field.ty).is_some();
|
let field_ty = field.ty.to_owned();
|
||||||
let field_ty = get_field_type(&actix_admin_attr, &field).to_owned();
|
let is_primary_key = actix_admin_attr.map_or(false, |attr| attr.primary_key.is_some());
|
||||||
Some((field_vis, field_ident, field_ty, is_option))
|
|
||||||
|
let model_field = ModelField {
|
||||||
|
visibility: field_vis,
|
||||||
|
ident: field_ident,
|
||||||
|
ty: field_ty,
|
||||||
|
inner_type: inner_type,
|
||||||
|
primary_key: is_primary_key
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(model_field)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -78,7 +48,7 @@ pub fn filter_fields(fields: &Fields) -> Vec<(Visibility, Ident, Type, bool)> {
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_type_from_option(ty: &syn::Type) -> Option<&syn::Type> {
|
fn extract_type_from_option(ty: &syn::Type) -> Option<syn::Type> {
|
||||||
use syn::{GenericArgument, Path, PathArguments, PathSegment};
|
use syn::{GenericArgument, Path, PathArguments, PathSegment};
|
||||||
|
|
||||||
fn extract_type_path(ty: &syn::Type) -> Option<&Path> {
|
fn extract_type_path(ty: &syn::Type) -> Option<&Path> {
|
||||||
@ -117,7 +87,125 @@ fn extract_type_from_option(ty: &syn::Type) -> Option<&syn::Type> {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.and_then(|generic_arg| match *generic_arg {
|
.and_then(|generic_arg| match *generic_arg {
|
||||||
GenericArgument::Type(ref ty) => Some(ty),
|
GenericArgument::Type(ref ty) => Some(ty.to_owned()),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_field_names(fields: &Vec<ModelField>) -> Vec<TokenStream> {
|
||||||
|
fields
|
||||||
|
.iter()
|
||||||
|
.filter(|model_field| !model_field.primary_key)
|
||||||
|
.map(|model_field| {
|
||||||
|
let ident_name = model_field.ident.to_string();
|
||||||
|
quote! {
|
||||||
|
#ident_name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_field_for_primary_key(fields: &Vec<ModelField>) -> TokenStream {
|
||||||
|
let primary_key_model_field = fields
|
||||||
|
.iter()
|
||||||
|
// TODO: filter id attr based on struct attr or sea_orm primary_key attr
|
||||||
|
.find(|model_field| model_field.primary_key)
|
||||||
|
.expect("model must have a single primary key");
|
||||||
|
|
||||||
|
let ident = primary_key_model_field.ident.to_owned();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
primary_key: Some(model.#ident.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_primary_key_field_name(fields: &Vec<ModelField>) -> String {
|
||||||
|
let primary_key_model_field = fields
|
||||||
|
.iter()
|
||||||
|
// TODO: filter id attr based on struct attr or sea_orm primary_key attr
|
||||||
|
.find(|model_field| model_field.primary_key)
|
||||||
|
.expect("model must have a single primary key");
|
||||||
|
|
||||||
|
primary_key_model_field.ident.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_fields_for_from_model(fields: &Vec<ModelField>) -> Vec<TokenStream> {
|
||||||
|
fields
|
||||||
|
.iter()
|
||||||
|
.filter(|model_field| !model_field.primary_key)
|
||||||
|
.map(|model_field| {
|
||||||
|
let ident_name = model_field.ident.to_string();
|
||||||
|
let ident = model_field.ident.to_owned();
|
||||||
|
|
||||||
|
match model_field.is_option() {
|
||||||
|
true => {
|
||||||
|
quote! {
|
||||||
|
#ident_name => match model.#ident {
|
||||||
|
Some(val) => val.to_string(),
|
||||||
|
None => "".to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false => {
|
||||||
|
quote! {
|
||||||
|
#ident_name => model.#ident.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_fields_for_create_model(fields: &Vec<ModelField>) -> Vec<TokenStream> {
|
||||||
|
fields
|
||||||
|
.iter()
|
||||||
|
// TODO: filter id attr based on struct attr or sea_orm primary_key attr
|
||||||
|
.filter(|model_field| !model_field.primary_key)
|
||||||
|
.map(|model_field| {
|
||||||
|
let ident_name = model_field.ident.to_string();
|
||||||
|
let ident = model_field.ident.to_owned();
|
||||||
|
let ty = model_field.ty.to_owned();
|
||||||
|
|
||||||
|
match model_field.is_option() {
|
||||||
|
true => {
|
||||||
|
let inner_ty = model_field.inner_type.to_owned().unwrap();
|
||||||
|
quote! {
|
||||||
|
#ident: Set(model.get_value::<#inner_ty>(#ident_name))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false => {
|
||||||
|
quote! {
|
||||||
|
#ident: Set(model.get_value::<#ty>(#ident_name).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_fields_for_edit_model(fields: &Vec<ModelField>) -> Vec<TokenStream> {
|
||||||
|
fields
|
||||||
|
.iter()
|
||||||
|
// TODO: filter id attr based on struct attr or sea_orm primary_key attr
|
||||||
|
.filter(|model_field| !model_field.primary_key)
|
||||||
|
.map(|model_field| {
|
||||||
|
let ident_name = model_field.ident.to_string();
|
||||||
|
let ident = model_field.ident.to_owned();
|
||||||
|
let ty = model_field.ty.to_owned();
|
||||||
|
|
||||||
|
match model_field.is_option() {
|
||||||
|
true => {
|
||||||
|
let inner_ty = model_field.inner_type.to_owned().unwrap();
|
||||||
|
quote! {
|
||||||
|
entity.#ident = Set(model.get_value::<#inner_ty>(#ident_name))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false => {
|
||||||
|
quote! {
|
||||||
|
entity.#ident = Set(model.get_value::<#ty>(#ident_name).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
@ -17,6 +17,7 @@ pub trait ActixAdminModelTrait {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
pub struct ActixAdminModel {
|
pub struct ActixAdminModel {
|
||||||
|
pub primary_key: Option<String>,
|
||||||
pub values: HashMap<String, String>,
|
pub values: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,13 +33,12 @@ impl From<String> for ActixAdminModel {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ActixAdminModel { values: hashmap }
|
ActixAdminModel { primary_key: None, values: hashmap }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActixAdminModel {
|
impl ActixAdminModel {
|
||||||
pub fn get_value<T: std::str::FromStr>(&self, key: &str) -> Option<T> {
|
pub fn get_value<T: std::str::FromStr>(&self, key: &str) -> Option<T> {
|
||||||
println!("get value for key {}", key);
|
|
||||||
let value = self.values.get(key).unwrap().to_string().parse::<T>();
|
let value = self.values.get(key).unwrap().to_string().parse::<T>();
|
||||||
match value {
|
match value {
|
||||||
Ok(val) => Some(val),
|
Ok(val) => Some(val),
|
||||||
|
@ -12,8 +12,8 @@ pub async fn create_post<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>
|
|||||||
let entity_name = E::get_entity_name();
|
let entity_name = E::get_entity_name();
|
||||||
let actix_admin = data.get_actix_admin();
|
let actix_admin = data.get_actix_admin();
|
||||||
let view_model = actix_admin.view_models.get(&entity_name).unwrap();
|
let view_model = actix_admin.view_models.get(&entity_name).unwrap();
|
||||||
let mut admin_model = ActixAdminModel::from(text);
|
let mut _admin_model = ActixAdminModel::from(text);
|
||||||
admin_model = E::create_entity(db, admin_model).await;
|
_admin_model = E::create_entity(db, _admin_model).await;
|
||||||
|
|
||||||
Ok(HttpResponse::Found()
|
Ok(HttpResponse::Found()
|
||||||
.append_header((
|
.append_header((
|
||||||
|
@ -13,8 +13,8 @@ pub async fn edit_post<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
|
|||||||
let entity_name = E::get_entity_name();
|
let entity_name = E::get_entity_name();
|
||||||
let actix_admin = data.get_actix_admin();
|
let actix_admin = data.get_actix_admin();
|
||||||
let view_model = actix_admin.view_models.get(&entity_name).unwrap();
|
let view_model = actix_admin.view_models.get(&entity_name).unwrap();
|
||||||
let mut admin_model = ActixAdminModel::from(text);
|
let mut _admin_model = ActixAdminModel::from(text);
|
||||||
admin_model = E::edit_entity(db, id.into_inner(), admin_model).await;
|
_admin_model = E::edit_entity(db, id.into_inner(), _admin_model).await;
|
||||||
|
|
||||||
Ok(HttpResponse::Found()
|
Ok(HttpResponse::Found()
|
||||||
.append_header((
|
.append_header((
|
||||||
|
@ -37,7 +37,6 @@ pub async fn list<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
|
|||||||
let result: (usize, Vec<ActixAdminModel>) = E::list(db, page, entities_per_page).await;
|
let result: (usize, Vec<ActixAdminModel>) = E::list(db, page, entities_per_page).await;
|
||||||
let entities = result.1;
|
let entities = result.1;
|
||||||
let num_pages = result.0;
|
let num_pages = result.0;
|
||||||
println!("{:?}", entities);
|
|
||||||
|
|
||||||
let mut ctx = Context::new();
|
let mut ctx = Context::new();
|
||||||
ctx.insert("entity_names", &entity_names);
|
ctx.insert("entity_names", &entity_names);
|
||||||
|
@ -25,5 +25,6 @@ pub trait ActixAdminViewModelTrait {
|
|||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
pub struct ActixAdminViewModel {
|
pub struct ActixAdminViewModel {
|
||||||
pub entity_name: String,
|
pub entity_name: String,
|
||||||
|
pub primary_key: String,
|
||||||
pub fields: Vec<(String, ActixAdminField)>,
|
pub fields: Vec<(String, ActixAdminField)>,
|
||||||
}
|
}
|
@ -5,6 +5,7 @@
|
|||||||
<table role="grid">
|
<table role="grid">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>{{ view_model.primary_key }}</th>
|
||||||
{% for model_field in view_model.fields -%}
|
{% for model_field in view_model.fields -%}
|
||||||
<th>{{ model_field[0] }}</th>
|
<th>{{ model_field[0] }}</th>
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
@ -17,12 +18,13 @@
|
|||||||
<tbody hx-confirm="Are you sure?" hx-target="closest tr" hx-swap="outerHTML">
|
<tbody hx-confirm="Are you sure?" hx-target="closest tr" hx-swap="outerHTML">
|
||||||
{% for entity in entities -%}
|
{% for entity in entities -%}
|
||||||
<tr>
|
<tr>
|
||||||
|
<td>{{ entity.primary_key }}</td>
|
||||||
{% for model_field in view_model.fields -%}
|
{% for model_field in view_model.fields -%}
|
||||||
<td>{{ entity.values | get(key=model_field[0]) }}</td>
|
<td>{{ entity.values | get(key=model_field[0]) }}</td>
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
<td>
|
<td>
|
||||||
<a href="edit/{{ entity.values | get(key=view_model.fields[0][0]) }}">✎</a>
|
<a href="edit/{{ entity.primary_key }}">✎</a>
|
||||||
<a hx-post="delete/{{ entity.values | get(key=view_model.fields[0][0]) }}">🗑</a>
|
<a hx-post="delete/{{ entity.primary_key }}">🗑</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
|
@ -125,7 +125,6 @@ async fn read_user(api_base_url: &str, access_token: &AccessToken) -> UserInfo {
|
|||||||
Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
|
Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("{} {}", &resp.status_code, s);
|
|
||||||
serde_json::from_slice(&resp.body).unwrap()
|
serde_json::from_slice(&resp.body).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
database.db-wal
BIN
database.db-wal
Binary file not shown.
@ -7,6 +7,7 @@ use actix_admin::prelude::*;
|
|||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
|
#[actix_admin(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub comment: String,
|
pub comment: String,
|
||||||
#[sea_orm(column_type = "Text")]
|
#[sea_orm(column_type = "Text")]
|
||||||
|
@ -29,7 +29,7 @@ pub async fn create_post_table(db: &DbConn) -> Result<ExecResult, DbErr> {
|
|||||||
.col(ColumnDef::new(post::Column::TeaOptional).string())
|
.col(ColumnDef::new(post::Column::TeaOptional).string())
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
|
||||||
create_table(db, &stmt).await;
|
let _result = create_table(db, &stmt).await;
|
||||||
|
|
||||||
let stmt = sea_query::Table::create()
|
let stmt = sea_query::Table::create()
|
||||||
.table(comment::Entity)
|
.table(comment::Entity)
|
||||||
|
@ -10,12 +10,13 @@ use std::fmt::Display;
|
|||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
|
#[actix_admin(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
#[sea_orm(column_type = "Text")]
|
#[sea_orm(column_type = "Text")]
|
||||||
pub text: String,
|
pub text: String,
|
||||||
pub tea_mandatory: Tea,
|
pub tea_mandatory: Tea,
|
||||||
#[actix_admin(inner_type=Tea)]
|
#[actix_admin()]
|
||||||
pub tea_optional: Option<Tea>,
|
pub tea_optional: Option<Tea>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user