Skip to content

Commit

Permalink
Merge pull request #234 from srdc/draft-mapping
Browse files Browse the repository at this point in the history
✨ feat: Implement draft mapping feature.
  • Loading branch information
dogukan10 authored Oct 2, 2024
2 parents 8a2557f + 28a7e54 commit 2267849
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -348,21 +348,29 @@ class FhirMappingJobManager(
/**
* Read and join the source data
*
* @param task FHIR Mapping task
* @param sourceSettings The source settings of the mapping job
* @param timeRange Time range for the source data to load
* @param jobId The identifier of mapping job which executes the mapping
* @param task FHIR Mapping task
* @param sourceSettings The source settings of the mapping job
* @param timeRange Time range for the source data to load
* @param jobId The identifier of mapping job which executes the mapping
* @param isTestExecution Indicates whether the execution is a test
*/
def readJoinSourceData(task: FhirMappingTask,
sourceSettings: Map[String, MappingJobSourceSettings],
timeRange: Option[(LocalDateTime, LocalDateTime)] = None,
jobId: Option[String] = None): (FhirMapping, MappingJobSourceSettings, DataFrame) = {
jobId: Option[String] = None,
isTestExecution: Boolean = false): (FhirMapping, MappingJobSourceSettings, DataFrame) = {
// if the FhirMapping task includes the mapping to be executed (the case where the mapping is being tested), use it,
// otherwise retrieve it from the repository
val mapping = task.mapping match {
case Some(mapping) => mapping
case None => fhirMappingRepository.getFhirMappingByUrl(task.mappingRef)
}

// ensure that the mapping is not marked as draft unless this is a test execution.
if(mapping.isDraft && !isTestExecution){
throw FhirMappingException(s"Cannot execute mapping '${mapping.name}' because it is currently marked as draft.");
}

// remove slice names from the mapping, otherwise FHIR resources will be created with slice names in fields starting with @
val fhirMapping = mapping.removeSliceNames()
// verify that the provided source bindings in the mapping job match the source aliases defined in the mapping
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import java.util.UUID
* @param url Canonical url for the mapping
* @param name Computer friendly name
* @param title Human friendly title
* @param isDraft Indicates whether the mapping is in a draft state and not yet ready for execution
* @param description Description of the mapping
* @param source Metadata about source for the mapping
* @param context Further context to use for mapping evaluation e.g. ConceptMap for terminology mapping, definition of unit conversion functions
Expand All @@ -22,6 +23,7 @@ case class FhirMapping(id: String,
url: String,
name: String,
title: Option[String] = None,
isDraft: Boolean = false,
description: Option[String] = None,
source: Seq[FhirMappingSource],
context: Map[String, FhirMappingContextDefinition] = Map.empty,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"id": "patient-mapping-with-draft",
"url": "https://aiccelerate.eu/fhir/mappings/patient-mapping-with-draft",
"name": "patient-mapping-with-draft",
"isDraft": true,
"title": "Mapping of some patient data with draft",
"source": [{
"alias": "source",
"url": "https://aiccelerate.eu/fhir/StructureDefinition/Ext-patient-extra"
}],
"mapping": [
{
"expression": {
"name": "result",
"language": "application/fhir-template+json",
"value": {
"resourceType": "Parameters",
"parameter": [
{
"name": "operation",
"part": [
{
"name": "type",
"valueCode": "add"
},
{
"name": "path",
"valueString": "Patient"
},
{
"name": "name",
"valueString": "maritalStatus"
},
{
"name": "value",
"valueCodeableConcept": {
"coding": [
{
"system":"http://terminology.hl7.org/CodeSystem/v3-MaritalStatus",
"code": "{{maritalStatusCode}}",
"display": "{{maritalStatusDisplay}}"
}
]
}
}
]
},
{
"name": "operation",
"part": [
{
"name": "type",
"valueCode": "replace"
},
{
"name": "path",
"valueString": "Patient.gender"
},
{
"name": "value",
"valueCode": "{{gender}}"
}
]
}
]
}
},
"fhirInteraction": {
"type": "patch",
"rid": "Patient/{{mpp:getHashedId('Patient',pid)}}"
}
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ class FhirMappingJobManagerTest extends AsyncFlatSpec with BeforeAndAfterAll wit
sourceBinding = Map("source" -> FileSystemSource(path = "patients.zip", contentType = SourceContentTypes.CSV))
)

val patientMappingTaskWithDraftMapping: FhirMappingTask = FhirMappingTask(
name = "patient-mapping-with-draft",
mappingRef = "https://aiccelerate.eu/fhir/mappings/patient-mapping-with-draft",
sourceBinding = Map("source" -> FileSystemSource(path = "patients.csv", contentType = SourceContentTypes.CSV))
)

val testMappingJobFilePath: String = getClass.getResource("/test-mappingjob.json").toURI.getPath
val testMappingJobWithIdentityServiceFilePath: String = getClass.getResource("/test-mappingjob-using-services.json").toURI.getPath

Expand Down Expand Up @@ -176,6 +182,20 @@ class FhirMappingJobManagerTest extends AsyncFlatSpec with BeforeAndAfterAll wit
}
}

it should "not execute the draft patient mapping task and return error" in {
val fhirMappingJobManager = new FhirMappingJobManager(mappingRepository, contextLoader, schemaRepository, Map.empty, sparkSession)
val fhirMappingJobWithDraftMapping = fhirMappingJob.copy(mappings = Seq(patientMappingTaskWithDraftMapping));
fhirMappingJobManager.executeMappingTaskAndReturn(mappingJobExecution = FhirMappingJobExecution(
job = fhirMappingJobWithDraftMapping,
mappingTasks = Seq(patientMappingTaskWithDraftMapping)) , mappingJobSourceSettings = mappingJobSourceSettings) flatMap { _ =>
fail("The draft mapping should not be executed!")
} recover {
case fhirMappingException: FhirMappingException =>
fhirMappingException.getMessage shouldBe "Cannot execute mapping 'patient-mapping-with-draft' because it is currently marked as draft."
case _ => fail("Unexpected error is thrown!")
}
}

it should "execute a mapping job with two data sources" in {
val mappingJob = FhirMappingJobFormatter.readMappingJobFromFile(getClass.getResource("/patient-mapping-job-with-two-sources.json").toURI.getPath)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ class ExecutionService(jobRepository: IJobRepository, mappingRepository: IMappin
toFhirEngine.functionLibraries,
toFhirEngine.sparkSession
)
val (fhirMapping, mappingJobSourceSettings, dataFrame) = fhirMappingJobManager.readJoinSourceData(mappingTask, mappingJob.sourceSettings, jobId = Some(jobId))
val (fhirMapping, mappingJobSourceSettings, dataFrame) = fhirMappingJobManager.readJoinSourceData(mappingTask, mappingJob.sourceSettings, jobId = Some(jobId), isTestExecution = true)
val selected = DataFrameUtil.applyResourceFilter(dataFrame, testResourceCreationRequest.resourceFilter)
fhirMappingJobManager.executeTask(mappingJob.id, mappingTask.name, fhirMapping, selected, mappingJobSourceSettings, mappingJob.terminologyServiceSettings, mappingJob.getIdentityServiceSettings(), projectId = Some(projectId))
.map { dataFrame =>
Expand Down

0 comments on commit 2267849

Please sign in to comment.