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 #[serde(default)]
98 pub omit_nodes: bool,
99}
100
101#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
102#[serde(rename_all = "camelCase")]
103pub struct DecisionNodeContent {
104 pub key: String,
105 #[serde(flatten)]
106 pub transform_attributes: TransformAttributes,
107}
108
109#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
110#[serde(rename_all = "camelCase")]
111pub struct DecisionTableContent {
112 pub rules: Vec<HashMap<String, String>>,
113 pub inputs: Vec<DecisionTableInputField>,
114 pub outputs: Vec<DecisionTableOutputField>,
115 pub hit_policy: DecisionTableHitPolicy,
116 #[serde(flatten)]
117 pub transform_attributes: TransformAttributes,
118}
119
120#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
121#[serde(rename_all = "camelCase")]
122pub enum DecisionTableHitPolicy {
123 First,
124 Collect,
125}
126
127#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
128#[serde(rename_all = "camelCase")]
129pub struct DecisionTableInputField {
130 pub id: String,
131 pub name: String,
132 #[serde(default, deserialize_with = "empty_string_is_none")]
133 pub field: Option<String>,
134}
135
136#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
137#[serde(rename_all = "camelCase")]
138pub struct DecisionTableOutputField {
139 pub id: String,
140 pub name: String,
141 pub field: String,
142}
143
144#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
145#[serde(rename_all = "camelCase")]
146pub struct ExpressionNodeContent {
147 pub expressions: Vec<Expression>,
148 #[serde(flatten)]
149 pub transform_attributes: TransformAttributes,
150}
151
152#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
153#[serde(rename_all = "camelCase")]
154pub struct Expression {
155 pub id: String,
156 pub key: String,
157 pub value: String,
158}
159
160#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
161#[serde(rename_all = "camelCase")]
162pub struct SwitchNodeContent {
163 #[serde(default)]
164 pub hit_policy: SwitchStatementHitPolicy,
165 pub statements: Vec<SwitchStatement>,
166}
167
168#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
169#[serde(rename_all = "camelCase")]
170pub struct SwitchStatement {
171 pub id: String,
172 pub condition: String,
173}
174
175#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)]
176#[serde(rename_all = "camelCase")]
177pub enum SwitchStatementHitPolicy {
178 #[default]
179 First,
180 Collect,
181}
182
183#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)]
184#[serde(rename_all = "camelCase")]
185pub struct TransformAttributes {
186 #[serde(default, deserialize_with = "empty_string_is_none")]
187 pub input_field: Option<String>,
188 #[serde(default, deserialize_with = "empty_string_is_none")]
189 pub output_path: Option<String>,
190 #[serde(default)]
191 pub execution_mode: TransformExecutionMode,
192 #[serde(default)]
193 pub pass_through: bool,
194}
195
196#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)]
197#[serde(rename_all = "camelCase")]
198pub enum TransformExecutionMode {
199 #[default]
200 Single,
201 Loop,
202}
203
204#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)]
205#[serde(rename_all = "camelCase")]
206pub struct CustomNodeContent {
207 pub kind: String,
208 pub config: Arc<Value>,
209}
210
211fn empty_string_is_none<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
212where
213 D: Deserializer<'de>,
214{
215 #[derive(Deserialize)]
216 #[serde(untagged)]
217 enum StringOrNull {
218 String(String),
219 Null,
220 }
221
222 match StringOrNull::deserialize(deserializer)? {
223 StringOrNull::String(s) if s.trim().is_empty() => Ok(None),
224 StringOrNull::String(s) => Ok(Some(s)),
225 StringOrNull::Null => Ok(None),
226 }
227}