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(_, _) => { }
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}