mf_engine/handler/
custom_node_adapter.rs1use crate::handler::node::{NodeRequest, NodeResult};
2use crate::model::{DecisionNode, DecisionNodeKind};
3use anyhow::anyhow;
4use json_dotpath::DotPaths;
5use serde::Serialize;
6use serde_json::Value;
7use std::ops::Deref;
8use std::sync::Arc;
9use mf_expression::variable::Variable;
10use mf_template::TemplateRenderError;
11
12pub trait CustomNodeAdapter {
13 fn handle(
14 &self,
15 request: CustomNodeRequest,
16 ) -> impl std::future::Future<Output = NodeResult>;
17}
18
19#[derive(Default, Debug)]
20pub struct NoopCustomNode;
21
22impl CustomNodeAdapter for NoopCustomNode {
23 async fn handle(
24 &self,
25 _: CustomNodeRequest,
26 ) -> NodeResult {
27 Err(anyhow!("Custom node handler not provided"))
28 }
29}
30
31#[derive(Serialize)]
32#[serde(rename_all = "camelCase")]
33pub struct CustomNodeRequest {
34 pub input: Variable,
35 pub node: CustomDecisionNode,
36}
37
38impl TryFrom<NodeRequest> for CustomNodeRequest {
39 type Error = ();
40
41 fn try_from(value: NodeRequest) -> Result<Self, Self::Error> {
42 Ok(Self {
43 input: value.input.clone(),
44 node: value.node.deref().try_into()?,
45 })
46 }
47}
48
49impl CustomNodeRequest {
50 pub fn get_field(
51 &self,
52 path: &str,
53 ) -> Result<Option<Variable>, TemplateRenderError> {
54 let Some(selected_value) = self.get_field_raw(path) else {
55 return Ok(None);
56 };
57
58 let Variable::String(template) = selected_value else {
59 return Ok(Some(selected_value));
60 };
61
62 let template_value =
63 mf_template::render(template.as_ref(), self.input.clone())?;
64 Ok(Some(template_value))
65 }
66
67 fn get_field_raw(
68 &self,
69 path: &str,
70 ) -> Option<Variable> {
71 self.node.config.dot_get(path).ok().flatten()
72 }
73}
74
75#[derive(Serialize)]
76#[serde(rename_all = "camelCase")]
77pub struct CustomDecisionNode {
78 pub id: String,
79 pub name: String,
80 pub kind: String,
81 pub config: Arc<Value>,
82}
83
84impl TryFrom<&DecisionNode> for CustomDecisionNode {
85 type Error = ();
86
87 fn try_from(value: &DecisionNode) -> Result<Self, Self::Error> {
88 let DecisionNodeKind::CustomNode { content } = &value.kind else {
89 return Err(());
90 };
91
92 Ok(Self {
93 id: value.id.clone(),
94 name: value.name.clone(),
95 kind: content.kind.clone(),
96 config: content.config.clone(),
97 })
98 }
99}