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
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum DatasetKind {
14 Code1,
16 Code2,
18 Unknown(i32),
20}
21
22impl DatasetKind {
23 #[must_use]
25 #[inline]
26 pub fn from_code(value: i32) -> Self {
27 match value {
28 1 => Self::Code1,
29 2 => Self::Code2,
30 other => Self::Unknown(other),
31 }
32 }
33
34 #[must_use]
36 #[inline]
37 pub fn code(self) -> i32 {
38 match self {
39 Self::Code1 => 1,
40 Self::Code2 => 2,
41 Self::Unknown(value) => value,
42 }
43 }
44}
45
46impl<'de> Deserialize<'de> for DatasetKind {
47 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
48 where
49 D: Deserializer<'de>,
50 {
51 Ok(Self::from_code(i32::deserialize(deserializer)?))
52 }
53}
54
55#[derive(Debug, Clone, PartialEq, Eq)]
57pub enum DatasetReporting {
58 Period,
60 Unknown(String),
62}
63
64impl DatasetReporting {
65 #[must_use]
67 #[inline]
68 pub fn as_str(&self) -> &str {
69 match self {
70 Self::Period => "period",
71 Self::Unknown(value) => value.as_str(),
72 }
73 }
74}
75
76impl<'de> Deserialize<'de> for DatasetReporting {
77 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
78 where
79 D: Deserializer<'de>,
80 {
81 let value = String::deserialize(deserializer)?;
82 Ok(match value.as_str() {
83 "period" => Self::Period,
84 _ => Self::Unknown(value),
85 })
86 }
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91pub enum SeriesType {
92 Code1,
94 Code2,
96 Code3,
98 Unknown(i32),
100}
101
102impl SeriesType {
103 #[must_use]
105 #[inline]
106 pub fn from_code(value: i32) -> Self {
107 match value {
108 1 => Self::Code1,
109 2 => Self::Code2,
110 3 => Self::Code3,
111 other => Self::Unknown(other),
112 }
113 }
114
115 #[must_use]
117 #[inline]
118 pub fn code(self) -> i32 {
119 match self {
120 Self::Code1 => 1,
121 Self::Code2 => 2,
122 Self::Code3 => 3,
123 Self::Unknown(value) => value,
124 }
125 }
126}
127
128impl<'de> Deserialize<'de> for SeriesType {
129 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
130 where
131 D: Deserializer<'de>,
132 {
133 Ok(Self::from_code(i32::deserialize(deserializer)?))
134 }
135}
136
137#[derive(Debug, Clone, Deserialize, PartialEq)]
139pub struct Publication {
140 pub id: PublicationId,
141 pub parent_id: ParentRef<PublicationId>,
142 pub category_name: String,
143 #[serde(rename = "NoActive", deserialize_with = "deserialize_zero_one_bool")]
144 pub no_active: bool,
145 #[serde(default)]
146 pub pub_description: Option<String>,
147 #[serde(default)]
148 pub updated_time: Option<IsoDateTime>,
149}
150
151#[derive(Debug, Clone, Deserialize, PartialEq)]
153pub struct Dataset {
154 pub id: DatasetId,
155 pub parent_id: ParentRef<PublicationId>,
156 pub name: String,
157 pub full_name: String,
158 #[serde(rename = "type")]
159 pub kind: DatasetKind,
160 pub reporting: DatasetReporting,
161 pub link: String,
162 #[serde(default)]
163 pub updated_time: Option<IsoDateTime>,
164}
165
166#[derive(Debug, Clone, Deserialize, PartialEq)]
168pub struct MeasuresResponse {
169 pub measure: Vec<Measure>,
171}
172
173#[derive(Debug, Clone, Deserialize, PartialEq)]
175pub struct Measure {
176 pub id: MeasureId,
177 pub parent_id: ParentRef<DatasetId>,
178 pub name: String,
179 #[serde(default)]
180 pub sort: Option<i32>,
181}
182
183#[derive(Debug, Clone, Deserialize, PartialEq)]
185pub struct YearRange {
186 #[serde(rename = "FromYear")]
187 pub from_year: Option<Year>,
188 #[serde(rename = "ToYear")]
189 pub to_year: Option<Year>,
190}
191
192#[derive(Debug, Clone, Deserialize, PartialEq)]
194pub struct DatasetsExResponse {
195 pub indicators: Vec<DatasetExIndicator>,
196 #[serde(rename = "measures_1")]
197 pub measures_1: Vec<DatasetExMeasure1>,
198 #[serde(rename = "measures_2")]
199 pub measures_2: Vec<DatasetExMeasure2>,
200 pub units: Vec<DatasetExUnit>,
201 pub years: Vec<YearRange>,
202}
203
204#[derive(Debug, Clone, PartialEq)]
206pub struct NamedEntity<Id, ParentId> {
207 pub id: Id,
208 pub parent_id: ParentRef<ParentId>,
209 pub name: String,
210}
211
212impl<'de, Id, ParentId> Deserialize<'de> for NamedEntity<Id, ParentId>
213where
214 Id: Deserialize<'de>,
215 ParentId: TryFrom<i32, Error = InputError> + Copy,
216{
217 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
218 where
219 D: Deserializer<'de>,
220 {
221 #[derive(Deserialize)]
222 struct RawNamedEntity<Id> {
223 id: Id,
224 parent_id: i32,
225 name: String,
226 }
227
228 let raw = RawNamedEntity::deserialize(deserializer)?;
229 Ok(Self {
230 id: raw.id,
231 parent_id: ParentRef::new(raw.parent_id).map_err(serde::de::Error::custom)?,
232 name: raw.name,
233 })
234 }
235}
236
237pub type DatasetExIndicator = NamedEntity<IndicatorId, IndicatorId>;
239
240pub type DatasetExMeasure1 = NamedEntity<MeasureId, IndicatorId>;
242
243pub type DatasetExMeasure2 = NamedEntity<MeasureId, IndicatorId>;
245
246pub type DatasetExUnit = NamedEntity<UnitId, UnitId>;
248
249#[derive(Debug, Clone, Deserialize, PartialEq)]
251pub struct DataResponse {
252 #[serde(rename = "RawData")]
253 pub raw_data: Vec<DataRow>,
254 #[serde(rename = "headerData")]
255 pub header_data: Vec<DataHeader>,
256 pub units: Vec<DataUnit>,
257 #[serde(rename = "DTRange")]
258 pub dt_range: Vec<DataRange>,
259 #[serde(rename = "SType")]
260 pub s_type: Vec<DataSeriesType>,
261}
262
263#[derive(Debug, Clone, Deserialize, PartialEq)]
265pub struct DataRow {
266 #[serde(rename = "colId")]
267 pub col_id: Option<ColumnId>,
268 pub element_id: Option<ElementId>,
269 pub measure_id: Option<MeasureId>,
270 pub unit_id: Option<UnitId>,
271 pub obs_val: Option<f64>,
272 #[serde(rename = "rowId")]
273 pub row_id: Option<RowId>,
274 pub dt: Option<String>,
275 pub periodicity: Option<Periodicity>,
276 pub date: Option<IsoDateTime>,
277 pub digits: Option<i32>,
278}
279
280#[derive(Debug, Clone, Deserialize, PartialEq)]
282pub struct DataHeader {
283 pub id: Option<ColumnId>,
284 pub elname: Option<String>,
285}
286
287#[derive(Debug, Clone, Deserialize, PartialEq)]
289pub struct DataUnit {
290 pub id: Option<UnitId>,
291 pub val: Option<String>,
292}
293
294#[derive(Debug, Clone, Deserialize, PartialEq)]
296pub struct DataRange {
297 #[serde(rename = "FromY")]
298 pub from_year: Option<Year>,
299 #[serde(rename = "ToY")]
300 pub to_year: Option<Year>,
301}
302
303#[derive(Debug, Clone, Deserialize, PartialEq)]
305pub struct DataSeriesType {
306 #[serde(rename = "sType")]
307 pub s_type: Option<SeriesType>,
308 #[serde(rename = "dsName")]
309 pub ds_name: Option<String>,
310 #[serde(rename = "PublName")]
311 pub publ_name: Option<String>,
312}
313
314#[derive(Debug, Clone, Deserialize, PartialEq)]
316pub struct DataExResponse {
317 #[serde(rename = "RawData")]
318 pub raw_data: Vec<DataExRow>,
319 pub links: Vec<DataExLink>,
320}
321
322#[derive(Debug, Clone, Deserialize, PartialEq)]
324pub struct DataExRow {
325 pub indicator_id: Option<IndicatorId>,
326 pub measure_1_id: Option<MeasureId>,
327 pub measure_2_id: Option<MeasureId>,
328 pub unit_id: Option<UnitId>,
329 pub value: Option<f64>,
330 pub period_id: Option<PeriodId>,
331 pub period: Option<String>,
332 pub periodicity: Option<Periodicity>,
333 pub date: Option<DmyDate>,
334 #[serde(rename = "rowId")]
335 pub row_id: Option<RowId>,
336}
337
338#[derive(Debug, Clone, Deserialize, PartialEq)]
340pub struct DataExLink {
341 pub indicator_id: Option<IndicatorId>,
342 pub measure_1_id: Option<MeasureId>,
343 pub measure_2_id: Option<MeasureId>,
344 pub unit_id: Option<UnitId>,
345 pub name: Option<String>,
346 #[serde(rename = "sSort")]
347 pub s_sort: Option<SortKey>,
348}
349
350#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
352#[serde(untagged)]
353pub enum SortKey {
354 Numeric(i32),
356 Text(String),
358}
359
360impl<'de> Deserialize<'de> for SortKey {
361 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
362 where
363 D: Deserializer<'de>,
364 {
365 struct SortKeyVisitor;
366
367 impl Visitor<'_> for SortKeyVisitor {
368 type Value = SortKey;
369
370 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
371 formatter.write_str("an integer or a string")
372 }
373
374 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
375 where
376 E: de::Error,
377 {
378 let value = i32::try_from(value)
379 .map_err(|_| E::custom(format!("sort key is out of i32 range: {value}")))?;
380 Ok(SortKey::Numeric(value))
381 }
382
383 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
384 where
385 E: de::Error,
386 {
387 let value = i32::try_from(value)
388 .map_err(|_| E::custom(format!("sort key is out of i32 range: {value}")))?;
389 Ok(SortKey::Numeric(value))
390 }
391
392 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
393 where
394 E: de::Error,
395 {
396 match value.parse::<i32>() {
397 Ok(parsed) => Ok(SortKey::Numeric(parsed)),
398 Err(_) => Ok(SortKey::Text(value.to_owned())),
399 }
400 }
401
402 fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
403 where
404 E: de::Error,
405 {
406 match value.parse::<i32>() {
407 Ok(parsed) => Ok(SortKey::Numeric(parsed)),
408 Err(_) => Ok(SortKey::Text(value)),
409 }
410 }
411 }
412
413 deserializer.deserialize_any(SortKeyVisitor)
414 }
415}
416
417impl SortKey {
418 #[must_use]
420 #[inline]
421 pub fn as_numeric(&self) -> Option<i32> {
422 match self {
423 Self::Numeric(value) => Some(*value),
424 Self::Text(_) => None,
425 }
426 }
427
428 #[must_use]
430 #[inline]
431 pub fn as_text(&self) -> Option<&str> {
432 match self {
433 Self::Numeric(_) => None,
434 Self::Text(value) => Some(value.as_str()),
435 }
436 }
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}