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#[serde(rename_all = "camelCase")]
30pub struct RegionCriterion {
31    /// BO4E metadata
32    #[serde(flatten)]
33    pub meta: Bo4eMeta,
34
35    /// Whether this is an inclusive or exclusive criterion (Gueltigkeitstyp)
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub validity_type: Option<ValidityType>,
38
39    /// The type of criterion, e.g., federal state, postal code (Regionskriteriumtyp)
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub criterion_type: Option<RegionCriterionType>,
42
43    /// The value the criterion takes, e.g., "NRW" or "50667" (Wert)
44    /// Note: For BUNDESWEIT (nationwide), this value is not relevant.
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub value: Option<String>,
47}
48
49impl Bo4eObject for RegionCriterion {
50    fn type_name_german() -> &'static str {
51        "Regionskriterium"
52    }
53
54    fn type_name_english() -> &'static str {
55        "RegionCriterion"
56    }
57
58    fn meta(&self) -> &Bo4eMeta {
59        &self.meta
60    }
61
62    fn meta_mut(&mut self) -> &mut Bo4eMeta {
63        &mut self.meta
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn test_region_criterion_default() {
73        let criterion = RegionCriterion::default();
74        assert!(criterion.validity_type.is_none());
75        assert!(criterion.criterion_type.is_none());
76        assert!(criterion.value.is_none());
77    }
78
79    #[test]
80    fn test_region_criterion_postal_code() {
81        let criterion = RegionCriterion {
82            validity_type: Some(ValidityType::OnlyIn),
83            criterion_type: Some(RegionCriterionType::PostalCode),
84            value: Some("50667".to_string()),
85            ..Default::default()
86        };
87
88        let json = serde_json::to_string(&criterion).unwrap();
89        assert!(json.contains(r#""validityType":"NUR_IN""#));
90        assert!(json.contains(r#""criterionType":"POSTLEITZAHL""#));
91        assert!(json.contains(r#""value":"50667""#));
92    }
93
94    #[test]
95    fn test_region_criterion_federal_state() {
96        let criterion = RegionCriterion {
97            validity_type: Some(ValidityType::NotIn),
98            criterion_type: Some(RegionCriterionType::FederalStateName),
99            value: Some("Bayern".to_string()),
100            ..Default::default()
101        };
102
103        let json = serde_json::to_string(&criterion).unwrap();
104        assert!(json.contains(r#""validityType":"NICHT_IN""#));
105        assert!(json.contains(r#""criterionType":"BUNDESLAND_NAME""#));
106    }
107
108    #[test]
109    fn test_region_criterion_nationwide() {
110        let criterion = RegionCriterion {
111            validity_type: Some(ValidityType::OnlyIn),
112            criterion_type: Some(RegionCriterionType::Nationwide),
113            value: None, // Not relevant for nationwide
114            ..Default::default()
115        };
116
117        let json = serde_json::to_string(&criterion).unwrap();
118        assert!(json.contains(r#""criterionType":"BUNDESWEIT""#));
119        assert!(!json.contains(r#""value""#)); // Should be skipped
120    }
121
122    #[test]
123    fn test_region_criterion_roundtrip() {
124        let criterion = RegionCriterion {
125            meta: Bo4eMeta::with_type("Regionskriterium"),
126            validity_type: Some(ValidityType::OnlyInCombinationWith),
127            criterion_type: Some(RegionCriterionType::MunicipalityName),
128            value: Some("Köln".to_string()),
129        };
130
131        let json = serde_json::to_string(&criterion).unwrap();
132        let parsed: RegionCriterion = serde_json::from_str(&json).unwrap();
133        assert_eq!(criterion, parsed);
134    }
135
136    #[test]
137    fn test_bo4e_object_impl() {
138        assert_eq!(RegionCriterion::type_name_german(), "Regionskriterium");
139        assert_eq!(RegionCriterion::type_name_english(), "RegionCriterion");
140    }
141}