evento_core/metadata.rs
1//! Standard event metadata types.
2//!
3//! This module provides standard metadata types for events, including
4//! user identification and unique metadata IDs.
5//!
6//! # Types
7//!
8//! - [`Metadata`] - Standard metadata with ID and extensible key-value storage
9//! - [`Event`] - Typed event wrapper with deserialized data
10//! - [`RawEvent`] - Raw event without deserialization (for batch processing)
11//!
12//! # Example
13//!
14//! ```rust,ignore
15//! use evento::metadata::Metadata;
16//!
17//! // Create default metadata (anonymous)
18//! let mut metadata = Metadata::default();
19//!
20//! // Set who is making the request
21//! metadata.set_requested_by("user-123");
22//!
23//! // Set who the request is on behalf of (for impersonation)
24//! metadata.set_requested_as("impersonated-user-789");
25//!
26//! // Use with event creation
27//! create()
28//! .event(&my_event)
29//! .metadata(&metadata)
30//! .commit(&executor)
31//! .await?;
32//!
33//! // Access metadata from events
34//! if let Ok(user_id) = event.metadata.requested_by() {
35//! println!("Requested by: {}", user_id);
36//! }
37//! ```
38
39use std::{collections::HashMap, marker::PhantomData, ops::Deref};
40use thiserror::Error;
41use ulid::Ulid;
42
43const REQUESTED_BY: &str = "EVENTO_REQUESTED_BY";
44const REQUESTED_AS: &str = "EVENTO_REQUESTED_AS";
45
46/// Errors when accessing metadata fields.
47#[derive(Debug, Error)]
48pub enum MetadataError {
49 #[error("not found")]
50 NotFound,
51
52 #[error("decode: {0}")]
53 Decode(#[from] bitcode::Error),
54}
55
56/// Standard event metadata.
57///
58/// Contains a unique ID and user identification. Default creates
59/// anonymous metadata with an auto-generated ULID.
60#[derive(Clone, PartialEq, Debug, bitcode::Encode, bitcode::Decode)]
61pub struct Metadata {
62 /// Unique metadata ID (ULID)
63 pub id: String,
64 meta: HashMap<String, Vec<u8>>,
65}
66
67impl Metadata {
68 pub(crate) fn insert_enc<V: bitcode::Encode>(
69 &mut self,
70 key: impl Into<String>,
71 value: &V,
72 ) -> &mut Self {
73 self.meta.insert(key.into(), bitcode::encode(value));
74
75 self
76 }
77
78 pub fn try_get<D: bitcode::DecodeOwned>(&self, key: &str) -> Result<D, MetadataError> {
79 let Some(value) = self.meta.get(key) else {
80 return Err(MetadataError::NotFound);
81 };
82
83 Ok(bitcode::decode(value)?)
84 }
85
86 pub fn set_requested_as(&mut self, value: impl Into<String>) -> &mut Self {
87 let value = value.into();
88 self.insert_enc(REQUESTED_AS, &value);
89
90 self
91 }
92
93 pub fn requested_as(&self) -> Result<String, MetadataError> {
94 self.try_get(REQUESTED_AS)
95 }
96
97 pub fn set_requested_by(&mut self, value: impl Into<String>) -> &mut Self {
98 let value = value.into();
99 self.insert_enc(REQUESTED_BY, &value);
100
101 self
102 }
103
104 pub fn requested_by(&self) -> Result<String, MetadataError> {
105 self.try_get(REQUESTED_BY)
106 }
107}
108
109impl Default for Metadata {
110 fn default() -> Self {
111 Self {
112 id: Ulid::new().to_string(),
113 meta: Default::default(),
114 }
115 }
116}
117
118impl Deref for Metadata {
119 type Target = HashMap<String, Vec<u8>>;
120
121 fn deref(&self) -> &Self::Target {
122 &self.meta
123 }
124}
125
126impl From<&Metadata> for Metadata {
127 fn from(value: &Metadata) -> Self {
128 value.clone()
129 }
130}
131
132/// Typed event with deserialized data.
133///
134/// `Event` wraps a raw [`crate::Event`] and provides typed access
135/// to the deserialized event data. It implements `Deref` to
136/// provide access to the underlying event fields (id, timestamp, version, metadata, etc.).
137///
138/// # Type Parameters
139///
140/// - `D`: The event data type (e.g., `AccountOpened`)
141///
142/// # Example
143///
144/// ```rust,ignore
145/// use evento::metadata::Event;
146///
147/// #[evento::handler]
148/// async fn handle_deposit(
149/// event: Event<MoneyDeposited>,
150/// view: &mut AccountView,
151/// ) -> anyhow::Result<()> {
152/// // Access typed data
153/// println!("Amount: {}", event.data.amount);
154///
155/// // Access metadata via Deref
156/// if let Ok(user) = event.metadata.requested_by() {
157/// println!("By user: {}", user);
158/// }
159///
160/// // Access underlying event fields via Deref
161/// println!("Event ID: {}", event.id);
162/// println!("Version: {}", event.version);
163///
164/// Ok(())
165/// }
166/// ```
167pub struct Event<D> {
168 event: crate::Event,
169 /// The typed event data
170 pub data: D,
171}
172
173impl<D> Deref for Event<D> {
174 type Target = crate::Event;
175
176 fn deref(&self) -> &Self::Target {
177 &self.event
178 }
179}
180
181impl<D> TryFrom<&crate::Event> for Event<D>
182where
183 D: bitcode::DecodeOwned,
184{
185 type Error = bitcode::Error;
186
187 fn try_from(value: &crate::Event) -> Result<Self, Self::Error> {
188 let data = bitcode::decode::<D>(&value.data)?;
189 Ok(Event {
190 data,
191 event: value.clone(),
192 })
193 }
194}
195
196pub struct RawEvent<D>(pub crate::Event, pub PhantomData<D>);
197
198impl<D> Deref for RawEvent<D> {
199 type Target = crate::Event;
200
201 fn deref(&self) -> &Self::Target {
202 &self.0
203 }
204}