use super::super::graphql::{
CompiledFilterInputTarget, CompiledInputDefinition, CompiledInputType, CompiledOperation,
CompiledVariableCodec,
};
use super::super::manifest::ClientManifest;
use super::super::ClientCompileError;
use super::artifact::render_operation_artifact_json;
use super::common::json_string;
use super::typescript::{render_data_type, render_variables_type};
pub(super) fn render_operation_module(
operation: &CompiledOperation,
manifest: &ClientManifest,
) -> Result<String, ClientCompileError> {
let variables_name = format!("{}_Variables", operation.export_name);
let data_name = format!("{}_Data", operation.export_name);
let variables = render_variables_type(operation, &variables_name)?;
let data = render_data_type(operation, &data_name)?;
let artifact_json = render_operation_artifact_json(operation, manifest)?;
let replica_value_import =
variable_codec_uses_replica_value(&operation.variable_codec).then_some(", ReplicaValue");
Ok(format!(
"/** GENERATED by distributed client. Do not edit. */\n\
import type {{ ReplicaOperationArtifact{} }} from '@hops-ops/distributed/replica';\n\
\n\
{variables}\n\
\n\
{data}\n\
\n\
/** Exact canonical query bytes sent to the server. */\n\
export const {}Document = {};\n\
\n\
/** Typed normalized-replica operation descriptor. */\n\
export const {}: ReplicaOperationArtifact<{}, {}> = {};\n",
replica_value_import.unwrap_or_default(),
operation.export_name,
json_string(&operation.query_document)?,
operation.export_name,
data_name,
variables_name,
artifact_json,
))
}
fn variable_codec_uses_replica_value(codec: &CompiledVariableCodec) -> bool {
fn input_type_uses_replica_value(input: &CompiledInputType) -> bool {
match input {
CompiledInputType::Scalar { codec, .. } => codec == "json",
CompiledInputType::List { item, .. } => input_type_uses_replica_value(item),
CompiledInputType::Enum { .. } | CompiledInputType::Input { .. } => false,
}
}
codec.variables.values().any(input_type_uses_replica_value)
|| codec.inputs.values().any(|input| match input {
CompiledInputDefinition::Filter {
fields,
relationships,
..
} => {
fields.iter().any(|field| field.codec == "json")
|| relationships.iter().any(|relationship| {
matches!(&relationship.target, CompiledFilterInputTarget::Opaque)
})
}
CompiledInputDefinition::Order { .. } => false,
})
}