use crate::codegen::naming::{go_param_name, go_type_name, to_go_name};
use crate::core::ir::TypeRef;
pub(crate) fn adapter_flattened_field<'a>(
adapter: &crate::core::config::AdapterConfig,
types: &'a [crate::core::ir::TypeDef],
) -> Option<&'a crate::core::ir::FieldDef> {
if adapter.request_type.is_none() || adapter.params.len() != 1 {
return None;
}
let param_ty_name = &adapter.params[0].ty;
types.iter().find(|t| &t.name == param_ty_name)?.fields.first()
}
pub(in crate::backends::go::gen_bindings) fn gen_adapter_wrapper(
adapter: &crate::core::config::AdapterConfig,
_pkg_name: &str,
types: &[crate::core::ir::TypeDef],
) -> String {
let adapter_name = &adapter.name;
let go_func_name = to_go_name(adapter_name);
let owner_type_raw = adapter.owner_type.as_deref().unwrap_or_else(|| {
panic!(
"go adapter `{adapter_name}`: streaming adapter requires `owner_type` in `[[adapters]]` config (the Rust handle type that owns the streaming method)"
)
});
let owner_type = go_type_name(owner_type_raw);
let owner_type = owner_type.as_str();
let _item_type = adapter.item_type.as_deref().unwrap_or_else(|| {
panic!(
"go adapter `{adapter_name}`: streaming adapter requires `item_type` in `[[adapters]]` config (the Rust item type yielded by the stream)"
)
});
let request_type = adapter.request_type.as_deref().unwrap_or_else(|| {
panic!(
"go adapter `{adapter_name}`: streaming adapter requires `request_type` in `[[adapters]]` config (the Rust request payload type)"
)
});
let request_type_simple = request_type.rsplit("::").next().unwrap_or(request_type);
let (param_parts, request_construction) = if let Some(first_field) = adapter_flattened_field(adapter, types) {
let field_name = &first_field.name;
let field_name_go = to_go_name(field_name);
let go_field_type = match &first_field.ty {
TypeRef::String => "string".to_string(),
TypeRef::Vec(inner) if matches!(**inner, TypeRef::String) => "[]string".to_string(),
TypeRef::Vec(_) => "[]interface{}".to_string(),
other => crate::backends::go::type_map::go_type(other).into_owned(),
};
let wrapper_params = vec![
format!("engine *{owner_type}"),
format!("{field_name_go} {go_field_type}"),
];
let struct_field_name = to_go_name(field_name);
let construction = format!("req := &{request_type_simple}{{{struct_field_name}: {field_name_go}}}\n\t");
(wrapper_params, Some(construction))
} else {
let mut params = vec![format!("engine *{owner_type}")];
for p in &adapter.params {
let go_param_type = match p.ty.as_str() {
"String" => "string".to_string(),
ty => ty.rsplit("::").next().unwrap_or(ty).to_string(),
};
let param_name = go_param_name(&p.name);
params.push(format!("{param_name} {go_param_type}"));
}
(params, None)
};
let method_call_name = to_go_name(adapter_name);
let stream_type_name = format!("{owner_type}{method_call_name}Stream");
let context_return_type = format!("*{stream_type_name}, error");
let item_type = go_type_name(_item_type.rsplit("::").next().unwrap_or(_item_type));
let compatibility_return_type = format!("<-chan {item_type}, error");
let method_call = if request_construction.is_some() {
format!("engine.{}WithContext(ctx, *req)", method_call_name)
} else {
let param_args = adapter
.params
.iter()
.map(|p| go_param_name(&p.name))
.collect::<Vec<_>>()
.join(", ");
if param_args.is_empty() {
format!("engine.{}WithContext(ctx)", method_call_name)
} else {
format!("engine.{}WithContext(ctx, {})", method_call_name, param_args)
}
};
let context_params = std::iter::once("ctx context.Context".to_string())
.chain(param_parts.iter().cloned())
.collect::<Vec<_>>()
.join(", ");
let compatibility_args = std::iter::once("context.Background()".to_string())
.chain(std::iter::once("engine".to_string()))
.chain(adapter_flattened_field(adapter, types).map(|field| to_go_name(&field.name)))
.chain(if adapter_flattened_field(adapter, types).is_some() {
Vec::new()
} else {
adapter.params.iter().map(|p| go_param_name(&p.name)).collect()
})
.collect::<Vec<_>>()
.join(", ");
crate::backends::go::template_env::render(
"adapter_wrapper.jinja",
minijinja::context! {
go_func_name => &go_func_name,
go_func_with_context_name => format!("{go_func_name}WithContext"),
owner_type => owner_type,
method_call_name => &method_call_name,
params => param_parts.join(", "),
context_params => &context_params,
compatibility_args => &compatibility_args,
compatibility_return_type => &compatibility_return_type,
context_return_type => &context_return_type,
request_construction => request_construction.as_deref(),
method_call => &method_call,
},
)
}