1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use std::collections::HashMap;
4
5#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
7pub struct EventConsumptionStrategyDefinition {
8 #[serde(skip_serializing_if = "Option::is_none")]
10 pub all: Option<Vec<EventFilterDefinition>>,
11
12 #[serde(skip_serializing_if = "Option::is_none")]
14 pub any: Option<Vec<EventFilterDefinition>>,
15
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub one: Option<EventFilterDefinition>,
19
20 #[serde(skip_serializing_if = "Option::is_none")]
22 pub until: Option<Box<OneOfEventConsumptionStrategyDefinitionOrExpression>>,
23}
24
25#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
27pub struct EventFilterDefinition {
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub with: Option<HashMap<String, Value>>,
31
32 #[serde(skip_serializing_if = "Option::is_none")]
34 pub correlate: Option<HashMap<String, CorrelationKeyDefinition>>,
35}
36
37#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
39pub struct CorrelationKeyDefinition {
40 pub from: String,
42
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub expect: Option<String>,
46}
47impl CorrelationKeyDefinition {
48 pub fn new(from: &str, expect: Option<String>) -> Self {
49 Self {
50 from: from.to_string(),
51 expect,
52 }
53 }
54}
55
56#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
58pub struct EventDefinition {
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub id: Option<String>,
62
63 #[serde(skip_serializing_if = "Option::is_none")]
65 pub source: Option<String>,
66
67 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
69 pub type_: Option<String>,
70
71 #[serde(skip_serializing_if = "Option::is_none")]
73 pub time: Option<String>,
74
75 #[serde(skip_serializing_if = "Option::is_none")]
77 pub subject: Option<String>,
78
79 #[serde(rename = "datacontenttype", skip_serializing_if = "Option::is_none")]
81 pub data_content_type: Option<String>,
82
83 #[serde(rename = "dataschema", skip_serializing_if = "Option::is_none")]
85 pub data_schema: Option<String>,
86
87 #[serde(skip_serializing_if = "Option::is_none")]
89 pub data: Option<Value>,
90
91 #[serde(default)]
93 pub with: HashMap<String, Value>,
94}
95impl EventDefinition {
96 pub fn new(with: HashMap<String, Value>) -> Self {
97 Self {
98 with,
99 ..Default::default()
100 }
101 }
102}
103
104#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
106#[serde(untagged)]
107pub enum OneOfEventConsumptionStrategyDefinitionOrExpression {
108 Strategy(EventConsumptionStrategyDefinition),
110 Expression(String),
112 Bool(bool),
114}
115impl Default for OneOfEventConsumptionStrategyDefinitionOrExpression {
116 fn default() -> Self {
117 OneOfEventConsumptionStrategyDefinitionOrExpression::Expression(String::default())
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn test_event_definition_deserialize() {
127 let json = r#"{
128 "id": "evt-123",
129 "source": "https://example.com/events",
130 "type": "com.example.event",
131 "time": "2025-01-01T00:00:00Z",
132 "subject": "user/123",
133 "datacontenttype": "application/json",
134 "dataschema": "https://example.com/schema"
135 }"#;
136 let event: EventDefinition = serde_json::from_str(json).unwrap();
137 assert_eq!(event.id, Some("evt-123".to_string()));
138 assert_eq!(event.source, Some("https://example.com/events".to_string()));
139 assert_eq!(event.type_, Some("com.example.event".to_string()));
140 assert_eq!(event.subject, Some("user/123".to_string()));
141 assert_eq!(
142 event.data_content_type,
143 Some("application/json".to_string())
144 );
145 }
146
147 #[test]
148 fn test_event_definition_roundtrip() {
149 let json = r#"{
150 "id": "evt-123",
151 "source": "https://example.com/events",
152 "type": "com.example.event"
153 }"#;
154 let event: EventDefinition = serde_json::from_str(json).unwrap();
155 let serialized = serde_json::to_string(&event).unwrap();
156 let deserialized: EventDefinition = serde_json::from_str(&serialized).unwrap();
157 assert_eq!(event, deserialized);
158 }
159
160 #[test]
161 fn test_event_filter_deserialize() {
162 let json = r#"{
163 "with": {"type": "com.example.event", "source": "https://example.com"},
164 "correlate": {
165 "userId": {"from": "${ .userId }", "expect": "user-123"}
166 }
167 }"#;
168 let filter: EventFilterDefinition = serde_json::from_str(json).unwrap();
169 assert!(filter.with.is_some());
170 assert!(filter.correlate.is_some());
171 let corr = filter.correlate.unwrap();
172 assert_eq!(corr.get("userId").unwrap().from, "${ .userId }");
173 }
174
175 #[test]
176 fn test_correlation_key_deserialize() {
177 let json = r#"{"from": "${ .orderId }", "expect": "order-456"}"#;
178 let key: CorrelationKeyDefinition = serde_json::from_str(json).unwrap();
179 assert_eq!(key.from, "${ .orderId }");
180 assert_eq!(key.expect, Some("order-456".to_string()));
181 }
182
183 #[test]
184 fn test_correlation_key_without_expect() {
185 let json = r#"{"from": "${ .userId }"}"#;
186 let key: CorrelationKeyDefinition = serde_json::from_str(json).unwrap();
187 assert_eq!(key.from, "${ .userId }");
188 assert!(key.expect.is_none());
189 }
190
191 #[test]
192 fn test_consumption_strategy_all() {
193 let json = r#"{
194 "all": [
195 {"with": {"type": "event1"}},
196 {"with": {"type": "event2"}}
197 ]
198 }"#;
199 let strategy: EventConsumptionStrategyDefinition = serde_json::from_str(json).unwrap();
200 assert!(strategy.all.is_some());
201 assert_eq!(strategy.all.unwrap().len(), 2);
202 assert!(strategy.any.is_none());
203 assert!(strategy.one.is_none());
204 }
205
206 #[test]
207 fn test_consumption_strategy_any() {
208 let json = r#"{
209 "any": [
210 {"with": {"type": "event1"}},
211 {"with": {"type": "event2"}}
212 ]
213 }"#;
214 let strategy: EventConsumptionStrategyDefinition = serde_json::from_str(json).unwrap();
215 assert!(strategy.any.is_some());
216 assert!(strategy.all.is_none());
217 }
218
219 #[test]
220 fn test_consumption_strategy_one() {
221 let json = r#"{
222 "one": {"with": {"type": "event1"}}
223 }"#;
224 let strategy: EventConsumptionStrategyDefinition = serde_json::from_str(json).unwrap();
225 assert!(strategy.one.is_some());
226 assert!(strategy.all.is_none());
227 assert!(strategy.any.is_none());
228 }
229
230 #[test]
231 fn test_consumption_strategy_with_until_strategy() {
232 let json = r#"{
233 "any": [{"with": {"type": "event1"}}],
234 "until": {"any": [{"with": {"type": "stop-event"}}]}
235 }"#;
236 let strategy: EventConsumptionStrategyDefinition = serde_json::from_str(json).unwrap();
237 assert!(strategy.until.is_some());
238 match *strategy.until.unwrap() {
239 OneOfEventConsumptionStrategyDefinitionOrExpression::Strategy(s) => {
240 assert!(s.any.is_some());
241 }
242 _ => panic!("Expected Strategy variant"),
243 }
244 }
245
246 #[test]
247 fn test_consumption_strategy_with_until_expression() {
248 let json = r#"{
249 "any": [{"with": {"type": "event1"}}],
250 "until": "${ .count >= 5 }"
251 }"#;
252 let strategy: EventConsumptionStrategyDefinition = serde_json::from_str(json).unwrap();
253 assert!(strategy.until.is_some());
254 match *strategy.until.unwrap() {
255 OneOfEventConsumptionStrategyDefinitionOrExpression::Expression(expr) => {
256 assert_eq!(expr, "${ .count >= 5 }");
257 }
258 _ => panic!("Expected Expression variant"),
259 }
260 }
261
262 #[test]
263 fn test_consumption_strategy_with_until_false() {
264 let json = r#"{
265 "any": [{"with": {"type": "event1"}}],
266 "until": false
267 }"#;
268 let strategy: EventConsumptionStrategyDefinition = serde_json::from_str(json).unwrap();
269 assert!(strategy.until.is_some());
270 match *strategy.until.unwrap() {
271 OneOfEventConsumptionStrategyDefinitionOrExpression::Bool(b) => {
272 assert!(!b);
273 }
274 _ => panic!("Expected Bool variant"),
275 }
276 }
277
278 #[test]
279 fn test_event_consumption_roundtrip() {
280 let json = r#"{
281 "all": [{"with": {"type": "event1"}}],
282 "until": false
283 }"#;
284 let strategy: EventConsumptionStrategyDefinition = serde_json::from_str(json).unwrap();
285 let serialized = serde_json::to_string(&strategy).unwrap();
286 let deserialized: EventConsumptionStrategyDefinition =
287 serde_json::from_str(&serialized).unwrap();
288 assert_eq!(strategy, deserialized);
289 }
290
291 #[test]
292 fn test_event_with_additional_properties() {
293 let json = r#"{
294 "id": "evt-123",
295 "type": "com.example.event",
296 "customField": "customValue"
297 }"#;
298 let event: EventDefinition = serde_json::from_str(json).unwrap();
299 assert_eq!(event.id, Some("evt-123".to_string()));
300 assert_eq!(event.type_, Some("com.example.event".to_string()));
301 }
302
303 #[test]
306 fn test_emit_event_properties_full() {
307 let json = r#"{
309 "id": "event-id",
310 "source": "http://example.com/source",
311 "type": "example.event.type",
312 "time": "2023-01-01T00:00:00Z",
313 "subject": "example.subject",
314 "datacontenttype": "application/json",
315 "dataschema": "http://example.com/schema",
316 "extra": "value"
317 }"#;
318 let event: EventDefinition = serde_json::from_str(json).unwrap();
319 assert_eq!(event.id, Some("event-id".to_string()));
320 assert_eq!(event.source, Some("http://example.com/source".to_string()));
321 assert_eq!(event.type_, Some("example.event.type".to_string()));
322 assert_eq!(event.time, Some("2023-01-01T00:00:00Z".to_string()));
323 assert_eq!(event.subject, Some("example.subject".to_string()));
324 assert_eq!(
325 event.data_content_type,
326 Some("application/json".to_string())
327 );
328 assert_eq!(
329 event.data_schema,
330 Some("http://example.com/schema".to_string())
331 );
332 }
333
334 #[test]
335 fn test_event_filter_roundtrip() {
336 let json = r#"{
337 "with": {"type": "com.example.event", "source": "http://example.com/source"},
338 "correlate": {
339 "orderId": {"from": "${ .orderId }", "expect": "order-123"}
340 }
341 }"#;
342 let filter: EventFilterDefinition = serde_json::from_str(json).unwrap();
343 let serialized = serde_json::to_string(&filter).unwrap();
344 let deserialized: EventFilterDefinition = serde_json::from_str(&serialized).unwrap();
345 assert_eq!(filter, deserialized);
346 }
347
348 #[test]
349 fn test_event_definition_roundtrip_full() {
350 let json = r#"{
352 "id": "evt-456",
353 "source": "https://example.com/events",
354 "type": "com.example.event",
355 "time": "2025-06-15T10:30:00Z",
356 "subject": "user/456",
357 "datacontenttype": "application/json",
358 "dataschema": "https://example.com/schema"
359 }"#;
360 let event: EventDefinition = serde_json::from_str(json).unwrap();
361 let serialized = serde_json::to_string(&event).unwrap();
362 let deserialized: EventDefinition = serde_json::from_str(&serialized).unwrap();
363 assert_eq!(event, deserialized);
364 }
365
366 #[test]
367 fn test_consumption_until_disabled() {
368 let json = r#"{
371 "any": [{"with": {"type": "event1"}}],
372 "until": false
373 }"#;
374 let strategy: EventConsumptionStrategyDefinition = serde_json::from_str(json).unwrap();
375 match *strategy.until.unwrap() {
376 OneOfEventConsumptionStrategyDefinitionOrExpression::Bool(b) => {
377 assert!(!b);
378 }
379 _ => panic!("Expected Bool(false) variant"),
380 }
381 }
382
383 #[test]
384 fn test_consumption_until_expression_string() {
385 let json = r#"{
387 "any": [{"with": {"type": "event1"}}],
388 "until": "workflow.data.condition == true"
389 }"#;
390 let strategy: EventConsumptionStrategyDefinition = serde_json::from_str(json).unwrap();
391 match *strategy.until.unwrap() {
392 OneOfEventConsumptionStrategyDefinitionOrExpression::Expression(expr) => {
393 assert_eq!(expr, "workflow.data.condition == true");
394 }
395 _ => panic!("Expected Expression variant"),
396 }
397 }
398
399 #[test]
400 fn test_consumption_until_nested_strategy() {
401 let json = r#"{
403 "any": [{"with": {"type": "event1"}}],
404 "until": {"one": {"with": {"type": "example.event.type"}}}
405 }"#;
406 let strategy: EventConsumptionStrategyDefinition = serde_json::from_str(json).unwrap();
407 match *strategy.until.unwrap() {
408 OneOfEventConsumptionStrategyDefinitionOrExpression::Strategy(s) => {
409 assert!(s.one.is_some());
410 assert!(s.all.is_none());
411 assert!(s.any.is_none());
412 }
413 _ => panic!("Expected Strategy variant"),
414 }
415 }
416
417 #[test]
418 fn test_correlation_key_roundtrip() {
419 let json = r#"{"from": "${ .orderId }", "expect": "order-789"}"#;
420 let key: CorrelationKeyDefinition = serde_json::from_str(json).unwrap();
421 let serialized = serde_json::to_string(&key).unwrap();
422 let deserialized: CorrelationKeyDefinition = serde_json::from_str(&serialized).unwrap();
423 assert_eq!(key, deserialized);
424 }
425
426 #[test]
427 fn test_event_filter_minimal() {
428 let json = r#"{"with": {"type": "com.example.event"}}"#;
430 let filter: EventFilterDefinition = serde_json::from_str(json).unwrap();
431 assert!(filter.with.is_some());
432 assert!(filter.correlate.is_none());
433 }
434}