use dysql_core::{save_sql_template, hash_it};
use dysql_tpl::Template;
use quote::quote;
use crate::DyClosure;
pub(crate) struct SqlExpand;
impl SqlExpand {
pub fn fetch_all(&self, st: &DyClosure) -> syn::Result<proc_macro2::TokenStream>{
let dto_ident = &st.dto_info.src;
let executor_token = st.executor_info.gen_token();
let ret_type = &st.ret_type;
let named_template_declare = self.gen_named_template_declare(st)?;
let dto_token = st.dto_info.gen_token();
let execute_query = match dto_ident {
Some(_) => quote!(
#executor_token.dy_fetch_all::<_, #ret_type>(template_id, named_template, Some(#dto_token)).await
),
None => quote!(
#executor_token.dy_fetch_all::<dysql::EmptyObject, #ret_type>(template_id, named_template, None).await
),
};
let ret = quote!('rst_block: {
#[cfg(feature = "tokio-postgres")]
use dysql::TokioPgExecutorAdatper;
#[cfg(feature="sqlx")]
use dysql::SqlxExecutorAdatper;
#[cfg(feature="rbatis")]
use dysql::RbatisExecutorAdatper;
#named_template_declare
#execute_query
});
Ok(ret)
}
pub fn fetch_one(&self, st: &DyClosure) -> syn::Result<proc_macro2::TokenStream>{
let dto_ident = &st.dto_info.src;
let executor_token = st.executor_info.gen_token();
let ret_type = &st.ret_type;
let named_template_declare = self.gen_named_template_declare(st)?;
let dto_token = st.dto_info.gen_token();
let execute_query = match dto_ident {
Some(_) => quote!(
#executor_token.dy_fetch_one::<_, #ret_type>(template_id, named_template, Some(#dto_token)).await
),
None => quote!(
#executor_token.dy_fetch_one::<dysql::EmptyObject, #ret_type>(template_id, named_template, None).await
),
};
let ret = quote!('rst_block: {
#[cfg(feature = "tokio-postgres")]
use dysql::TokioPgExecutorAdatper;
#[cfg(feature="sqlx")]
use dysql::SqlxExecutorAdatper;
#[cfg(feature="rbatis")]
use dysql::RbatisExecutorAdatper;
#named_template_declare
#execute_query
});
Ok(ret)
}
pub fn fetch_scalar(&self, st: &DyClosure) -> syn::Result<proc_macro2::TokenStream>{
let dto_ident = &st.dto_info.src;
let executor_token = st.executor_info.gen_token();
let ret_type = &st.ret_type;
let named_template_declare = self.gen_named_template_declare(st)?;
let dto_token = st.dto_info.gen_token();
let execute_query = match dto_ident {
Some(_) => quote!(
#executor_token.dy_fetch_scalar::< _, #ret_type>(template_id, named_template, Some(#dto_token)).await
),
None => quote!(
#executor_token.dy_fetch_scalar::<dysql::EmptyObject, #ret_type>(template_id, named_template, None).await
),
};
let ret = quote!('rst_block: {
#[cfg(feature = "tokio-postgres")]
use dysql::TokioPgExecutorAdatper;
#[cfg(feature="sqlx")]
use dysql::SqlxExecutorAdatper;
#[cfg(feature="rbatis")]
use dysql::RbatisExecutorAdatper;
#named_template_declare
#execute_query
});
Ok(ret)
}
pub fn execute(&self, st: &DyClosure) -> syn::Result<proc_macro2::TokenStream>{
let dto_ident = &st.dto_info.src;
let executor_token = st.executor_info.gen_token();
let named_template_declare = self.gen_named_template_declare(st)?;
let dto_token = st.dto_info.gen_token();
let execute_query = match dto_ident {
Some(_) => quote!(
#executor_token.dy_execute(template_id, named_template, Some(#dto_token)).await
),
None => quote!(
#executor_token.dy_execute::<_, dysql::EmptyObject>(template_id, named_template, None).await
),
};
let ret = quote!('rst_block: {
#[cfg(feature = "tokio-postgres")]
use dysql::TokioPgExecutorAdatper;
#[cfg(feature="sqlx")]
use dysql::SqlxExecutorAdatper;
#[cfg(feature="rbatis")]
use dysql::RbatisExecutorAdatper;
#named_template_declare
#execute_query
});
Ok(ret)
}
pub fn insert(&self, st: &DyClosure) -> syn::Result<proc_macro2::TokenStream>{
let dto_ident = &st.dto_info.src;
let executor_token = st.executor_info.gen_token();
let ret_type = &st.ret_type;
let named_template_declare = self.gen_named_template_declare(st)?;
let dto_token = st.dto_info.gen_token();
let execute_query = match dto_ident {
Some(_) => quote!(
let insert_rst = #executor_token.dy_insert::<_, #ret_type>(template_id, named_template, Some(#dto_token)).await;
),
None => quote!(
let insert_rst = #executor_token.dy_insert::<dysql::EmptyObject, #ret_type>(template_id, named_template, None).await;
),
};
let ret = quote!('rst_block: {
#[cfg(feature = "tokio-postgres")]
use dysql::TokioPgExecutorAdatper;
#[cfg(feature="sqlx")]
use dysql::SqlxExecutorAdatper;
#[cfg(feature="rbatis")]
use dysql::RbatisExecutorAdatper;
#named_template_declare
#execute_query
let rst = match insert_rst {
Ok(Some(insert_id)) => Ok(insert_id),
Ok(None) => match #executor_token.dy_fetch_insert_id::<#ret_type>().await {
Ok(Some(insert_id)) => Ok(insert_id),
Ok(None) => {
break 'rst_block Err(dysql::DySqlError(dysql::ErrorInner::new(dysql::Kind::QueryError, None, None)));
}
Err(e) => {
break 'rst_block Err(dysql::DySqlError(dysql::ErrorInner::new(dysql::Kind::QueryError, Some(Box::new(e)), None)));
}
}
Err(e) => {
break 'rst_block Err(dysql::DySqlError(dysql::ErrorInner::new(dysql::Kind::QueryError, Some(Box::new(e)), None)));
}
};
let rst = rst.map(|v| v as #ret_type);
rst
});
Ok(ret)
}
pub fn page(&self, st: &DyClosure) -> syn::Result<proc_macro2::TokenStream>{
let dto_ident = &st.dto_info.src;
let executor_token = st.executor_info.gen_token();
let ret_type = &st.ret_type;
let dto_token = st.dto_info.gen_token();
let named_template_declare = self.gen_named_template_declare(st)?;
let execute_count_query = match dto_ident {
Some(_) => quote!(
let count_rst = #executor_token.dy_page_count::<_, i64>(template_id, named_template.clone(), Some(&#dto_token)).await;
),
None => quote!(
let count_rst = #executor_token.dy_page_count::<dysql::EmptyObject, i64>(template_id, named_template.clone(), None).await;
),
};
let ret = quote!('rst_block: {
#[cfg(feature = "tokio-postgres")]
use dysql::TokioPgExecutorAdatper;
#[cfg(feature="sqlx")]
use dysql::SqlxExecutorAdatper;
#[cfg(feature="rbatis")]
use dysql::RbatisExecutorAdatper;
#named_template_declare
#execute_count_query
if let Err(e) = count_rst {
break 'rst_block Err(dysql::DySqlError(dysql::ErrorInner::new(dysql::Kind::QueryError, Some(Box::new(e)), None)))
}
let count = count_rst.expect("Unexpected error");
#dto_ident.init(count as u64);
#executor_token.dy_page_all::<_, #ret_type>(template_id, named_template, &#dto_token).await
});
Ok(ret)
}
fn gen_named_template_declare(&self, st: &crate::DyClosure) -> syn::Result<proc_macro2::TokenStream> {
let template_id = hash_it(&st.body);
let source_file = if let Some(path) = st.source_file.to_str() {
path
} else {
Err(syn::Error::new(proc_macro2::Span::call_site(), format!("source_file path can not convert to string: {:?}", st.source_file)))?
};
match std::env::var("DYSQL_PESIST_SQL") {
Ok(val) if val.to_ascii_uppercase() == "TRUE" => {
save_sql_template(source_file, template_id, &st.body, st.sql_name.clone()).unwrap();
},
_ => (),
}
let template = Template::new(&st.body).expect("error: generate template from sql failed");
let serd_template = template.serialize();
let rst = quote!(
let (named_template, template_id) = match dysql::get_sql_template(#template_id) {
Some(tpl) => (tpl, #template_id),
None => {
let serd_template = [#(#serd_template,)*];
let tpl = dysql::put_sql_template(#template_id, &serd_template).expect("Unexpected error when put_sql_template");
(tpl, #template_id)
},
};
);
Ok(rst)
}
}