use crate::model::component::{function_result_types, Component};
use crate::model::text::fmt::log_error;
use crate::model::wave::type_wave_compatible;
use crate::model::IdempotencyKey;
use anyhow::{anyhow, bail};
use golem_client::model::InvokeResult;
use golem_wasm_rpc::{print_value_and_type, ValueAndType};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct InvokeResultView {
pub idempotency_key: String,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub result_json: Option<ValueAndType>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub result_wave: Option<Vec<String>>,
}
impl InvokeResultView {
pub fn new_invoke(
idempotency_key: IdempotencyKey,
result: InvokeResult,
component: &Component,
function: &str,
) -> Self {
let wave = match Self::try_parse_wave(&result.result, component, function) {
Ok(wave) => Some(wave),
Err(err) => {
log_error(format!("{err}"));
None
}
};
Self {
idempotency_key: idempotency_key.0,
result_json: result.result,
result_wave: wave,
}
}
pub fn new_trigger(idempotency_key: IdempotencyKey) -> Self {
Self {
idempotency_key: idempotency_key.0,
result_json: None,
result_wave: None,
}
}
fn try_parse_wave(
result: &Option<ValueAndType>,
component: &Component,
function: &str,
) -> anyhow::Result<Vec<String>> {
let results: Vec<_> = result.iter().cloned().collect();
let result_types = function_result_types(component, function)?;
if results.len() != result_types.len() {
bail!("Unexpected number of results.".to_string());
}
if !result_types.iter().all(|typ| type_wave_compatible(typ)) {
bail!("Result type is not supported by wave".to_string(),);
}
let wave = results
.into_iter()
.map(Self::try_wave_format)
.collect::<Result<Vec<_>, _>>()?;
Ok(wave)
}
fn try_wave_format(parsed: ValueAndType) -> anyhow::Result<String> {
match print_value_and_type(&parsed) {
Ok(res) => Ok(res),
Err(err) => Err(anyhow!("Failed to format parsed value as wave: {err}")),
}
}
}