aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMelody Horn / boringcactus <melody@boringcactus.com>2021-06-19 23:10:53 -0600
committerMelody Horn / boringcactus <melody@boringcactus.com>2021-06-19 23:10:53 -0600
commit88d527d574567420d7aa72f37205bd6b345b8dd7 (patch)
tree4cbec62f262d29c88b15df02e1d37f003991d99e
parentf2009f7135f92959e919a85a02584d7a0d7b8e47 (diff)
downloadtosin-88d527d574567420d7aa72f37205bd6b345b8dd7.tar.gz
tosin-88d527d574567420d7aa72f37205bd6b345b8dd7.zip
generate diesel::table! in derive(Model)
-rw-r--r--examples/tutorial01/main.rs2
-rw-r--r--examples/tutorial02/main.rs2
-rw-r--r--src/bin/tosin-admin.rs5
-rw-r--r--src/db/mod.rs3
-rw-r--r--tests/tutorial/mod.rs7
-rw-r--r--tosin-macros/src/lib.rs50
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<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()
}