use cratestack_core::{Field, Model};
use quote::quote;
use crate::include::grpc_pb::scalar::wire_from_domain_expr;
use crate::shared::ident;
use super::rpc_inputs::pk_domain_type;
pub(super) fn build_model_api(model: &Model, pk: &Field) -> proc_macro2::TokenStream {
let model_name = &model.name;
let model_ident = ident(model_name);
let api_ident = ident(&format!("{model_name}GrpcApi"));
let pk_input_ident = ident(&format!("{model_name}RpcPkInput"));
let update_wrapper_ident = ident(&format!("{model_name}RpcUpdateInput"));
let list_input_ident = ident(&format!("{model_name}RpcListInput"));
let page_of_ident = ident(&format!("PageOf{model_name}"));
let create_input_ident = ident(&format!("Create{model_name}Input"));
let update_input_ident = ident(&format!("Update{model_name}Input"));
let pk_type = pk_domain_type(pk);
let pk_to_wire = wire_from_domain_expr(pk.ty.name.as_str(), quote! { id.clone() });
let list_op = format!("model.{model_name}.list");
let get_op = format!("model.{model_name}.get");
let create_op = format!("model.{model_name}.create");
let update_op = format!("model.{model_name}.update");
let delete_op = format!("model.{model_name}.delete");
let list_method = cratestack_proto::op_id_to_method_name(&list_op);
let get_method = cratestack_proto::op_id_to_method_name(&get_op);
let create_method = cratestack_proto::op_id_to_method_name(&create_op);
let update_method = cratestack_proto::op_id_to_method_name(&update_op);
let delete_method = cratestack_proto::op_id_to_method_name(&delete_op);
let create_method_tokens = crate::include::grpc_pb::fields::model_allows_create(model).then(|| {
quote! {
pub async fn create(
&mut self,
input: &super::inputs::#create_input_ident,
) -> ::core::result::Result<super::#model_ident, ::cratestack::client_rust::grpc::GrpcClientError> {
let request = pb::#create_input_ident::from(input);
let response: pb::#model_ident = self.grpc.unary(#create_method, request).await?;
<super::#model_ident as ::core::convert::TryFrom<pb::#model_ident>>::try_from(response)
.map_err(::cratestack::client_rust::grpc::GrpcClientError::Codec)
}
}
});
quote! {
#[derive(Debug, Clone)]
pub struct #api_ident<T> {
grpc: ::cratestack::client_rust::grpc::CratestackGrpcClient<T>,
}
impl<T> #api_ident<T>
where
T: ::cratestack::grpc::tonic::client::GrpcService<::cratestack::grpc::tonic::body::Body>,
T::Error: ::core::convert::Into<::cratestack::grpc::tonic::codegen::StdError>,
T::ResponseBody: ::cratestack::grpc::tonic::codegen::Body<Data = ::cratestack::grpc::tonic::codegen::Bytes>
+ ::core::marker::Send
+ 'static,
<T::ResponseBody as ::cratestack::grpc::tonic::codegen::Body>::Error:
::core::convert::Into<::cratestack::grpc::tonic::codegen::StdError> + ::core::marker::Send,
{
pub async fn list(
&mut self,
input: &::cratestack::rpc::RpcListInput,
) -> ::core::result::Result<::cratestack::Page<super::#model_ident>, ::cratestack::client_rust::grpc::GrpcClientError>
{
let request = pb::#list_input_ident {
limit: input.limit,
offset: input.offset,
fields: input.fields.clone().unwrap_or_default(),
include: input.include.clone().unwrap_or_default(),
include_fields: input
.include_fields
.iter()
.map(|(key, values)| (key.clone(), pb::StringList { values: values.clone() }))
.collect(),
sort: input.sort.clone(),
where_expr: input.where_expr.clone(),
or: input.or.clone(),
filters: input
.filters
.iter()
.map(|predicate| pb::RpcListPredicate {
key: predicate.key.clone(),
value: predicate.value.clone(),
})
.collect(),
};
let response: pb::#page_of_ident = self.grpc.unary(#list_method, request).await?;
let items = response
.items
.into_iter()
.map(<super::#model_ident as ::core::convert::TryFrom<pb::#model_ident>>::try_from)
.collect::<::core::result::Result<::std::vec::Vec<_>, ::cratestack::CoolError>>()
.map_err(::cratestack::client_rust::grpc::GrpcClientError::Codec)?;
let page_info = response
.page_info
.map(|info| ::cratestack::PageInfo {
limit: info.limit,
offset: info.offset,
has_next_page: info.has_next_page,
has_previous_page: info.has_previous_page,
})
.unwrap_or_default();
Ok(::cratestack::Page::new(items, page_info).with_total_count(response.total_count))
}
pub async fn get(
&mut self,
id: &#pk_type,
) -> ::core::result::Result<super::#model_ident, ::cratestack::client_rust::grpc::GrpcClientError>
{
let request = pb::#pk_input_ident { id: Some(#pk_to_wire) };
let response: pb::#model_ident = self.grpc.unary(#get_method, request).await?;
<super::#model_ident as ::core::convert::TryFrom<pb::#model_ident>>::try_from(response)
.map_err(::cratestack::client_rust::grpc::GrpcClientError::Codec)
}
#create_method_tokens
pub async fn update(
&mut self,
id: &#pk_type,
patch: &super::inputs::#update_input_ident,
) -> ::core::result::Result<super::#model_ident, ::cratestack::client_rust::grpc::GrpcClientError>
{
let request = pb::#update_wrapper_ident {
id: Some(#pk_to_wire),
patch: Some(Box::new(pb::#update_input_ident::from(patch))),
};
let response: pb::#model_ident = self.grpc.unary(#update_method, request).await?;
<super::#model_ident as ::core::convert::TryFrom<pb::#model_ident>>::try_from(response)
.map_err(::cratestack::client_rust::grpc::GrpcClientError::Codec)
}
pub async fn delete(
&mut self,
id: &#pk_type,
) -> ::core::result::Result<super::#model_ident, ::cratestack::client_rust::grpc::GrpcClientError>
{
let request = pb::#pk_input_ident { id: Some(#pk_to_wire) };
let response: pb::#model_ident = self.grpc.unary(#delete_method, request).await?;
<super::#model_ident as ::core::convert::TryFrom<pb::#model_ident>>::try_from(response)
.map_err(::cratestack::client_rust::grpc::GrpcClientError::Codec)
}
}
}
}