use crate::SofError;
use crate::constants::ConstantValue;
use helios_fhir::FhirResource;
use helios_fhirpath::EvaluationResult;
pub trait ViewDefinitionTrait {
type Select: ViewDefinitionSelectTrait;
type Where: ViewDefinitionWhereTrait;
type Constant: ViewDefinitionConstantTrait;
fn resource(&self) -> Option<&str>;
fn select(&self) -> Option<&[Self::Select]>;
fn where_clauses(&self) -> Option<&[Self::Where]>;
fn constants(&self) -> Option<&[Self::Constant]>;
}
pub trait ViewDefinitionSelectTrait {
type Column: ViewDefinitionColumnTrait;
type Select: ViewDefinitionSelectTrait;
fn column(&self) -> Option<&[Self::Column]>;
fn select(&self) -> Option<&[Self::Select]>;
fn for_each(&self) -> Option<&str>;
fn for_each_or_null(&self) -> Option<&str>;
fn repeat(&self) -> Option<Vec<&str>>;
fn union_all(&self) -> Option<&[Self::Select]>;
}
pub trait ViewDefinitionColumnTrait {
fn name(&self) -> Option<&str>;
fn path(&self) -> Option<&str>;
fn collection(&self) -> Option<bool>;
}
pub trait ViewDefinitionWhereTrait {
fn path(&self) -> Option<&str>;
}
pub trait ViewDefinitionConstantTrait {
fn name(&self) -> Option<&str>;
fn to_evaluation_result(&self) -> Result<EvaluationResult, SofError>;
}
pub trait BundleTrait {
type Resource: ResourceTrait;
fn entries(&self) -> Vec<&Self::Resource>;
}
pub trait ResourceTrait: Clone {
fn resource_name(&self) -> &str;
fn to_fhir_resource(&self) -> FhirResource;
fn get_last_updated(&self) -> Option<chrono::DateTime<chrono::Utc>>;
}
#[cfg(feature = "R4")]
mod r4_impl {
use super::*;
use helios_fhir::r4::*;
impl ViewDefinitionTrait for ViewDefinition {
type Select = ViewDefinitionSelect;
type Where = ViewDefinitionWhere;
type Constant = ViewDefinitionConstant;
fn resource(&self) -> Option<&str> {
self.resource.value.as_deref()
}
fn select(&self) -> Option<&[Self::Select]> {
self.select.as_deref()
}
fn where_clauses(&self) -> Option<&[Self::Where]> {
self.r#where.as_deref()
}
fn constants(&self) -> Option<&[Self::Constant]> {
self.constant.as_deref()
}
}
impl ViewDefinitionSelectTrait for ViewDefinitionSelect {
type Column = ViewDefinitionSelectColumn;
type Select = ViewDefinitionSelect;
fn column(&self) -> Option<&[Self::Column]> {
self.column.as_deref()
}
fn select(&self) -> Option<&[Self::Select]> {
self.select.as_deref()
}
fn for_each(&self) -> Option<&str> {
self.for_each.as_ref()?.value.as_deref()
}
fn for_each_or_null(&self) -> Option<&str> {
self.for_each_or_null.as_ref()?.value.as_deref()
}
fn repeat(&self) -> Option<Vec<&str>> {
self.repeat
.as_ref()
.map(|paths| paths.iter().filter_map(|p| p.value.as_deref()).collect())
}
fn union_all(&self) -> Option<&[Self::Select]> {
self.union_all.as_deref()
}
}
impl ViewDefinitionColumnTrait for ViewDefinitionSelectColumn {
fn name(&self) -> Option<&str> {
self.name.value.as_deref()
}
fn path(&self) -> Option<&str> {
self.path.value.as_deref()
}
fn collection(&self) -> Option<bool> {
self.collection.as_ref()?.value
}
}
impl ViewDefinitionWhereTrait for ViewDefinitionWhere {
fn path(&self) -> Option<&str> {
self.path.value.as_deref()
}
}
impl ViewDefinitionConstantTrait for ViewDefinitionConstant {
fn name(&self) -> Option<&str> {
self.name.value.as_deref()
}
fn to_evaluation_result(&self) -> Result<EvaluationResult, SofError> {
let name = self.name().unwrap_or("unknown");
let value = self.value.as_ref().ok_or_else(|| {
SofError::InvalidViewDefinition(format!("Constant '{name}' must have a value"))
})?;
r4_constant_to_neutral(value).to_evaluation_result()
}
}
fn r4_constant_to_neutral(value: &ViewDefinitionConstantValue) -> ConstantValue {
match value {
ViewDefinitionConstantValue::String(s) => {
ConstantValue::String(s.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Boolean(b) => {
ConstantValue::Boolean(b.value.unwrap_or(false))
}
ViewDefinitionConstantValue::Integer(i) => {
ConstantValue::Integer(i.value.unwrap_or(0) as i64)
}
ViewDefinitionConstantValue::PositiveInt(p) => {
ConstantValue::PositiveInt(p.value.unwrap_or(1) as i64)
}
ViewDefinitionConstantValue::UnsignedInt(u) => {
ConstantValue::UnsignedInt(u.value.unwrap_or(0) as i64)
}
ViewDefinitionConstantValue::Decimal(d) => ConstantValue::Decimal(
d.value
.as_ref()
.map(|p| p.original_string().to_string())
.unwrap_or_else(|| "0".to_string()),
),
ViewDefinitionConstantValue::Date(d) => {
ConstantValue::Date(d.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::DateTime(dt) => {
ConstantValue::DateTime(dt.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::Time(t) => {
ConstantValue::Time(t.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::Instant(i) => {
ConstantValue::Instant(i.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::Code(c) => {
ConstantValue::Code(c.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Base64Binary(b) => {
ConstantValue::Base64Binary(b.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Id(i) => {
ConstantValue::Identifier(i.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Oid(o) => {
ConstantValue::Identifier(o.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Uri(u) => {
ConstantValue::Identifier(u.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Url(u) => {
ConstantValue::Identifier(u.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Uuid(u) => {
ConstantValue::Identifier(u.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Canonical(c) => {
ConstantValue::Identifier(c.value.clone().unwrap_or_default())
}
}
}
impl BundleTrait for Bundle {
type Resource = Resource;
fn entries(&self) -> Vec<&Self::Resource> {
self.entry
.as_ref()
.map(|entries| entries.iter().filter_map(|e| e.resource.as_ref()).collect())
.unwrap_or_default()
}
}
impl ResourceTrait for Resource {
fn resource_name(&self) -> &str {
self.resource_name()
}
fn to_fhir_resource(&self) -> FhirResource {
FhirResource::R4(Box::new(self.clone()))
}
fn get_last_updated(&self) -> Option<chrono::DateTime<chrono::Utc>> {
self.get_last_updated()
}
}
}
#[cfg(feature = "R4B")]
mod r4b_impl {
use super::*;
use helios_fhir::r4b::*;
impl ViewDefinitionTrait for ViewDefinition {
type Select = ViewDefinitionSelect;
type Where = ViewDefinitionWhere;
type Constant = ViewDefinitionConstant;
fn resource(&self) -> Option<&str> {
self.resource.value.as_deref()
}
fn select(&self) -> Option<&[Self::Select]> {
self.select.as_deref()
}
fn where_clauses(&self) -> Option<&[Self::Where]> {
self.r#where.as_deref()
}
fn constants(&self) -> Option<&[Self::Constant]> {
self.constant.as_deref()
}
}
impl ViewDefinitionSelectTrait for ViewDefinitionSelect {
type Column = ViewDefinitionSelectColumn;
type Select = ViewDefinitionSelect;
fn column(&self) -> Option<&[Self::Column]> {
self.column.as_deref()
}
fn select(&self) -> Option<&[Self::Select]> {
self.select.as_deref()
}
fn for_each(&self) -> Option<&str> {
self.for_each.as_ref()?.value.as_deref()
}
fn for_each_or_null(&self) -> Option<&str> {
self.for_each_or_null.as_ref()?.value.as_deref()
}
fn repeat(&self) -> Option<Vec<&str>> {
self.repeat
.as_ref()
.map(|paths| paths.iter().filter_map(|p| p.value.as_deref()).collect())
}
fn union_all(&self) -> Option<&[Self::Select]> {
self.union_all.as_deref()
}
}
impl ViewDefinitionColumnTrait for ViewDefinitionSelectColumn {
fn name(&self) -> Option<&str> {
self.name.value.as_deref()
}
fn path(&self) -> Option<&str> {
self.path.value.as_deref()
}
fn collection(&self) -> Option<bool> {
self.collection.as_ref()?.value
}
}
impl ViewDefinitionWhereTrait for ViewDefinitionWhere {
fn path(&self) -> Option<&str> {
self.path.value.as_deref()
}
}
impl ViewDefinitionConstantTrait for ViewDefinitionConstant {
fn name(&self) -> Option<&str> {
self.name.value.as_deref()
}
fn to_evaluation_result(&self) -> Result<EvaluationResult, SofError> {
let name = self.name().unwrap_or("unknown");
let value = self.value.as_ref().ok_or_else(|| {
SofError::InvalidViewDefinition(format!("Constant '{name}' must have a value"))
})?;
r4b_constant_to_neutral(value).to_evaluation_result()
}
}
fn r4b_constant_to_neutral(value: &ViewDefinitionConstantValue) -> ConstantValue {
match value {
ViewDefinitionConstantValue::String(s) => {
ConstantValue::String(s.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Boolean(b) => {
ConstantValue::Boolean(b.value.unwrap_or(false))
}
ViewDefinitionConstantValue::Integer(i) => {
ConstantValue::Integer(i.value.unwrap_or(0) as i64)
}
ViewDefinitionConstantValue::PositiveInt(p) => {
ConstantValue::PositiveInt(p.value.unwrap_or(1) as i64)
}
ViewDefinitionConstantValue::UnsignedInt(u) => {
ConstantValue::UnsignedInt(u.value.unwrap_or(0) as i64)
}
ViewDefinitionConstantValue::Decimal(d) => ConstantValue::Decimal(
d.value
.as_ref()
.map(|p| p.original_string().to_string())
.unwrap_or_else(|| "0".to_string()),
),
ViewDefinitionConstantValue::Date(d) => {
ConstantValue::Date(d.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::DateTime(dt) => {
ConstantValue::DateTime(dt.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::Time(t) => {
ConstantValue::Time(t.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::Instant(i) => {
ConstantValue::Instant(i.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::Code(c) => {
ConstantValue::Code(c.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Base64Binary(b) => {
ConstantValue::Base64Binary(b.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Id(i) => {
ConstantValue::Identifier(i.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Oid(o) => {
ConstantValue::Identifier(o.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Uri(u) => {
ConstantValue::Identifier(u.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Url(u) => {
ConstantValue::Identifier(u.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Uuid(u) => {
ConstantValue::Identifier(u.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Canonical(c) => {
ConstantValue::Identifier(c.value.clone().unwrap_or_default())
}
}
}
impl BundleTrait for Bundle {
type Resource = Resource;
fn entries(&self) -> Vec<&Self::Resource> {
self.entry
.as_ref()
.map(|entries| entries.iter().filter_map(|e| e.resource.as_ref()).collect())
.unwrap_or_default()
}
}
impl ResourceTrait for Resource {
fn resource_name(&self) -> &str {
self.resource_name()
}
fn to_fhir_resource(&self) -> FhirResource {
FhirResource::R4B(Box::new(self.clone()))
}
fn get_last_updated(&self) -> Option<chrono::DateTime<chrono::Utc>> {
self.get_last_updated()
}
}
}
#[cfg(feature = "R5")]
mod r5_impl {
use super::*;
use helios_fhir::r5::*;
impl ViewDefinitionTrait for ViewDefinition {
type Select = ViewDefinitionSelect;
type Where = ViewDefinitionWhere;
type Constant = ViewDefinitionConstant;
fn resource(&self) -> Option<&str> {
self.resource.value.as_deref()
}
fn select(&self) -> Option<&[Self::Select]> {
self.select.as_deref()
}
fn where_clauses(&self) -> Option<&[Self::Where]> {
self.r#where.as_deref()
}
fn constants(&self) -> Option<&[Self::Constant]> {
self.constant.as_deref()
}
}
impl ViewDefinitionSelectTrait for ViewDefinitionSelect {
type Column = ViewDefinitionSelectColumn;
type Select = ViewDefinitionSelect;
fn column(&self) -> Option<&[Self::Column]> {
self.column.as_deref()
}
fn select(&self) -> Option<&[Self::Select]> {
self.select.as_deref()
}
fn for_each(&self) -> Option<&str> {
self.for_each.as_ref()?.value.as_deref()
}
fn for_each_or_null(&self) -> Option<&str> {
self.for_each_or_null.as_ref()?.value.as_deref()
}
fn repeat(&self) -> Option<Vec<&str>> {
self.repeat
.as_ref()
.map(|paths| paths.iter().filter_map(|p| p.value.as_deref()).collect())
}
fn union_all(&self) -> Option<&[Self::Select]> {
self.union_all.as_deref()
}
}
impl ViewDefinitionColumnTrait for ViewDefinitionSelectColumn {
fn name(&self) -> Option<&str> {
self.name.value.as_deref()
}
fn path(&self) -> Option<&str> {
self.path.value.as_deref()
}
fn collection(&self) -> Option<bool> {
self.collection.as_ref()?.value
}
}
impl ViewDefinitionWhereTrait for ViewDefinitionWhere {
fn path(&self) -> Option<&str> {
self.path.value.as_deref()
}
}
impl ViewDefinitionConstantTrait for ViewDefinitionConstant {
fn name(&self) -> Option<&str> {
self.name.value.as_deref()
}
fn to_evaluation_result(&self) -> Result<EvaluationResult, SofError> {
let name = self.name().unwrap_or("unknown");
let value = self.value.as_ref().ok_or_else(|| {
SofError::InvalidViewDefinition(format!("Constant '{name}' must have a value"))
})?;
r5_constant_to_neutral(value).to_evaluation_result()
}
}
fn r5_constant_to_neutral(value: &ViewDefinitionConstantValue) -> ConstantValue {
match value {
ViewDefinitionConstantValue::String(s) => {
ConstantValue::String(s.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Boolean(b) => {
ConstantValue::Boolean(b.value.unwrap_or(false))
}
ViewDefinitionConstantValue::Integer(i) => {
ConstantValue::Integer(i.value.unwrap_or(0) as i64)
}
ViewDefinitionConstantValue::Integer64(i) => {
ConstantValue::Integer64(i.value.unwrap_or(0))
}
ViewDefinitionConstantValue::PositiveInt(p) => {
ConstantValue::PositiveInt(p.value.unwrap_or(1) as i64)
}
ViewDefinitionConstantValue::UnsignedInt(u) => {
ConstantValue::UnsignedInt(u.value.unwrap_or(0) as i64)
}
ViewDefinitionConstantValue::Decimal(d) => ConstantValue::Decimal(
d.value
.as_ref()
.map(|p| p.original_string().to_string())
.unwrap_or_else(|| "0".to_string()),
),
ViewDefinitionConstantValue::Date(d) => {
ConstantValue::Date(d.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::DateTime(dt) => {
ConstantValue::DateTime(dt.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::Time(t) => {
ConstantValue::Time(t.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::Instant(i) => {
ConstantValue::Instant(i.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::Code(c) => {
ConstantValue::Code(c.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Base64Binary(b) => {
ConstantValue::Base64Binary(b.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Id(i) => {
ConstantValue::Identifier(i.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Oid(o) => {
ConstantValue::Identifier(o.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Uri(u) => {
ConstantValue::Identifier(u.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Url(u) => {
ConstantValue::Identifier(u.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Uuid(u) => {
ConstantValue::Identifier(u.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Canonical(c) => {
ConstantValue::Identifier(c.value.clone().unwrap_or_default())
}
}
}
impl BundleTrait for Bundle {
type Resource = Resource;
fn entries(&self) -> Vec<&Self::Resource> {
self.entry
.as_ref()
.map(|entries| {
entries
.iter()
.filter_map(|e| e.resource.as_deref()) .collect()
})
.unwrap_or_default()
}
}
impl ResourceTrait for Resource {
fn resource_name(&self) -> &str {
self.resource_name()
}
fn to_fhir_resource(&self) -> FhirResource {
FhirResource::R5(Box::new(self.clone()))
}
fn get_last_updated(&self) -> Option<chrono::DateTime<chrono::Utc>> {
self.get_last_updated()
}
}
}
#[cfg(feature = "R6")]
mod r6_impl {
use super::*;
use helios_fhir::r6::*;
impl ViewDefinitionTrait for ViewDefinition {
type Select = ViewDefinitionSelect;
type Where = ViewDefinitionWhere;
type Constant = ViewDefinitionConstant;
fn resource(&self) -> Option<&str> {
self.resource.value.as_deref()
}
fn select(&self) -> Option<&[Self::Select]> {
self.select.as_deref()
}
fn where_clauses(&self) -> Option<&[Self::Where]> {
self.r#where.as_deref()
}
fn constants(&self) -> Option<&[Self::Constant]> {
self.constant.as_deref()
}
}
impl ViewDefinitionSelectTrait for ViewDefinitionSelect {
type Column = ViewDefinitionSelectColumn;
type Select = ViewDefinitionSelect;
fn column(&self) -> Option<&[Self::Column]> {
self.column.as_deref()
}
fn select(&self) -> Option<&[Self::Select]> {
self.select.as_deref()
}
fn for_each(&self) -> Option<&str> {
self.for_each.as_ref()?.value.as_deref()
}
fn for_each_or_null(&self) -> Option<&str> {
self.for_each_or_null.as_ref()?.value.as_deref()
}
fn repeat(&self) -> Option<Vec<&str>> {
self.repeat
.as_ref()
.map(|paths| paths.iter().filter_map(|p| p.value.as_deref()).collect())
}
fn union_all(&self) -> Option<&[Self::Select]> {
self.union_all.as_deref()
}
}
impl ViewDefinitionColumnTrait for ViewDefinitionSelectColumn {
fn name(&self) -> Option<&str> {
self.name.value.as_deref()
}
fn path(&self) -> Option<&str> {
self.path.value.as_deref()
}
fn collection(&self) -> Option<bool> {
self.collection.as_ref()?.value
}
}
impl ViewDefinitionWhereTrait for ViewDefinitionWhere {
fn path(&self) -> Option<&str> {
self.path.value.as_deref()
}
}
impl ViewDefinitionConstantTrait for ViewDefinitionConstant {
fn name(&self) -> Option<&str> {
self.name.value.as_deref()
}
fn to_evaluation_result(&self) -> Result<EvaluationResult, SofError> {
let name = self.name().unwrap_or("unknown");
let value = self.value.as_ref().ok_or_else(|| {
SofError::InvalidViewDefinition(format!("Constant '{name}' must have a value"))
})?;
r6_constant_to_neutral(value).to_evaluation_result()
}
}
fn r6_constant_to_neutral(value: &ViewDefinitionConstantValue) -> ConstantValue {
match value {
ViewDefinitionConstantValue::String(s) => {
ConstantValue::String(s.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Boolean(b) => {
ConstantValue::Boolean(b.value.unwrap_or(false))
}
ViewDefinitionConstantValue::Integer(i) => {
ConstantValue::Integer(i.value.unwrap_or(0) as i64)
}
ViewDefinitionConstantValue::Integer64(i) => {
ConstantValue::Integer64(i.value.unwrap_or(0))
}
ViewDefinitionConstantValue::PositiveInt(p) => {
ConstantValue::PositiveInt(p.value.unwrap_or(1) as i64)
}
ViewDefinitionConstantValue::UnsignedInt(u) => {
ConstantValue::UnsignedInt(u.value.unwrap_or(0) as i64)
}
ViewDefinitionConstantValue::Decimal(d) => ConstantValue::Decimal(
d.value
.as_ref()
.map(|p| p.original_string().to_string())
.unwrap_or_else(|| "0".to_string()),
),
ViewDefinitionConstantValue::Date(d) => {
ConstantValue::Date(d.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::DateTime(dt) => {
ConstantValue::DateTime(dt.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::Time(t) => {
ConstantValue::Time(t.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::Instant(i) => {
ConstantValue::Instant(i.value.clone().unwrap_or_default().to_string())
}
ViewDefinitionConstantValue::Code(c) => {
ConstantValue::Code(c.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Base64Binary(b) => {
ConstantValue::Base64Binary(b.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Id(i) => {
ConstantValue::Identifier(i.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Oid(o) => {
ConstantValue::Identifier(o.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Uri(u) => {
ConstantValue::Identifier(u.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Url(u) => {
ConstantValue::Identifier(u.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Uuid(u) => {
ConstantValue::Identifier(u.value.clone().unwrap_or_default())
}
ViewDefinitionConstantValue::Canonical(c) => {
ConstantValue::Identifier(c.value.clone().unwrap_or_default())
}
}
}
impl BundleTrait for Bundle {
type Resource = Resource;
fn entries(&self) -> Vec<&Self::Resource> {
self.entry
.as_ref()
.map(|entries| {
entries
.iter()
.filter_map(|e| e.resource.as_deref()) .collect()
})
.unwrap_or_default()
}
}
impl ResourceTrait for Resource {
fn resource_name(&self) -> &str {
self.resource_name()
}
fn to_fhir_resource(&self) -> FhirResource {
FhirResource::R6(Box::new(self.clone()))
}
fn get_last_updated(&self) -> Option<chrono::DateTime<chrono::Utc>> {
self.get_last_updated()
}
}
}