use proc_macro2::{Ident, TokenStream};
use quote::format_ident;
use crate::analysis::QueryParam;
use crate::codegen::MethodHandler;
use crate::parsing::types::UnifiedType;
use crate::utils::strings;
pub(crate) struct OptionalSetter<'a> {
pub(crate) name: &'a str,
pub(crate) field_type: &'a UnifiedType,
}
pub(crate) trait SetterRender {
fn supports(&self, setter: &OptionalSetter<'_>) -> bool;
fn render_setter(
&self,
setter: &OptionalSetter<'_>,
param_ident: &Ident,
with_method: &Ident,
) -> TokenStream;
}
pub(crate) fn generate_builder_pattern<R: SetterRender>(
method: &MethodHandler<'_>,
is_list: bool,
render: &R,
) -> Vec<TokenStream> {
let mut calls = Vec::new();
for query_param in method.plan.query_parameters() {
if is_optional_query(query_param, is_list) {
let setter = OptionalSetter {
name: &query_param.name,
field_type: &query_param.field_type,
};
if render.supports(&setter) {
calls.push(render_one(&setter, render));
}
}
}
for body_field in method.plan.body_fields() {
if body_field.is_optional() {
let setter = OptionalSetter {
name: &body_field.name,
field_type: &body_field.field_type,
};
if render.supports(&setter) {
calls.push(render_one(&setter, render));
}
}
}
calls
}
fn is_optional_query(param: &QueryParam, is_list: bool) -> bool {
param.is_optional() && !(is_list && param.name == "page_token")
}
fn render_one<R: SetterRender>(setter: &OptionalSetter<'_>, render: &R) -> TokenStream {
let param_ident = format_ident!("{}", strings::operation_to_method_name(setter.name));
let with_method = format_ident!("with_{}", setter.name);
render.render_setter(setter, ¶m_ident, &with_method)
}