Skip to content

Commit e7b31b0

Browse files
authored
Merge pull request #28 from pbs-data-solutions/deserialize
Refactor deserializers to work with both json and xml
2 parents 291f063 + 793eb97 commit e7b31b0

File tree

6 files changed

+1137
-47
lines changed

6 files changed

+1137
-47
lines changed

src/lib.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ pub fn parse_site_native_file(xml_path: &Path) -> Result<SiteNative, Error> {
140140
/// name: "Demographics".to_string(),
141141
/// category_type: "normal".to_string(),
142142
/// highest_index: 0,
143-
/// fields: vec![
143+
/// fields: Some(vec![
144144
/// Field {
145145
/// name: "address".to_string(),
146146
/// field_type: "text".to_string(),
@@ -245,13 +245,13 @@ pub fn parse_site_native_file(xml_path: &Path) -> Result<SiteNative, Error> {
245245
/// },
246246
/// ]),
247247
/// },
248-
/// ],
248+
/// ]),
249249
/// },
250250
/// Category {
251251
/// name: "Enrollment".to_string(),
252252
/// category_type: "normal".to_string(),
253253
/// highest_index: 0,
254-
/// fields: vec![
254+
/// fields: Some(vec![
255255
/// Field {
256256
/// name: "enrollment_closed_date".to_string(),
257257
/// field_type: "popUpCalendar".to_string(),
@@ -305,7 +305,7 @@ pub fn parse_site_native_file(xml_path: &Path) -> Result<SiteNative, Error> {
305305
/// keep_history: true,
306306
/// entries: None,
307307
/// },
308-
/// ],
308+
/// ]),
309309
/// },
310310
/// ]),
311311
/// }]),
@@ -353,7 +353,7 @@ pub fn parse_site_native_file(xml_path: &Path) -> Result<SiteNative, Error> {
353353
/// name: "Demographics".to_string(),
354354
/// category_type: "normal".to_string(),
355355
/// highest_index: 0,
356-
/// fields: vec![Field {
356+
/// fields: Some(vec![Field {
357357
/// name: "address".to_string(),
358358
/// field_type: "text".to_string(),
359359
/// data_type: Some("string".to_string()),
@@ -375,7 +375,7 @@ pub fn parse_site_native_file(xml_path: &Path) -> Result<SiteNative, Error> {
375375
/// }),
376376
/// reason: None,
377377
/// }]),
378-
/// }],
378+
/// }]),
379379
/// }]),
380380
/// }]),
381381
/// },
@@ -493,7 +493,7 @@ pub fn parse_subject_native_file(xml_path: &Path) -> Result<SubjectNative, Error
493493
/// name: "Demographics".to_string(),
494494
/// category_type: "normal".to_string(),
495495
/// highest_index: 0,
496-
/// fields: vec![Field {
496+
/// fields: Some(vec![Field {
497497
/// name: "breed".to_string(),
498498
/// field_type: "combo-box".to_string(),
499499
/// data_type: Some("string".to_string()),
@@ -515,7 +515,7 @@ pub fn parse_subject_native_file(xml_path: &Path) -> Result<SubjectNative, Error
515515
/// }),
516516
/// reason: None,
517517
/// }]),
518-
/// }],
518+
/// }]),
519519
/// }]),
520520
/// }]),
521521
/// },
@@ -561,7 +561,7 @@ pub fn parse_subject_native_file(xml_path: &Path) -> Result<SubjectNative, Error
561561
/// name: "Demographics".to_string(),
562562
/// category_type: "normal".to_string(),
563563
/// highest_index: 0,
564-
/// fields: vec![Field {
564+
/// fields: Some(vec![Field {
565565
/// name: "breed".to_string(),
566566
/// field_type: "combo-box".to_string(),
567567
/// data_type: Some("string".to_string()),
@@ -583,13 +583,14 @@ pub fn parse_subject_native_file(xml_path: &Path) -> Result<SubjectNative, Error
583583
/// }),
584584
/// reason: None,
585585
/// }]),
586-
/// }],
586+
/// }]),
587587
/// }]),
588588
/// }]),
589589
/// },
590590
/// ],
591591
/// };
592592
/// let result = parse_subject_native_string(xml).unwrap();
593+
///
593594
/// assert_eq!(result, expected);
594595
/// ```
595596
pub fn parse_subject_native_string(xml_str: &str) -> Result<SubjectNative, Error> {
@@ -696,7 +697,7 @@ pub fn parse_user_native_file(xml_path: &Path) -> Result<UserNative, Error> {
696697
/// name: "demographics".to_string(),
697698
/// category_type: "normal".to_string(),
698699
/// highest_index: 0,
699-
/// fields: vec![
700+
/// fields: Some(vec![
700701
/// Field {
701702
/// name: "address".to_string(),
702703
/// field_type: "text".to_string(),
@@ -731,13 +732,13 @@ pub fn parse_user_native_file(xml_path: &Path) -> Result<UserNative, Error> {
731732
/// reason: None,
732733
/// }]),
733734
/// },
734-
/// ],
735+
/// ]),
735736
/// },
736737
/// Category {
737738
/// name: "Administrative".to_string(),
738739
/// category_type: "normal".to_string(),
739740
/// highest_index: 0,
740-
/// fields: vec![
741+
/// fields: Some(vec![
741742
/// Field {
742743
/// name: "study_assignment".to_string(),
743744
/// field_type: "text".to_string(),
@@ -771,14 +772,15 @@ pub fn parse_user_native_file(xml_path: &Path) -> Result<UserNative, Error> {
771772
/// },
772773
/// ]),
773774
/// },
774-
/// ],
775+
/// ]),
775776
/// },
776777
/// ]),
777778
/// }]),
778779
/// }],
779780
/// };
780781
///
781782
/// let result = parse_user_native_string(xml).unwrap();
783+
///
782784
/// assert_eq!(result, expected);
783785
/// ```
784786
pub fn parse_user_native_string(xml_str: &str) -> Result<UserNative, Error> {

src/native/common.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub struct Value {
2626
pub role: String,
2727
pub when: DateTime<Utc>,
2828

29-
#[serde(rename = "$value")]
29+
#[serde(alias = "$value")]
3030
pub value: String,
3131
}
3232

@@ -45,7 +45,7 @@ pub struct Value {
4545
pub role: String,
4646
pub when: DateTime<Utc>,
4747

48-
#[serde(rename = "$value")]
48+
#[serde(alias = "$value")]
4949
pub value: String,
5050
}
5151

@@ -93,7 +93,7 @@ pub struct Reason {
9393
pub role: String,
9494
pub when: DateTime<Utc>,
9595

96-
#[serde(rename = "$value")]
96+
#[serde(alias = "$value")]
9797
pub value: String,
9898
}
9999

@@ -113,7 +113,7 @@ pub struct Reason {
113113
pub role: String,
114114
pub when: DateTime<Utc>,
115115

116-
#[serde(rename = "$value")]
116+
#[serde(alias = "$value")]
117117
pub value: String,
118118
}
119119

@@ -185,7 +185,7 @@ pub struct Field {
185185
pub when_created: DateTime<Utc>,
186186
pub keep_history: bool,
187187

188-
#[serde(rename = "entry")]
188+
#[serde(alias = "entry")]
189189
pub entries: Option<Vec<Entry>>,
190190
}
191191

@@ -209,7 +209,7 @@ pub struct Field {
209209
pub when_created: DateTime<Utc>,
210210
pub keep_history: bool,
211211

212-
#[serde(rename = "entry")]
212+
#[serde(alias = "entry")]
213213
pub entries: Option<Vec<Entry>>,
214214
}
215215

@@ -263,8 +263,8 @@ pub struct Category {
263263

264264
pub highest_index: usize,
265265

266-
#[serde(rename = "field", default)]
267-
pub fields: Vec<Field>,
266+
#[serde(alias = "field")]
267+
pub fields: Option<Vec<Field>>,
268268
}
269269

270270
#[cfg(feature = "python")]
@@ -279,8 +279,8 @@ pub struct Category {
279279

280280
pub highest_index: usize,
281281

282-
#[serde(rename = "field", default)]
283-
pub fields: Vec<Field>,
282+
#[serde(alias = "field")]
283+
pub fields: Option<Vec<Field>>,
284284
}
285285

286286
#[cfg(not(feature = "python"))]
@@ -390,10 +390,10 @@ pub struct Form {
390390

391391
pub form_state: String,
392392

393-
#[serde(rename = "state", default)]
393+
#[serde(alias = "state")]
394394
pub states: Option<Vec<State>>,
395395

396-
#[serde(rename = "category", default)]
396+
#[serde(alias = "category")]
397397
pub categories: Option<Vec<Category>>,
398398
}
399399

@@ -450,10 +450,10 @@ pub struct Form {
450450

451451
pub form_state: String,
452452

453-
#[serde(rename = "state", default)]
453+
#[serde(alias = "state")]
454454
pub states: Option<Vec<State>>,
455455

456-
#[serde(rename = "category", default)]
456+
#[serde(alias = "category")]
457457
pub categories: Option<Vec<Category>>,
458458
}
459459

src/native/deserializers.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,24 @@ pub fn deserialize_empty_string_as_none_datetime<'de, D>(
1414
where
1515
D: Deserializer<'de>,
1616
{
17-
let s: String = Deserialize::deserialize(deserializer)?;
18-
if s.is_empty() {
19-
Ok(None)
20-
} else {
21-
// Parse the datetime with a fixed offset, then convert it to UTC
22-
let dt_with_offset = DateTime::parse_from_str(&s, "%Y-%m-%d %H:%M:%S %z")
23-
.map_err(serde::de::Error::custom)?;
24-
Ok(Some(dt_with_offset.with_timezone(&Utc)))
17+
let s: Option<String> = Deserialize::deserialize(deserializer)?;
18+
match s {
19+
Some(v) => {
20+
if v.is_empty() {
21+
Ok(None)
22+
} else {
23+
// Parse the datetime with a fixed offset, then convert it to UTC
24+
25+
let dt_with_offset = if v.ends_with('Z') {
26+
DateTime::parse_from_rfc3339(&v).map_err(serde::de::Error::custom)?
27+
} else {
28+
DateTime::parse_from_str(&v, "%Y-%m-%d %H:%M:%S %z")
29+
.map_err(serde::de::Error::custom)?
30+
};
31+
Ok(Some(dt_with_offset.with_timezone(&Utc)))
32+
}
33+
}
34+
None => Ok(None),
2535
}
2636
}
2737

0 commit comments

Comments
 (0)