postgres_named_parameters_derive/
statement.rs

1use attribute_derive::FromAttr;
2use quote::quote;
3use syn::DeriveInput;
4
5#[derive(FromAttr)]
6#[attribute(ident = statement)]
7struct StatementTraitHelperAttribute {
8    #[attribute(example = r#""DELETE FROM Person WHERE id = @id""#)]
9    sql: String,
10}
11
12pub fn derive_statement_impl(ast: DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
13    let args = StatementTraitHelperAttribute::from_attributes(&ast.attrs)?;
14    let syn::Data::Struct(struct_ast) = ast.data else {
15        return Err(syn::Error::new(
16            ast.ident.span(),
17            "#[derive(Statement)] can only be used on structs",
18        ));
19    };
20
21    let named_parameters = crate::util::get_field_names(&struct_ast);
22    let parameter_list = crate::util::get_parameter_list(&struct_ast);
23    let transformed_sql = match crate::numberify::numberify(args.sql, named_parameters) {
24        Ok(sql) => sql,
25        Err(err) => {
26            let err = format!("Error with SQL provided to #[derive(Statement)]: {}", err);
27            return Err(syn::Error::new(ast.ident.span(), err));
28        }
29    };
30
31    let generics = ast.generics;
32    let ident = ast.ident;
33    let where_clause = &generics.where_clause;
34
35    let output = quote! {
36        #[automatically_derived]
37        impl #generics postgres_named_parameters::Statement for #ident #generics #where_clause {
38            fn execute_statement(&self, connection: &mut impl postgres_named_parameters::postgres::GenericClient) -> Result<u64, postgres_named_parameters::postgres::error::Error> {
39                connection.execute(#transformed_sql, #parameter_list)
40            }
41        }
42    };
43    Ok(output.into())
44}