feat: support default values for annotated server_fn arguments with #[server(default)] (#1762)

This allows form submission with checkbox inputs to work.
For example:

    let doit = create_server_action::<DoItSFn>();
    <ActionForm action=doit>
      <input type="checkbox" name="is_good" value="true"/>
      <input type="submit"/>
    </ActionForm>

    #[server(DoItSFn, "/api")]
    pub async fn doit(#[server(default)] is_good: bool) -> Result<(), ServerFnError> {}

If is_good is absent in the request to the server API,
`Default::default()` is used instead.
This commit is contained in:
Gabriel de Perthuis 2023-09-21 02:43:20 +02:00 committed by GitHub
parent f2117b1186
commit 2c8f46466b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -84,7 +84,7 @@ pub fn server_macro_impl(
let fn_path = fn_path.unwrap_or_else(|| Literal::string(""));
let encoding = quote!(#server_fn_path::#encoding);
let body = syn::parse::<ServerFnBody>(body.into())?;
let mut body = syn::parse::<ServerFnBody>(body.into())?;
let fn_name = &body.ident;
let fn_name_as_str = body.ident.to_string();
let vis = body.vis;
@ -92,7 +92,7 @@ pub fn server_macro_impl(
let fields = body
.inputs
.iter()
.iter_mut()
.filter(|f| {
if let Some(ctx) = &server_context {
!fn_arg_is_cx(f, ctx)
@ -110,8 +110,33 @@ pub fn server_macro_impl(
}
FnArg::Typed(t) => t,
};
quote! { pub #typed_arg }
});
let mut default = false;
let mut other_attrs = Vec::new();
for attr in typed_arg.attrs.iter() {
if !attr.path().is_ident("server") {
other_attrs.push(attr.clone());
continue;
}
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("default") && meta.input.is_empty() {
default = true;
Ok(())
} else {
Err(meta.error(
"Unrecognized #[server] attribute, expected \
#[server(default)]",
))
}
})?;
}
typed_arg.attrs = other_attrs;
if default {
Ok(quote! { #[serde(default)] pub #typed_arg })
} else {
Ok(quote! { pub #typed_arg })
}
})
.collect::<Result<Vec<_>>>()?;
let cx_arg = body.inputs.iter().next().and_then(|f| {
server_context