From 10f8e4201490723c51156797f8c6f244991c0c04 Mon Sep 17 00:00:00 2001 From: yagince Date: Wed, 20 Dec 2023 00:11:05 +0900 Subject: [PATCH] Add `DontImplCloneOnSqlType` attribute. Because, if schema definitions are separated into other crate, implementing Clone for ExistingType will happen compile error. cf. https://github.com/adwhit/diesel-derive-enum/issues/93 --- src/lib.rs | 20 ++++++++++++++++++-- tests/src/lib.rs | 2 ++ tests/src/pg_clone_impl.rs | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 tests/src/pg_clone_impl.rs diff --git a/src/lib.rs b/src/lib.rs index 7664e3e..dee8958 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,7 +31,14 @@ use syn::*; /// * `#[db_rename = "variant"]` specifies the db name for a specific variant. #[proc_macro_derive( DbEnum, - attributes(PgType, DieselType, ExistingTypePath, DbValueStyle, db_rename) + attributes( + PgType, + DieselType, + ExistingTypePath, + DbValueStyle, + db_rename, + DontImplCloneOnSqlType + ) )] pub fn derive(input: TokenStream) -> TokenStream { let input: DeriveInput = parse_macro_input!(input as DeriveInput); @@ -70,6 +77,9 @@ pub fn derive(input: TokenStream) -> TokenStream { .expect("ExistingTypePath is not a valid token") }); let new_diesel_mapping = Ident::new(new_diesel_mapping.as_ref(), Span::call_site()); + + let with_clone = !contains_in_attrs(&input.attrs, "DontImplCloneOnSqlType"); + if let Data::Enum(syn::DataEnum { variants: data_variants, .. @@ -81,6 +91,7 @@ pub fn derive(input: TokenStream) -> TokenStream { &pg_internal_type, case_style, &input.ident, + with_clone, &data_variants, ) } else { @@ -115,6 +126,10 @@ fn val_from_attrs(attrs: &[Attribute], attrname: &str) -> Option { None } +fn contains_in_attrs(attrs: &[Attribute], attrname: &str) -> bool { + attrs.iter().any(|e| e.path().is_ident(attrname)) +} + /// Defines the casing for the database representation. Follows serde naming convention. #[derive(Copy, Clone, Debug, PartialEq)] enum CaseStyle { @@ -148,6 +163,7 @@ fn generate_derive_enum_impls( pg_internal_type: &str, case_style: CaseStyle, enum_ty: &Ident, + with_clone: bool, variants: &syn::punctuated::Punctuated, ) -> TokenStream { let modname = Ident::new(&format!("db_enum_impl_{}", enum_ty), Span::call_site()); @@ -201,7 +217,7 @@ fn generate_derive_enum_impls( match existing_mapping_path { Some(path) => { let common_impls_on_existing_diesel_mapping = generate_common_impls(path, enum_ty); - let postgres_impl = generate_postgres_impl(path, enum_ty, true); + let postgres_impl = generate_postgres_impl(path, enum_ty, with_clone); Some(quote! { #common_impls_on_existing_diesel_mapping #postgres_impl diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 19a2fa1..e9ee188 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -9,6 +9,8 @@ mod nullable; #[cfg(feature = "postgres")] mod pg_array; #[cfg(feature = "postgres")] +mod pg_clone_impl; +#[cfg(feature = "postgres")] mod pg_remote_type; mod simple; mod value_style; diff --git a/tests/src/pg_clone_impl.rs b/tests/src/pg_clone_impl.rs new file mode 100644 index 0000000..184208a --- /dev/null +++ b/tests/src/pg_clone_impl.rs @@ -0,0 +1,35 @@ +use diesel::prelude::*; + +#[cfg(feature = "postgres")] +#[derive(diesel::sql_types::SqlType)] +#[diesel(postgres_type(name = "my_remote_enum"))] +pub struct MyRemoteEnumMapping; + +table! { + use diesel::sql_types::Integer; + use super::MyRemoteEnumMapping; + test_remote { + id -> Integer, + my_enum -> MyRemoteEnumMapping, + } +} + +#[derive(Insertable, Queryable, Identifiable, Debug, Clone, PartialEq)] +#[diesel(table_name = test_remote)] +struct Data { + id: i32, + my_enum: MyRemoteEnum, +} + +#[derive(Debug, PartialEq, Clone, diesel_derive_enum::DbEnum)] +#[ExistingTypePath = "MyRemoteEnumMapping"] +pub enum MyRemoteEnum { + This, + That, +} + +#[test] +fn clone_impl_on_sql_type() { + let x = MyRemoteEnumMapping {}; + let _ = x.clone(); +}