use darling::FromMeta;
use proc_macro::TokenStream;
use quote::quote;
use crate::bundlepart::{self, FnSpec};
#[derive(Debug, FromMeta, Default)]
struct PgNotifyConfMeta {
#[darling(default)]
channel: Option<String>,
#[darling(default)]
target: Option<String>,
}
pub(crate) fn parse_pgnotify(attr: TokenStream, item: TokenStream) -> TokenStream {
bundlepart::generate_bundle_part::<PgNotifyConfMeta>(
attr,
item,
"pgnotify",
build_pgnotify_conf,
)
}
fn build_pgnotify_conf(
conf: &PgNotifyConfMeta,
_spec: &FnSpec,
) -> Result<proc_macro2::TokenStream, syn::Error> {
let channel = conf.channel.as_ref().ok_or_else(|| {
syn::Error::new(
proc_macro2::Span::call_site(),
"PostgreSQL LISTEN channel is required. Use: #[pgnotify(channel = \"my_channel\")]"
)
})?;
validate_channel_name(channel)?;
let target = if let Some(target_str) = &conf.target {
quote! { ::uxar::emitters::EmitTarget::from_str(#target_str).unwrap_or_default() }
} else {
quote! { ::uxar::emitters::EmitTarget::default() }
};
Ok(quote! {
::uxar::emitters::PgNotifyConf {
channel: #channel.to_string(),
target: #target,
}
})
}
fn validate_channel_name(channel: &str) -> Result<(), syn::Error> {
if channel.trim().is_empty() {
return Err(syn::Error::new(
proc_macro2::Span::call_site(),
"PostgreSQL channel name cannot be empty"
));
}
Ok(())
}