Skip to content

Commit 551895d

Browse files
authored
Merge pull request #110 from pbs-data-solutions/json
Add methods to convert native structs to json
2 parents 7c79ece + e5f4843 commit 551895d

File tree

6 files changed

+199
-1
lines changed

6 files changed

+199
-1
lines changed

src/native/site_native.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use chrono::{DateTime, Utc};
22

33
#[cfg(feature = "python")]
44
use pyo3::{
5+
exceptions::PyValueError,
56
prelude::*,
67
types::{PyDateTime, PyDict},
78
};
@@ -133,6 +134,32 @@ pub struct SiteNative {
133134
pub sites: Vec<Site>,
134135
}
135136

137+
#[cfg(not(feature = "python"))]
138+
impl SiteNative {
139+
/// Convert to a JSON string
140+
///
141+
/// # Example
142+
///
143+
/// ```
144+
/// use std::path::Path;
145+
///
146+
/// use prelude_xml_parser::parse_site_native_file;
147+
///
148+
/// let file_path = Path::new("tests/assets/site_native_small.xml");
149+
/// let native = parse_site_native_file(&file_path).unwrap();
150+
/// let json = native.to_json().unwrap();
151+
/// println!("{json}");
152+
/// let expected = r#"{"sites":[{"name":"Some Site","uniqueId":"1681574834910","numberOfPatients":4,"countOfRandomizedPatients":0,"whenCreated":"2023-04-15T16:08:19Z","creator":"Paul Sanders","numberOfForms":1,"forms":[{"name":"demographic.form.name.site.demographics","lastModified":"2023-04-15T16:08:19Z","whoLastModifiedName":"Paul Sanders","whoLastModifiedRole":"Project Manager","whenCreated":1681574834930,"hasErrors":false,"hasWarnings":false,"locked":false,"user":null,"dateTimeChanged":null,"formTitle":"Site Demographics","formIndex":1,"formGroup":"Demographic","formState":"In-Work","states":[{"value":"form.state.in.work","signer":"Paul Sanders - Project Manager","signerUniqueId":"1681162687395","dateSigned":"2023-04-15T16:08:19Z"}],"categories":[{"name":"Demographics","categoryType":"normal","highestIndex":0,"fields":[{"name":"address","fieldType":"text","dataType":"string","errorCode":"valid","whenCreated":"2023-04-15T16:07:14Z","keepHistory":true,"entries":null,"comments":null},{"name":"company","fieldType":"text","dataType":"string","errorCode":"valid","whenCreated":"2023-04-15T16:07:14Z","keepHistory":true,"entries":[{"entryId":"1","value":{"by":"Paul Sanders","byUniqueId":"1681162687395","role":"Project Manager","when":"2023-04-15T16:08:19Z","value":"Some Company"},"reason":null}],"comments":[{"commentId":"1","value":{"by":"Paul Sanders","byUniqueId":"1681162687395","role":"Project Manager","when":"2023-04-15T16:09:02Z","value":"Some Comment"}}]}]}]}]}]}"#;;
153+
///
154+
/// assert_eq!(json, expected);
155+
/// ```
156+
pub fn to_json(&self) -> serde_json::Result<String> {
157+
let json = serde_json::to_string(&self)?;
158+
159+
Ok(json)
160+
}
161+
}
162+
136163
#[cfg(feature = "python")]
137164
/// Contains the information from the Prelude native site XML.
138165
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
@@ -162,6 +189,12 @@ impl SiteNative {
162189
dict.set_item("sites", site_dicts)?;
163190
Ok(dict)
164191
}
192+
193+
/// Convert the class instance to a JSON string
194+
fn to_json(&self) -> PyResult<String> {
195+
serde_json::to_string(&self)
196+
.map_err(|_| PyErr::new::<PyValueError, _>("Error converting to JSON"))
197+
}
165198
}
166199

167200
#[cfg(test)]

src/native/subject_native.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use chrono::{DateTime, Utc};
22

33
#[cfg(feature = "python")]
44
use pyo3::{
5+
exceptions::PyValueError,
56
prelude::*,
67
types::{PyDateTime, PyDict},
78
};
@@ -149,6 +150,31 @@ pub struct SubjectNative {
149150
pub patients: Vec<Patient>,
150151
}
151152

153+
#[cfg(not(feature = "python"))]
154+
impl SubjectNative {
155+
/// Convert to a JSON string
156+
///
157+
/// # Example
158+
///
159+
/// ```
160+
/// use std::path::Path;
161+
///
162+
/// use prelude_xml_parser::parse_subject_native_file;
163+
///
164+
/// let file_path = Path::new("tests/assets/subject_native_small.xml");
165+
/// let native = parse_subject_native_file(&file_path).unwrap();
166+
/// let expected = r#"{"patients":[{"patientId":"ABC-001","uniqueId":"1681574905819","whenCreated":"2023-04-15T16:09:02Z","creator":"Paul Sanders","siteName":"Some Site","siteUniqueId":"1681574834910","lastLanguage":null,"numberOfForms":6,"forms":[{"name":"day.0.form.name.demographics","lastModified":"2023-04-15T16:09:15Z","whoLastModifiedName":"Paul Sanders","whoLastModifiedRole":"Project Manager","whenCreated":1681574905839,"hasErrors":false,"hasWarnings":false,"locked":false,"user":null,"dateTimeChanged":null,"formTitle":"Demographics","formIndex":1,"formGroup":"Day 0","formState":"In-Work","states":[{"value":"form.state.in.work","signer":"Paul Sanders - Project Manager","signerUniqueId":"1681162687395","dateSigned":"2023-04-15T16:09:02Z"}],"categories":[{"name":"Demographics","categoryType":"normal","highestIndex":0,"fields":[{"name":"breed","fieldType":"combo-box","dataType":"string","errorCode":"valid","whenCreated":"2023-04-15T16:08:26Z","keepHistory":true,"entries":[{"entryId":"1","value":{"by":"Paul Sanders","byUniqueId":"1681162687395","role":"Project Manager","when":"2023-04-15T16:09:02Z","value":"Labrador"},"reason":null}],"comments":[{"commentId":"1","value":{"by":"Paul Sanders","byUniqueId":"1681162687395","role":"Project Manager","when":"2023-04-15T16:09:02Z","value":"Some Comment"}}]}]}]}]}]}"#;
167+
/// let json = native.to_json().unwrap();
168+
///
169+
/// assert_eq!(json, expected);
170+
/// ```
171+
pub fn to_json(&self) -> serde_json::Result<String> {
172+
let json = serde_json::to_string(&self)?;
173+
174+
Ok(json)
175+
}
176+
}
177+
152178
#[cfg(feature = "python")]
153179
/// Contains the information from the Prelude native subject XML.
154180
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
@@ -178,6 +204,12 @@ impl SubjectNative {
178204
dict.set_item("patients", patient_dicts)?;
179205
Ok(dict)
180206
}
207+
208+
/// Convert the class instance to a JSON string
209+
fn to_json(&self) -> PyResult<String> {
210+
serde_json::to_string(&self)
211+
.map_err(|_| PyErr::new::<PyValueError, _>("Error converting to JSON"))
212+
}
181213
}
182214

183215
#[cfg(test)]

src/native/user_native.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use serde::{Deserialize, Serialize};
22

33
#[cfg(feature = "python")]
4-
use pyo3::{prelude::*, types::PyDict};
4+
use pyo3::{exceptions::PyValueError, prelude::*, types::PyDict};
55

66
pub use crate::native::{
77
common::{Category, Comment, Entry, Field, Form, Reason, State, Value},
@@ -102,6 +102,31 @@ pub struct UserNative {
102102
pub users: Vec<User>,
103103
}
104104

105+
#[cfg(not(feature = "python"))]
106+
impl UserNative {
107+
/// Convert to a JSON string
108+
///
109+
/// # Example
110+
///
111+
/// ```
112+
/// use std::path::Path;
113+
///
114+
/// use prelude_xml_parser::parse_user_native_file;
115+
///
116+
/// let file_path = Path::new("tests/assets/user_native_small.xml");
117+
/// let native = parse_user_native_file(&file_path).unwrap();
118+
/// let expected = r#"{"users":[{"uniqueId":"1691421275437","lastLanguage":null,"creator":"Paul Sanders(1681162687395)","numberOfForms":1,"forms":[{"name":"form.name.demographics","lastModified":"2023-08-07T15:15:41Z","whoLastModifiedName":"Paul Sanders","whoLastModifiedRole":"Project Manager","whenCreated":1691421341578,"hasErrors":false,"hasWarnings":false,"locked":false,"user":null,"dateTimeChanged":null,"formTitle":"User Demographics","formIndex":1,"formGroup":null,"formState":"In-Work","states":[{"value":"form.state.in.work","signer":"Paul Sanders - Project Manager","signerUniqueId":"1681162687395","dateSigned":"2023-08-07T15:15:41Z"}],"categories":[{"name":"demographics","categoryType":"normal","highestIndex":0,"fields":[{"name":"address","fieldType":"text","dataType":"string","errorCode":"undefined","whenCreated":"2024-01-12T20:14:09Z","keepHistory":true,"entries":null,"comments":null},{"name":"email","fieldType":"text","dataType":"string","errorCode":"undefined","whenCreated":"2023-08-07T15:15:41Z","keepHistory":true,"entries":[{"entryId":"1","value":{"by":"Paul Sanders","byUniqueId":"1681162687395","role":"Project Manager","when":"2023-08-07T15:15:41Z","value":"[email protected]"},"reason":null}],"comments":[{"commentId":"1","value":{"by":"Paul Sanders","byUniqueId":"1681162687395","role":"Project Manager","when":"2023-04-15T16:09:02Z","value":"Some Comment"}}]}]},{"name":"Administrative","categoryType":"normal","highestIndex":0,"fields":[{"name":"study_assignment","fieldType":"text","dataType":null,"errorCode":"undefined","whenCreated":"2023-08-07T15:15:41Z","keepHistory":true,"entries":[{"entryId":"1","value":{"by":"set from calculation","byUniqueId":null,"role":"System","when":"2023-08-07T15:15:41Z","value":"On 07-Aug-2023 10:15 -0500, Paul Sanders assigned user from another study"},"reason":{"by":"set from calculation","byUniqueId":null,"role":"System","when":"2023-08-07T15:15:41Z","value":"calculated value"}}],"comments":null}]}]}]},{"uniqueId":"1681162687395","lastLanguage":null,"creator":"1609858291483(1609858291483)","numberOfForms":2,"forms":[{"name":"form.name.demographics","lastModified":"2023-04-10T21:39:30Z","whoLastModifiedName":"1609858291483","whoLastModifiedRole":"role.administrator","whenCreated":1681162770378,"hasErrors":false,"hasWarnings":false,"locked":false,"user":null,"dateTimeChanged":null,"formTitle":"User Demographics","formIndex":1,"formGroup":null,"formState":"In-Work","states":[{"value":"form.state.in.work","signer":"1609858291483 - Administrator","signerUniqueId":"1609858291483","dateSigned":"2023-04-10T21:39:30Z"}],"categories":[{"name":"demographics","categoryType":"normal","highestIndex":0,"fields":[{"name":"address","fieldType":"text","dataType":"string","errorCode":"undefined","whenCreated":"2023-04-15T15:21:14Z","keepHistory":true,"entries":null,"comments":null},{"name":"email","fieldType":"text","dataType":"string","errorCode":"undefined","whenCreated":"2023-04-10T21:39:30Z","keepHistory":true,"entries":[{"entryId":"1","value":{"by":"1609858291483","byUniqueId":"1609858291483","role":"Administrator","when":"2023-04-10T21:39:30Z","value":"[email protected]"},"reason":null}],"comments":null}]},{"name":"Administrative","categoryType":"normal","highestIndex":0,"fields":[{"name":"study_assignment","fieldType":"text","dataType":null,"errorCode":"undefined","whenCreated":"2023-04-10T21:39:30Z","keepHistory":true,"entries":[{"entryId":"1","value":{"by":"set from calculation","byUniqueId":null,"role":"System","when":"2023-04-10T21:39:30Z","value":"On 10-Apr-2023 16:39 -0500, 1609858291483 assigned user from another study"},"reason":{"by":"set from calculation","byUniqueId":null,"role":"System","when":"2023-04-10T21:39:30Z","value":"calculated value"}}],"comments":null}]}]},{"name":"training.form.name.checklist","lastModified":null,"whoLastModifiedName":null,"whoLastModifiedRole":null,"whenCreated":1702998014133,"hasErrors":false,"hasWarnings":false,"locked":false,"user":null,"dateTimeChanged":null,"formTitle":"Training Checklist","formIndex":1,"formGroup":"Training","formState":"New","states":[{"value":"form.state.new","signer":"System set","signerUniqueId":"system","dateSigned":"2023-12-19T15:00:14Z"}],"categories":[{"name":"Training_Modules","categoryType":"normal","highestIndex":0,"fields":[{"name":"date(1)","fieldType":"setToday","dataType":"date","errorCode":"undefined","whenCreated":"2023-12-19T15:00:15Z","keepHistory":true,"entries":null,"comments":null}]},{"name":"Other_Training_Modules","categoryType":"indexed","highestIndex":1,"fields":[{"name":"date_field(1)","fieldType":"setToday","dataType":"date","errorCode":"undefined","whenCreated":"2023-12-19T15:00:15Z","keepHistory":true,"entries":null,"comments":null}]},{"name":"21CFR11","categoryType":"normal","highestIndex":0,"fields":null}]}]}]}"#;
119+
/// let json = native.to_json().unwrap();
120+
///
121+
/// assert_eq!(json, expected);
122+
/// ```
123+
pub fn to_json(&self) -> serde_json::Result<String> {
124+
let json = serde_json::to_string(&self)?;
125+
126+
Ok(json)
127+
}
128+
}
129+
105130
#[cfg(feature = "python")]
106131
/// Contains the information from the Prelude native user XML.
107132
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
@@ -131,6 +156,12 @@ impl UserNative {
131156
dict.set_item("users", user_dicts)?;
132157
Ok(dict)
133158
}
159+
160+
/// Convert the class instance to a JSON string
161+
fn to_json(&self) -> PyResult<String> {
162+
serde_json::to_string(&self)
163+
.map_err(|_| PyErr::new::<PyValueError, _>("Error converting to JSON"))
164+
}
134165
}
135166

136167
#[cfg(test)]

tests/assets/site_native_small.xml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<export_from_vision_EDC date="01-Jun-2024 18:17 -0500" createdBy="Paul Sanders" role="Project Manager" numberSubjectsProcessed="2">
3+
4+
<site name="Some Site" uniqueId="1681574834910" numberOfPatients="4" countOfRandomizedPatients="0" whenCreated="2023-04-15 12:08:19 -0400" creator="Paul Sanders" numberOfForms="1">
5+
<form name="demographic.form.name.site.demographics" lastModified="2023-04-15 12:08:19 -0400" whoLastModifiedName="Paul Sanders" whoLastModifiedRole="Project Manager" whenCreated="1681574834930" hasErrors="false" hasWarnings="false" locked="false" user="" dateTimeChanged="" formTitle="Site Demographics" formIndex="1" formGroup="Demographic" formState="In-Work">
6+
<state value="form.state.in.work" signer="Paul Sanders - Project Manager" signerUniqueId="1681162687395" dateSigned="2023-04-15 12:08:19 -0400" />
7+
<category name="Demographics" type="normal" highestIndex="0">
8+
<field name="address" type="text" dataType="string" errorCode="valid" whenCreated="2023-04-15 11:07:14 -0500" keepHistory="true" />
9+
<field name="company" type="text" dataType="string" errorCode="valid" whenCreated="2023-04-15 11:07:14 -0500" keepHistory="true">
10+
<entry id="1">
11+
<value by="Paul Sanders" byUniqueId="1681162687395" role="Project Manager" when="2023-04-15 12:08:19 -0400" xml:space="preserve">Some Company</value>
12+
</entry>
13+
<comment id="1">
14+
<value by="Paul Sanders" byUniqueId="1681162687395" role="Project Manager" when="2023-04-15 12:09:02 -0400" xml:space="preserve">Some Comment</value>
15+
</comment>
16+
</field>
17+
</category>
18+
</form>
19+
</site>
20+
21+
</export_from_vision_EDC>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<export_from_vision_EDC date="30-May-2024 10:35 -0500" createdBy="Paul Sanders" role="Project Manager" numberSubjectsProcessed="4">
3+
4+
<patient patientId="ABC-001" uniqueId="1681574905819" whenCreated="2023-04-15 12:09:02 -0400" creator="Paul Sanders" siteName="Some Site" siteUniqueId="1681574834910" lastLanguage="" numberOfForms="6">
5+
<form name="day.0.form.name.demographics" lastModified="2023-04-15 12:09:15 -0400" whoLastModifiedName="Paul Sanders" whoLastModifiedRole="Project Manager" whenCreated="1681574905839" hasErrors="false" hasWarnings="false" locked="false" user="" dateTimeChanged="" formTitle="Demographics" formIndex="1" formGroup="Day 0" formState="In-Work">
6+
<state value="form.state.in.work" signer="Paul Sanders - Project Manager" signerUniqueId="1681162687395" dateSigned="2023-04-15 12:09:02 -0400" />
7+
<category name="Demographics" type="normal" highestIndex="0">
8+
<field name="breed" type="combo-box" dataType="string" errorCode="valid" whenCreated="2023-04-15 12:08:26 -0400" keepHistory="true">
9+
<entry id="1">
10+
<value by="Paul Sanders" byUniqueId="1681162687395" role="Project Manager" when="2023-04-15 12:09:02 -0400" xml:space="preserve">Labrador</value>
11+
</entry>
12+
<comment id="1">
13+
<value by="Paul Sanders" byUniqueId="1681162687395" role="Project Manager" when="2023-04-15 12:09:02 -0400" xml:space="preserve">Some Comment</value>
14+
</comment>
15+
</field>
16+
</category>
17+
</form>
18+
</patient>
19+
20+
</export_from_vision_EDC>

0 commit comments

Comments
 (0)