Skip to content

Commit

Permalink
Merge pull request #4168 from Aethelflaed/identifiable-as
Browse files Browse the repository at this point in the history
Convert primary keys to serialize_as type
  • Loading branch information
weiznich authored Sep 7, 2024
2 parents 87fdeff + 2c842cf commit 158f113
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Increasing the minimal supported Rust version will always be coupled at least wi

### Added

* Fixed `#[derive(Identifiable)]` ignoring attribute `#[diesel(serialize_as)]` on primary keys
* Added embedded struct support for `AsChangeset` via `#[diesel(embed)]`
* Support for libsqlite3-sys 0.30.0
* Add support for built-in PostgreSQL range operators and functions
Expand Down
26 changes: 19 additions & 7 deletions diesel_derives/src/identifiable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use syn::parse_quote;
use syn::DeriveInput;
use syn::Result;

use crate::attrs::AttributeSpanWrapper;
use crate::field::Field;
use crate::model::Model;
use crate::util::wrap_in_dummy_mod;

Expand All @@ -21,9 +23,19 @@ pub fn derive(item: DeriveInput) -> Result<TokenStream> {
let mut field_ty = Vec::new();
let mut field_name = Vec::new();
for pk in model.primary_key_names.iter() {
let f = model.find_column(pk)?;
field_ty.push(&f.ty);
field_name.push(&f.name);
let Field {
ty,
name,
serialize_as,
..
} = &model.find_column(pk)?;
if let Some(AttributeSpanWrapper { item: ty, .. }) = serialize_as.as_ref() {
field_ty.push(quote!(#ty));
field_name.push(quote!(::std::convert::Into::<#ty>::into(self.#name.clone())));
} else {
field_ty.push(quote!(&'ident #ty));
field_name.push(quote!(&self.#name));
}
}

Ok(wrap_in_dummy_mod(quote! {
Expand All @@ -42,20 +54,20 @@ pub fn derive(item: DeriveInput) -> Result<TokenStream> {
impl #ref_generics Identifiable for &'ident #struct_name #ty_generics
#where_clause
{
type Id = (#(&'ident #field_ty),*);
type Id = (#(#field_ty),*);

fn id(self) -> Self::Id {
(#(&self.#field_name),*)
(#(#field_name),*)
}
}

impl #ref_generics Identifiable for &'_ &'ident #struct_name #ty_generics
#where_clause
{
type Id = (#(&'ident #field_ty),*);
type Id = (#(#field_ty),*);

fn id(self) -> Self::Id {
(#(&self.#field_name),*)
(#(#field_name),*)
}
}
}))
Expand Down
46 changes: 46 additions & 0 deletions diesel_derives/tests/identifiable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,49 @@ fn derive_identifiable_with_composite_pk() {
assert_eq!((&2, &3), foo1.id());
assert_eq!((&6, &7), foo2.id());
}

#[test]
fn derive_identifiable_with_pk_serialize_as() {
#[derive(Debug, PartialEq, Eq, Hash)]
struct MyI32(i32);

impl From<i32> for MyI32 {
fn from(value: i32) -> Self {
MyI32(value)
}
}

#[derive(Identifiable)]
struct Foo {
#[diesel(serialize_as = MyI32)]
id: i32,
}

let foo1 = Foo { id: 1 };
let foo2 = Foo { id: 2 };
assert_eq!(MyI32(1), foo1.id());
assert_eq!(MyI32(2), foo2.id());
}

#[test]
fn derive_identifiable_with_non_copy_pk_serialize() {
#[derive(Debug, PartialEq, Eq, Hash)]
struct MyString(String);

impl From<String> for MyString {
fn from(value: String) -> Self {
MyString(value)
}
}

#[derive(Identifiable)]
struct Foo {
#[diesel(serialize_as = MyString)]
id: String,
}

let foo1 = Foo { id: "1".to_owned() };
let foo2 = Foo { id: "2".to_owned() };
assert_eq!(MyString("1".to_owned()), foo1.id());
assert_eq!(MyString("2".to_owned()), foo2.id());
}

0 comments on commit 158f113

Please sign in to comment.