1use geojson::GeoJson;
7use url::Url;
8
9use crate::{
10 namespace::LocationNamespaceUrl, DateTime, Keyword, LocationId, MeetingId, OrganizationId,
11 PaperId, PersonId,
12};
13
14#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
15#[serde(rename_all = "camelCase")]
16pub struct Location {
17 pub id: LocationId,
18
19 #[serde(rename = "type")]
20 pub namespace: LocationNamespaceUrl,
21
22 #[serde(default, skip_serializing_if = "Option::is_none")]
23 pub description: Option<String>,
24
25 #[serde(default, skip_serializing_if = "Option::is_none")]
26 pub geojson: Option<GeoJson>,
27
28 #[serde(default, skip_serializing_if = "Option::is_none")]
29 pub street_address: Option<String>,
30
31 #[serde(default, skip_serializing_if = "Option::is_none")]
32 pub room: Option<String>,
33
34 #[serde(default, skip_serializing_if = "Option::is_none")]
35 pub postal_code: Option<String>,
36
37 #[serde(default, skip_serializing_if = "Option::is_none")]
38 pub sub_locality: Option<String>,
39
40 #[serde(default, skip_serializing_if = "Option::is_none")]
41 pub locality: Option<String>,
42
43 #[serde(default, skip_serializing_if = "Vec::is_empty")]
44 pub bodies: Vec<Url>,
45
46 #[serde(default, skip_serializing_if = "Vec::is_empty")]
47 pub organizations: Vec<OrganizationId>,
48
49 #[serde(default, skip_serializing_if = "Vec::is_empty")]
50 pub persons: Vec<PersonId>,
51
52 #[serde(default, skip_serializing_if = "Vec::is_empty")]
53 pub meetings: Vec<MeetingId>,
54
55 #[serde(default, skip_serializing_if = "Vec::is_empty")]
56 pub papers: Vec<PaperId>,
57
58 #[serde(default, skip_serializing_if = "Option::is_none")]
59 pub license: Option<Url>,
60
61 #[serde(default, skip_serializing_if = "Vec::is_empty")]
62 pub keyword: Vec<Keyword>,
63
64 pub created: DateTime,
65
66 pub modified: DateTime,
67
68 #[serde(default, skip_serializing_if = "Option::is_none")]
69 pub web: Option<Url>,
70
71 #[serde(default, skip_serializing_if = "Option::is_none")]
72 pub deleted: Option<bool>,
73}
74
75#[cfg(test)]
76mod serde_tests {
77 use super::Location;
78 use crate::namespace::LocationNamespaceUrl;
79
80 use pretty_assertions::assert_eq;
81 use serde_json::json;
82 use time::macros::datetime;
83
84 fn example_location() -> Location {
85 let geojson_feature = {
86 let mut f =
87 geojson::Feature::from(geojson::Geometry::new(geojson::Value::Point(vec![
88 50.1234, 10.4321,
89 ])));
90 f.set_property("name", "Rathausplatz");
91 f
92 };
93
94 Location {
95 id: "https://oparl.example.org/location/0"
96 .parse()
97 .expect("value must be parseable as id"),
98 namespace: LocationNamespaceUrl::Identifier,
99 description: Some(
100 "Rathaus der Beispielstadt, Ratshausplatz 1, 12345 Beispielstadt".to_string(),
101 ),
102 geojson: Some(geojson_feature.into()),
103 street_address: None,
104 room: None,
105 postal_code: None,
106 sub_locality: None,
107 locality: None,
108 bodies: vec![],
109 organizations: vec![],
110 persons: vec![],
111 meetings: vec![],
112 papers: vec![],
113 license: None,
114 keyword: vec![],
115 created: datetime!(2014-01-08 14:28:31 +01:00).into(),
116 modified: datetime!(2014-01-08 14:28:31 +01:00).into(),
117 web: None,
118 deleted: None,
119 }
120 }
121
122 fn example_location_json() -> serde_json::Value {
123 json!({
124 "id": "https://oparl.example.org/location/0",
125 "type": "https://schema.oparl.org/1.1/Location",
126 "description": "Rathaus der Beispielstadt, Ratshausplatz 1, 12345 Beispielstadt",
127 "created": "2014-01-08T14:28:31+01:00",
128 "modified": "2014-01-08T14:28:31+01:00",
129 "geojson": {
130 "type": "Feature",
131 "geometry": {
132 "type": "Point",
133 "coordinates": [
134 50.1234,
135 10.4321
136 ]
137 },
138 "properties": {
139 "name": "Rathausplatz"
140 }
141 }
142 })
143 }
144
145 #[test]
146 fn serialize() {
147 assert_eq!(json!(example_location()), example_location_json());
148 }
149
150 #[test]
151 fn deserialize_good() {
152 let deserialized: Location = serde_json::from_value(example_location_json())
153 .expect("value must be deserializable as Location");
154 assert_eq!(deserialized, example_location());
155 }
156
157 #[test]
158 fn deserialize_bad() {
159 assert!(serde_json::from_value::<Location>(json!("xyzabcd")).is_err());
160 assert!(serde_json::from_value::<Location>(json!(true)).is_err());
161 assert!(serde_json::from_value::<Location>(json!(123)).is_err());
162 }
163}