pjson_rs/application/dto/
json_path_dto.rs

1//! JsonPath Data Transfer Object for serialization
2//!
3//! Handles serialization/deserialization of JsonPath domain objects
4//! while keeping domain layer clean of serialization concerns.
5
6use crate::{
7    application::dto::priority_dto::{FromDto, ToDto},
8    domain::{DomainError, DomainResult, value_objects::JsonPath},
9};
10use serde::{Deserialize, Serialize};
11
12/// Serializable representation of JsonPath domain object
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(transparent)]
15pub struct JsonPathDto {
16    path: String,
17}
18
19impl JsonPathDto {
20    /// Create from path string with validation
21    pub fn new(path: impl Into<String>) -> DomainResult<Self> {
22        let path = path.into();
23        // Validate using domain rules
24        JsonPath::new(&path)?;
25        Ok(Self { path })
26    }
27
28    /// Create root path DTO
29    pub fn root() -> Self {
30        Self {
31            path: "$".to_string(),
32        }
33    }
34
35    /// Get path string
36    pub fn path(&self) -> &str {
37        &self.path
38    }
39
40    /// Get owned path string
41    pub fn into_path(self) -> String {
42        self.path
43    }
44}
45
46impl From<JsonPath> for JsonPathDto {
47    fn from(json_path: JsonPath) -> Self {
48        Self {
49            path: json_path.as_str().to_string(),
50        }
51    }
52}
53
54impl TryFrom<JsonPathDto> for JsonPath {
55    type Error = DomainError;
56
57    fn try_from(dto: JsonPathDto) -> Result<Self, Self::Error> {
58        JsonPath::new(dto.path)
59    }
60}
61
62/// Utility trait implementation for JsonPath
63impl ToDto<JsonPathDto> for JsonPath {
64    fn to_dto(self) -> JsonPathDto {
65        JsonPathDto::from(self)
66    }
67}
68
69/// Utility trait implementation for JsonPath
70impl FromDto<JsonPathDto> for JsonPath {
71    type Error = DomainError;
72
73    fn from_dto(dto: JsonPathDto) -> Result<Self, Self::Error> {
74        JsonPath::try_from(dto)
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81    use serde_json;
82
83    #[test]
84    fn test_json_path_dto_serialization() {
85        let json_path = JsonPath::new("$.users[0].name").unwrap();
86        let dto = JsonPathDto::from(json_path);
87
88        // Test JSON serialization
89        let json = serde_json::to_string(&dto).unwrap();
90        assert_eq!(json, "\"$.users[0].name\"");
91
92        // Test JSON deserialization
93        let deserialized: JsonPathDto = serde_json::from_str(&json).unwrap();
94        assert_eq!(deserialized.path(), "$.users[0].name");
95
96        // Test conversion back to domain
97        let domain_path = JsonPath::from_dto(deserialized).unwrap();
98        assert_eq!(domain_path.as_str(), "$.users[0].name");
99    }
100
101    #[test]
102    fn test_json_path_dto_validation() {
103        // Valid path
104        assert!(JsonPathDto::new("$.valid.path").is_ok());
105
106        // Invalid path
107        assert!(JsonPathDto::new("invalid.path").is_err());
108        assert!(JsonPathDto::new("$.").is_err());
109    }
110
111    #[test]
112    fn test_json_path_dto_root() {
113        let root_dto = JsonPathDto::root();
114        assert_eq!(root_dto.path(), "$");
115
116        let domain_root = JsonPath::from_dto(root_dto).unwrap();
117        assert_eq!(domain_root, JsonPath::root());
118    }
119
120    #[test]
121    fn test_conversion_traits() {
122        let json_path = JsonPath::new("$.test.path").unwrap();
123
124        // Test ToDto trait
125        let dto = json_path.to_dto();
126        assert_eq!(dto.path(), "$.test.path");
127
128        // Test FromDto trait
129        let converted = JsonPath::from_dto(dto).unwrap();
130        assert_eq!(converted.as_str(), "$.test.path");
131    }
132
133    #[test]
134    fn test_json_path_dto_edge_cases() {
135        let paths = vec![
136            "$",
137            "$.key",
138            "$.array[0]",
139            "$.nested.deep.path",
140            "$.array[123].field",
141        ];
142
143        for path in paths {
144            let original = JsonPath::new(path).unwrap();
145            let original_str = original.as_str().to_string(); // Save string before move
146            let dto = original.to_dto();
147            let serialized = serde_json::to_string(&dto).unwrap();
148            let deserialized: JsonPathDto = serde_json::from_str(&serialized).unwrap();
149            let restored = JsonPath::from_dto(deserialized).unwrap();
150
151            assert_eq!(original_str, restored.as_str());
152        }
153    }
154}