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 }
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}