sdmx_json/
metadata.rs

1use crate::primitives::{
2	Action, Annotation, DataType, Link, LocalizedText, Meta, NumberOrString, SdmxMessage,
3	SdmxValue, StatusMessage,
4};
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use std::collections::HashMap;
8use std::str::FromStr;
9
10/// The top-level type of a JSON file that conforms to the
11/// SDMX-JSON Metadata Message format.
12///
13/// # Deserializing
14/// ## From a string
15/// ```no_run
16/// use std::str::FromStr;
17/// use std::fs::read_to_string;
18/// use sdmx_json::metadata::MetadataMessage;
19///
20/// fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
21///     let file = read_to_string("sdmx-data.json")?;
22///     let message = MetadataMessage::from_str(file.as_str())?;
23///     Ok(())
24/// }
25/// ```
26///
27/// ## From a byte slice
28/// ```no_run
29/// use std::fs::read;
30/// use sdmx_json::metadata::MetadataMessage;
31///
32/// fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
33///     let file = read("sdmx-data.json")?;
34///     let message = MetadataMessage::try_from(file.as_slice())?;
35///     Ok(())
36/// }
37/// ```
38///
39/// ## From a `serde_json::Value`
40/// ```no_run
41/// use serde_json::json;
42/// use sdmx_json::metadata::MetadataMessage;
43///
44/// fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
45///     let value = json!({}); // assuming this has content
46///     let message = MetadataMessage::try_from(value);
47///     Ok(())
48/// }
49/// ```
50#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
51pub struct MetadataMessage {
52	#[serde(skip_serializing_if = "Option::is_none")]
53	pub meta: Option<Meta>,
54	#[serde(skip_serializing_if = "Option::is_none")]
55	pub data: Option<Data>,
56	#[serde(skip_serializing_if = "Option::is_none")]
57	pub errors: Option<Vec<StatusMessage>>,
58	#[serde(skip_serializing_if = "Option::is_none")]
59	#[serde(flatten)]
60	pub other: Option<HashMap<String, Value>>,
61}
62
63impl SdmxMessage for MetadataMessage {
64	type Data = Data;
65	fn meta(&self) -> Option<&Meta> {
66		self.meta.as_ref()
67	}
68
69	fn data(&self) -> Option<&Self::Data> {
70		self.data.as_ref()
71	}
72
73	fn errors(&self) -> Option<&Vec<StatusMessage>> {
74		self.errors.as_ref()
75	}
76}
77
78impl<'a> TryFrom<&'a [u8]> for MetadataMessage {
79	type Error = serde_json::Error;
80	fn try_from(slice: &'a [u8]) -> Result<Self, Self::Error> {
81		serde_json::from_slice(slice)
82	}
83}
84
85impl FromStr for MetadataMessage {
86	type Err = serde_json::Error;
87	fn from_str(s: &str) -> Result<Self, Self::Err> {
88		serde_json::from_str(s)
89	}
90}
91
92impl TryFrom<Value> for MetadataMessage {
93	type Error = serde_json::Error;
94	fn try_from(value: Value) -> Result<Self, Self::Error> {
95		serde_json::from_value(value)
96	}
97}
98
99/// The associated data with a metadata message.
100#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
101#[serde(rename_all = "camelCase")]
102pub struct Data {
103	#[serde(skip_serializing_if = "Option::is_none")]
104	pub metadata_sets: Option<Vec<MetadataSet>>,
105	#[serde(skip_serializing_if = "Option::is_none")]
106	#[serde(flatten)]
107	pub other: Option<HashMap<String, Value>>,
108}
109
110/// A collection of reported metadata against a set of values
111/// for a given full or partial target identifier,
112/// as described in a metadata structure definition.
113#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
114#[serde(rename_all = "camelCase")]
115pub struct MetadataSet {
116	#[serde(skip_serializing_if = "Option::is_none")]
117	pub action: Option<Action>,
118	#[serde(skip_serializing_if = "Option::is_none")]
119	pub publication_period: Option<String>,
120	#[serde(skip_serializing_if = "Option::is_none")]
121	pub publication_year: Option<String>,
122	#[serde(skip_serializing_if = "Option::is_none")]
123	pub reporting_begin: Option<String>,
124	#[serde(skip_serializing_if = "Option::is_none")]
125	pub reporting_year: Option<String>,
126	pub id: String,
127	#[serde(rename = "agencyID")]
128	pub agency_id: String,
129	#[serde(skip_serializing_if = "Option::is_none")]
130	pub version: Option<String>,
131	#[serde(skip_serializing_if = "Option::is_none")]
132	pub is_external_reference: Option<bool>,
133	pub metadataflow: Option<String>,
134	pub metadata_provision_agreement: Option<String>,
135	#[serde(skip_serializing_if = "Option::is_none")]
136	pub valid_from: Option<String>,
137	#[serde(skip_serializing_if = "Option::is_none")]
138	pub valid_to: Option<String>,
139	#[serde(skip_serializing_if = "Option::is_none")]
140	pub annotations: Option<Vec<Annotation>>,
141	#[serde(skip_serializing_if = "Option::is_none")]
142	pub links: Option<Vec<Link>>,
143	pub name: String,
144	#[serde(skip_serializing_if = "Option::is_none")]
145	pub names: Option<LocalizedText>,
146	#[serde(skip_serializing_if = "Option::is_none")]
147	pub description: Option<String>,
148	#[serde(skip_serializing_if = "Option::is_none")]
149	pub descriptions: Option<LocalizedText>,
150	pub targets: Vec<String>,
151	pub attributes: Vec<Attribute>,
152	#[serde(skip_serializing_if = "Option::is_none")]
153	#[serde(flatten)]
154	pub other: Option<HashMap<String, Value>>,
155}
156
157/// A reported metadata attribute value.
158#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
159pub struct Attribute {
160	pub id: String,
161	#[serde(skip_serializing_if = "Option::is_none")]
162	pub annotations: Option<Vec<Annotation>>,
163	#[serde(skip_serializing_if = "Option::is_none")]
164	pub format: Option<Format>,
165	pub value: Option<SdmxValue>,
166	pub attributes: Option<Vec<Attribute>>,
167	#[serde(skip_serializing_if = "Option::is_none")]
168	#[serde(flatten)]
169	pub other: Option<HashMap<String, Value>>,
170}
171
172/// The representation for a component which describes
173/// the possible content for component values.
174#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
175pub struct Format {
176	#[serde(skip_serializing_if = "Option::is_none")]
177	pub data_type: Option<DataType>,
178	#[serde(skip_serializing_if = "Option::is_none")]
179	pub is_sequence: Option<bool>,
180	#[serde(skip_serializing_if = "Option::is_none")]
181	pub interval: Option<isize>,
182	#[serde(skip_serializing_if = "Option::is_none")]
183	pub start_time: Option<String>,
184	#[serde(skip_serializing_if = "Option::is_none")]
185	pub end_time: Option<String>,
186	#[serde(skip_serializing_if = "Option::is_none")]
187	pub min_length: Option<usize>,
188	#[serde(skip_serializing_if = "Option::is_none")]
189	pub max_length: Option<usize>,
190	#[serde(skip_serializing_if = "Option::is_none")]
191	pub min_value: Option<isize>,
192	#[serde(skip_serializing_if = "Option::is_none")]
193	pub max_value: Option<isize>,
194	#[serde(skip_serializing_if = "Option::is_none")]
195	pub decimals: Option<usize>,
196	#[serde(skip_serializing_if = "Option::is_none")]
197	pub is_multilingual: Option<bool>,
198	#[serde(skip_serializing_if = "Option::is_none")]
199	pub sentinel_values: Option<Vec<NumberOrString>>,
200	#[serde(skip_serializing_if = "Option::is_none")]
201	#[serde(flatten)]
202	pub other: Option<HashMap<String, Value>>,
203}
204
205impl_extendable!(MetadataMessage, Data, MetadataSet, Attribute, Format);