Skip to main content

diesel_derives/
field.rs

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