Skip to content

Commit

Permalink
feat: Implement IdentifiableResource
Browse files Browse the repository at this point in the history
  • Loading branch information
FlixCoder committed Mar 25, 2023
1 parent 580af42 commit 32144de
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 4 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ This is a [FHIR](https://www.hl7.org/fhir/) library in its early stages. The mod
- [x] Linked code-fields to respective enums
- [x] Builders for types and resources
- [x] Allow to convert code enums to Coding and CodeableConcept
- [ ] Implementation of base traits
- [x] Implementation of base traits
- [x] (Base)Resource
- [x] NamedResource
- [x] DomainResource
- [ ] IdentifiableResource
- [ ] FHIR client implmentation
- [x] IdentifiableResource
- [ ] Extension traits (e.g. more convenience on identifier access)
- [ ] FHIR client implementation
- [ ] FHIRpath implementation
- [ ] Resource validation using FHIRpath
- [ ] Search parameters
Expand Down
194 changes: 194 additions & 0 deletions crates/fhir-model/src/r4b/resources/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,197 @@
mod generated;

pub use generated::*;

use super::types::{FieldExtension, Identifier};

/// Trait for all resources with multiple identifiers in the `identifier` field.
/// Simplifies access to identifiers.
pub trait IdentifiableResource {
/// Get the identifier field.
fn identifier(&self) -> &Vec<Option<Identifier>>;
/// Get the identifier field mutably.
fn identifier_mut(&mut self) -> &mut Vec<Option<Identifier>>;
/// Set the identifier field.
fn set_identifier(&mut self, value: Vec<Option<Identifier>>);

/// Get the identifier extension field.
fn identifier_ext(&self) -> &Vec<Option<FieldExtension>>;
/// Get the identifier extension field mutably.
fn identifier_ext_mut(&mut self) -> &mut Vec<Option<FieldExtension>>;
/// Set the identifier extension field.
fn set_identifier_ext(&mut self, value: Vec<Option<FieldExtension>>);
}

/// Implement the IdentifiableResource trait for the resources and the resource
/// enum.
macro_rules! impl_identifiable_resource {
([$($resource:ident),*$(,)?]) => {
$(impl_identifiable_resource!($resource);)*

impl Resource {
/// Return the resource as identifiable resource.
#[must_use]
pub fn as_identifiable_resource(&self) -> Option<&dyn IdentifiableResource> {
match self {
$(
Self::$resource(r) => Some(r),
)*
_ => None,
}
}

/// Return the resource as mutable identifiable resource.
#[must_use]
pub fn as_identifiable_resource_mut(&mut self) -> Option<&mut dyn IdentifiableResource> {
match self {
$(
Self::$resource(r) => Some(r),
)*
_ => None,
}
}
}
};
($resource:ident) => {
impl IdentifiableResource for $resource {
fn identifier(&self) -> &Vec<Option<Identifier>> {
&self.identifier
}

fn identifier_mut(&mut self) -> &mut Vec<Option<Identifier>> {
&mut self.identifier
}

fn set_identifier(&mut self, value: Vec<Option<Identifier>>) {
self.identifier = value;
}

fn identifier_ext(&self) -> &Vec<Option<FieldExtension>> {
&self.identifier_ext
}

fn identifier_ext_mut(&mut self) -> &mut Vec<Option<FieldExtension>> {
&mut self.identifier_ext
}

fn set_identifier_ext(&mut self, value: Vec<Option<FieldExtension>>) {
self.identifier_ext = value;
}
}
};
}

impl_identifiable_resource!([
Account,
ActivityDefinition,
AdministrableProductDefinition,
AllergyIntolerance,
Appointment,
AppointmentResponse,
Basic,
BiologicallyDerivedProduct,
BodyStructure,
CarePlan,
CareTeam,
CatalogEntry,
ChargeItem,
ChargeItemDefinition,
Citation,
Claim,
ClaimResponse,
ClinicalImpression,
ClinicalUseDefinition,
CodeSystem,
Communication,
CommunicationRequest,
Condition,
Consent,
Contract,
Coverage,
CoverageEligibilityRequest,
CoverageEligibilityResponse,
DetectedIssue,
Device,
DeviceDefinition,
DeviceMetric,
DeviceRequest,
DeviceUseStatement,
DiagnosticReport,
DocumentManifest,
DocumentReference,
Encounter,
Endpoint,
EnrollmentRequest,
EnrollmentResponse,
EpisodeOfCare,
EventDefinition,
Evidence,
EvidenceReport,
EvidenceVariable,
ExampleScenario,
ExplanationOfBenefit,
FamilyMemberHistory,
Flag,
Goal,
Group,
GuidanceResponse,
HealthcareService,
ImagingStudy,
Immunization,
ImmunizationEvaluation,
ImmunizationRecommendation,
InsurancePlan,
Invoice,
Library,
List,
Location,
ManufacturedItemDefinition,
Measure,
MeasureReport,
Media,
Medication,
MedicationAdministration,
MedicationDispense,
MedicationRequest,
MedicationStatement,
MedicinalProductDefinition,
MessageDefinition,
MolecularSequence,
NutritionOrder,
Observation,
ObservationDefinition,
Organization,
OrganizationAffiliation,
PackagedProductDefinition,
Patient,
PaymentNotice,
PaymentReconciliation,
Person,
PlanDefinition,
Practitioner,
PractitionerRole,
Procedure,
Questionnaire,
RegulatedAuthorization,
RelatedPerson,
RequestGroup,
ResearchDefinition,
ResearchElementDefinition,
ResearchStudy,
ResearchSubject,
RiskAssessment,
Schedule,
ServiceRequest,
Slot,
Specimen,
StructureDefinition,
StructureMap,
SubscriptionTopic,
Substance,
SubstanceDefinition,
SupplyDelivery,
SupplyRequest,
Task,
ValueSet,
VisionPrescription
]);
22 changes: 21 additions & 1 deletion crates/fhir-model/tests/test_resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use fhir_model::r4b::{
Basic, NamedResource, Patient, RequestGroup, RequestGroupAction, RequestGroupActionTiming,
Resource, WrongResourceType,
},
types::{CodeableConcept, Coding},
types::{CodeableConcept, Coding, Identifier},
};
use serde_json::Value;

Expand Down Expand Up @@ -91,3 +91,23 @@ fn resource_traits() {
patient.as_base_resource_mut().set_id(None);
assert!(patient.as_base_resource().id().is_none());
}

#[test]
fn identifiable_resource() {
let patient: Resource = Patient::builder()
.identifier(vec![Some(
Identifier::builder().system("system".to_owned()).value("bla".to_owned()).build(),
)])
.build()
.into();
assert!(patient.as_identifiable_resource().is_some());

let identifier = patient
.as_identifiable_resource()
.expect("Patient has identifiers")
.identifier()
.first()
.and_then(Option::as_ref)
.expect("We set one identifier");
assert_eq!(identifier.system.as_deref(), Some("system"));
}

0 comments on commit 32144de

Please sign in to comment.