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