Skip to main content

appletheia_application/outbox/
ordering_key.rs

1use std::{fmt, fmt::Display, str::FromStr};
2
3use serde::{Deserialize, Serialize};
4use thiserror::Error;
5
6use crate::event::{AggregateIdValue, AggregateTypeOwned};
7use crate::request_context::CorrelationId;
8
9#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize)]
10pub struct OrderingKey(String);
11
12impl OrderingKey {
13    pub fn new(value: String) -> Result<Self, OrderingKeyError> {
14        if value.trim().is_empty() {
15            return Err(OrderingKeyError::Empty);
16        }
17        Ok(Self(value))
18    }
19
20    pub fn as_str(&self) -> &str {
21        &self.0
22    }
23}
24
25impl Display for OrderingKey {
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        f.write_str(&self.0)
28    }
29}
30
31impl FromStr for OrderingKey {
32    type Err = OrderingKeyError;
33
34    fn from_str(s: &str) -> Result<Self, Self::Err> {
35        Self::new(s.to_string())
36    }
37}
38
39impl<'de> Deserialize<'de> for OrderingKey {
40    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
41    where
42        D: serde::Deserializer<'de>,
43    {
44        let value = String::deserialize(deserializer)?;
45        OrderingKey::new(value).map_err(serde::de::Error::custom)
46    }
47}
48
49impl From<(&AggregateTypeOwned, &AggregateIdValue)> for OrderingKey {
50    fn from((aggregate_type, aggregate_id): (&AggregateTypeOwned, &AggregateIdValue)) -> Self {
51        Self(format!(
52            "{}:{}",
53            aggregate_type.value(),
54            aggregate_id.value()
55        ))
56    }
57}
58
59impl From<CorrelationId> for OrderingKey {
60    fn from(value: CorrelationId) -> Self {
61        Self(value.to_string())
62    }
63}
64
65#[derive(Debug, Error)]
66pub enum OrderingKeyError {
67    #[error("ordering key cannot be empty")]
68    Empty,
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn accepts_non_empty() {
77        let key = OrderingKey::new("abc".to_string()).unwrap();
78        assert_eq!(key.as_str(), "abc");
79    }
80
81    #[test]
82    fn rejects_empty() {
83        let err = OrderingKey::new("".to_string()).unwrap_err();
84        assert!(matches!(err, OrderingKeyError::Empty));
85    }
86}