use crate::{
AgendaItemUrl, ConsultationUrl, DateTime, File, Keyword, MeetingUrl, Name, Url,
namespace::AgendaItemNamespaceUrl,
};
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AgendaItem {
pub id: AgendaItemUrl,
#[serde(rename = "type")]
pub namespace: AgendaItemNamespaceUrl,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub meeting: Option<MeetingUrl>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub number: Option<String>,
pub order: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<Name>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub public: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub consultation: Option<ConsultationUrl>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub result: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub resolution_text: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub resolution_file: Option<File>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub auxiliary_file: Vec<File>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub start: Option<DateTime>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub end: Option<DateTime>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub license: Option<Url>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub keyword: Vec<Keyword>,
pub created: DateTime,
pub modified: DateTime,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub web: Option<Url>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub deleted: Option<bool>,
#[serde(default, flatten)]
pub extensions: serde_json::Map<String, serde_json::Value>,
}
#[cfg(test)]
mod serde_tests {
use pretty_assertions::assert_eq;
use serde_json::json;
use time::macros::datetime;
use super::AgendaItem;
use crate::namespace::AgendaItemNamespaceUrl;
fn example_agenda_item() -> AgendaItem {
AgendaItem {
id: "https://oparl.example.org/agendaitem/3271"
.parse()
.expect("value must be parseable as id"),
namespace: AgendaItemNamespaceUrl::Identifier,
meeting: Some(
"https://oparl.example.org/meeting/281"
.parse()
.expect("value must be parseable as url"),
),
number: Some("10.1".into()),
order: 0,
name: Some("Satzungsänderung für Ausschreibungen".into()),
public: Some(true),
consultation: Some(
"https://oparl.example.org/consultation/1034"
.parse()
.expect("value must be parseable as url"),
),
result: Some("Geändert beschlossen".into()),
resolution_text: Some("Der Beschluss weicht wie folgt vom Antrag ab: ...".into()),
resolution_file: None,
auxiliary_file: vec![],
start: None,
end: None,
license: None,
keyword: vec![],
created: datetime!(2012-01-06 12:01:00 +01:00).into(),
modified: datetime!(2012-01-08 14:05:27 +01:00).into(),
web: None,
deleted: None,
extensions: serde_json::Map::new(),
}
}
fn example_agenda_item_json() -> serde_json::Value {
json!( {
"id": "https://oparl.example.org/agendaitem/3271",
"type": "https://schema.oparl.org/1.1/AgendaItem",
"meeting": "https://oparl.example.org/meeting/281",
"number": "10.1",
"order": 0,
"name": "Satzungsänderung für Ausschreibungen",
"public": true,
"consultation": "https://oparl.example.org/consultation/1034",
"result": "Geändert beschlossen",
"resolutionText": "Der Beschluss weicht wie folgt vom Antrag ab: ...",
"created": "2012-01-06T12:01:00+01:00",
"modified": "2012-01-08T14:05:27+01:00"
})
}
#[test]
fn serialize() {
assert_eq!(json!(example_agenda_item()), example_agenda_item_json());
}
#[test]
fn deserialize_good() {
let deserialized: AgendaItem = serde_json::from_value(example_agenda_item_json())
.expect("value must be deserializable as AgendaItem");
assert_eq!(deserialized, example_agenda_item());
}
#[test]
fn deserialize_bad() {
assert!(serde_json::from_value::<AgendaItem>(json!("xyzabcd")).is_err());
assert!(serde_json::from_value::<AgendaItem>(json!(true)).is_err());
assert!(serde_json::from_value::<AgendaItem>(json!(123)).is_err());
}
}