Skip to main content

arts_n_crafts/core/
command.rs

1use crate::core::base_payload::BasePayload;
2use chrono::Utc;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
7pub struct Command<TPayload>
8where
9    TPayload: BasePayload,
10{
11    pub command_type: String,
12    pub aggregate_id: String,
13    pub payload: TPayload,
14    pub timestamp: i64,
15    pub metadata: HashMap<String, String>,
16}
17
18impl<TPayload> Command<TPayload>
19where
20    TPayload: BasePayload + AsRef<str>,
21{
22    pub fn create(aggregate_id: String, payload: TPayload) -> Self {
23        Command {
24            command_type: payload.as_ref().to_string(),
25            aggregate_id: aggregate_id.to_string(),
26            payload: payload.clone(),
27            timestamp: Utc::now().timestamp_millis(),
28            metadata: HashMap::new(),
29        }
30    }
31
32    pub fn add_to_metadata(&mut self, key: String, value: String) {
33        self.metadata.insert(key, value);
34    }
35
36    pub fn set_correlation_id(&mut self, correlation_id: String) {
37        self.metadata
38            .insert("correlation_id".to_string(), correlation_id);
39    }
40
41    pub fn set_causation_id(&mut self, causation_id: String) {
42        self.metadata
43            .insert("causation_id".to_string(), causation_id);
44    }
45}
46
47#[cfg(test)]
48mod command_tests {
49    use super::*;
50    use rstest::rstest;
51    use serde::{Deserialize, Serialize};
52    use strum_macros::AsRefStr;
53    use uuid::Uuid;
54
55    #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, AsRefStr)]
56    pub enum UserCommandPayload {
57        CreateUser { name: String },
58        LikeUser { user_id: String },
59    }
60
61    #[rstest]
62    fn it_should_create_a_domain_event() {
63        let aggregate_id = Uuid::now_v7().to_string();
64        let payload = UserCommandPayload::CreateUser {
65            name: "John Doe".to_string(),
66        };
67        let event = Command::create(aggregate_id.clone(), payload.clone());
68        assert_eq!(event.payload.as_ref(), payload.as_ref());
69        assert_eq!(event.aggregate_id, aggregate_id);
70        assert_eq!(event.payload, payload);
71        assert_eq!(event.metadata, HashMap::new());
72    }
73
74    #[rstest]
75    fn it_should_add_metadata_causation_id_and_correlation_id() {
76        let aggregate_id = Uuid::now_v7().to_string();
77        let payload = UserCommandPayload::CreateUser {
78            name: "John Doe".to_string(),
79        };
80        let mut event = Command::create(aggregate_id.to_string(), payload.clone());
81        let causation_id = Uuid::now_v7();
82        let correlation_id = Uuid::now_v7();
83        event.set_causation_id(causation_id.clone().to_string());
84        event.set_correlation_id(correlation_id.clone().to_string());
85        event.add_to_metadata("version".to_string(), "1".to_string());
86
87        assert_eq!(
88            *event.metadata.get("correlation_id").unwrap(),
89            correlation_id.to_string()
90        );
91        assert_eq!(
92            *event.metadata.get("causation_id").unwrap(),
93            causation_id.to_string()
94        );
95        assert_eq!(*event.metadata.get("version").unwrap(), "1".to_string());
96    }
97}