1use std::fmt;
2
3use serde::de::{self, Visitor};
4use serde::{Deserialize, Deserializer, Serialize};
5
6use crate::types::{
7 CategoryId, ColumnId, DatasetId, DmyDate, ElementId, IndicatorId, InputError, IsoDateTime,
8 MeasureId, ParentRef, PeriodId, Periodicity, PublicationId, RowId, UnitId, Year,
9};
10
11pub type DatasetExIndicator = NamedEntity<IndicatorId, IndicatorId>;
13
14pub type DatasetExMeasure1 = NamedEntity<MeasureId, IndicatorId>;
16
17pub type DatasetExMeasure2 = NamedEntity<MeasureId, IndicatorId>;
19
20pub type DatasetExUnit = NamedEntity<UnitId, UnitId>;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum DatasetKind {
26 Code1,
28 Code2,
30 Unknown(i32),
32}
33
34impl DatasetKind {
35 #[must_use]
37 #[inline]
38 pub fn from_code(value: i32) -> Self {
39 match value {
40 1 => Self::Code1,
41 2 => Self::Code2,
42 other => Self::Unknown(other),
43 }
44 }
45
46 #[must_use]
48 #[inline]
49 pub fn code(self) -> i32 {
50 match self {
51 Self::Code1 => 1,
52 Self::Code2 => 2,
53 Self::Unknown(value) => value,
54 }
55 }
56}
57
58impl<'de> Deserialize<'de> for DatasetKind {
59 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
60 where
61 D: Deserializer<'de>,
62 {
63 Ok(Self::from_code(i32::deserialize(deserializer)?))
64 }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq)]
69pub enum DatasetReporting {
70 Period,
72 Unknown(String),
74}
75
76impl DatasetReporting {
77 #[must_use]
79 #[inline]
80 pub fn as_str(&self) -> &str {
81 match self {
82 Self::Period => "period",
83 Self::Unknown(value) => value.as_str(),
84 }
85 }
86}
87
88impl<'de> Deserialize<'de> for DatasetReporting {
89 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
90 where
91 D: Deserializer<'de>,
92 {
93 let value = String::deserialize(deserializer)?;
94 Ok(match value.as_str() {
95 "period" => Self::Period,
96 _ => Self::Unknown(value),
97 })
98 }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub enum SeriesType {
104 Code1,
106 Code2,
108 Code3,
110 Unknown(i32),
112}
113
114impl SeriesType {
115 #[must_use]
117 #[inline]
118 pub fn from_code(value: i32) -> Self {
119 match value {
120 1 => Self::Code1,
121 2 => Self::Code2,
122 3 => Self::Code3,
123 other => Self::Unknown(other),
124 }
125 }
126
127 #[must_use]
129 #[inline]
130 pub fn code(self) -> i32 {
131 match self {
132 Self::Code1 => 1,
133 Self::Code2 => 2,
134 Self::Code3 => 3,
135 Self::Unknown(value) => value,
136 }
137 }
138}
139
140impl<'de> Deserialize<'de> for SeriesType {
141 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
142 where
143 D: Deserializer<'de>,
144 {
145 Ok(Self::from_code(i32::deserialize(deserializer)?))
146 }
147}
148
149#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
151#[serde(untagged)]
152pub enum SortKey {
153 Numeric(i32),
155 Text(String),
157}
158
159impl SortKey {
160 #[must_use]
162 #[inline]
163 pub fn as_numeric(&self) -> Option<i32> {
164 match self {
165 Self::Numeric(value) => Some(*value),
166 Self::Text(_) => None,
167 }
168 }
169
170 #[must_use]
172 #[inline]
173 pub fn as_text(&self) -> Option<&str> {
174 match self {
175 Self::Numeric(_) => None,
176 Self::Text(value) => Some(value.as_str()),
177 }
178 }
179}
180
181impl<'de> Deserialize<'de> for SortKey {
182 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
183 where
184 D: Deserializer<'de>,
185 {
186 struct SortKeyVisitor;
187
188 impl Visitor<'_> for SortKeyVisitor {
189 type Value = SortKey;
190
191 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
192 formatter.write_str("an integer or a string")
193 }
194
195 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
196 where
197 E: de::Error,
198 {
199 let value = i32::try_from(value)
200 .map_err(|_| E::custom(format!("sort key is out of i32 range: {value}")))?;
201 Ok(SortKey::Numeric(value))
202 }
203
204 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
205 where
206 E: de::Error,
207 {
208 let value = i32::try_from(value)
209 .map_err(|_| E::custom(format!("sort key is out of i32 range: {value}")))?;
210 Ok(SortKey::Numeric(value))
211 }
212
213 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
214 where
215 E: de::Error,
216 {
217 match value.parse::<i32>() {
218 Ok(parsed) => Ok(SortKey::Numeric(parsed)),
219 Err(_) => Ok(SortKey::Text(value.to_owned())),
220 }
221 }
222
223 fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
224 where
225 E: de::Error,
226 {
227 match value.parse::<i32>() {
228 Ok(parsed) => Ok(SortKey::Numeric(parsed)),
229 Err(_) => Ok(SortKey::Text(value)),
230 }
231 }
232 }
233
234 deserializer.deserialize_any(SortKeyVisitor)
235 }
236}
237
238#[derive(Debug, Clone, Deserialize, PartialEq)]
240pub struct Publication {
241 pub id: PublicationId,
242 pub parent_id: ParentRef<PublicationId>,
243 pub category_name: String,
244 #[serde(rename = "NoActive", deserialize_with = "deserialize_zero_one_bool")]
245 pub no_active: bool,
246 #[serde(default)]
247 pub pub_description: Option<String>,
248 #[serde(default)]
249 pub updated_time: Option<IsoDateTime>,
250}
251
252#[derive(Debug, Clone, Deserialize, PartialEq)]
254pub struct Dataset {
255 pub id: DatasetId,
256 pub parent_id: ParentRef<PublicationId>,
257 pub name: String,
258 pub full_name: String,
259 #[serde(rename = "type")]
260 pub kind: DatasetKind,
261 pub reporting: DatasetReporting,
262 pub link: String,
263 #[serde(default)]
264 pub updated_time: Option<IsoDateTime>,
265}
266
267#[derive(Debug, Clone, Deserialize, PartialEq)]
269pub struct MeasuresResponse {
270 pub measure: Vec<Measure>,
272}
273
274#[derive(Debug, Clone, Deserialize, PartialEq)]
276pub struct Measure {
277 pub id: MeasureId,
278 pub parent_id: ParentRef<DatasetId>,
279 pub name: String,
280 #[serde(default)]
281 pub sort: Option<i32>,
282}
283
284#[derive(Debug, Clone, Deserialize, PartialEq)]
286pub struct YearRange {
287 #[serde(rename = "FromYear")]
288 pub from_year: Option<Year>,
289 #[serde(rename = "ToYear")]
290 pub to_year: Option<Year>,
291}
292
293#[derive(Debug, Clone, Deserialize, PartialEq)]
295pub struct DatasetsExResponse {
296 pub indicators: Vec<DatasetExIndicator>,
297 #[serde(rename = "measures_1")]
298 pub measures_1: Vec<DatasetExMeasure1>,
299 #[serde(rename = "measures_2")]
300 pub measures_2: Vec<DatasetExMeasure2>,
301 pub units: Vec<DatasetExUnit>,
302 pub years: Vec<YearRange>,
303}
304
305#[derive(Debug, Clone, PartialEq)]
307pub struct NamedEntity<Id, ParentId> {
308 pub id: Id,
309 pub parent_id: ParentRef<ParentId>,
310 pub name: String,
311}
312
313impl<'de, Id, ParentId> Deserialize<'de> for NamedEntity<Id, ParentId>
314where
315 Id: Deserialize<'de>,
316 ParentId: TryFrom<i32, Error = InputError> + Copy,
317{
318 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
319 where
320 D: Deserializer<'de>,
321 {
322 #[derive(Deserialize)]
323 struct RawNamedEntity<Id> {
324 id: Id,
325 parent_id: i32,
326 name: String,
327 }
328
329 let raw = RawNamedEntity::deserialize(deserializer)?;
330 Ok(Self {
331 id: raw.id,
332 parent_id: ParentRef::new(raw.parent_id).map_err(serde::de::Error::custom)?,
333 name: raw.name,
334 })
335 }
336}
337
338#[derive(Debug, Clone, Deserialize, PartialEq)]
340pub struct DataResponse {
341 #[serde(rename = "RawData")]
342 pub raw_data: Vec<DataRow>,
343 #[serde(rename = "headerData")]
344 pub header_data: Vec<DataHeader>,
345 pub units: Vec<DataUnit>,
346 #[serde(rename = "DTRange")]
347 pub dt_range: Vec<DataRange>,
348 #[serde(rename = "SType")]
349 pub s_type: Vec<DataSeriesType>,
350}
351
352#[derive(Debug, Clone, Deserialize, PartialEq)]
354pub struct DataRow {
355 #[serde(rename = "colId")]
356 pub col_id: Option<ColumnId>,
357 pub element_id: Option<ElementId>,
358 pub measure_id: Option<MeasureId>,
359 pub unit_id: Option<UnitId>,
360 pub obs_val: Option<f64>,
361 #[serde(rename = "rowId")]
362 pub row_id: Option<RowId>,
363 pub dt: Option<String>,
364 pub periodicity: Option<Periodicity>,
365 pub date: Option<IsoDateTime>,
366 pub digits: Option<i32>,
367}
368
369#[derive(Debug, Clone, Deserialize, PartialEq)]
371pub struct DataHeader {
372 pub id: Option<ColumnId>,
373 pub elname: Option<String>,
374}
375
376#[derive(Debug, Clone, Deserialize, PartialEq)]
378pub struct DataUnit {
379 pub id: Option<UnitId>,
380 pub val: Option<String>,
381}
382
383#[derive(Debug, Clone, Deserialize, PartialEq)]
385pub struct DataRange {
386 #[serde(rename = "FromY")]
387 pub from_year: Option<Year>,
388 #[serde(rename = "ToY")]
389 pub to_year: Option<Year>,
390}
391
392#[derive(Debug, Clone, Deserialize, PartialEq)]
394pub struct DataSeriesType {
395 #[serde(rename = "sType")]
396 pub s_type: Option<SeriesType>,
397 #[serde(rename = "dsName")]
398 pub ds_name: Option<String>,
399 #[serde(rename = "PublName")]
400 pub publ_name: Option<String>,
401}
402
403#[derive(Debug, Clone, Deserialize, PartialEq)]
405pub struct DataExResponse {
406 #[serde(rename = "RawData")]
407 pub raw_data: Vec<DataExRow>,
408 pub links: Vec<DataExLink>,
409}
410
411#[derive(Debug, Clone, Deserialize, PartialEq)]
413pub struct DataExRow {
414 pub indicator_id: Option<IndicatorId>,
415 pub measure_1_id: Option<MeasureId>,
416 pub measure_2_id: Option<MeasureId>,
417 pub unit_id: Option<UnitId>,
418 pub value: Option<f64>,
419 pub period_id: Option<PeriodId>,
420 pub period: Option<String>,
421 pub periodicity: Option<Periodicity>,
422 pub date: Option<DmyDate>,
423 #[serde(rename = "rowId")]
424 pub row_id: Option<RowId>,
425}
426
427#[derive(Debug, Clone, Deserialize, PartialEq)]
429pub struct DataExLink {
430 pub indicator_id: Option<IndicatorId>,
431 pub measure_1_id: Option<MeasureId>,
432 pub measure_2_id: Option<MeasureId>,
433 pub unit_id: Option<UnitId>,
434 pub name: Option<String>,
435 #[serde(rename = "sSort")]
436 pub s_sort: Option<SortKey>,
437}
438
439#[derive(Debug, Clone, Deserialize, PartialEq)]
441pub struct DatasetDescription {
442 pub description: String,
443}
444
445#[derive(Debug, Clone, Deserialize, PartialEq)]
447pub struct CategoryNewResponse {
448 pub category: Vec<CategoryNewItem>,
450}
451
452#[derive(Debug, Clone, Deserialize, PartialEq)]
454pub struct CategoryNewItem {
455 pub category_id: CategoryId,
456 pub category_name: String,
457 pub indicator_id: IndicatorId,
458 pub indicator_parent: ParentRef<IndicatorId>,
459 pub indicator_name: String,
460 pub link: String,
461 pub begin_dt: Year,
462 pub end_dt: Year,
463}
464
465#[derive(Debug, Clone, Deserialize, PartialEq)]
467pub struct DataNewResponse {
468 #[serde(rename = "RowData")]
469 pub row_data: Vec<DataNewRow>,
470 #[serde(rename = "Links")]
471 pub links: Vec<DataNewLink>,
472}
473
474#[derive(Debug, Clone, Deserialize, PartialEq)]
476pub struct DataNewRow {
477 pub id: Option<RowId>,
478 pub indicator_id: Option<IndicatorId>,
479 pub measure1_id: Option<MeasureId>,
480 pub measure2_id: Option<MeasureId>,
481 pub unit_id: Option<UnitId>,
482 pub obs_val: Option<f64>,
483 pub date: Option<IsoDateTime>,
484 pub periodicity: Option<Periodicity>,
485}
486
487#[derive(Debug, Clone, Deserialize, PartialEq)]
489pub struct DataNewLink {
490 pub indicator_id: Option<IndicatorId>,
491 pub indicator_parent: Option<ParentRef<IndicatorId>>,
492 pub measure1_id: Option<MeasureId>,
493 pub measure2_id: Option<MeasureId>,
494 pub unit_id: Option<UnitId>,
495 pub indicator_name: Option<String>,
496 pub measure1_name: Option<String>,
497 pub measure2_name: Option<String>,
498 pub un_name: Option<String>,
499}
500
501fn deserialize_zero_one_bool<'de, D>(deserializer: D) -> Result<bool, D::Error>
502where
503 D: Deserializer<'de>,
504{
505 match i32::deserialize(deserializer)? {
506 0 => Ok(false),
507 1 => Ok(true),
508 value => Err(serde::de::Error::custom(format!(
509 "expected 0 or 1 for boolean flag, got {value}"
510 ))),
511 }
512}