Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 5722ad0

Browse files
committedNov 16, 2024·
adding custom macro attributes for mapping fields
1 parent 13b71e2 commit 5722ad0

File tree

3 files changed

+49
-29
lines changed

3 files changed

+49
-29
lines changed
 

‎src/dto_builder.rs

+32-12
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,7 @@ fn build_into_fields(
138138

139139
// let selected_fields =
140140
// get_selected_fields(&st_entry, &ignore_fields, &map_fields);
141-
let selected_fields = if mp_entry.exactly && map_fields.len() == 0 && ignore_fields.len() == 0 {
142-
get_all_fields(&st_entry)
143-
} else {
144-
get_selected_fields(&st_entry, &ignore_fields, &map_fields)
145-
};
141+
let selected_fields = extract_selected_fields(&st_entry, mp_entry, &map_fields, &ignore_fields);
146142

147143
selected_fields
148144
.iter()
@@ -182,37 +178,61 @@ fn build_into_fields(
182178
.collect()
183179
}
184180

181+
fn extract_selected_fields(
182+
st_entry: &StructEntry,
183+
mp_entry: &MapperEntry,
184+
map_fields: &HashMap<String, MapValue>,
185+
ignore_fields: &HashSet<String>,
186+
) -> Vec<FieldEntry> {
187+
if mp_entry.exactly && map_fields.len() == 0 && ignore_fields.len() == 0 {
188+
get_all_fields(&st_entry)
189+
} else {
190+
get_selected_fields(&st_entry, &ignore_fields, &map_fields)
191+
}
192+
}
193+
185194
fn build_fields(st_entry: &StructEntry, mp_entry: &MapperEntry) -> Vec<TokenStream> {
186195
//we retrieve a hashmap of MapValue with key=source_field_name in the struct , and the the value as MapValue
187196
let map_fields = get_map_of_mapvalue(mp_entry);
188197

189198
// Let us retrieve the ignore fields
190199
let ignore_fields = get_ignore_fields(mp_entry);
191200

192-
let selected_fields = if mp_entry.exactly && map_fields.len() == 0 && ignore_fields.len() == 0 {
193-
get_all_fields(&st_entry)
194-
} else {
195-
get_selected_fields(&st_entry, &ignore_fields, &map_fields)
196-
};
201+
let selected_fields = extract_selected_fields(&st_entry, mp_entry, &map_fields, &ignore_fields);
197202

198203
let tk_stream_iterator = selected_fields.iter().map(|field| {
199204
let mut name = format!("{}", field.field_name.to_string());
200205
let mut name_ident = format_ident!("{}", name.as_str());
201206

202207
let ty = &field.field_type;
208+
209+
let mut attributes: Vec<TokenStream> = Vec::new();
210+
203211
if let Some(m_value) = map_fields.get(&name) {
204212
//let's rename the struct field if there is a mapping for it
205213
if let Some(ref new_name) = m_value.to_field {
206214
name = new_name.clone();
207215
name_ident = format_ident!("{}", name.as_str())
208216
}
209217

218+
attributes = m_value
219+
.macro_attr
220+
.iter()
221+
.map(|attr| parse_str(attr).unwrap())
222+
.collect();
223+
210224
if !m_value.required && !field.is_optional {
211-
return quote! { pub #name_ident: Option<#ty> };
225+
return quote! {
226+
#(#attributes)*
227+
pub #name_ident: Option<#ty>
228+
};
212229
}
213230
}
214231

215-
quote! { pub #name_ident: #ty }
232+
quote! {
233+
#(#attributes)*
234+
pub #name_ident: #ty
235+
}
216236
});
217237

218238
let mut struct_fields = tk_stream_iterator.collect::<Vec<TokenStream>>();

‎src/mapper_entry.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use syn::{
66
use crate::utils;
77
use crate::utils::isblank;
88

9-
pub type MapTuple = (String, bool);
9+
pub type MapTuple = (String, bool, Vec<String>);
1010
#[derive(Debug, Default)]
1111
pub struct MapperEntry {
1212
pub dto: String,
@@ -20,12 +20,13 @@ pub struct MapperEntry {
2020
}
2121

2222
//DataStructure for the type of mapper values found in each entry
23-
#[derive(Debug, Clone)]
23+
#[derive(Debug, Default, Clone)]
2424
pub struct MapValue {
2525
//Literal value are consited of properties with key=value
2626
// dto="MyDto" , ignore="true"
2727
pub from_field: String,
2828
pub to_field: Option<String>,
29+
pub macro_attr: Vec<String>,
2930
pub required: bool,
3031
}
3132

@@ -49,16 +50,6 @@ impl NewField {
4950
}
5051
}
5152

52-
impl Default for MapValue {
53-
fn default() -> Self {
54-
Self {
55-
from_field: "".into(),
56-
to_field: None,
57-
required: true,
58-
}
59-
}
60-
}
61-
6253
impl MapValue {
6354
fn new(map_tuple: &MapTuple) -> Self {
6455
let fields = map_tuple.0.as_str().split(":");
@@ -69,13 +60,15 @@ impl MapValue {
6960
if fields.len() > 1 && !fields[1].trim().is_empty() {
7061
to_field = Some(fields[1].trim().to_string());
7162
}
63+
let macro_attr: Vec<String> = map_tuple.2.clone();
7264

7365
let required = map_tuple.1;
7466

7567
Self {
7668
from_field,
7769
to_field,
7870
required,
71+
macro_attr,
7972
}
8073
}
8174
}
@@ -287,29 +280,36 @@ impl MapperEntry {
287280
}
288281

289282
fn parse_array_of_tuple(expr_arr: &ExprArray) -> Vec<MapTuple> {
290-
let mut vec_tuple: Vec<(String, bool)> = Vec::new();
283+
let mut vec_tuple: Vec<(String, bool, Vec<String>)> = Vec::new();
291284

292285
for elem in expr_arr.elems.iter() {
293286
if let Expr::Tuple(el_exp) = elem {
294287
//println!("{} content is a Tuple",keyname);
295288
let mut str_val: Option<String> = None;
296289
let mut flag: Option<bool> = None;
290+
let mut attrs: Vec<String> = Vec::new();
297291
for content_expr in el_exp.elems.iter() {
298292
if let Expr::Lit(content_lit) = content_expr {
299293
if let Lit::Str(content) = &content_lit.lit {
300294
//print!("valueStr={}",content.value());
301295
str_val = utils::remove_white_space(&content.value()).into();
302296
}
303297

298+
//There can only exist one boolean
304299
if let Lit::Bool(content) = &content_lit.lit {
305300
//print!(" valueBool={}",content.value());
306301
flag = content.value.into();
307302
}
308303
}
304+
305+
//this will parse macro attributes for mapped fields
306+
if let Expr::Array(content_arr) = content_expr {
307+
attrs = Self::parse_array_of_macro_attr(&content_arr);
308+
}
309309
}
310310

311311
if str_val.is_some() && flag.is_some() {
312-
let tuple: MapTuple = (str_val.unwrap(), flag.unwrap());
312+
let tuple: MapTuple = (str_val.unwrap(), flag.unwrap(), attrs);
313313
vec_tuple.push(tuple);
314314
}
315315
//println!("");

‎tests/test_dto_creation.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ mod test_dto_creation {
2222
#[mapper(
2323
dto="CustomDtoWithAttribute" ,
2424
no_builder=true ,
25-
map=[ ("email",false) ],
25+
map=[ ("email", false, ["#[serde(rename = \"email_address\")]"] ) ],
2626
derive=(Debug, Clone, Serialize, Deserialize),
2727
new_fields=[(
2828
"name: String",
2929
"concat_str( self.firstname.as_str(), self.lastname.as_str() )",
30-
["#[serde(rename = \"renamed_name\")]"],
30+
["#[serde(rename = \"full_name\")]"],
3131
)],
3232
macro_attr=["serde(rename_all = \"UPPERCASE\")"]
3333
)]
@@ -161,7 +161,7 @@ mod test_dto_creation {
161161
let json_string = serde_json::to_string(&custom_dto).unwrap();
162162
assert_eq!(
163163
json_string,
164-
r#"{"EMAIL":"Dessalines@gmail.com","renamed_name":"Jean Jacques"}"#
164+
r#"{"email_address":"Dessalines@gmail.com","full_name":"Jean Jacques"}"#
165165
);
166166
}
167167
}

0 commit comments

Comments
 (0)