sdmx_json/
data.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 Data 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::data::DataMessage;
19///
20/// fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
21///     let file = read_to_string("sdmx-data.json")?;
22///     let message = DataMessage::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::data::DataMessage;
31///
32/// fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
33///     let file = read("sdmx-data.json")?;
34///     let message = DataMessage::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::data::DataMessage;
43///
44/// fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
45///     let value = json!({}); // assuming this has content
46///     let message = DataMessage::try_from(value);
47///     Ok(())
48/// }
49/// ```
50#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
51pub struct DataMessage {
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 DataMessage {
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 DataMessage {
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 DataMessage {
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 DataMessage {
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 data 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 structures: Option<Vec<Structure>>,
105	#[serde(skip_serializing_if = "Option::is_none")]
106	pub data_sets: Option<Vec<DataSet>>,
107	#[serde(skip_serializing_if = "Option::is_none")]
108	#[serde(flatten)]
109	pub other: Option<HashMap<String, Value>>,
110}
111
112/// The structural metadata for interpreting the data contained
113/// in the message.
114#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
115#[serde(rename_all = "camelCase")]
116pub struct Structure {
117	#[serde(skip_serializing_if = "Option::is_none")]
118	pub links: Option<Vec<Link>>,
119	pub dimensions: Dimensions,
120	#[serde(skip_serializing_if = "Option::is_none")]
121	pub measures: Option<Measures>,
122	pub attributes: Attributes,
123	#[serde(skip_serializing_if = "Option::is_none")]
124	pub annotations: Option<Vec<Annotation>>,
125	#[serde(skip_serializing_if = "Option::is_none")]
126	pub dataset: Option<DataSet>,
127	#[serde(skip_serializing_if = "Option::is_none")]
128	#[serde(flatten)]
129	pub other: Option<HashMap<String, Value>>,
130}
131
132/// A short, convenient type alias to [`DimsMeasuresAttributes`].
133pub type Dimensions = DimsMeasuresAttributes;
134/// A short, convenient type alias to [`DimsMeasuresAttributes`].
135pub type Measures = DimsMeasuresAttributes;
136/// A short, convenient type alias to [`DimsMeasuresAttributes`].
137pub type Attributes = DimsMeasuresAttributes;
138
139/// An object which either represents multiple dimensions,
140/// multiple measures, or multiple attributes.
141#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
142#[serde(rename_all = "camelCase")]
143pub struct DimsMeasuresAttributes {
144	#[serde(skip_serializing_if = "Option::is_none")]
145	pub data_set: Option<Vec<Component>>,
146	#[serde(skip_serializing_if = "Option::is_none")]
147	pub dimension_group: Option<Vec<Component>>,
148	#[serde(skip_serializing_if = "Option::is_none")]
149	pub series: Option<Vec<Component>>,
150	#[serde(skip_serializing_if = "Option::is_none")]
151	pub observation: Option<Vec<Component>>,
152	#[serde(skip_serializing_if = "Option::is_none")]
153	#[serde(flatten)]
154	pub other: Option<HashMap<String, Value>>,
155}
156
157/// A dimension, measure, or attribute used in the message.
158#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
159#[serde(rename_all = "camelCase")]
160pub struct Component {
161	pub id: String,
162	#[serde(skip_serializing_if = "Option::is_none")]
163	pub name: Option<String>,
164	#[serde(skip_serializing_if = "Option::is_none")]
165	pub names: Option<LocalizedText>,
166	pub description: Option<String>,
167	#[serde(skip_serializing_if = "Option::is_none")]
168	pub descriptions: Option<LocalizedText>,
169	pub key_position: Option<usize>,
170	#[serde(skip_serializing_if = "Option::is_none")]
171	pub roles: Option<Vec<String>>,
172	#[serde(skip_serializing_if = "Option::is_none")]
173	pub is_mandatory: Option<bool>,
174	pub relationship: Option<AttributeRelationship>,
175	#[serde(skip_serializing_if = "Option::is_none")]
176	pub format: Option<Format>,
177	#[serde(skip_serializing_if = "Option::is_none")]
178	pub default_value: Option<NumberOrString>,
179	#[serde(skip_serializing_if = "Option::is_none")]
180	pub links: Option<Vec<Link>>,
181	#[serde(skip_serializing_if = "Option::is_none")]
182	pub annotations: Option<Vec<usize>>,
183	#[serde(skip_serializing_if = "Option::is_none")]
184	pub values: Option<Vec<Option<ComponentValue>>>,
185	#[serde(skip_serializing_if = "Option::is_none")]
186	#[serde(flatten)]
187	pub other: Option<HashMap<String, Value>>,
188}
189
190/// The relationship between an attribute and other data structure
191/// definition components as defined in the data structure definition.
192#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
193#[serde(rename_all = "camelCase")]
194pub struct AttributeRelationship {
195	#[serde(skip_serializing_if = "Option::is_none")]
196	pub dataflow: Option<Value>,
197	#[serde(skip_serializing_if = "Option::is_none")]
198	pub dimensions: Option<Vec<String>>,
199	#[serde(skip_serializing_if = "Option::is_none")]
200	pub observation: Option<Value>,
201	#[serde(skip_serializing_if = "Option::is_none")]
202	pub primary_measure: Option<String>,
203	#[serde(skip_serializing_if = "Option::is_none")]
204	pub measures: Option<Vec<String>>,
205	#[serde(skip_serializing_if = "Option::is_none")]
206	#[serde(flatten)]
207	pub other: Option<HashMap<String, Value>>,
208}
209
210/// The representation for a component.
211#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
212#[serde(rename_all = "camelCase")]
213pub struct Format {
214	#[serde(skip_serializing_if = "Option::is_none")]
215	pub min_occurs: Option<usize>,
216	#[serde(skip_serializing_if = "Option::is_none")]
217	pub max_occurs: Option<usize>,
218	#[serde(skip_serializing_if = "Option::is_none")]
219	pub data_type: Option<DataType>,
220	#[serde(skip_serializing_if = "Option::is_none")]
221	pub is_sequence: Option<bool>,
222	#[serde(skip_serializing_if = "Option::is_none")]
223	pub interval: Option<String>,
224	#[serde(skip_serializing_if = "Option::is_none")]
225	pub start_time: Option<String>,
226	#[serde(skip_serializing_if = "Option::is_none")]
227	pub end_time: Option<String>,
228	#[serde(skip_serializing_if = "Option::is_none")]
229	pub min_length: Option<usize>,
230	#[serde(skip_serializing_if = "Option::is_none")]
231	pub max_length: Option<usize>,
232	#[serde(skip_serializing_if = "Option::is_none")]
233	pub min_value: Option<isize>,
234	#[serde(skip_serializing_if = "Option::is_none")]
235	pub max_value: Option<isize>,
236	#[serde(skip_serializing_if = "Option::is_none")]
237	pub decimals: Option<usize>,
238	#[serde(skip_serializing_if = "Option::is_none")]
239	pub is_multilingual: Option<bool>,
240	#[serde(skip_serializing_if = "Option::is_none")]
241	pub sentinel_values: Option<Vec<NumberOrString>>,
242	#[serde(skip_serializing_if = "Option::is_none")]
243	#[serde(flatten)]
244	pub other: Option<HashMap<String, Value>>,
245}
246
247/// A particular value for a component in a message.
248#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
249pub struct ComponentValue {
250	pub id: String,
251	#[serde(skip_serializing_if = "Option::is_none")]
252	pub name: Option<String>,
253	#[serde(skip_serializing_if = "Option::is_none")]
254	pub names: Option<LocalizedText>,
255	#[serde(skip_serializing_if = "Option::is_none")]
256	pub values: Option<Vec<SdmxValue>>,
257	pub description: Option<String>,
258	#[serde(skip_serializing_if = "Option::is_none")]
259	pub descriptions: Option<LocalizedText>,
260	#[serde(skip_serializing_if = "Option::is_none")]
261	pub start: Option<String>,
262	#[serde(skip_serializing_if = "Option::is_none")]
263	pub end: Option<String>,
264	#[serde(skip_serializing_if = "Option::is_none")]
265	pub parent: Option<String>,
266	#[serde(skip_serializing_if = "Option::is_none")]
267	pub order: Option<isize>,
268	#[serde(skip_serializing_if = "Option::is_none")]
269	pub links: Option<Vec<Link>>,
270	#[serde(skip_serializing_if = "Option::is_none")]
271	pub annotations: Option<Vec<usize>>,
272	#[serde(skip_serializing_if = "Option::is_none")]
273	#[serde(flatten)]
274	pub other: Option<HashMap<String, Value>>,
275}
276
277/// A collection of observations with meta-information
278/// about the dataset (when it was published, reported,
279/// how long the dataset is valid, etc).
280#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
281#[serde(rename_all = "camelCase")]
282pub struct DataSet {
283	#[serde(skip_serializing_if = "Option::is_none")]
284	pub structure: Option<isize>,
285	#[serde(skip_serializing_if = "Option::is_none")]
286	pub action: Option<Action>,
287	#[serde(skip_serializing_if = "Option::is_none")]
288	pub reporting_begin: Option<String>,
289	#[serde(skip_serializing_if = "Option::is_none")]
290	pub reporting_end: Option<String>,
291	#[serde(skip_serializing_if = "Option::is_none")]
292	pub valid_from: Option<String>,
293	#[serde(skip_serializing_if = "Option::is_none")]
294	pub valid_to: Option<String>,
295	#[serde(skip_serializing_if = "Option::is_none")]
296	pub publication_year: Option<String>,
297	#[serde(skip_serializing_if = "Option::is_none")]
298	pub publication_period: Option<String>,
299	#[serde(skip_serializing_if = "Option::is_none")]
300	pub links: Option<Vec<Link>>,
301	#[serde(skip_serializing_if = "Option::is_none")]
302	pub annotations: Option<Vec<usize>>,
303	#[serde(skip_serializing_if = "Option::is_none")]
304	pub attributes: Option<Vec<SdmxValue>>,
305	#[serde(skip_serializing_if = "Option::is_none")]
306	pub dimension_group_attributes: Option<HashMap<String, Vec<SdmxValue>>>,
307	#[serde(skip_serializing_if = "Option::is_none")]
308	pub series: Option<HashMap<String, Series>>,
309	#[serde(skip_serializing_if = "Option::is_none")]
310	pub observations: Option<HashMap<String, Vec<SdmxValue>>>,
311	#[serde(skip_serializing_if = "Option::is_none")]
312	#[serde(flatten)]
313	pub other: Option<HashMap<String, Value>>,
314}
315
316/// A set of data points.
317#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
318pub struct Series {
319	#[serde(skip_serializing_if = "Option::is_none")]
320	pub annotations: Option<Vec<usize>>,
321	#[serde(skip_serializing_if = "Option::is_none")]
322	pub attributes: Option<Vec<SdmxValue>>,
323	#[serde(skip_serializing_if = "Option::is_none")]
324	pub observations: Option<HashMap<String, Vec<SdmxValue>>>,
325	#[serde(skip_serializing_if = "Option::is_none")]
326	#[serde(flatten)]
327	pub other: Option<HashMap<String, Value>>,
328}
329
330impl_extendable!(
331	DataMessage,
332	Data,
333	Structure,
334	DimsMeasuresAttributes,
335	Component,
336	AttributeRelationship,
337	Format,
338	ComponentValue,
339	DataSet,
340	Series,
341);