postgres_named_parameters_derive/
query.rs1use attribute_derive::FromAttr;
2use quote::quote;
3use syn::{DeriveInput, Type};
4
5#[derive(FromAttr)]
6#[attribute(ident = query)]
7struct QueryTraitHelperAttribute {
8 #[attribute(example = r#""SELECT * FROM Person WHERE first_name = @name""#)]
9 sql: String,
10 #[attribute(example = "crate::my_database_tables::Person")]
11 row: Type,
12}
13
14pub fn derive_query_impl(ast: DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
15 let args = QueryTraitHelperAttribute::from_attributes(&ast.attrs)?;
16 let syn::Data::Struct(struct_ast) = ast.data else {
17 return Err(syn::Error::new(
18 ast.ident.span(),
19 "#[derive(Query)] can only be used on structs",
20 ));
21 };
22 let named_parameters = crate::util::get_field_names(&struct_ast);
23 let parameter_list = crate::util::get_parameter_list(&struct_ast);
24 let transformed_sql = match crate::numberify::numberify(args.sql, named_parameters) {
25 Ok(sql) => sql,
26 Err(err) => {
27 let err = format!("Error with SQL provided to #[derive(Query)]: {}", err);
28 return Err(syn::Error::new(ast.ident.span(), err));
29 }
30 };
31
32 let generics = ast.generics;
33 let ident = ast.ident;
34 let where_clause = &generics.where_clause;
35 let row_type = args.row;
36
37 let output = quote! {
38 #[automatically_derived]
39 impl #generics postgres_named_parameters::Query for #ident #generics #where_clause {
40 type Row = #row_type;
41 fn query_all(
42 &self,
43 connection: &mut impl postgres_named_parameters::postgres::GenericClient,
44 ) -> Result<Vec<Self::Row>, postgres_named_parameters::postgres::error::Error> {
45 let rows = connection.query(#transformed_sql, #parameter_list)?;
46 rows
47 .iter()
48 .map(postgres_named_parameters::internal::wrapper_for_derive_macro::try_from_row::<Self::Row>)
49 .collect()
50 }
51
52 fn query_opt(
53 &self,
54 connection: &mut impl postgres_named_parameters::postgres::GenericClient,
55 ) -> Result<Option<Self::Row>, postgres_named_parameters::postgres::error::Error> {
56 let maybe_row = connection.query_opt(#transformed_sql, #parameter_list)?;
57 match maybe_row {
58 None => Ok(None),
59 Some(row) => {
60 let decoded_row = postgres_named_parameters::internal::wrapper_for_derive_macro::try_from_row::<Self::Row>(&row)?;
61 Ok(Some(decoded_row))
62 }
63 }
64 }
65
66 fn query_one(
67 &self,
68 connection: &mut impl postgres_named_parameters::postgres::GenericClient,
69 ) -> Result<Self::Row, postgres_named_parameters::postgres::error::Error> {
70 let row = connection.query_one(#transformed_sql, #parameter_list)?;
71 postgres_named_parameters::internal::wrapper_for_derive_macro::try_from_row::<Self::Row>(&row)
72 }
73 }
74 };
75 Ok(output.into())
76}