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::{parse_attributes, AttributeSpanWrapper, FieldAttr, SqlIdentifier};
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                    serialize_as = Some(AttributeSpanWrapper {
76                        item: Type::Path(value),
77                        attribute_span,
78                        ident_span,
79                    })
80                }
81                FieldAttr::DeserializeAs(_, value) => {
82                    deserialize_as = Some(AttributeSpanWrapper {
83                        item: Type::Path(value),
84                        attribute_span,
85                        ident_span,
86                    })
87                }
88                FieldAttr::SelectExpression(_, value) => {
89                    select_expression = Some(AttributeSpanWrapper {
90                        item: value,
91                        attribute_span,
92                        ident_span,
93                    })
94                }
95                FieldAttr::SelectExpressionType(_, value) => {
96                    select_expression_type = Some(AttributeSpanWrapper {
97                        item: value,
98                        attribute_span,
99                        ident_span,
100                    })
101                }
102                FieldAttr::Embed(_) => {
103                    embed = Some(AttributeSpanWrapper {
104                        item: true,
105                        attribute_span,
106                        ident_span,
107                    })
108                }
109                FieldAttr::SkipInsertion(_) => {
110                    skip_insertion = Some(AttributeSpanWrapper {
111                        item: true,
112                        attribute_span,
113                        ident_span,
114                    })
115                }
116                FieldAttr::SkipUpdate(_) => {
117                    skip_update = Some(AttributeSpanWrapper {
118                        item: true,
119                        attribute_span,
120                        ident_span,
121                    })
122                }
123            }
124        }
125
126        let name = match ident.clone() {
127            Some(x) => FieldName::Named(x),
128            None => FieldName::Unnamed(index.into()),
129        };
130
131        let span = match name {
132            FieldName::Named(ref ident) => ident.span(),
133            FieldName::Unnamed(_) => ty.span(),
134        };
135
136        Ok(Self {
137            ty: ty.clone(),
138            span,
139            name,
140            column_name,
141            sql_type,
142            treat_none_as_default_value,
143            treat_none_as_null,
144            serialize_as,
145            deserialize_as,
146            select_expression,
147            select_expression_type,
148            embed,
149            skip_insertion,
150            skip_update,
151        })
152    }
153
154    pub fn column_name(&self) -> Result<SqlIdentifier> {
155        let identifier = self.column_name.as_ref().map(|a| a.item.clone());
156        if let Some(identifier) = identifier {
157            Ok(identifier)
158        } else {
159            match self.name {
160                FieldName::Named(ref x) => Ok(x.into()),
161                FieldName::Unnamed(ref x) => Err(syn::Error::new(
162                    x.span(),
163                    "All fields of tuple structs must be annotated with `#[diesel(column_name)]`",
164                )),
165            }
166        }
167    }
168
169    pub fn ty_for_deserialize(&self) -> &Type {
170        if let Some(AttributeSpanWrapper { item: value, .. }) = &self.deserialize_as {
171            value
172        } else {
173            &self.ty
174        }
175    }
176
177    pub(crate) fn embed(&self) -> bool {
178        self.embed.as_ref().map(|a| a.item).unwrap_or(false)
179    }
180
181    pub(crate) fn skip_insertion(&self) -> bool {
182        self.skip_insertion
183            .as_ref()
184            .map(|a| a.item)
185            .unwrap_or(false)
186    }
187
188    pub(crate) fn skip_update(&self) -> bool {
189        self.skip_update.as_ref().map(|a| a.item).unwrap_or(false)
190    }
191}
192
193pub enum FieldName {
194    Named(Ident),
195    Unnamed(Index),
196}
197
198impl quote::ToTokens for FieldName {
199    fn to_tokens(&self, tokens: &mut TokenStream) {
200        match *self {
201            FieldName::Named(ref x) => x.to_tokens(tokens),
202            FieldName::Unnamed(ref x) => x.to_tokens(tokens),
203        }
204    }
205}