2828/// ```
2929#[ macro_export]
3030macro_rules! impl_Identifiable {
31- // Extract table name from meta item
31+ // Find table name in options
3232 (
3333 $( ( ) ) *
34- # [ table_name ( $table_name : ident) ]
35- $( $rest: tt) *
34+ $ ( # [ $option_name : ident $option_value : tt ] ) *
35+ $( pub ) * struct $ ( $rest: tt) *
3636 ) => {
37- impl_Identifiable! {
38- ( table_name = $table_name, )
39- $( $rest) *
37+ __diesel_find_option_with_name! {
38+ ( options = [ $( #[ $option_name $option_value] ) * ] , body = $( $rest) * ) ,
39+ option_name = table_name,
40+ args = [ $( #[ $option_name $option_value] ) * ] ,
41+ callback = impl_Identifiable,
4042 }
4143 } ;
4244
43- // Strip meta items that aren't table name
45+ // Next, find primary key name in options
4446 (
45- $ args: tt
46- # [ $ignore : meta ]
47- $ ( $rest : tt ) *
47+ ( options = $options : tt , $ ( $ args: tt) * ) ,
48+ found_option_with_name = table_name ,
49+ value = ( $table_name : ident ) ,
4850 ) => {
49- impl_Identifiable!( $args $( $rest) * ) ;
51+ __diesel_find_option_with_name! {
52+ ( options = $options, table_name = $table_name, $( $args) * ) ,
53+ option_name = primary_key,
54+ args = $options,
55+ callback = impl_Identifiable,
56+ default = ( id) ,
57+ }
5058 } ;
5159
52- // Strip pub (if present) and struct from definition
53- // After this step, we will go to the step at the bottom.
60+ // Options extracted, deal with the struct body (bottom two branches)
5461 (
55- $args: tt
56- $( pub ) * struct $( $body: tt) *
62+ (
63+ options = $ignore: tt,
64+ table_name = $table_name: ident,
65+ body = $( $body: tt) *
66+ ) ,
67+ found_option_with_name = primary_key,
68+ value = ( $primary_key_name: ident) ,
5769 ) => {
58- impl_Identifiable!( $args $( $body) * ) ;
70+ impl_Identifiable! {
71+ (
72+ table_name = $table_name,
73+ primary_key_name = $primary_key_name,
74+ )
75+ $( $body) *
76+ }
5977 } ;
6078
61- // We found the `id` field, return the final impl
79+ // We found the primary key field, return the final impl
6280 (
6381 (
6482 table_name = $table_name: ident,
6583 struct_ty = $struct_ty: ty,
6684 lifetimes = ( $( $lifetimes: tt) ,* ) ,
6785 ) ,
68- fields = [ {
69- field_name: id ,
86+ primary_key_field = {
87+ field_name: $field_name : ident ,
7088 column_name: $column_name: ident,
7189 field_ty: $field_ty: ty,
7290 field_kind: $field_kind: ident,
7391 $( $rest: tt) *
74- } $ ( $fields : tt ) * ] ,
92+ } ,
7593 ) => {
7694 impl <$( $lifetimes) ,* > $crate:: associations:: HasTable for $struct_ty {
7795 type Table = $table_name:: table;
@@ -85,25 +103,45 @@ macro_rules! impl_Identifiable {
85103 type Id = & ' ident $field_ty;
86104
87105 fn id( self ) -> Self :: Id {
88- & self . id
106+ & self . $field_name
89107 }
90108 }
91109 } ;
92110
93- // Search for the `id` field and continue
111+ // Search for the primary key field and continue
94112 (
95- $args: tt,
113+ (
114+ table_name = $table_name: ident,
115+ primary_key_name = $primary_key_name: ident,
116+ $( $args: tt) *
117+ ) ,
96118 fields = [ {
97119 field_name: $field_name: ident,
98- column_name: $column_name: ident,
99- field_ty: $field_ty: ty,
100- field_kind: $field_kind: ident,
101120 $( $rest: tt) *
102121 } $( $fields: tt) * ] ,
103122 ) => {
104- impl_Identifiable! {
105- $args,
106- fields = [ $( $fields) * ] ,
123+ static_cond! {
124+ if $primary_key_name == $field_name {
125+ impl_Identifiable! {
126+ (
127+ table_name = $table_name,
128+ $( $args) *
129+ ) ,
130+ primary_key_field = {
131+ field_name: $field_name,
132+ $( $rest) *
133+ } ,
134+ }
135+ } else {
136+ impl_Identifiable! {
137+ (
138+ table_name = $table_name,
139+ primary_key_name = $primary_key_name,
140+ $( $args) *
141+ ) ,
142+ fields = [ $( $fields) * ] ,
143+ }
144+ }
107145 }
108146 } ;
109147
@@ -253,3 +291,57 @@ fn derive_identifiable_on_struct_with_lifetime() {
253291 assert_eq ! ( & "hi" , foo1. id( ) ) ;
254292 assert_eq ! ( & "there" , foo2. id( ) ) ;
255293}
294+
295+ #[ test]
296+ fn derive_identifiable_with_non_standard_pk ( ) {
297+ use associations:: Identifiable ;
298+
299+ #[ allow( missing_debug_implementations, missing_copy_implementations, dead_code) ]
300+ struct Foo < ' a > {
301+ id : i32 ,
302+ foo_id : & ' a str ,
303+ foo : i32 ,
304+ }
305+
306+ impl_Identifiable ! {
307+ #[ table_name( bars) ]
308+ #[ primary_key( foo_id) ]
309+ struct Foo <' a> {
310+ id: i32 ,
311+ foo_id: & ' a str ,
312+ foo: i32 ,
313+ }
314+ }
315+
316+ let foo1 = Foo { id : 1 , foo_id : "hi" , foo : 2 } ;
317+ let foo2 = Foo { id : 2 , foo_id : "there" , foo : 3 } ;
318+ assert_eq ! ( & "hi" , foo1. id( ) ) ;
319+ assert_eq ! ( & "there" , foo2. id( ) ) ;
320+ }
321+
322+ #[ test]
323+ fn derive_identifiable_with_non_standard_pk_given_before_table_name ( ) {
324+ use associations:: Identifiable ;
325+
326+ #[ allow( missing_debug_implementations, missing_copy_implementations, dead_code) ]
327+ struct Foo < ' a > {
328+ id : i32 ,
329+ foo_id : & ' a str ,
330+ foo : i32 ,
331+ }
332+
333+ impl_Identifiable ! {
334+ #[ primary_key( foo_id) ]
335+ #[ table_name( bars) ]
336+ struct Foo <' a> {
337+ id: i32 ,
338+ foo_id: & ' a str ,
339+ foo: i32 ,
340+ }
341+ }
342+
343+ let foo1 = Foo { id : 1 , foo_id : "hi" , foo : 2 } ;
344+ let foo2 = Foo { id : 2 , foo_id : "there" , foo : 3 } ;
345+ assert_eq ! ( & "hi" , foo1. id( ) ) ;
346+ assert_eq ! ( & "there" , foo2. id( ) ) ;
347+ }
0 commit comments