Skip to main content

bo4e_core/com/
region_criterion.rs

1//! Region criterion (Regionskriterium) component.
2
3use serde::{Deserialize, Serialize};
4
5use crate::enums::{RegionCriterionType, ValidityType};
6use crate::traits::{Bo4eMeta, Bo4eObject};
7
8/// Component for modeling a regional criterion.
9///
10/// Used to define criteria for regional delimitation, such as postal codes,
11/// federal states, or network areas.
12///
13/// German: Regionskriterium
14///
15/// # Example
16///
17/// ```rust
18/// use bo4e_core::com::RegionCriterion;
19/// use bo4e_core::enums::{RegionCriterionType, ValidityType};
20///
21/// let criterion = RegionCriterion {
22///     validity_type: Some(ValidityType::OnlyIn),
23///     criterion_type: Some(RegionCriterionType::PostalCode),
24///     value: Some("50667".to_string()),
25///     ..Default::default()
26/// };
27/// ```
28#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
29#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
30#[cfg_attr(feature = "json-schema", schemars(rename = "Regionskriterium"))]
31#[serde(rename_all = "camelCase")]
32pub struct RegionCriterion {
33    /// BO4E metadata
34    #[serde(flatten)]
35    pub meta: Bo4eMeta,
36
37    /// Whether this is an inclusive or exclusive criterion (Gueltigkeitstyp)
38    #[serde(skip_serializing_if = "Option::is_none")]
39    #[cfg_attr(feature = "json-schema", schemars(rename = "gueltigkeitstyp"))]
40    pub validity_type: Option<ValidityType>,
41
42    /// The type of criterion, e.g., federal state, postal code (Regionskriteriumtyp)
43    #[serde(skip_serializing_if = "Option::is_none")]
44    #[cfg_attr(feature = "json-schema", schemars(rename = "regionskriteriumtyp"))]
45    pub criterion_type: Option<RegionCriterionType>,
46
47    /// The value the criterion takes, e.g., "NRW" or "50667" (Wert)
48    /// Note: For BUNDESWEIT (nationwide), this value is not relevant.
49    #[serde(skip_serializing_if = "Option::is_none")]
50    #[cfg_attr(feature = "json-schema", schemars(rename = "wert"))]
51    pub value: Option<String>,
52}
53
54impl Bo4eObject for RegionCriterion {
55    fn type_name_german() -> &'static str {
56        "Regionskriterium"
57    }
58
59    fn type_name_english() -> &'static str {
60        "RegionCriterion"
61    }
62
63    fn meta(&self) -> &Bo4eMeta {
64        &self.meta
65    }
66
67    fn meta_mut(&mut self) -> &mut Bo4eMeta {
68        &mut self.meta
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn test_region_criterion_default() {
78        let criterion = RegionCriterion::default();
79        assert!(criterion.validity_type.is_none());
80        assert!(criterion.criterion_type.is_none());
81        assert!(criterion.value.is_none());
82    }
83
84    #[test]
85    fn test_region_criterion_postal_code() {
86        let criterion = RegionCriterion {
87            validity_type: Some(ValidityType::OnlyIn),
88            criterion_type: Some(RegionCriterionType::PostalCode),
89            value: Some("50667".to_string()),
90            ..Default::default()
91        };
92
93        let json = serde_json::to_string(&criterion).unwrap();
94        assert!(json.contains(r#""validityType":"NUR_IN""#));
95        assert!(json.contains(r#""criterionType":"POSTLEITZAHL""#));
96        assert!(json.contains(r#""value":"50667""#));
97    }
98
99    #[test]
100    fn test_region_criterion_federal_state() {
101        let criterion = RegionCriterion {
102            validity_type: Some(ValidityType::NotIn),
103            criterion_type: Some(RegionCriterionType::FederalStateName),
104            value: Some("Bayern".to_string()),
105            ..Default::default()
106        };
107
108        let json = serde_json::to_string(&criterion).unwrap();
109        assert!(json.contains(r#""validityType":"NICHT_IN""#));
110        assert!(json.contains(r#""criterionType":"BUNDESLAND_NAME""#));
111    }
112
113    #[test]
114    fn test_region_criterion_nationwide() {
115        let criterion = RegionCriterion {
116            validity_type: Some(ValidityType::OnlyIn),
117            criterion_type: Some(RegionCriterionType::Nationwide),
118            value: None, // Not relevant for nationwide
119            ..Default::default()
120        };
121
122        let json = serde_json::to_string(&criterion).unwrap();
123        assert!(json.contains(r#""criterionType":"BUNDESWEIT""#));
124        assert!(!json.contains(r#""value""#)); // Should be skipped
125    }
126
127    #[test]
128    fn test_region_criterion_roundtrip() {
129        let criterion = RegionCriterion {
130            meta: Bo4eMeta::with_type("Regionskriterium"),
131            validity_type: Some(ValidityType::OnlyInCombinationWith),
132            criterion_type: Some(RegionCriterionType::MunicipalityName),
133            value: Some("Köln".to_string()),
134        };
135
136        let json = serde_json::to_string(&criterion).unwrap();
137        let parsed: RegionCriterion = serde_json::from_str(&json).unwrap();
138        assert_eq!(criterion, parsed);
139    }
140
141    #[test]
142    fn test_bo4e_object_impl() {
143        assert_eq!(RegionCriterion::type_name_german(), "Regionskriterium");
144        assert_eq!(RegionCriterion::type_name_english(), "RegionCriterion");
145    }
146}