diff --git a/diesel_compile_tests/tests/fail/table_without_primary_key.rs b/diesel_compile_tests/tests/fail/table_without_primary_key.rs new file mode 100644 index 000000000000..691c75b69242 --- /dev/null +++ b/diesel_compile_tests/tests/fail/table_without_primary_key.rs @@ -0,0 +1,10 @@ +#[macro_use] extern crate diesel; + +table! { + user { + user_id -> Integer, + name -> Text, + } +} + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/table_without_primary_key.stderr b/diesel_compile_tests/tests/fail/table_without_primary_key.stderr new file mode 100644 index 000000000000..832158cb7a6d --- /dev/null +++ b/diesel_compile_tests/tests/fail/table_without_primary_key.stderr @@ -0,0 +1,14 @@ +error: Neither an explict primary key found nor does an `id` column exist. + Consider explicitly defining a primary key. + For example for specifying `user_id` as primary key: + + table! { + user (user_id) { + user_id -> Integer, + name -> Text, + } + } + --> tests/fail/table_without_primary_key.rs:4:5 + | +4 | user { + | ^^^^ diff --git a/diesel_derives/src/table.rs b/diesel_derives/src/table.rs index 377004bc99b5..a0b372164408 100644 --- a/diesel_derives/src/table.rs +++ b/diesel_derives/src/table.rs @@ -44,12 +44,43 @@ pub(crate) fn expand(input: TableDecl) -> TokenStream { .collect::>(); let column_names = &column_names; let primary_key: TokenStream = match input.primary_keys.as_ref() { - None => { + None if column_names.contains(&&syn::Ident::new( + DEFAULT_PRIMARY_KEY_NAME, + proc_macro2::Span::call_site(), + )) => + { let id = syn::Ident::new(DEFAULT_PRIMARY_KEY_NAME, proc_macro2::Span::call_site()); parse_quote! { #id } } + None => { + let mut message = format!( + "Neither an explict primary key found nor does an `id` column exist.\n\ + Consider explicitly defining a primary key. \n\ + For example for specifying `{}` as primary key:\n\n\ + table! {{\n", + column_names[0], + ); + message += &format!("\t{table_name} ({}) {{\n", &column_names[0]); + for c in &input.column_defs { + let tpe = c + .tpe + .path + .segments + .iter() + .map(|p| p.ident.to_string()) + .collect::>() + .join("::"); + message += &format!("\t\t{} -> {tpe},\n", c.column_name); + } + message += "\t}\n}"; + + let span = input.table_name.span(); + return quote::quote_spanned! {span=> + compile_error!(#message); + }; + } Some(a) if a.keys.len() == 1 => { let k = a.keys.first().unwrap(); parse_quote! {