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