Skip to main content

diesel_derives/
field.rs

1use proc_macro2::{Span, TokenStream};
2use syn::spanned::Spanned;
3use syn::{Expr, Field as SynField, Ident, Index, Result, Type};
4
5use crate::attrs::{AttributeSpanWrapper, FieldAttr, SqlIdentifier, parse_attributes};
6
7pub struct Field {
8    pub ty: Type,
9    pub span: Span,
10    pub name: FieldName,
11    column_name: Option<AttributeSpanWrapper<SqlIdentifier>>,
12    pub sql_type: Option<AttributeSpanWrapper<Type>>,
13    pub treat_none_as_default_value: Option<AttributeSpanWrapper<bool>>,
14    pub treat_none_as_null: Option<AttributeSpanWrapper<bool>>,
15    pub serialize_as: Option<AttributeSpanWrapper<Type>>,
16    pub deserialize_as: Option<AttributeSpanWrapper<Type>>,
17    pub select_expression: Option<AttributeSpanWrapper<Expr>>,
18    pub select_expression_type: Option<AttributeSpanWrapper<Type>>,
19    pub embed: Option<AttributeSpanWrapper<bool>>,
20    pub skip_insertion: Option<AttributeSpanWrapper<bool>>,
21    pub skip_update: Option<AttributeSpanWrapper<bool>>,
22}
23
24impl Field {
25    pub fn from_struct_field(field: &SynField, index: usize) -> Result<Self> {
26        let SynField {
27            ident, attrs, ty, ..
28        } = field;
29
30        let mut column_name = None;
31        let mut sql_type = None;
32        let mut serialize_as = None;
33        let mut deserialize_as = None;
34        let mut embed = None;
35        let mut skip_insertion = None;
36        let mut skip_update = None;
37        let mut select_expression = None;
38        let mut select_expression_type = None;
39        let mut treat_none_as_default_value = None;
40        let mut treat_none_as_null = None;
41
42        for attr in parse_attributes(attrs)? {
43            let attribute_span = attr.attribute_span;
44            let ident_span = attr.ident_span;
45            match attr.item {
46                FieldAttr::ColumnName(_, value) => {
47                    column_name = Some(AttributeSpanWrapper {
48                        item: value,
49                        attribute_span,
50                        ident_span,
51                    })
52                }
53                FieldAttr::SqlType(_, value) => {
54                    sql_type = Some(AttributeSpanWrapper {
55                        item: Type::Path(value),
56                        attribute_span,
57                        ident_span,
58                    })
59                }
60                FieldAttr::TreatNoneAsDefaultValue(_, value) => {
61                    treat_none_as_default_value = Some(AttributeSpanWrapper {
62                        item: value.value,
63                        attribute_span,
64                        ident_span,
65                    })
66                }
67                FieldAttr::TreatNoneAsNull(_, value) => {
68                    treat_none_as_null = Some(AttributeSpanWrapper {
69                        item: value.value,
70                        attribute_span,
71                        ident_span,
72                    })
73                }
74                FieldAttr::SerializeAs(_, value) => {
75                    check_serde_as_supported_type(&value, "serialize_as")?;
76                    serialize_as = Some(AttributeSpanWrapper {
77                        item: value,
78                        attribute_span,
79                        ident_span,
80                    })
81                }
82                FieldAttr::DeserializeAs(_, value) => {
83                    check_serde_as_supported_type(&value, "deserialize_as")?;
84                    deserialize_as = Some(AttributeSpanWrapper {
85                        item: value,
86                        attribute_span,
87                        ident_span,
88                    })
89                }
90                FieldAttr::SelectExpression(_, value) => {
91                    select_expression = Some(AttributeSpanWrapper {
92                        item: value,
93                        attribute_span,
94                        ident_span,
95                    })
96                }
97                FieldAttr::SelectExpressionType(_, value) => {
98                    select_expression_type = Some(AttributeSpanWrapper {
99                        item: value,
100                        attribute_span,
101                        ident_span,
102                    })
103                }
104                FieldAttr::Embed(_) => {
105                    embed = Some(AttributeSpanWrapper {
106                        item: true,
107                        attribute_span,
108                        ident_span,
109                    })
110                }
111                FieldAttr::SkipInsertion(_) => {
112                    skip_insertion = Some(AttributeSpanWrapper {
113                        item: true,
114                        attribute_span,
115                        ident_span,
116                    })
117                }
118                FieldAttr::SkipUpdate(_) => {
119                    skip_update = Some(AttributeSpanWrapper {
120                        item: true,
121                        attribute_span,
122                        ident_span,
123                    })
124                }
125                FieldAttr::Rename(_, _) => { /*ignore here as only relevant for enums*/ }
126            }
127        }
128
129        let name = match ident.clone() {
130            Some(x) => FieldName::Named(x),
131            None => FieldName::Unnamed(index.into()),
132        };
133        let span = match name {
134            FieldName::Named(ref ident) => ident.span(),
135            FieldName::Unnamed(_) => ty.span(),
136        };
137        let span = Span::mixed_site().located_at(span);
138
139        Ok(Self {
140            ty: ty.clone(),
141            span,
142            name,
143            column_name,
144            sql_type,
145            treat_none_as_default_value,
146            treat_none_as_null,
147            serialize_as,
148            deserialize_as,
149            select_expression,
150            select_expression_type,
151            embed,
152            skip_insertion,
153            skip_update,
154        })
155    }
156
157    pub fn column_name(&self) -> Result<SqlIdentifier> {
158        let identifier = self.column_name.as_ref().map(|a| a.item.clone());
159        if let Some(identifier) = identifier {
160            Ok(identifier)
161        } else {
162            match self.name {
163                FieldName::Named(ref x) => Ok(x.into()),
164                FieldName::Unnamed(ref x) => Err(syn::Error::new(
165                    x.span(),
166                    "all fields of tuple structs must be annotated with `#[diesel(column_name)]`",
167                )),
168            }
169        }
170    }
171
172    pub fn ty_for_deserialize(&self) -> &Type {
173        if let Some(AttributeSpanWrapper { item: value, .. }) = &self.deserialize_as {
174            value
175        } else {
176            &self.ty
177        }
178    }
179
180    pub(crate) fn embed(&self) -> bool {
181        self.embed.as_ref().map(|a| a.item).unwrap_or(false)
182    }
183
184    pub(crate) fn skip_insertion(&self) -> bool {
185        self.skip_insertion
186            .as_ref()
187            .map(|a| a.item)
188            .unwrap_or(false)
189    }
190
191    pub(crate) fn skip_update(&self) -> bool {
192        self.skip_update.as_ref().map(|a| a.item).unwrap_or(false)
193    }
194}
195
196pub enum FieldName {
197    Named(Ident),
198    Unnamed(Index),
199}
200
201impl quote::ToTokens for FieldName {
202    fn to_tokens(&self, tokens: &mut TokenStream) {
203        match *self {
204            FieldName::Named(ref x) => x.to_tokens(tokens),
205            FieldName::Unnamed(ref x) => x.to_tokens(tokens),
206        }
207    }
208}
209
210fn check_serde_as_supported_type(ty: &Type, attr_name: &str) -> Result<()> {
211    match ty {
212        Type::Path(_) => Ok(()),
213        Type::Array(syn::TypeArray { elem, .. }) => check_serde_as_supported_type(elem, attr_name),
214        Type::Paren(syn::TypeParen { elem, .. }) | Type::Group(syn::TypeGroup { elem, .. }) => {
215            check_serde_as_supported_type(elem, attr_name)
216        }
217        Type::Tuple(syn::TypeTuple { elems, .. }) => elems
218            .iter()
219            .try_for_each(|ty| check_serde_as_supported_type(ty, attr_name)),
220        Type::Ptr(_) => Err(syn::Error::new_spanned(
221            ty,
222            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` does not support pointer types",
                attr_name))
    })format!("`{attr_name}` does not support pointer types"),
223        )),
224        Type::BareFn(_) => Err(syn::Error::new_spanned(
225            ty,
226            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` does not support function pointer types",
                attr_name))
    })format!("`{attr_name}` does not support function pointer types"),
227        )),
228        Type::Infer(_) => Err(syn::Error::new_spanned(
229            ty,
230            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` does not support inference types",
                attr_name))
    })format!("`{attr_name}` does not support inference types"),
231        )),
232
233        Type::Reference(_) => Err(syn::Error::new_spanned(
234            ty,
235            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` does not support reference types",
                attr_name))
    })format!("`{attr_name}` does not support reference types"),
236        )),
237        Type::Slice(_) => Err(syn::Error::new_spanned(
238            ty,
239            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` does not support unsized slice types, use an array instead",
                attr_name))
    })format!("`{attr_name}` does not support unsized slice types, use an array instead"),
240        )),
241        Type::TraitObject(_) => Err(syn::Error::new_spanned(
242            ty,
243            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` does not support trait objects",
                attr_name))
    })format!("`{attr_name}` does not support trait objects"),
244        )),
245        Type::Macro(_) => Err(syn::Error::new_spanned(
246            ty,
247            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("macro invocation is not supported in `{0}`",
                attr_name))
    })format!("macro invocation is not supported in `{attr_name}`"),
248        )),
249        Type::ImplTrait(_) => Err(syn::Error::new_spanned(
250            ty,
251            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` does not support impl trait types",
                attr_name))
    })format!("`{attr_name}` does not support impl trait types"),
252        )),
253        _ => Err(syn::Error::new_spanned(
254            ty,
255            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` does not support this type",
                attr_name))
    })format!("`{attr_name}` does not support this type"),
256        )),
257    }
258}