1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
//! This module contains the definition of a [Message] type, which
//! can be used to describe some sort of domain value such as a [Domain Event][crate::event::Envelope],
//! a [Domain Command][crate::command::Envelope], and so on.
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
/// Represents a piece of domain data that occurs in the system.
///
/// Each Message has a specific name to it, which should ideally be
/// unique within the domain you're operating in. Example: a Domain Event
/// that represents when an Order was created can have a `name()`: `"OrderWasCreated"`.
pub trait Message {
/// Returns the domain name of the [Message].
fn name(&self) -> &'static str;
}
/// Optional metadata to attach to an [Envelope] to provide additional context
/// to the [Message] carried out.
pub type Metadata = HashMap<String, String>;
/// Represents a [Message] packaged for persistance and/or processing by other
/// parts of the system.
///
/// It carries both the actual message (i.e. a payload) and some optional [Metadata].
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Envelope<T>
where
T: Message,
{
/// The message payload.
pub message: T,
/// Optional metadata to provide additional context to the message.
pub metadata: Metadata,
}
impl<T> Envelope<T>
where
T: Message,
{
/// Adds a new entry in the [Envelope]'s [Metadata].
#[must_use]
pub fn with_metadata(mut self, key: String, value: String) -> Self {
self.metadata.insert(key, value);
self
}
}
impl<T> From<T> for Envelope<T>
where
T: Message,
{
fn from(message: T) -> Self {
Envelope {
message,
metadata: Metadata::default(),
}
}
}
impl<T> PartialEq for Envelope<T>
where
T: Message + PartialEq,
{
fn eq(&self, other: &Envelope<T>) -> bool {
self.message == other.message
}
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct StringMessage(pub(crate) &'static str);
impl Message for StringMessage {
fn name(&self) -> &'static str {
"string_payload"
}
}
#[test]
fn message_with_metadata_does_not_affect_equality() {
let message = Envelope {
message: StringMessage("hello"),
metadata: Metadata::default(),
};
let new_message = message
.clone()
.with_metadata("hello_world".into(), "test".into())
.with_metadata("test_number".into(), 1.to_string());
println!("Message: {message:?}");
println!("New message: {new_message:?}");
// Metadata does not affect equality of message.
assert_eq!(message, new_message);
}
}