use crate::message_registry;
use dataflow_rs::engine::error::{DataflowError, Result};
use serde_json::Value;
pub fn map_document_element_to_message_type(element_name: &str) -> Result<String> {
if let Some(msg_type) = message_registry::element_to_message_type(element_name) {
return Ok(msg_type.to_string());
}
let message_type = match element_name {
"FinInstnCdtTrf" => "pacs.009", "Rct" => "camt.025", "ClmNonRct" | "ClaimNonReceiptV07" => "camt.027", _ => {
return Err(DataflowError::Validation(format!(
"Unknown document element: {}",
element_name
)));
}
};
Ok(message_type.to_string())
}
pub fn extract_message_type(data: &Value) -> Result<String> {
if let Some(mt) = data.get("message_type").and_then(Value::as_str) {
return Ok(mt.to_string());
}
if let Some(doc) = data.get("Document") {
if let Some(obj) = doc.as_object()
&& let Some(first_key) = obj.keys().next()
{
return map_document_element_to_message_type(first_key);
}
}
Err(DataflowError::Validation(
"Could not determine message type from parsed data".to_string(),
))
}
pub fn extract_message_type_from_xml(xml_str: &str) -> Result<String> {
let xml_str = xml_str.trim();
if let Some(doc_start) = xml_str.find("<Document") {
if let Some(doc_end) = xml_str[doc_start..].find('>') {
let after_doc = &xml_str[doc_start + doc_end + 1..];
if let Some(elem_start) = after_doc.find('<')
&& after_doc.as_bytes()[elem_start + 1] != b'/'
{
let elem_name_start = elem_start + 1;
let elem_name_end = after_doc[elem_name_start..]
.find([' ', '>', '/'])
.map(|i| elem_name_start + i)
.unwrap_or(after_doc.len());
let element_name = &after_doc[elem_name_start..elem_name_end];
let element_name = if let Some(colon_pos) = element_name.rfind(':') {
&element_name[colon_pos + 1..]
} else {
element_name
};
return map_document_element_to_message_type(element_name);
}
}
}
Err(DataflowError::Validation(
"Could not extract message type from XML".to_string(),
))
}
pub fn extract_mx_content(
message_data: &Value,
field_name: &str,
message_payload: &Value,
) -> Result<String> {
if field_name == "payload" {
if let Some(s) = message_payload.as_str() {
Ok(s.to_string())
} else {
Ok(message_payload.to_string().trim_matches('"').to_string())
}
} else {
let field_value = message_data.get(field_name).ok_or_else(|| {
DataflowError::Validation(format!(
"MX message field '{}' not found in message data",
field_name
))
})?;
if let Some(mx_msg) = field_value.get("mx_message").and_then(Value::as_str) {
Ok(mx_msg.to_string())
} else if let Some(s) = field_value.as_str() {
Ok(s.to_string())
} else {
Err(DataflowError::Validation(format!(
"Field '{}' does not contain a valid MX message",
field_name
)))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_map_document_element_to_message_type() {
assert_eq!(
map_document_element_to_message_type("FIToFICstmrCdtTrf").unwrap(),
"pacs.008"
);
assert_eq!(
map_document_element_to_message_type("BkToCstmrStmt").unwrap(),
"camt.053"
);
assert_eq!(
map_document_element_to_message_type("CstmrCdtTrfInitn").unwrap(),
"pain.001"
);
assert!(map_document_element_to_message_type("UnknownElement").is_err());
}
#[test]
fn test_extract_message_type() {
let data = json!({"message_type": "pacs.008", "other": "data"});
assert_eq!(extract_message_type(&data).unwrap(), "pacs.008");
let data = json!({
"Document": {
"FIToFICstmrCdtTrf": {
"GrpHdr": {}
}
}
});
assert_eq!(extract_message_type(&data).unwrap(), "pacs.008");
let data = json!({"other": "data"});
assert!(extract_message_type(&data).is_err());
}
#[test]
fn test_extract_mx_content() {
let payload = json!("test content");
let data = json!({
"field1": "direct string",
"field2": {
"mx_message": "nested message"
}
});
assert_eq!(
extract_mx_content(&data, "payload", &payload).unwrap(),
"test content"
);
assert_eq!(
extract_mx_content(&data, "field1", &payload).unwrap(),
"direct string"
);
assert_eq!(
extract_mx_content(&data, "field2", &payload).unwrap(),
"nested message"
);
assert!(extract_mx_content(&data, "missing", &payload).is_err());
}
}