made_core/entities/
task_metadata.rs1use serde::{Deserialize, Serialize};
2
3use crate::events::EventEnvelope;
4use crate::value_objects::{Attributes, CouncilContractId, EventId, OutputContractId};
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
8#[serde(default)]
9pub struct TaskMetadata {
10 source_event_id: Option<EventId>,
11 causation_id: Option<EventId>,
12 correlation_id: Option<EventId>,
13 council_contract_id: Option<CouncilContractId>,
14 output_contract_id: Option<OutputContractId>,
15 execution_profile: Attributes,
16}
17
18impl TaskMetadata {
19 #[must_use]
20 pub fn new(
21 source_event_id: Option<EventId>,
22 causation_id: Option<EventId>,
23 correlation_id: Option<EventId>,
24 council_contract_id: Option<CouncilContractId>,
25 output_contract_id: Option<OutputContractId>,
26 execution_profile: Attributes,
27 ) -> Self {
28 Self {
29 source_event_id,
30 causation_id,
31 correlation_id,
32 council_contract_id,
33 output_contract_id,
34 execution_profile,
35 }
36 }
37
38 #[must_use]
39 pub fn from_trigger_envelope(envelope: &EventEnvelope) -> Self {
40 Self::default().with_trigger_envelope(envelope)
41 }
42
43 #[must_use]
44 pub fn with_trigger_envelope(mut self, envelope: &EventEnvelope) -> Self {
45 if self.source_event_id.is_none() {
46 self.source_event_id = Some(envelope.event_id().clone());
47 }
48 if self.causation_id.is_none() {
49 self.causation_id = envelope
50 .causation_id()
51 .cloned()
52 .or_else(|| Some(envelope.event_id().clone()));
53 }
54 if self.correlation_id.is_none() {
55 self.correlation_id = envelope
56 .correlation_id()
57 .cloned()
58 .or_else(|| Some(envelope.event_id().clone()));
59 }
60 self
61 }
62
63 #[must_use]
64 pub fn source_event_id(&self) -> Option<&EventId> {
65 self.source_event_id.as_ref()
66 }
67
68 #[must_use]
69 pub fn causation_id(&self) -> Option<&EventId> {
70 self.causation_id.as_ref()
71 }
72
73 #[must_use]
74 pub fn correlation_id(&self) -> Option<&EventId> {
75 self.correlation_id.as_ref()
76 }
77
78 #[must_use]
79 pub fn council_contract_id(&self) -> Option<&CouncilContractId> {
80 self.council_contract_id.as_ref()
81 }
82
83 #[must_use]
84 pub fn output_contract_id(&self) -> Option<&OutputContractId> {
85 self.output_contract_id.as_ref()
86 }
87
88 #[must_use]
89 pub fn execution_profile(&self) -> &Attributes {
90 &self.execution_profile
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97 use time::macros::datetime;
98
99 #[test]
100 fn derives_causality_from_trigger_envelope() {
101 let envelope = EventEnvelope::new_with_causation(
102 EventId::new("trigger-1").unwrap(),
103 datetime!(2026-04-15 12:00:00 UTC),
104 "pir",
105 Some(EventId::new("corr-1").unwrap()),
106 Some(EventId::new("cause-1").unwrap()),
107 )
108 .unwrap();
109
110 let metadata = TaskMetadata::from_trigger_envelope(&envelope);
111
112 assert_eq!(metadata.source_event_id().unwrap().as_str(), "trigger-1");
113 assert_eq!(metadata.causation_id().unwrap().as_str(), "cause-1");
114 assert_eq!(metadata.correlation_id().unwrap().as_str(), "corr-1");
115 }
116}