From 88d527d574567420d7aa72f37205bd6b345b8dd7 Mon Sep 17 00:00:00 2001 From: Melody Horn / boringcactus Date: Sat, 19 Jun 2021 23:10:53 -0600 Subject: generate diesel::table! in derive(Model) --- examples/tutorial01/main.rs | 2 ++ examples/tutorial02/main.rs | 2 ++ src/bin/tosin-admin.rs | 5 ++++- src/db/mod.rs | 3 +++ tests/tutorial/mod.rs | 7 +++++++ tosin-macros/src/lib.rs | 50 +++++++++++++++++++++++++++++++++++---------- 6 files changed, 57 insertions(+), 12 deletions(-) diff --git a/examples/tutorial01/main.rs b/examples/tutorial01/main.rs index 7426ab7..52ae922 100644 --- a/examples/tutorial01/main.rs +++ b/examples/tutorial01/main.rs @@ -1,3 +1,5 @@ +#[macro_use] extern crate diesel; + use tosin::Settings; use tosin::contrib::admin; use tosin::db::backend::Connectable; diff --git a/examples/tutorial02/main.rs b/examples/tutorial02/main.rs index 0f8dc11..8f0eebe 100644 --- a/examples/tutorial02/main.rs +++ b/examples/tutorial02/main.rs @@ -1,3 +1,5 @@ +#[macro_use] extern crate diesel; + use tosin::Settings; use tosin::contrib::admin; use tosin::db::backend::Connectable; diff --git a/src/bin/tosin-admin.rs b/src/bin/tosin-admin.rs index 4ca2d15..034e4a9 100644 --- a/src/bin/tosin-admin.rs +++ b/src/bin/tosin-admin.rs @@ -6,8 +6,11 @@ use std::process::Command; use structopt::StructOpt; -const TOSIN_DEPENDENCY: &str = concat!(r#"tosin = { path = ""#, env!("CARGO_MANIFEST_DIR"), r#"" }"#); +const TOSIN_DEPENDENCY: &str = concat!(r#"tosin = { path = ""#, env!("CARGO_MANIFEST_DIR"), r#"" } +diesel = { version = "1.4.4", features = ["sqlite"] }"#); const PROJECT_MAIN: &str = r#" +#[macro_use] extern crate diesel; + use tosin::Settings; use tosin::contrib::admin; use tosin::db::backend::Connectable; diff --git a/src/db/mod.rs b/src/db/mod.rs index 05c38df..e04fe06 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,3 +1,6 @@ pub mod backend; pub mod migration; pub mod models; + +pub use diesel::*; +pub use diesel::backend as diesel_backend; diff --git a/tests/tutorial/mod.rs b/tests/tutorial/mod.rs index b26aa39..25f251b 100644 --- a/tests/tutorial/mod.rs +++ b/tests/tutorial/mod.rs @@ -117,6 +117,8 @@ pub fn urls() -> UrlMap { // update main.rs fs::write("src/main.rs", r#" +#[macro_use] extern crate diesel; + use tosin::Settings; use tosin::contrib::admin; use tosin::db::backend::Connectable; @@ -174,6 +176,8 @@ pub fn step2() { step1(); // update main.rs fs::write("src/main.rs", r#" +#[macro_use] extern crate diesel; + use tosin::Settings; use tosin::contrib::admin; use tosin::db::backend::Connectable; @@ -217,6 +221,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +diesel = { version = "1.4.4", features = ["sqlite"] } time = "0.2.27" tosin = { path = "/home/cactus/Documents/tosin" } "#).unwrap(); @@ -250,6 +255,8 @@ gather!(); // update main.rs fs::write("src/main.rs", r#" +#[macro_use] extern crate diesel; + use tosin::Settings; use tosin::contrib::admin; use tosin::db::backend::Connectable; 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") { - 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() } -- cgit v1.2.3