1+ use serde:: { Deserialize , Deserializer , Serializer } ;
2+ use serde:: de:: Unexpected ;
3+ use uuid:: Uuid ;
4+
5+ /// Custom deserializer for optional UUID that treats empty strings as None.
6+ pub fn de_string_as_optional_uuid < ' de , D > ( deserializer : D ) -> Result < Option < Uuid > , D :: Error >
7+ where
8+ D : Deserializer < ' de > ,
9+ {
10+ let s: Option < String > = Option :: deserialize ( deserializer) ?;
11+ match s {
12+ None => Ok ( None ) ,
13+ Some ( ref s) if s. is_empty ( ) => Ok ( None ) ,
14+ Some ( s) => s. parse :: < Uuid > ( )
15+ . map ( Some )
16+ . map_err ( |_e| serde:: de:: Error :: invalid_type ( Unexpected :: Str ( & s) , & "Valid Uuid" ) ) ,
17+ }
18+ }
19+
20+ /// Custom serializer for optional UUID that serializes None as an empty string.
21+ pub fn ser_optional_uuid_as_string < S > (
22+ value : & Option < Uuid > ,
23+ serializer : S ,
24+ ) -> Result < S :: Ok , S :: Error >
25+ where
26+ S : Serializer ,
27+ {
28+ match value {
29+ Some ( uuid) => serializer. serialize_str ( & uuid. to_string ( ) ) ,
30+ None => serializer. serialize_str ( "" ) ,
31+ }
32+ }
33+
34+ #[ cfg( test) ]
35+ mod tests {
36+ use super :: * ;
37+ use serde:: { Deserialize , Serialize } ;
38+ use serde_json:: json;
39+
40+ #[ derive( Debug , Serialize , Deserialize , PartialEq ) ]
41+ struct TestStruct {
42+ #[ serde(
43+ deserialize_with = "de_string_as_optional_uuid" ,
44+ serialize_with = "ser_optional_uuid_as_string"
45+ ) ]
46+ id : Option < Uuid > ,
47+ }
48+
49+ #[ test]
50+ fn test_deserialize_null_uuid ( ) {
51+ let json = json ! ( { "id" : null} ) ;
52+ let result: TestStruct = serde_json:: from_value ( json) . unwrap ( ) ;
53+ assert_eq ! ( result. id, None ) ;
54+ }
55+
56+ #[ test]
57+ fn test_deserialize_empty_string_uuid ( ) {
58+ let json = json ! ( { "id" : "" } ) ;
59+ let result: TestStruct = serde_json:: from_value ( json) . unwrap ( ) ;
60+ assert_eq ! ( result. id, None ) ;
61+ }
62+
63+ #[ test]
64+ fn test_deserialize_valid_uuid ( ) {
65+ let uuid_str = "550e8400-e29b-41d4-a716-446655440000" ;
66+ let json = json ! ( { "id" : uuid_str} ) ;
67+ let result: TestStruct = serde_json:: from_value ( json) . unwrap ( ) ;
68+ assert_eq ! ( result. id, Some ( Uuid :: parse_str( uuid_str) . unwrap( ) ) ) ;
69+ }
70+
71+ #[ test]
72+ fn test_deserialize_invalid_uuid ( ) {
73+ let json = json ! ( { "id" : "not-a-valid-uuid" } ) ;
74+ let result: Result < TestStruct , _ > = serde_json:: from_value ( json) ;
75+ assert ! ( result. is_err( ) ) ;
76+
77+ // Verify the error message contains something about UUID parsing
78+ let err = result. unwrap_err ( ) ;
79+ let err_msg = err. to_string ( ) . to_lowercase ( ) ;
80+ assert ! ( err_msg. contains( "uuid" ) || err_msg. contains( "invalid" ) ) ;
81+ }
82+
83+ #[ test]
84+ fn test_serialize_none_as_empty_string ( ) {
85+ let test_struct = TestStruct { id : None } ;
86+ let json = serde_json:: to_value ( & test_struct) . unwrap ( ) ;
87+ assert_eq ! ( json, json!( { "id" : "" } ) ) ;
88+ }
89+
90+ #[ test]
91+ fn test_serialize_some_uuid ( ) {
92+ let uuid = Uuid :: parse_str ( "550e8400-e29b-41d4-a716-446655440000" ) . unwrap ( ) ;
93+ let test_struct = TestStruct { id : Some ( uuid) } ;
94+ let json = serde_json:: to_value ( & test_struct) . unwrap ( ) ;
95+ assert_eq ! ( json, json!( { "id" : "550e8400-e29b-41d4-a716-446655440000" } ) ) ;
96+ }
97+
98+ #[ test]
99+ fn test_roundtrip_none ( ) {
100+ let original = TestStruct { id : None } ;
101+ let json = serde_json:: to_value ( & original) . unwrap ( ) ;
102+ let deserialized: TestStruct = serde_json:: from_value ( json) . unwrap ( ) ;
103+ assert_eq ! ( original, deserialized) ;
104+ }
105+
106+ #[ test]
107+ fn test_roundtrip_some ( ) {
108+ let uuid = Uuid :: parse_str ( "550e8400-e29b-41d4-a716-446655440000" ) . unwrap ( ) ;
109+ let original = TestStruct { id : Some ( uuid) } ;
110+ let json = serde_json:: to_value ( & original) . unwrap ( ) ;
111+ let deserialized: TestStruct = serde_json:: from_value ( json) . unwrap ( ) ;
112+ assert_eq ! ( original, deserialized) ;
113+ }
114+ }
0 commit comments