From 709eb44ccb8d08ad7f26cdac2932eadc7ccd48e7 Mon Sep 17 00:00:00 2001 From: Melody Horn / boringcactus Date: Fri, 18 Jun 2021 10:12:16 -0600 Subject: make model metadata available in AppConfig --- examples/tutorial01/polls/mod.rs | 2 ++ examples/tutorial01/polls/models.rs | 5 ++++- examples/tutorial02/polls/mod.rs | 1 + examples/tutorial02/polls/models.rs | 4 +++- src/apps.rs | 2 ++ src/bin/tosin-admin.rs | 7 ++++++- src/contrib/admin/mod.rs | 2 ++ src/contrib/admin/models.rs | 6 ++++++ src/db/models/meta.rs | 3 +++ src/db/models/mod.rs | 5 ++++- tests/tutorial/mod.rs | 4 +++- tosin-macros/src/lib.rs | 41 ++++++++++++++++++++++++++++++++++--- 12 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 src/contrib/admin/models.rs create mode 100644 src/db/models/meta.rs diff --git a/examples/tutorial01/polls/mod.rs b/examples/tutorial01/polls/mod.rs index 0b039d9..d15a1ca 100644 --- a/examples/tutorial01/polls/mod.rs +++ b/examples/tutorial01/polls/mod.rs @@ -7,7 +7,9 @@ pub mod views; pub use urls::urls; +#[allow(dead_code)] pub const APP: AppConfig = AppConfig { name: module_path!(), + models: models::ALL, migrations: migrations::migrations, }; diff --git a/examples/tutorial01/polls/models.rs b/examples/tutorial01/polls/models.rs index 82aa7fd..bc1cd9b 100644 --- a/examples/tutorial01/polls/models.rs +++ b/examples/tutorial01/polls/models.rs @@ -1,3 +1,6 @@ -use tosin::db::models::{Model, Id}; +#[allow(unused_imports)] +use tosin::db::models::{Model, Id, gather}; // TODO define models + +gather!(); diff --git a/examples/tutorial02/polls/mod.rs b/examples/tutorial02/polls/mod.rs index 0b039d9..1968d5a 100644 --- a/examples/tutorial02/polls/mod.rs +++ b/examples/tutorial02/polls/mod.rs @@ -9,5 +9,6 @@ pub use urls::urls; pub const APP: AppConfig = AppConfig { name: module_path!(), + models: models::ALL, migrations: migrations::migrations, }; diff --git a/examples/tutorial02/polls/models.rs b/examples/tutorial02/polls/models.rs index 5ed52c5..fb8be8f 100644 --- a/examples/tutorial02/polls/models.rs +++ b/examples/tutorial02/polls/models.rs @@ -1,4 +1,4 @@ -use tosin::db::models::{Model, Id}; +use tosin::db::models::{Model, Id, gather}; #[derive(Model)] pub struct Question { @@ -19,3 +19,5 @@ pub struct Choice { #[model(default = 0)] votes: usize, } + +gather!(); diff --git a/src/apps.rs b/src/apps.rs index f72a883..8c16136 100644 --- a/src/apps.rs +++ b/src/apps.rs @@ -1,6 +1,8 @@ use crate::db::migration::Migration; +use crate::db::models::ModelMeta; pub struct AppConfig { pub name: &'static str, + pub models: &'static [ModelMeta], pub migrations: &'static [Migration], } diff --git a/src/bin/tosin-admin.rs b/src/bin/tosin-admin.rs index 0a359d3..a0ea850 100644 --- a/src/bin/tosin-admin.rs +++ b/src/bin/tosin-admin.rs @@ -38,8 +38,10 @@ pub mod views; pub use urls::urls; +#[allow(dead_code)] pub const APP: AppConfig = AppConfig { name: module_path!(), + models: models::ALL, migrations: migrations::migrations, }; "#; @@ -49,9 +51,12 @@ use tosin::db::migration::{Migration, gather}; gather!(); "#; const APP_MODELS: &str = r#" -use tosin::db::models::{Model, Id}; +#[allow(unused_imports)] +use tosin::db::models::{Model, Id, gather}; // TODO define models + +gather!(); "#; const APP_URLS: &str = r#" use tosin::urls::{UrlMap, url_map}; diff --git a/src/contrib/admin/mod.rs b/src/contrib/admin/mod.rs index f92e709..8572f8d 100644 --- a/src/contrib/admin/mod.rs +++ b/src/contrib/admin/mod.rs @@ -1,9 +1,11 @@ use crate::apps::AppConfig; mod migrations; +mod models; pub mod site; pub const APP: AppConfig = AppConfig { name: module_path!(), + models: models::ALL, migrations: migrations::migrations, }; diff --git a/src/contrib/admin/models.rs b/src/contrib/admin/models.rs new file mode 100644 index 0000000..7fde44a --- /dev/null +++ b/src/contrib/admin/models.rs @@ -0,0 +1,6 @@ +#[allow(unused_imports)] +use crate::db::models::{Model, Id, ModelMeta}; + +pub const ALL: &[ModelMeta] = &[ + +]; diff --git a/src/db/models/meta.rs b/src/db/models/meta.rs new file mode 100644 index 0000000..50729a8 --- /dev/null +++ b/src/db/models/meta.rs @@ -0,0 +1,3 @@ +pub struct ModelMeta { + pub name: &'static str, +} diff --git a/src/db/models/mod.rs b/src/db/models/mod.rs index 492df92..feadb43 100644 --- a/src/db/models/mod.rs +++ b/src/db/models/mod.rs @@ -1,4 +1,7 @@ -pub use tosin_macros::Model; +pub use tosin_macros::{Model, gather_models as gather}; + +mod meta; +pub use meta::*; pub type Id = usize; diff --git a/tests/tutorial/mod.rs b/tests/tutorial/mod.rs index 0bd626e..fb05066 100644 --- a/tests/tutorial/mod.rs +++ b/tests/tutorial/mod.rs @@ -223,7 +223,7 @@ tosin = { path = "/home/cactus/Documents/tosin" } // update polls/models.rs fs::write("src/polls/models.rs", r#" -use tosin::db::models::{Model, Id}; +use tosin::db::models::{Model, Id, gather}; #[derive(Model)] pub struct Question { @@ -244,6 +244,8 @@ pub struct Choice { #[model(default = 0)] votes: usize, } + +gather!(); "#).unwrap(); // update main.rs diff --git a/tosin-macros/src/lib.rs b/tosin-macros/src/lib.rs index 7efbac6..408378f 100644 --- a/tosin-macros/src/lib.rs +++ b/tosin-macros/src/lib.rs @@ -2,6 +2,8 @@ extern crate proc_macro; +use std::fs; + use proc_macro::TokenStream; use quote::quote; @@ -19,9 +21,9 @@ fn impl_model(ast: &syn::DeriveInput) -> TokenStream { let name = &ast.ident; let gen = quote! { impl #name { - fn hello_macro() { - println!("Hello, Macro! My name is {}!", stringify!(#name)); - } + pub const META: tosin::db::models::ModelMeta = tosin::db::models::ModelMeta { + name: stringify!(#name), + }; } }; gen.into() @@ -55,3 +57,36 @@ pub fn gather_migrations(_input: TokenStream) -> TokenStream { gen.into() } + +#[proc_macro] +pub fn gather_models(_input: TokenStream) -> TokenStream { + let call_site = proc_macro::Span::call_site(); + let call_site_file = call_site.source_file(); + let call_site_path = call_site_file.path(); + if !call_site_file.is_real() { + panic!("call site does not have a real path"); + } + + let call_site_ast = syn::parse_file(&fs::read_to_string(call_site_path).unwrap()).unwrap(); + let models = call_site_ast.items.iter() + .filter_map(|item| if let syn::Item::Struct(item) = item { Some(item) } else { None }) + .filter(|item| item.attrs.iter().any(|attr| { + let attr = if let Ok(syn::Meta::List(attr)) = attr.parse_meta() { attr } else { return false; }; + if attr.path.get_ident().map_or(false, |hopefully_derive| hopefully_derive == "derive") { + let mut derived = attr.nested.iter() + .filter_map(|derived| if let syn::NestedMeta::Meta(derived) = derived { Some(derived) } else { None }); + derived.any(|derived| derived.path().get_ident().map_or(false, |hopefully_model| hopefully_model == "Model")) + } else { + false + } + })) + .map(|item| &item.ident); + + let gen = quote! { + pub const ALL: &[tosin::db::models::ModelMeta] = &[ + #(#models::META),* + ]; + }; + + gen.into() +} -- cgit v1.2.3