bo4e_core/com/
address.rs

1//! Address (Adresse) component.
2
3use serde::{Deserialize, Serialize};
4
5use crate::enums::Country;
6use crate::traits::{Bo4eMeta, Bo4eObject};
7
8/// Physical or postal address.
9///
10/// German: Adresse
11///
12/// # Example
13///
14/// ```rust
15/// use bo4e_core::com::Address;
16///
17/// let address = Address {
18///     street: Some("Musterstraße".to_string()),
19///     house_number: Some("42".to_string()),
20///     postal_code: Some("50667".to_string()),
21///     city: Some("Köln".to_string()),
22///     ..Default::default()
23/// };
24/// ```
25#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
26#[serde(rename_all = "camelCase")]
27pub struct Address {
28    /// BO4E metadata
29    #[serde(flatten)]
30    pub meta: Bo4eMeta,
31
32    /// Street name (Strasse)
33    #[serde(skip_serializing_if = "Option::is_none", alias = "strasse")]
34    pub street: Option<String>,
35
36    /// House number (Hausnummer)
37    #[serde(skip_serializing_if = "Option::is_none", alias = "hausnummer")]
38    pub house_number: Option<String>,
39
40    /// Postal code (Postleitzahl)
41    #[serde(skip_serializing_if = "Option::is_none", alias = "postleitzahl")]
42    pub postal_code: Option<String>,
43
44    /// City/town (Ort)
45    #[serde(skip_serializing_if = "Option::is_none", alias = "ort")]
46    pub city: Option<String>,
47
48    /// District (Ortsteil)
49    #[serde(skip_serializing_if = "Option::is_none", alias = "ortsteil")]
50    pub district: Option<String>,
51
52    /// PO Box number (Postfach)
53    #[serde(skip_serializing_if = "Option::is_none", alias = "postfach")]
54    pub po_box: Option<String>,
55
56    /// Address addition/note (Adresszusatz)
57    #[serde(skip_serializing_if = "Option::is_none", alias = "adresszusatz")]
58    pub address_addition: Option<String>,
59
60    /// Co-location info - c/o address (CoErgaenzung)
61    #[serde(skip_serializing_if = "Option::is_none", alias = "coErgaenzung")]
62    pub co_ergaenzung: Option<String>,
63
64    /// Country code (Landescode)
65    #[serde(skip_serializing_if = "Option::is_none", alias = "landescode")]
66    pub country_code: Option<Country>,
67}
68
69impl Bo4eObject for Address {
70    fn type_name_german() -> &'static str {
71        "Adresse"
72    }
73
74    fn type_name_english() -> &'static str {
75        "Address"
76    }
77
78    fn meta(&self) -> &Bo4eMeta {
79        &self.meta
80    }
81
82    fn meta_mut(&mut self) -> &mut Bo4eMeta {
83        &mut self.meta
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_address_default() {
93        let address = Address::default();
94        assert!(address.street.is_none());
95        assert!(address.city.is_none());
96    }
97
98    #[test]
99    fn test_address_serialize() {
100        let address = Address {
101            street: Some("Hauptstraße".to_string()),
102            house_number: Some("1".to_string()),
103            postal_code: Some("12345".to_string()),
104            city: Some("Berlin".to_string()),
105            ..Default::default()
106        };
107
108        let json = serde_json::to_string(&address).unwrap();
109        assert!(json.contains(r#""street":"Hauptstraße""#));
110        assert!(json.contains(r#""houseNumber":"1""#));
111        assert!(json.contains(r#""postalCode":"12345""#));
112        assert!(json.contains(r#""city":"Berlin""#));
113    }
114
115    #[test]
116    fn test_address_deserialize() {
117        let json = r#"{
118            "street": "Musterweg",
119            "houseNumber": "42a",
120            "postalCode": "50667",
121            "city": "Köln"
122        }"#;
123
124        let address: Address = serde_json::from_str(json).unwrap();
125        assert_eq!(address.street, Some("Musterweg".to_string()));
126        assert_eq!(address.house_number, Some("42a".to_string()));
127        assert_eq!(address.postal_code, Some("50667".to_string()));
128        assert_eq!(address.city, Some("Köln".to_string()));
129    }
130
131    #[test]
132    fn test_address_roundtrip() {
133        let address = Address {
134            meta: Bo4eMeta::with_type("Adresse"),
135            street: Some("Teststraße".to_string()),
136            house_number: Some("123".to_string()),
137            postal_code: Some("99999".to_string()),
138            city: Some("Teststadt".to_string()),
139            ..Default::default()
140        };
141
142        let json = serde_json::to_string(&address).unwrap();
143        let parsed: Address = serde_json::from_str(&json).unwrap();
144        assert_eq!(address, parsed);
145    }
146
147    #[test]
148    fn test_address_with_country() {
149        let address = Address {
150            street: Some("Musterstraße".to_string()),
151            city: Some("München".to_string()),
152            country_code: Some(Country::Germany),
153            ..Default::default()
154        };
155
156        let json = serde_json::to_string(&address).unwrap();
157        assert!(json.contains(r#""countryCode":"DE""#));
158
159        let parsed: Address = serde_json::from_str(&json).unwrap();
160        assert_eq!(parsed.country_code, Some(Country::Germany));
161    }
162
163    #[test]
164    fn test_bo4e_object_impl() {
165        assert_eq!(Address::type_name_german(), "Adresse");
166        assert_eq!(Address::type_name_english(), "Address");
167    }
168}