Skip to main content

diesel_derives/
as_changeset.rs

1use std::collections::{HashMap, HashSet};
2
3use proc_macro2::{Span, TokenStream};
4use quote::{quote, quote_spanned};
5use syn::spanned::Spanned as _;
6use syn::{DeriveInput, Expr, Path, Result, Type, parse_quote};
7
8use crate::attrs::AttributeSpanWrapper;
9use crate::field::Field;
10use crate::model::Model;
11use crate::util::{inner_of_option_ty, is_option_ty, wrap_in_dummy_mod};
12
13pub fn derive(item: DeriveInput) -> Result<TokenStream> {
14    let model = Model::from_item(&item, false, false)?;
15
16    let struct_name = &item.ident;
17    let table_name = &model.table_names()[0];
18
19    let fields_for_update = model
20        .fields()
21        .iter()
22        .filter(|f| {
23            !model
24                .primary_key_names
25                .iter()
26                .any(|p| f.column_name().map(|f| f == *p).unwrap_or_default())
27        })
28        .collect::<Vec<_>>();
29
30    if fields_for_update.is_empty() {
31        return Err(syn::Error::new(
32            proc_macro2::Span::mixed_site(),
33            "deriving `AsChangeset` on a structure that only contains primary keys isn't supported.\n\
34             help: if you want to change the primary key of a row, you should do so with `.set(table::id.eq(new_id))`.\n\
35             note: `#[derive(AsChangeset)]` never changes the primary key of a row.",
36        ));
37    }
38
39    let treat_none_as_null = model.treat_none_as_null();
40
41    let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
42
43    let mut generate_borrowed_changeset = true;
44
45    let mut direct_field_ty = Vec::with_capacity(fields_for_update.len());
46    let mut direct_field_assign = Vec::with_capacity(fields_for_update.len());
47    let mut ref_field_ty = Vec::with_capacity(fields_for_update.len());
48    let mut ref_field_assign = Vec::with_capacity(fields_for_update.len());
49
50    // Explicit trait bounds to improve error messages
51    let mut field_ty_bounds = Vec::with_capacity(model.fields().len());
52    let mut borrowed_field_ty_bounds = Vec::with_capacity(model.fields().len());
53    let mut field_ty_bounds_guard = HashMap::new();
54    let mut borrowed_field_ty_bounds_guard = HashMap::new();
55
56    for field in fields_for_update {
57        // skip this field while generating the update
58        if field.skip_update() {
59            continue;
60        }
61        // Use field-level attr. with fallback to the struct-level one.
62        let treat_none_as_null = match &field.treat_none_as_null {
63            Some(attr) => {
64                if let Some(embed) = &field.embed {
65                    return Err(syn::Error::new(
66                        embed.attribute_span,
67                        "`embed` and `treat_none_as_default_value` are mutually exclusive",
68                    ));
69                }
70
71                if !is_option_ty(&field.ty) {
72                    return Err(syn::Error::new(
73                        field.ty.span(),
74                        "expected `treat_none_as_null` field to be of type `Option<_>`",
75                    ));
76                }
77
78                attr.item
79            }
80            None => treat_none_as_null,
81        };
82
83        match (field.serialize_as.as_ref(), field.embed()) {
84            (Some(AttributeSpanWrapper { item: ty, .. }), false) => {
85                direct_field_ty.push(field_changeset_ty_serialize_as(
86                    field,
87                    table_name,
88                    ty,
89                    treat_none_as_null,
90                )?);
91                direct_field_assign.push(field_changeset_expr_serialize_as(
92                    field,
93                    table_name,
94                    ty,
95                    treat_none_as_null,
96                )?);
97                field_ty_bounds.push(generate_field_bound(
98                    field,
99                    table_name,
100                    Some(ty),
101                    None,
102                    &mut field_ty_bounds_guard,
103                    treat_none_as_null,
104                )?);
105
106                generate_borrowed_changeset = false; // as soon as we hit one field with #[diesel(serialize_as)] there is no point in generating the impl of AsChangeset for borrowed structs
107            }
108            (Some(AttributeSpanWrapper { attribute_span, .. }), true) => {
109                return Err(syn::Error::new(
110                    *attribute_span,
111                    "`#[diesel(embed)]` cannot be combined with `#[diesel(serialize_as)]`",
112                ));
113            }
114            (None, true) => {
115                direct_field_ty.push(field_changeset_ty_embed(field, None));
116                direct_field_assign.push(field_changeset_expr_embed(field, None));
117                ref_field_ty.push(field_changeset_ty_embed(field, Some({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_lifetime(&mut _s, "\'update");
    _s
}quote!(&'update))));
118                ref_field_assign.push(field_changeset_expr_embed(field, Some({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_and(&mut _s);
    _s
}quote!(&))));
119            }
120            (None, false) => {
121                direct_field_ty.push(field_changeset_ty(
122                    field,
123                    table_name,
124                    None,
125                    treat_none_as_null,
126                )?);
127                direct_field_assign.push(field_changeset_expr(
128                    field,
129                    table_name,
130                    None,
131                    treat_none_as_null,
132                )?);
133                ref_field_ty.push(field_changeset_ty(
134                    field,
135                    table_name,
136                    Some({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_lifetime(&mut _s, "\'update");
    _s
}quote!(&'update)),
137                    treat_none_as_null,
138                )?);
139                ref_field_assign.push(field_changeset_expr(
140                    field,
141                    table_name,
142                    Some({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_and(&mut _s);
    _s
}quote!(&)),
143                    treat_none_as_null,
144                )?);
145
146                field_ty_bounds.push(generate_field_bound(
147                    field,
148                    table_name,
149                    None,
150                    None,
151                    &mut field_ty_bounds_guard,
152                    treat_none_as_null,
153                )?);
154
155                borrowed_field_ty_bounds.push(generate_field_bound(
156                    field,
157                    table_name,
158                    None,
159                    Some(::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_lifetime(&mut _s, "\'update");
        _s
    })parse_quote!('update)),
160                    &mut borrowed_field_ty_bounds_guard,
161                    treat_none_as_null,
162                )?);
163            }
164        }
165    }
166
167    let field_ty_bounds = field_ty_bounds
168        .into_iter()
169        .filter_map(|(type_to_check, bound)| {
170            super::insertable::filter_bounds(&field_ty_bounds_guard, type_to_check, bound)
171        });
172
173    let tpe_lifetimes = item.generics.lifetimes();
174
175    let changeset_owned = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "fn");
    ::quote::__private::push_ident(&mut _s, "_check_owned");
    ::quote::__private::push_lt(&mut _s);
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut tpe_lifetimes, i) = tpe_lifetimes.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let tpe_lifetimes =
                match tpe_lifetimes.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&tpe_lifetimes, &mut _s);
            ::quote::__private::push_comma(&mut _s);
        }
    }
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_ident(&mut _s, "where");
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut field_ty_bounds, i) = field_ty_bounds.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let field_ty_bounds =
                match field_ty_bounds.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&field_ty_bounds, &mut _s);
            ::quote::__private::push_comma(&mut _s);
        }
    }
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "query_builder");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "AsChangeset");
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::ToTokens::to_tokens(&struct_name, &mut _s);
    ::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
    ::quote::ToTokens::to_tokens(&where_clause, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "type");
            ::quote::__private::push_ident(&mut _s, "Target");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&table_name, &mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "table");
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "type");
            ::quote::__private::push_ident(&mut _s, "Changeset");
            ::quote::__private::push_eq(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    {
                        use ::quote::__private::ext::*;
                        let has_iter = ::quote::__private::HasIterator::<false>;
                        #[allow(unused_mut)]
                        let (mut direct_field_ty, i) =
                            direct_field_ty.quote_into_iter();
                        let has_iter = has_iter | i;
                        <_ as
                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                        while true {
                            let direct_field_ty =
                                match direct_field_ty.next() {
                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                    None => break,
                                };
                            ::quote::ToTokens::to_tokens(&direct_field_ty, &mut _s);
                            ::quote::__private::push_comma(&mut _s);
                        }
                    }
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "as");
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "query_builder");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "AsChangeset");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Changeset");
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "as_changeset");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "self");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_ident(&mut _s, "as");
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "query_builder");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "AsChangeset");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Changeset");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "diesel");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "query_builder");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "AsChangeset");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "as_changeset");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    {
                                        use ::quote::__private::ext::*;
                                        let has_iter = ::quote::__private::HasIterator::<false>;
                                        #[allow(unused_mut)]
                                        let (mut direct_field_assign, i) =
                                            direct_field_assign.quote_into_iter();
                                        let has_iter = has_iter | i;
                                        <_ as
                                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                        while true {
                                            let direct_field_assign =
                                                match direct_field_assign.next() {
                                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                                    None => break,
                                                };
                                            ::quote::ToTokens::to_tokens(&direct_field_assign, &mut _s);
                                            ::quote::__private::push_comma(&mut _s);
                                        }
                                    }
                                    _s
                                });
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote! {
176        fn _check_owned<#(#tpe_lifetimes,)*>()
177        where #(#field_ty_bounds,)*
178        {}
179
180        impl #impl_generics diesel::query_builder::AsChangeset for #struct_name #ty_generics
181        #where_clause
182        {
183            type Target = #table_name::table;
184            type Changeset = <(#(#direct_field_ty,)*) as diesel::query_builder::AsChangeset>::Changeset;
185
186            fn as_changeset(self) -> <Self as diesel::query_builder::AsChangeset>::Changeset {
187                diesel::query_builder::AsChangeset::as_changeset((#(#direct_field_assign,)*))
188            }
189        }
190    };
191
192    let changeset_borrowed = if generate_borrowed_changeset {
193        let mut impl_generics = item.generics.clone();
194        impl_generics.params.push(::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_lifetime(&mut _s, "\'update");
        _s
    })parse_quote!('update));
195        let (impl_generics, _, _) = impl_generics.split_for_impl();
196        let borrowed_field_ty_bounds =
197            borrowed_field_ty_bounds
198                .into_iter()
199                .filter_map(|(type_to_check, bound)| {
200                    super::insertable::filter_bounds(
201                        &borrowed_field_ty_bounds_guard,
202                        type_to_check,
203                        bound,
204                    )
205                });
206        let tpe_lifetimes = item.generics.lifetimes().map(|lp| {
207            let lt = &lp.lifetime;
208            let bound = lp.bounds.iter();
209            if lp.bounds.is_empty() {
210                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&lt, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_lifetime(&mut _s, "\'update");
    _s
}quote!(#lt: 'update)
211            } else {
212                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&lt, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_lifetime(&mut _s, "\'update");
    ::quote::__private::push_add(&mut _s);
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut bound, i) = bound.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let bound =
                match bound.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&bound, &mut _s);
            ::quote::__private::push_add(&mut _s);
        }
    }
    _s
}quote!(#lt: 'update + #(#bound +)*)
213            }
214        });
215        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "allow");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "clippy");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s,
                        "multiple_bound_locations");
                    _s
                });
            _s
        });
    ::quote::__private::push_ident(&mut _s, "fn");
    ::quote::__private::push_ident(&mut _s, "_check_borrowed");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_lifetime(&mut _s, "\'update");
    ::quote::__private::push_comma(&mut _s);
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut tpe_lifetimes, i) = tpe_lifetimes.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let tpe_lifetimes =
                match tpe_lifetimes.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&tpe_lifetimes, &mut _s);
            ::quote::__private::push_comma(&mut _s);
        }
    }
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_ident(&mut _s, "where");
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut borrowed_field_ty_bounds, i) =
            borrowed_field_ty_bounds.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let borrowed_field_ty_bounds =
                match borrowed_field_ty_bounds.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&borrowed_field_ty_bounds, &mut _s);
            ::quote::__private::push_comma(&mut _s);
        }
    }
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "query_builder");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "AsChangeset");
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_lifetime(&mut _s, "\'update");
    ::quote::ToTokens::to_tokens(&struct_name, &mut _s);
    ::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
    ::quote::__private::push_ident(&mut _s, "where");
    ::quote::ToTokens::to_tokens(&where_clause, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            {
                use ::quote::__private::ext::*;
                let has_iter = ::quote::__private::HasIterator::<false>;
                #[allow(unused_mut)]
                let (mut ref_field_ty, i) = ref_field_ty.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let ref_field_ty =
                        match ref_field_ty.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    ::quote::ToTokens::to_tokens(&ref_field_ty, &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                }
            }
            _s
        });
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "query_builder");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "AsChangeset");
    ::quote::__private::push_comma(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "type");
            ::quote::__private::push_ident(&mut _s, "Target");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&table_name, &mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "table");
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "type");
            ::quote::__private::push_ident(&mut _s, "Changeset");
            ::quote::__private::push_eq(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    {
                        use ::quote::__private::ext::*;
                        let has_iter = ::quote::__private::HasIterator::<false>;
                        #[allow(unused_mut)]
                        let (mut ref_field_ty, i) = ref_field_ty.quote_into_iter();
                        let has_iter = has_iter | i;
                        <_ as
                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                        while true {
                            let ref_field_ty =
                                match ref_field_ty.next() {
                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                    None => break,
                                };
                            ::quote::ToTokens::to_tokens(&ref_field_ty, &mut _s);
                            ::quote::__private::push_comma(&mut _s);
                        }
                    }
                    _s
                });
            ::quote::__private::push_ident(&mut _s, "as");
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "query_builder");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "AsChangeset");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Changeset");
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "as_changeset");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "self");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_ident(&mut _s, "as");
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "query_builder");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "AsChangeset");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Changeset");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "diesel");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "query_builder");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "AsChangeset");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "as_changeset");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    {
                                        use ::quote::__private::ext::*;
                                        let has_iter = ::quote::__private::HasIterator::<false>;
                                        #[allow(unused_mut)]
                                        let (mut ref_field_assign, i) =
                                            ref_field_assign.quote_into_iter();
                                        let has_iter = has_iter | i;
                                        <_ as
                                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                        while true {
                                            let ref_field_assign =
                                                match ref_field_assign.next() {
                                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                                    None => break,
                                                };
                                            ::quote::ToTokens::to_tokens(&ref_field_assign, &mut _s);
                                            ::quote::__private::push_comma(&mut _s);
                                        }
                                    }
                                    _s
                                });
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote! {
216            #[allow(clippy::multiple_bound_locations)]
217            fn _check_borrowed<'update, #(#tpe_lifetimes,)*>()
218            where
219                #(#borrowed_field_ty_bounds,)*
220            {}
221
222            impl #impl_generics diesel::query_builder::AsChangeset for &'update #struct_name #ty_generics
223            where
224            #where_clause
225            (#(#ref_field_ty,)*): diesel::query_builder::AsChangeset,
226            {
227                type Target = #table_name::table;
228                type Changeset = <(#(#ref_field_ty,)*) as diesel::query_builder::AsChangeset>::Changeset;
229
230                fn as_changeset(self) -> <Self as diesel::query_builder::AsChangeset>::Changeset {
231                    diesel::query_builder::AsChangeset::as_changeset((#(#ref_field_assign,)*))
232                }
233            }
234        }
235    } else {
236        ::quote::__private::TokenStream::new();quote! {}
237    };
238
239    Ok(wrap_in_dummy_mod({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&changeset_owned, &mut _s);
    ::quote::ToTokens::to_tokens(&changeset_borrowed, &mut _s);
    _s
}quote!(
240        #changeset_owned
241
242        #changeset_borrowed
243    )))
244}
245
246fn generate_field_bound(
247    field: &Field,
248    table_name: &Path,
249    ty: Option<&Type>,
250    borrowed: Option<syn::Lifetime>,
251    guard: &mut HashMap<Type, HashSet<Vec<syn::Lifetime>>>,
252    treat_none_as_null: bool,
253) -> Result<(Type, TokenStream)> {
254    let (ty_for_guard, as_expression_bound) = super::insertable::generate_field_bound(
255        field,
256        table_name,
257        ty.unwrap_or_else(|| field_changeset_actual_ty(field, treat_none_as_null)),
258        treat_none_as_null,
259        borrowed.clone(),
260        guard,
261    )?;
262    Ok((ty_for_guard, as_expression_bound))
263}
264
265fn field_changeset_actual_ty(field: &Field, treat_none_as_null: bool) -> &Type {
266    if !treat_none_as_null && is_option_ty(&field.ty) {
267        inner_of_option_ty(&field.ty)
268    } else {
269        &field.ty
270    }
271}
272
273fn field_changeset_ty_embed(field: &Field, lifetime: Option<TokenStream>) -> TokenStream {
274    let field_ty = &field.ty;
275    let span = Span::mixed_site().located_at(field.span);
276    {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::ToTokens::to_tokens(&lifetime, &mut _s);
    ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
    _s
}quote_spanned!(span=> #lifetime #field_ty)
277}
278
279fn field_changeset_expr_embed(field: &Field, lifetime: Option<TokenStream>) -> TokenStream {
280    let field_name = &field.name;
281    {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&lifetime, &mut _s);
    ::quote::__private::push_ident(&mut _s, "self");
    ::quote::__private::push_dot(&mut _s);
    ::quote::ToTokens::to_tokens(&field_name, &mut _s);
    _s
}quote!(#lifetime self.#field_name)
282}
283
284fn field_changeset_ty(
285    field: &Field,
286    table_name: &Path,
287    lifetime: Option<TokenStream>,
288    treat_none_as_null: bool,
289) -> Result<TokenStream> {
290    let column_name = field.column_name()?.to_ident()?;
291    if !treat_none_as_null && is_option_ty(&field.ty) {
292        let field_ty = inner_of_option_ty(&field.ty);
293        Ok(
294            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "std");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Option");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "dsl");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Eq");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&table_name, &mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&column_name, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&lifetime, &mut _s);
    ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
    ::quote::__private::push_shr(&mut _s);
    _s
}quote!(std::option::Option<diesel::dsl::Eq<#table_name::#column_name, #lifetime #field_ty>>),
295        )
296    } else {
297        let field_ty = &field.ty;
298        Ok({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "dsl");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Eq");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&table_name, &mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&column_name, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&lifetime, &mut _s);
    ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(diesel::dsl::Eq<#table_name::#column_name, #lifetime #field_ty>))
299    }
300}
301
302fn field_changeset_expr(
303    field: &Field,
304    table_name: &Path,
305    lifetime: Option<TokenStream>,
306    treat_none_as_null: bool,
307) -> Result<TokenStream> {
308    let field_name = &field.name;
309    let column_name = field.column_name()?.to_ident()?;
310    if !treat_none_as_null && is_option_ty(&field.ty) {
311        if lifetime.is_some() {
312            Ok(
313                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "self");
    ::quote::__private::push_dot(&mut _s);
    ::quote::ToTokens::to_tokens(&field_name, &mut _s);
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "as_ref");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "map");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_or(&mut _s);
            ::quote::__private::push_ident(&mut _s, "x");
            ::quote::__private::push_or(&mut _s);
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "ExpressionMethods");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "eq");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&table_name, &mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::ToTokens::to_tokens(&column_name, &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "x");
                    _s
                });
            _s
        });
    _s
}quote!(self.#field_name.as_ref().map(|x| diesel::ExpressionMethods::eq(#table_name::#column_name, x))),
314            )
315        } else {
316            Ok(
317                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "self");
    ::quote::__private::push_dot(&mut _s);
    ::quote::ToTokens::to_tokens(&field_name, &mut _s);
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "map");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_or(&mut _s);
            ::quote::__private::push_ident(&mut _s, "x");
            ::quote::__private::push_or(&mut _s);
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "ExpressionMethods");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "eq");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&table_name, &mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::ToTokens::to_tokens(&column_name, &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "x");
                    _s
                });
            _s
        });
    _s
}quote!(self.#field_name.map(|x| diesel::ExpressionMethods::eq(#table_name::#column_name, x))),
318            )
319        }
320    } else {
321        Ok(
322            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ExpressionMethods");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "eq");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&table_name, &mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::ToTokens::to_tokens(&column_name, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&lifetime, &mut _s);
            ::quote::__private::push_ident(&mut _s, "self");
            ::quote::__private::push_dot(&mut _s);
            ::quote::ToTokens::to_tokens(&field_name, &mut _s);
            _s
        });
    _s
}quote!(diesel::ExpressionMethods::eq(#table_name::#column_name, #lifetime self.#field_name)),
323        )
324    }
325}
326
327fn field_changeset_ty_serialize_as(
328    field: &Field,
329    table_name: &Path,
330    ty: &Type,
331    treat_none_as_null: bool,
332) -> Result<TokenStream> {
333    let column_name = field.column_name()?.to_ident()?;
334    if !treat_none_as_null && is_option_ty(&field.ty) {
335        let inner_ty = inner_of_option_ty(ty);
336        Ok({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "std");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "option");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Option");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "dsl");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Eq");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&table_name, &mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&column_name, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&inner_ty, &mut _s);
    ::quote::__private::push_shr(&mut _s);
    _s
}quote!(std::option::Option<diesel::dsl::Eq<#table_name::#column_name, #inner_ty>>))
337    } else {
338        Ok({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "dsl");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Eq");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&table_name, &mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&column_name, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(diesel::dsl::Eq<#table_name::#column_name, #ty>))
339    }
340}
341
342fn field_changeset_expr_serialize_as(
343    field: &Field,
344    table_name: &Path,
345    ty: &Type,
346    treat_none_as_null: bool,
347) -> Result<TokenStream> {
348    let field_name = &field.name;
349    let column_name = field.column_name()?.to_ident()?;
350    let column: Expr = ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::ToTokens::to_tokens(&table_name, &mut _s);
        ::quote::__private::push_colon2(&mut _s);
        ::quote::ToTokens::to_tokens(&column_name, &mut _s);
        _s
    })parse_quote!(#table_name::#column_name);
351    if !treat_none_as_null && is_option_ty(&field.ty) {
352        Ok(
353            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "self");
    ::quote::__private::push_dot(&mut _s);
    ::quote::ToTokens::to_tokens(&field_name, &mut _s);
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "map");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_or(&mut _s);
            ::quote::__private::push_ident(&mut _s, "x");
            ::quote::__private::push_or(&mut _s);
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "ExpressionMethods");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "eq");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&column, &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "std");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "convert");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Into");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::ToTokens::to_tokens(&ty, &mut _s);
                    ::quote::__private::push_gt(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "into");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "x");
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote!(self.#field_name.map(|x| diesel::ExpressionMethods::eq(#column, ::std::convert::Into::<#ty>::into(x)))),
354        )
355    } else {
356        Ok({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&column, &mut _s);
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "eq");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "std");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "convert");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Into");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&ty, &mut _s);
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "into");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "self");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::ToTokens::to_tokens(&field_name, &mut _s);
                    _s
                });
            _s
        });
    _s
}quote!(#column.eq(::std::convert::Into::<#ty>::into(self.#field_name))))
357    }
358}