Skip to main content

pjson_rs/application/dto/
priority_dto.rs

1//! Priority Data Transfer Object for serialization
2//!
3//! Handles serialization/deserialization of Priority domain objects
4//! while keeping domain layer clean of serialization concerns.
5
6use crate::domain::value_objects::Priority;
7use crate::domain::{DomainError, DomainResult};
8use serde::{Deserialize, Serialize};
9
10/// Serializable representation of Priority domain object
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(transparent)]
13pub struct PriorityDto {
14    value: u8,
15}
16
17impl PriorityDto {
18    /// Create from raw value with validation
19    pub fn new(value: u8) -> DomainResult<Self> {
20        // Validate using domain rules
21        Priority::new(value)?;
22        Ok(Self { value })
23    }
24
25    /// Get raw value
26    pub fn value(self) -> u8 {
27        self.value
28    }
29}
30
31impl From<Priority> for PriorityDto {
32    fn from(priority: Priority) -> Self {
33        Self {
34            value: priority.value(),
35        }
36    }
37}
38
39impl TryFrom<PriorityDto> for Priority {
40    type Error = DomainError;
41
42    fn try_from(dto: PriorityDto) -> Result<Self, Self::Error> {
43        Priority::new(dto.value)
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50    use serde_json;
51
52    #[test]
53    fn test_priority_dto_serialization() {
54        let priority = Priority::CRITICAL;
55        let dto = PriorityDto::from(priority);
56
57        // Test JSON serialization
58        let json = serde_json::to_string(&dto).unwrap();
59        assert_eq!(json, "100");
60
61        // Test JSON deserialization
62        let deserialized: PriorityDto = serde_json::from_str(&json).unwrap();
63        assert_eq!(deserialized.value(), 100);
64
65        // Test conversion back to domain
66        let domain_priority = Priority::try_from(deserialized).unwrap();
67        assert_eq!(domain_priority, Priority::CRITICAL);
68    }
69
70    #[test]
71    fn test_priority_dto_validation() {
72        // Valid priority
73        assert!(PriorityDto::new(100).is_ok());
74
75        // Invalid priority (zero)
76        assert!(PriorityDto::new(0).is_err());
77    }
78
79    #[test]
80    fn test_try_from_invalid_priority_dto_fails() {
81        // `PriorityDto` is `#[serde(transparent)]` over a bare `u8` and derives
82        // `Deserialize` directly, so it can be built from wire data that bypasses
83        // `PriorityDto::new`'s validation entirely.
84        let invalid_dto: PriorityDto = serde_json::from_str("0").unwrap();
85
86        let result = Priority::try_from(invalid_dto);
87        assert!(matches!(result, Err(DomainError::InvalidPriority(_))));
88    }
89
90    #[test]
91    fn test_conversion_traits() {
92        let priority = Priority::HIGH;
93
94        // Test From trait
95        let dto: PriorityDto = priority.into();
96        assert_eq!(dto.value(), 80);
97
98        // Test TryFrom trait
99        let converted = Priority::try_from(dto).unwrap();
100        assert_eq!(converted, Priority::HIGH);
101    }
102}