use std::fmt;
use std::num::NonZeroU16;
use fhir_types::r4::identifier::Identifier;
use fhir_types::r4::parameters::{Parameters, ParametersParameter, ParametersParameterValue};
use fhir_types::r4::patient::Patient;
use fhir_types::r4::resource::Resource;
use secrecy::{ExposeSecret, SecretString};
use url::Url;
use super::error::InvalidInput;
pub struct MatchInput {
identifiers: Vec<(String, SecretString)>,
only_certain_matches: Option<bool>,
count: Option<NonZeroU16>,
}
impl MatchInput {
pub fn new(system: &str, value: &SecretString) -> Result<Self, InvalidInput> {
Self {
identifiers: Vec::new(),
only_certain_matches: None,
count: None,
}
.identifier(system, value)
}
pub fn identifier(mut self, system: &str, value: &SecretString) -> Result<Self, InvalidInput> {
if system.is_empty()
|| system.chars().any(char::is_whitespace)
|| Url::parse(system).is_err()
{
return Err(InvalidInput::System);
}
if value.expose_secret().is_empty() {
return Err(InvalidInput::EmptyValue);
}
self.identifiers
.push((system.to_owned(), SecretString::from(value.expose_secret())));
Ok(self)
}
#[must_use]
pub fn only_certain_matches(mut self, certain: bool) -> Self {
self.only_certain_matches = Some(certain);
self
}
#[must_use]
pub fn count(mut self, count: NonZeroU16) -> Self {
self.count = Some(count);
self
}
#[cfg(feature = "balp")]
pub(super) fn sole_identifier(&self) -> Option<(&str, &SecretString)> {
match self.identifiers.as_slice() {
[(system, value)] => Some((system.as_str(), value)),
_ => None,
}
}
pub(super) fn parameters(&self) -> Parameters {
let patient = Patient {
identifier: self
.identifiers
.iter()
.map(|(system, value)| Identifier {
system: Some(system.as_str().into()),
value: Some(value.expose_secret().into()),
..Identifier::default()
})
.collect(),
..Patient::default()
};
let mut parameter = vec![ParametersParameter {
name: "resource".into(),
resource: Some(Resource::Patient(Box::new(patient))),
..ParametersParameter::default()
}];
if let Some(certain) = self.only_certain_matches {
parameter.push(ParametersParameter {
name: "onlyCertainMatches".into(),
value: Some(ParametersParameterValue::Boolean(certain.into())),
..ParametersParameter::default()
});
}
if let Some(count) = self.count {
parameter.push(ParametersParameter {
name: "count".into(),
value: Some(ParametersParameterValue::Integer(
i32::from(count.get()).into(),
)),
..ParametersParameter::default()
});
}
Parameters {
parameter,
..Parameters::default()
}
}
}
impl fmt::Debug for MatchInput {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MatchInput")
.field("identifiers", &self.identifiers.len())
.field("only_certain_matches", &self.only_certain_matches)
.field("count", &self.count)
.finish()
}
}