use crate::vocabulary::{Cd, Ii};
use hl7_2_xml_lite_helper::Element;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Act {
pub class_code: String,
pub mood_code: String,
pub id: Vec<Ii>,
pub code: Option<Cd>,
pub status_code: Option<Cd>,
pub effective_time: Option<String>,
pub text: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Entity {
pub class_code: String,
pub determiner_code: Option<String>,
pub id: Vec<Ii>,
pub code: Option<Cd>,
pub name: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Role {
pub class_code: String,
pub id: Vec<Ii>,
pub code: Option<Cd>,
pub status_code: Option<Cd>,
pub effective_time: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Participation {
pub type_code: String,
pub time: Option<String>,
pub function_code: Option<Cd>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ActRelationship {
pub type_code: String,
pub inversion_ind: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct RoleLink {
pub type_code: String,
}
impl Act {
#[must_use]
pub fn from_element(element: &Element) -> Act {
Act {
class_code: element
.attribute("classCode")
.unwrap_or_default()
.to_string(),
mood_code: element
.attribute("moodCode")
.unwrap_or_default()
.to_string(),
id: element
.children_named("id")
.filter_map(Ii::from_element)
.collect(),
code: element.child("code").and_then(Cd::from_element),
status_code: element.child("statusCode").and_then(Cd::from_element),
effective_time: element
.child("effectiveTime")
.and_then(|time| time.attribute("value"))
.map(str::to_string),
text: element
.child("text")
.and_then(Element::text_opt)
.map(str::to_string),
}
}
}
impl Entity {
#[must_use]
pub fn from_element(element: &Element) -> Entity {
Entity {
class_code: element
.attribute("classCode")
.unwrap_or_default()
.to_string(),
determiner_code: element.attribute("determinerCode").map(str::to_string),
id: element
.children_named("id")
.filter_map(Ii::from_element)
.collect(),
code: element.child("code").and_then(Cd::from_element),
name: element
.child("name")
.and_then(Element::text_opt)
.map(str::to_string),
}
}
}
impl Role {
#[must_use]
pub fn from_element(element: &Element) -> Role {
Role {
class_code: element
.attribute("classCode")
.unwrap_or_default()
.to_string(),
id: element
.children_named("id")
.filter_map(Ii::from_element)
.collect(),
code: element.child("code").and_then(Cd::from_element),
status_code: element.child("statusCode").and_then(Cd::from_element),
effective_time: element
.child("effectiveTime")
.and_then(|time| time.attribute("value"))
.map(str::to_string),
}
}
}
impl Participation {
#[must_use]
pub fn from_element(element: &Element) -> Participation {
Participation {
type_code: element
.attribute("typeCode")
.unwrap_or_default()
.to_string(),
time: element
.child("time")
.and_then(|time| time.attribute("value"))
.map(str::to_string),
function_code: element.child("functionCode").and_then(Cd::from_element),
}
}
}
impl ActRelationship {
#[must_use]
pub fn from_element(element: &Element) -> ActRelationship {
ActRelationship {
type_code: element
.attribute("typeCode")
.unwrap_or_default()
.to_string(),
inversion_ind: element
.attribute("inversionInd")
.map(|value| value == "true"),
}
}
}
impl RoleLink {
#[must_use]
pub fn from_element(element: &Element) -> RoleLink {
RoleLink {
type_code: element
.attribute("typeCode")
.unwrap_or_default()
.to_string(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn act_reads_class_mood_id_code_status_and_time() {
let element = hl7_2_xml_lite_helper::parse(
r#"<observation classCode="OBS" moodCode="EVN">
<id root="2.16.840.1.113883.19.5" extension="1"/>
<code code="8302-2" codeSystem="2.16.840.1.113883.6.1" displayName="Height"/>
<statusCode code="completed"/>
<effectiveTime value="20260101"/>
</observation>"#,
)
.unwrap();
let act = Act::from_element(&element);
assert_eq!(act.class_code, "OBS");
assert_eq!(act.mood_code, "EVN");
assert_eq!(act.id.len(), 1);
assert_eq!(act.id[0].extension.as_deref(), Some("1"));
assert_eq!(act.code.unwrap().code, "8302-2");
assert_eq!(act.status_code.unwrap().code, "completed");
assert_eq!(act.effective_time.as_deref(), Some("20260101"));
}
#[test]
fn act_with_no_optional_children_still_reads() {
let element =
hl7_2_xml_lite_helper::parse(r#"<act classCode="ACT" moodCode="EVN"/>"#).unwrap();
let act = Act::from_element(&element);
assert_eq!(act.id, Vec::new());
assert_eq!(act.code, None);
assert_eq!(act.status_code, None);
assert_eq!(act.effective_time, None);
assert_eq!(act.text, None);
}
#[test]
fn entity_reads_class_determiner_and_name() {
let element = hl7_2_xml_lite_helper::parse(
r#"<representedOrganization classCode="ORG" determinerCode="INSTANCE">
<id root="2.16.840.1.113883.19.5"/>
<name>Acme Clinic</name>
</representedOrganization>"#,
)
.unwrap();
let entity = Entity::from_element(&element);
assert_eq!(entity.class_code, "ORG");
assert_eq!(entity.determiner_code.as_deref(), Some("INSTANCE"));
assert_eq!(entity.name.as_deref(), Some("Acme Clinic"));
}
#[test]
fn role_reads_class_and_status() {
let element = hl7_2_xml_lite_helper::parse(
r#"<patient classCode="PAT">
<id root="2.16.840.1.113883.19.5" extension="12345"/>
<statusCode code="active"/>
</patient>"#,
)
.unwrap();
let role = Role::from_element(&element);
assert_eq!(role.class_code, "PAT");
assert_eq!(role.id[0].extension.as_deref(), Some("12345"));
assert_eq!(role.status_code.unwrap().code, "active");
}
#[test]
fn participation_reads_type_and_function() {
let element = hl7_2_xml_lite_helper::parse(
r#"<author typeCode="AUT"><time value="20260101"/></author>"#,
)
.unwrap();
let participation = Participation::from_element(&element);
assert_eq!(participation.type_code, "AUT");
assert_eq!(participation.time.as_deref(), Some("20260101"));
}
#[test]
fn act_relationship_reads_type_and_inversion() {
let element =
hl7_2_xml_lite_helper::parse(r#"<component typeCode="COMP" inversionInd="true"/>"#)
.unwrap();
let relationship = ActRelationship::from_element(&element);
assert_eq!(relationship.type_code, "COMP");
assert_eq!(relationship.inversion_ind, Some(true));
}
#[test]
fn role_link_reads_type() {
let element = hl7_2_xml_lite_helper::parse(r#"<roleLink typeCode="REPL"/>"#).unwrap();
assert_eq!(RoleLink::from_element(&element).type_code, "REPL");
}
}