1use ahash::HashMap;
2use serde::{Deserialize, Deserializer, Serialize};
3use serde_json::Value;
4use std::sync::Arc;
5
6#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
8#[serde(rename_all = "camelCase")]
9pub struct DecisionContent {
10 pub nodes: Vec<Arc<DecisionNode>>,
11 pub edges: Vec<Arc<DecisionEdge>>,
12}
13
14#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
15#[serde(rename_all = "camelCase")]
16pub struct DecisionEdge {
17 pub id: String,
18 pub source_id: String,
19 pub target_id: String,
20 pub source_handle: Option<String>,
21}
22
23#[derive(Clone, Debug, Deserialize, Serialize)]
24#[serde(rename_all = "camelCase")]
25pub struct DecisionNode {
26 pub id: String,
27 pub name: String,
28 #[serde(rename = "type")]
29 #[serde(flatten)]
30 pub kind: DecisionNodeKind,
31}
32
33impl PartialEq for DecisionNode {
34 fn eq(&self, other: &Self) -> bool {
35 self.id == other.id
36 }
37}
38
39#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
40#[serde(tag = "type")]
41#[serde(rename_all = "camelCase")]
42pub enum DecisionNodeKind {
43 InputNode {
44 #[serde(default)]
45 content: InputNodeContent,
46 },
47 OutputNode {
48 #[serde(default)]
49 content: OutputNodeContent,
50 },
51 FunctionNode {
52 content: FunctionNodeContent,
53 },
54 DecisionNode {
55 content: DecisionNodeContent,
56 },
57 DecisionTableNode {
58 content: DecisionTableContent,
59 },
60 ExpressionNode {
61 content: ExpressionNodeContent,
62 },
63 SwitchNode {
64 content: SwitchNodeContent,
65 },
66 CustomNode {
67 content: CustomNodeContent,
68 },
69}
70
71#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)]
72#[serde(rename_all = "camelCase")]
73pub struct InputNodeContent {
74 #[serde(default, deserialize_with = "empty_string_is_none")]
75 pub schema: Option<String>,
76}
77
78#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)]
79#[serde(rename_all = "camelCase")]
80pub struct OutputNodeContent {
81 #[serde(default, deserialize_with = "empty_string_is_none")]
82 pub schema: Option<String>,
83}
84
85#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
86#[serde(rename_all = "camelCase")]
87#[serde(untagged)]
88pub enum FunctionNodeContent {
89 Version2(FunctionContent),
90 Version1(String),
91}
92
93#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)]
94#[serde(rename_all = "camelCase")]
95pub struct FunctionContent {
96 pub source: String,
97}
98
99#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
100#[serde(rename_all = "camelCase")]
101pub struct DecisionNodeContent {
102 pub key: String,
103 #[serde(flatten)]
104 pub transform_attributes: TransformAttributes,
105}
106
107#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
108#[serde(rename_all = "camelCase")]
109pub struct DecisionTableContent {
110 pub rules: Vec<HashMap<String, String>>,
111 pub inputs: Vec<DecisionTableInputField>,
112 pub outputs: Vec<DecisionTableOutputField>,
113 pub hit_policy: DecisionTableHitPolicy,
114 #[serde(flatten)]
115 pub transform_attributes: TransformAttributes,
116}
117
118#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
119#[serde(rename_all = "camelCase")]
120pub enum DecisionTableHitPolicy {
121 First,
122 Collect,
123}
124
125#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
126#[serde(rename_all = "camelCase")]
127pub struct DecisionTableInputField {
128 pub id: String,
129 pub name: String,
130 #[serde(default, deserialize_with = "empty_string_is_none")]
131 pub field: Option<String>,
132}
133
134#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
135#[serde(rename_all = "camelCase")]
136pub struct DecisionTableOutputField {
137 pub id: String,
138 pub name: String,
139 pub field: String,
140}
141
142#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
143#[serde(rename_all = "camelCase")]
144pub struct ExpressionNodeContent {
145 pub expressions: Vec<Expression>,
146 #[serde(flatten)]
147 pub transform_attributes: TransformAttributes,
148}
149
150#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
151#[serde(rename_all = "camelCase")]
152pub struct Expression {
153 pub id: String,
154 pub key: String,
155 pub value: String,
156}
157
158#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
159#[serde(rename_all = "camelCase")]
160pub struct SwitchNodeContent {
161 #[serde(default)]
162 pub hit_policy: SwitchStatementHitPolicy,
163 pub statements: Vec<SwitchStatement>,
164}
165
166#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
167#[serde(rename_all = "camelCase")]
168pub struct SwitchStatement {
169 pub id: String,
170 pub condition: String,
171}
172
173#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)]
174#[serde(rename_all = "camelCase")]
175pub enum SwitchStatementHitPolicy {
176 #[default]
177 First,
178 Collect,
179}
180
181#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)]
182#[serde(rename_all = "camelCase")]
183pub struct TransformAttributes {
184 #[serde(default, deserialize_with = "empty_string_is_none")]
185 pub input_field: Option<String>,
186 #[serde(default, deserialize_with = "empty_string_is_none")]
187 pub output_path: Option<String>,
188 #[serde(default)]
189 pub execution_mode: TransformExecutionMode,
190 #[serde(default)]
191 pub pass_through: bool,
192}
193
194#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)]
195#[serde(rename_all = "camelCase")]
196pub enum TransformExecutionMode {
197 #[default]
198 Single,
199 Loop,
200}
201
202#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)]
203#[serde(rename_all = "camelCase")]
204pub struct CustomNodeContent {
205 pub kind: String,
206 pub config: Arc<Value>,
207}
208
209fn empty_string_is_none<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
210where
211 D: Deserializer<'de>,
212{
213 #[derive(Deserialize)]
214 #[serde(untagged)]
215 enum StringOrNull {
216 String(String),
217 Null,
218 }
219
220 match StringOrNull::deserialize(deserializer)? {
221 StringOrNull::String(s) if s.trim().is_empty() => Ok(None),
222 StringOrNull::String(s) => Ok(Some(s)),
223 StringOrNull::Null => Ok(None),
224 }
225}