diff options
Diffstat (limited to 'tosin-macros')
-rw-r--r-- | tosin-macros/src/lib.rs | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/tosin-macros/src/lib.rs b/tosin-macros/src/lib.rs index 7028274..c9e352c 100644 --- a/tosin-macros/src/lib.rs +++ b/tosin-macros/src/lib.rs @@ -18,7 +18,9 @@ pub fn model_derive(input: TokenStream) -> TokenStream { impl_model(&ast) } -fn to_field_spec(field: &syn::Field) -> impl quote::ToTokens { +// TODO clean all this shit up + +fn to_field_spec(field: &syn::Field) -> (impl quote::ToTokens, impl quote::ToTokens) { fn parse_type(ty: &str) -> syn::Type { syn::parse_str(ty).unwrap() } @@ -39,24 +41,42 @@ fn to_field_spec(field: &syn::Field) -> impl quote::ToTokens { }) .collect(); if field_type == &parse_type("Option<Id>") { - quote! { ::tosin::db::models::Field::IntField { name: stringify!(#field_name) } } + ( + quote! { ::tosin::db::models::Field::IntField { name: stringify!(#field_name) } }, + quote! { #field_name -> Integer } + ) } else if field_type == &parse_type("Id") { // TODO foreign key constraint - quote! { ::tosin::db::models::Field::IntField { name: stringify!(#field_name) } } + ( + quote! { ::tosin::db::models::Field::IntField { name: stringify!(#field_name) } }, + quote! { #field_name -> Integer } + ) } else if field_type == &parse_type("usize") { // TODO default - quote! { ::tosin::db::models::Field::IntField { name: stringify!(#field_name) } } + ( + quote! { ::tosin::db::models::Field::IntField { name: stringify!(#field_name) } }, + quote! { #field_name -> Integer } + ) } else if field_type == &parse_type("String") { let max_length = model_options.iter() .find(|(name, _value)| name.get_ident().map_or(false, |path| path == "max_length")) .map(|(_name, value)| value); if let Some(max_length) = max_length { - quote! { ::tosin::db::models::Field::CharField { name: stringify!(#field_name), max_length: Some(#max_length) } } + ( + quote! { ::tosin::db::models::Field::CharField { name: stringify!(#field_name), max_length: Some(#max_length) } }, + quote! { #field_name -> Text } + ) } else { - quote! { ::tosin::db::models::Field::CharField { name: stringify!(#field_name), max_length: None } } + ( + quote! { ::tosin::db::models::Field::CharField { name: stringify!(#field_name), max_length: None } }, + quote! { #field_name -> Text } + ) } } else if field_type == &parse_type("time::PrimitiveDateTime") { - quote! { ::tosin::db::models::Field::DateTimeField { name: stringify!(#field_name) } } + ( + quote! { ::tosin::db::models::Field::DateTimeField { name: stringify!(#field_name) } }, + quote! { #field_name -> Timestamp } + ) } else { use quote::ToTokens; panic!("can't handle {}", field.to_token_stream()) @@ -65,19 +85,27 @@ fn to_field_spec(field: &syn::Field) -> impl quote::ToTokens { fn impl_model(ast: &syn::DeriveInput) -> TokenStream { let name = &ast.ident; - let fields = if let syn::Data::Struct(ast) = &ast.data { - ast.fields.iter() - .map(to_field_spec) + let lowercase_name = quote::format_ident!("{}", name.to_string().to_lowercase()); + let ast_data = if let syn::Data::Struct(ast_data) = &ast.data { + ast_data } else { panic!("not on a struct"); }; + let (tosin_fields, diesel_columns): (Vec<_>, Vec<_>) = ast_data.fields.iter().map(to_field_spec).unzip(); let gen = quote! { impl #name { pub const META: ::tosin::db::models::ModelMeta = ::tosin::db::models::ModelMeta { name: stringify!(#name), - fields: &[ #(#fields),* ], + fields: &[ #(#tosin_fields),* ], }; } + + // this means users need #[macro_use] extern crate diesel; but fuck doing it ourselves + table! { + #lowercase_name { + #(#diesel_columns,)* + } + } }; gen.into() } |