sql-fun 0.1.0

SQL query/statement execution code generator
Documentation
use super::TokioPostgresCodeGenerator;
use quote::quote;

impl TokioPostgresCodeGenerator {
    pub fn generate_query_opt(self) -> proc_macro2::TokenStream {
        let TokioPostgresCodeGenerator {
            row_type,
            error_type,
            client_arg_name,
            sql_str,
            placeholders,
            result_columns,
            collector_arg: _,
            handler_arg: _,
        } = self;
        let error_type = error_type.unwrap();

        let mut parameters = Vec::new();
        for placeholder in &placeholders {
            let ident = syn::Ident::new(placeholder, proc_macro::Span::call_site().into());
            let parameter = quote! { &#ident };
            parameters.push(parameter);
        }

        let mut check_column_names = Vec::new();
        let mut set_field_values = Vec::new();
        for (index, column) in result_columns.iter().enumerate() {
            check_column_names.push(Self::generate_check_column_existing(index, column));
            set_field_values.push(Self::generate_set_filed_value(index, column));
        }

        let result_field_count = check_column_names.len();

        quote! {
            {
                use std::sync::atomic::{AtomicBool, Ordering};
                static CHECKED: AtomicBool = AtomicBool::new(false);
                if !CHECKED.load(Ordering::Relaxed) {
                    let statement = #client_arg_name.prepare(#sql_str).await?;
                    let columns = statement.columns();
                    if columns.len() != #result_field_count {
                        Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "result set column count missmatch"))?;
                    }
                    #(#check_column_names)*;
                    CHECKED.store(true, Ordering::Relaxed);
                }
                let row = #client_arg_name.query_opt(#sql_str, &[#(#parameters),*]).await?;
                let mut row_builder = #row_type::builder();
                #(#set_field_values)*;
                Ok::<_, #error_type>(row_builder.build()?)
            }
        }
    }
}