refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/ConditionMapper.java
lines 921–988
1655 lines · java
1package org.miracum.etl.fhirtoomop.mapper; 3import static org.miracum.etl.fhirtoomop.Constants.CONCEPT_EHR; 4import static org.miracum.etl.fhirtoomop.Constants.CONCEPT_FINDING_SITE; 5import static org.miracum.etl.fhirtoomop.Constants.CONCEPT_SEVERITY; 6import static org.miracum.etl.fhirtoomop.Constants.CONCEPT_STAGE; 7import static org.miracum.etl.fhirtoomop.Constants.FHIR_RESOURCE_CONDITION_ACCEPTABLE_STATUS_LIST; 8import static org.miracum.etl.fhirtoomop.Constants.OMOP_DOMAIN_CONDITION; 9import static org.miracum.etl.fhirtoomop.Constants.OMOP_DOMAIN_MEASUREMENT; 10import static org.miracum.etl.fhirtoomop.Constants.OMOP_DOMAIN_OBSERVATION; 11import static org.miracum.etl.fhirtoomop.Constants.OMOP_DOMAIN_PROCEDURE; 12import static org.miracum.etl.fhirtoomop.Constants.SOURCE_VOCABULARY_ID_DIAGNOSTIC_CONFIDENCE; 13import static org.miracum.etl.fhirtoomop.Constants.SOURCE_VOCABULARY_ID_ICD_LOCALIZATION; 14import static org.miracum.etl.fhirtoomop.Constants.VOCABULARY_ICD10GM; 16import com.google.common.base.Strings; 17import io.micrometer.core.instrument.Counter; 18import java.sql.Timestamp; 19import java.time.LocalDate; 20import java.time.LocalDateTime; 21import java.util.ArrayList; 22import java.util.Arrays; 23import java.util.Collections; 25import lombok.extern.slf4j.Slf4j; 26import org.apache.commons.lang3.tuple.Pair; 27import org.hl7.fhir.r4.model.Coding; 28import org.hl7.fhir.r4.model.Condition; 29import org.hl7.fhir.r4.model.Enumerations.ResourceType; 30import org.hl7.fhir.r4.model.StringType; 31import org.miracum.etl.fhirtoomop.DbMappings; 32import org.miracum.etl.fhirtoomop.config.FhirSystems; 33import org.miracum.etl.fhirtoomop.mapper.helpers.FindOmopConcepts; 34import org.miracum.etl.fhirtoomop.mapper.helpers.MapperMetrics; 35import org.miracum.etl.fhirtoomop.mapper.helpers.ResourceCheckDataAbsentReason; 36import org.miracum.etl.fhirtoomop.mapper.helpers.ResourceFhirReferenceUtils; 37import org.miracum.etl.fhirtoomop.mapper.helpers.ResourceOmopReferenceUtils; 38import org.miracum.etl.fhirtoomop.mapper.helpers.ResourceOnset; 39import org.miracum.etl.fhirtoomop.model.IcdSnomedDomainLookup; 40import org.miracum.etl.fhirtoomop.model.OmopModelWrapper; 41import org.miracum.etl.fhirtoomop.model.OrphaSnomedMapping; 42import org.miracum.etl.fhirtoomop.model.PostProcessMap; 43import org.miracum.etl.fhirtoomop.model.omop.Concept; 44import org.miracum.etl.fhirtoomop.model.omop.ConditionOccurrence; 45import org.miracum.etl.fhirtoomop.model.omop.Measurement; 46import org.miracum.etl.fhirtoomop.model.omop.OmopObservation; 47import org.miracum.etl.fhirtoomop.model.omop.ProcedureOccurrence; 48import org.miracum.etl.fhirtoomop.model.omop.SourceToConceptMap; 49import org.miracum.etl.fhirtoomop.repository.service.ConditionMapperServiceImpl; 50import org.miracum.etl.fhirtoomop.repository.service.OmopConceptServiceImpl; 51import org.springframework.beans.factory.annotation.Autowired; 52import org.springframework.lang.Nullable; 53import org.springframework.stereotype.Component; 56 * The ConditionMapper class describes the business logic of transforming a FHIR Condition resource 64public class ConditionMapper implements FhirMapper<Condition> { 66 private static final FhirSystems fhirSystems = new FhirSystems(); 67 private final DbMappings dbMappings; 68 private final Boolean bulkload; 70 @Autowired OmopConceptServiceImpl omopConceptService; 71 @Autowired ResourceFhirReferenceUtils fhirReferenceUtils; 72 @Autowired ResourceOmopReferenceUtils omopReferenceUtils; 73 @Autowired ConditionMapperServiceImpl conditionService; 74 @Autowired ResourceCheckDataAbsentReason checkDataAbsentReason; 75 @Autowired FindOmopConcepts findOmopConcepts; 77 private static final Counter noStartDateCounter = 78 MapperMetrics.setNoStartDateCounter("stepProcessConditions"); 79 private static final Counter noPersonIdCounter = 80 MapperMetrics.setNoPersonIdCounter("stepProcessConditions"); 81 private static final Counter invalidCodeCounter = 82 MapperMetrics.setInvalidCodeCounter("stepProcessConditions"); 83 private static final Counter noCodeCounter = 84 MapperMetrics.setNoCodeCounter("stepProcessConditions"); 85 private static final Counter noFhirReferenceCounter = 86 MapperMetrics.setNoFhirReferenceCounter("stepProcessConditions"); 87 private static final Counter deletedFhirReferenceCounter = 88 MapperMetrics.setDeletedFhirRessourceCounter("stepProcessConditions"); 91 * Constructor for objects of the class ConditionMapper. 93 * @param referenceUtils utilities for the identification of FHIR resource references 94 * @param bulkload parameter which indicates whether the Job should be run as bulk load or 96 * @param dbMappings collections for the intermediate storage of data from OMOP CDM in RAM 99 public ConditionMapper(Boolean bulkload, DbMappings dbMappings) { 101 this.bulkload = bulkload; 102 this.dbMappings = dbMappings; 106 * Maps a FHIR Condition resource to several OMOP CDM tables. 108 * @param srcCondition FHIR Condition resource 109 * @param isDeleted a flag, whether the FHIR resource is deleted in the source 110 * @return OmopModelWrapper cache of newly created OMOP CDM records from the FHIR Condition 114 public OmopModelWrapper map(Condition srcCondition, boolean isDeleted) { 115 var wrapper = new OmopModelWrapper(); 117 var conditionLogicId = fhirReferenceUtils.extractId(srcCondition); 118 var conditionSourceIdentifier = fhirReferenceUtils.extractResourceFirstIdentifier(srcCondition); 119 if (Strings.isNullOrEmpty(conditionLogicId) 120 && Strings.isNullOrEmpty(conditionSourceIdentifier)) { 121 log.warn("No [Identifier] or [Id] found. [Condition] resource is invalid. Skip resource"); 122 noFhirReferenceCounter.increment(); 126 String conditionId = ""; 127 if (!Strings.isNullOrEmpty(conditionLogicId)) { 128 conditionId = srcCondition.getId(); 131 if (bulkload.equals(Boolean.FALSE)) { 132 deleteExistingConditionEntry(conditionLogicId, conditionSourceIdentifier); 134 deleteExistingPostProcessMapEntry(conditionLogicId, conditionSourceIdentifier); 135 deletedFhirReferenceCounter.increment(); 136 log.info("Found a deleted [Condition] resource {}. Deleting from OMOP DB.", conditionId); 139 updateExistingPostProcessMapEntry(conditionLogicId, conditionSourceIdentifier); 142 var verificationStatusValue = getVerificationStatusValue(srcCondition); 143 if (!Strings.isNullOrEmpty(verificationStatusValue) 144 && !FHIR_RESOURCE_CONDITION_ACCEPTABLE_STATUS_LIST.contains(verificationStatusValue)) { 146 "The [verification status]: {} of {} is not acceptable for writing into OMOP CDM. Skip resource.", 147 verificationStatusValue, 152 var diagnoseCodingList = getDiagnoseCoding(srcCondition); 153 if (diagnoseCodingList.isEmpty()) { 154 log.warn("No [code] found for [Condition]: {}. Skip resource.", conditionId); 155 noCodeCounter.increment(); 159 var personId = getPersonId(srcCondition, conditionLogicId, conditionId); 160 if (personId == null) { 161 log.warn("No matching [Person] found for [Condition]: {}. Skip resource", conditionId); 162 noPersonIdCounter.increment(); 166 var visitOccId = getVisitOccId(srcCondition, conditionId, personId); 168 var diagnoseOnset = getConditionOnset(srcCondition); 169 if (diagnoseOnset.getStartDateTime() == null) { 170 log.warn("No [Date] found for [Condition]: {}. Skip resource", conditionId); 171 noStartDateCounter.increment(); 174 var severityCoding = getSeverity(srcCondition); 175 var stageCoding = getStage(srcCondition); 177 if (diagnoseCodingList.size() == 1) { 178 var diagnoseCoding = diagnoseCodingList.get(0); 179 var icdBodyLocalizationConcepts = 180 getBodySiteLocalizationConcepts( 183 diagnoseOnset.getStartDateTime().toLocalDate(), 185 var diagnosticConfidence = getDiagnosticConfidence(diagnoseCoding, conditionId); 186 var diagnosticConfidenceConcept = getDiagnosticConfidenceConcept(diagnosticConfidence); 187 setDiagnoseCodesUsingSingleCoding( 190 conditionSourceIdentifier, 195 icdBodyLocalizationConcepts, 198 diagnosticConfidenceConcept, 201 setDiagnoseCodesUsingMultipleCodings( 204 conditionSourceIdentifier, 219 * Extracts the verification status from the FHIR Condition resource. 221 * @param srcMedication FHIR Condition resource 222 * @return verification status from the FHIR Condition resource 224 private String getVerificationStatusValue(Condition srcCondition) { 225 var verificationStatusCoding = srcCondition.getVerificationStatus(); 226 if (verificationStatusCoding == null) { 229 var verificationStatusValue = 230 verificationStatusCoding.getCoding().stream() 231 .filter(status -> fhirSystems.getVerificationStatus().contains(status.getSystem())) 233 if (verificationStatusValue.isPresent()) { 234 return verificationStatusValue.get().getCode(); 239 private void setDiagnoseCodesUsingMultipleCodings( 240 OmopModelWrapper wrapper, 241 String conditionLogicId, 242 String conditionSourceIdentifier, 245 ResourceOnset diagnoseOnset, 246 List<Coding> diagnoseCodings, 247 Coding severityCoding, 249 Condition srcCondition, 250 String conditionId) { 252 Coding uncheckedIcdCoding = null; 253 Coding uncheckedSnomedCoding = null; 254 Coding uncheckedOrphaCoding = null; 255 Coding diagnosisCoding = null; 257 for (var uncheckedCoding : diagnoseCodings) { 258 var system = uncheckedCoding.getSystem(); 259 if (fhirSystems.getOrpha().equals(system)) { 260 uncheckedOrphaCoding = uncheckedCoding; 262 if (fhirSystems.getIcd10gm().contains(system)) { 263 uncheckedIcdCoding = uncheckedCoding; 265 if (fhirSystems.getSnomed().equals(system)) { 266 uncheckedSnomedCoding = uncheckedCoding; 269 if (uncheckedIcdCoding == null 270 && uncheckedSnomedCoding == null 271 && uncheckedOrphaCoding == null) { 274 var diagnosticConfidence = getDiagnosticConfidence(uncheckedIcdCoding, conditionId); 275 var diagnosticConfidenceConcept = getDiagnosticConfidenceConcept(diagnosticConfidence); 276 var icdBodyLocalizationConcepts = 277 getBodySiteLocalizationConcepts( 280 diagnoseOnset.getStartDateTime().toLocalDate(), 283 var orphaSnomedMapPairList = 285 uncheckedOrphaCoding, diagnoseOnset.getStartDateTime().toLocalDate(), conditionId); 289 findOmopConcepts.getConcepts( 290 uncheckedSnomedCoding, 291 diagnoseOnset.getStartDateTime().toLocalDate(), 297 List<Coding> uncheckedIcdCodings = 298 splitDiagnoseCodes(uncheckedIcdCoding, uncheckedIcdCoding.getVersionElement()); 299 var icdSnomedMapPairList = 302 diagnoseOnset.getStartDateTime().toLocalDate(), 306 if (icdSnomedMapPairList.isEmpty() 307 && snomedConcept == null 308 && orphaSnomedMapPairList.isEmpty()) { 310 } else if (!orphaSnomedMapPairList.isEmpty()) { 312 diagnosisCoding = uncheckedOrphaCoding; 313 } else if (!icdSnomedMapPairList.isEmpty()) { 315 diagnosisCoding = uncheckedIcdCoding; 316 } else if (snomedConcept != null) { 318 diagnosisCoding = uncheckedSnomedCoding; 320 setDiagnoseCodesUsingSingleCoding( 323 conditionSourceIdentifier, 328 icdBodyLocalizationConcepts, 331 diagnosticConfidenceConcept, 335 private void setDiagnoseCodesUsingSingleCoding( 336 OmopModelWrapper wrapper, 337 String conditionLogicId, 338 String conditionSourceIdentifier, 341 ResourceOnset diagnoseOnset, 342 Coding diagnoseCoding, 343 Pair<String, Integer> icdBodyLocalizationConcepts, 344 Coding severityCoding, 346 SourceToConceptMap diagnosticConfidenceConcept, 347 String conditionId) { 349 List<Coding> uncheckedDiagnoseCodes = 350 splitDiagnoseCodes(diagnoseCoding, diagnoseCoding.getVersionElement()); 351 List<Pair<String, List<IcdSnomedDomainLookup>>> icdSnomedMapPairList = null; 352 List<Pair<String, List<OrphaSnomedMapping>>> orphaSnomedMapPairList = null; 353 Concept snomedConcept = null; 355 if (fhirSystems.getIcd10gm().contains(diagnoseCoding.getSystem())) { 358 icdSnomedMapPairList = 360 uncheckedDiagnoseCodes, 361 diagnoseOnset.getStartDateTime().toLocalDate(), 365 if (icdSnomedMapPairList.isEmpty()) { 368 for (var singlePair : icdSnomedMapPairList) { 375 diagnosticConfidenceConcept, 377 conditionSourceIdentifier, 382 if (icdSnomedMapPairList.size() == 2) { 384 setIcdPairs(icdSnomedMapPairList, conditionLogicId, conditionSourceIdentifier); 385 wrapper.setPostProcessMap(icdPairs); 387 } else if (fhirSystems.getSnomed().equals(diagnoseCoding.getSystem())) { 391 findOmopConcepts.getConcepts( 393 diagnoseOnset.getStartDateTime().toLocalDate(), 398 if (snomedConcept == null) { 408 diagnosticConfidenceConcept, 410 conditionSourceIdentifier, 413 } else if (fhirSystems.getOrpha().equals(diagnoseCoding.getSystem())) { 416 orphaSnomedMapPairList = 418 diagnoseCoding, diagnoseOnset.getStartDateTime().toLocalDate(), conditionId); 420 if (orphaSnomedMapPairList.isEmpty()) { 423 for (var orphaSnomedPair : orphaSnomedMapPairList) { 430 diagnosticConfidenceConcept, 432 conditionSourceIdentifier, 441 setBodySiteLocalization( 443 icdSnomedMapPairList, 446 conditionSourceIdentifier, 450 icdBodyLocalizationConcepts); 454 icdSnomedMapPairList, 457 conditionSourceIdentifier, 467 icdSnomedMapPairList, 470 conditionSourceIdentifier, 480 * Create new entry in Observation for bodySite or site localization of a diagnosis, and create 481 * new entry in POST_PROCESS_MAP for referencing later. 483 * @param wrapper the OMOP model wrapper 484 * @param icdSnomedMapList a List of pairs of ICD-Snomed mapping 485 * @param omopConcept extracted Concept from OMOP 486 * @param conditionLogicId logical id of the FHIR Condition resource 487 * @param conditionSourceIdentifier identifier of the FHIR Condition resource 488 * @param personId person_id of the referenced FHIR Patient resource 489 * @param visitOccId the visit_occurrence_id of the referenced FHIR Encounter resource from 490 * VISIT_OCCURRENCE table in OMOP CDM 491 * @param diagnoseOnset start date time and end date time of the FHIR Condition resource 492 * @param icdBodyLocalizationConcept a pair of the body site or site localization name and OMOP 495 private void setBodySiteLocalization( 496 OmopModelWrapper wrapper, 497 @Nullable List<Pair<String, List<IcdSnomedDomainLookup>>> icdSnomedMapList, 498 @Nullable Concept omopConcept, 499 String conditionLogicId, 500 String conditionSourceIdentifier, 503 ResourceOnset diagnoseOnset, 504 Pair<String, Integer> icdBodyLocalizationConcept) { 505 var siteLocalization = 506 createSiteLocalization( 507 icdBodyLocalizationConcept, 509 conditionSourceIdentifier, 513 if (siteLocalization != null) { 514 wrapper.getObservation().add(siteLocalization); 516 var icdSiteLocalization = 517 setBodySiteLocalizationReference( 523 conditionSourceIdentifier); 524 if (icdSiteLocalization != null) { 525 wrapper.getPostProcessMap().add(icdSiteLocalization); 531 * Create new entry in Observation for severity of a diagnosis, and create new entry in 532 * POST_PROCESS_MAP for referencing later. 534 * @param wrapper the OMOP model wrapper 535 * @param icdSnomedMapList a List of pairs of ICD-Snomed mapping 536 * @param omopConcept extracted Concept from OMOP 537 * @param conditionLogicId logical id of the FHIR Condition resource 538 * @param conditionSourceIdentifier identifier of the FHIR Condition resource 539 * @param personId person_id of the referenced FHIR Patient resource 540 * @param visitOccId the visit_occurrence_id of the referenced FHIR Encounter resource from 541 * VISIT_OCCURRENCE table in OMOP CDM 542 * @param diagnoseOnset start date time and end date time of the FHIR Condition resource 543 * @param severityCoding coding of severity information from FHIR Condition resource 545 private void setDiagnoseMetaInfo( 546 OmopModelWrapper wrapper, 547 @Nullable List<Pair<String, List<IcdSnomedDomainLookup>>> icdSnomedMapList, 548 @Nullable Concept omopConcept, 549 String conditionLogicId, 550 String conditionSourceIdentifier, 553 ResourceOnset diagnoseOnset, 554 Coding diagnoseMetaInfoCoding, 556 String conditionId) { 557 if (diagnoseMetaInfoCoding == null) { 560 var diagnoseMetaInfoConcept = 561 findOmopConcepts.getConcepts( 562 diagnoseMetaInfoCoding, 563 diagnoseOnset.getStartDateTime().toLocalDate(), 567 var diagnoseMetaInfo = 568 createDiagnoseMetaInfo( 569 diagnoseMetaInfoConcept, 571 conditionSourceIdentifier, 576 if (diagnoseMetaInfo == null) { 579 wrapper.getObservation().add(diagnoseMetaInfo); 581 var diagnoseMetaInfoReference = 582 setDiagnoseMetaInfoReference( 588 conditionSourceIdentifier, 590 if (diagnoseMetaInfoReference == null) { 593 wrapper.getPostProcessMap().add(diagnoseMetaInfoReference); 597 * Extract valid pairs of ICD code and its OMOP concept_id and domain information as a list 599 * @param uncheckedIcds unchecked ICD codes 600 * @param diagnoseDate the start date of diagnose 601 * @param conditionLogicId logical id of the FHIR Condition resource 602 * @return a list of valid pairs of ICD code and its OMOP concept_id and domain information 604 private List<Pair<String, List<IcdSnomedDomainLookup>>> getValidIcdCodes( 605 List<Coding> uncheckedIcds, 606 LocalDate diagnoseDate, 607 String conditionLogicId, 608 String conditionId) { 609 if (uncheckedIcds.isEmpty()) { 610 return Collections.emptyList(); 613 List<Pair<String, List<IcdSnomedDomainLookup>>> validIcdSnomedConceptMaps = new ArrayList<>(); 614 for (var uncheckedCode : uncheckedIcds) { 615 String icdCode = uncheckedCode.getCode(); 616 if (icdCode == null) { 617 return Collections.emptyList(); 620 List<IcdSnomedDomainLookup> icdSnomedMap = 621 findOmopConcepts.getIcdSnomedConcepts( 622 uncheckedCode, diagnoseDate, bulkload, dbMappings, conditionLogicId); 623 if (icdSnomedMap.isEmpty()) { 625 "ICD Code [{}] in [Condition] {} is not valid in OMOP.", 626 uncheckedCode.getCode(), 628 return Collections.emptyList(); 631 validIcdSnomedConceptMaps.add(Pair.of(uncheckedCode.getCode(), icdSnomedMap)); 633 return validIcdSnomedConceptMaps; 637 * Extract valid pairs of Orpha code and its SNOMED concept_id and domain information as a list 640 * @param diagnoseDate the start date of diagnose 641 * @param conditionId logical id of the FHIR Condition resource 642 * @return a list of valid pairs of Orpha code and its SNOMED concept_id and domain information 644 private List<Pair<String, List<OrphaSnomedMapping>>> getOrphaSnomedMap( 645 Coding orphaCoding, LocalDate diagnoseDate, String conditionId) { 646 if (orphaCoding.isEmpty()) { 647 return Collections.emptyList(); 650 List<Pair<String, List<OrphaSnomedMapping>>> validOrphaSnomedConceptMaps = new ArrayList<>(); 651 List<OrphaSnomedMapping> orphaSnomedMap = 652 findOmopConcepts.getOrphaSnomedConcepts( 653 orphaCoding, diagnoseDate, bulkload, dbMappings, conditionId); 654 if (orphaSnomedMap.isEmpty()) { 655 return Collections.emptyList(); 658 validOrphaSnomedConceptMaps.add(Pair.of(orphaCoding.getCode(), orphaSnomedMap)); 660 return validOrphaSnomedConceptMaps; 664 * Extracts information of diagnostic codes from the FHIR Condition resource. 666 * @param srcCondition FHIR Condition resource 667 * @return Coding part of the FHIR Condition resource, which contains diagnostic codes 669 private List<Coding> getDiagnoseCoding(Condition srcCondition) { 670 var diagnoseCodeableConcept = checkDataAbsentReason.getValue(srcCondition.getCode()); 671 if (diagnoseCodeableConcept == null) { 672 return Collections.emptyList(); 674 var diagnoseCodings = diagnoseCodeableConcept.getCoding(); 675 if (diagnoseCodings.isEmpty()) { 676 return Collections.emptyList(); 679 List<Coding> diagnoseCodingList = new ArrayList<>(); 681 for (var diagnoseCoding : diagnoseCodings) { 683 if (fhirSystems.getDiagnoseCode().contains(diagnoseCoding.getSystem())) { 684 diagnoseCodingList.add(diagnoseCoding); 687 return diagnoseCodingList; 691 * Returns the person_id of the referenced FHIR Patient resource for the processed FHIR Condition 694 * @param srcCondition FHIR Condition resource 695 * @param conditionLogicId logical id of the FHIR Condition resource 696 * @return person_id of the referenced FHIR Patient resource from person table in OMOP CDM 698 private Long getPersonId(Condition srcCondition, String conditionLogicId, String conditionId) { 699 var patientReferenceIdentifier = fhirReferenceUtils.getSubjectReferenceIdentifier(srcCondition); 700 var patientReferenceLogicalId = fhirReferenceUtils.getSubjectReferenceLogicalId(srcCondition); 702 return omopReferenceUtils.getPersonId( 703 patientReferenceIdentifier, patientReferenceLogicalId, conditionLogicId, conditionId); 707 * Returns the visit_occurrence_id of the referenced FHIR Encounter resource for the processed 708 * FHIR Condition resource. 710 * @param srcCondition FHIR Condition resource 711 * @param conditionId logical id of the FHIR Condition resource 712 * @param personId person_id of the referenced FHIR Patient resource 713 * @return visit_occurrence_id of the referenced FHIR Encounter resource from visit_occurrence 716 private Long getVisitOccId(Condition srcCondition, String conditionId, Long personId) { 717 var encounterReferenceIdentifier = 718 fhirReferenceUtils.getEncounterReferenceIdentifier(srcCondition); 719 var encounterReferenceLogicalId = 720 fhirReferenceUtils.getEncounterReferenceLogicalId(srcCondition); 722 omopReferenceUtils.getVisitOccId( 723 encounterReferenceIdentifier, encounterReferenceLogicalId, personId, conditionId); 724 if (visitOccId == null) { 725 log.debug("No matching [Encounter] found for [Condition]: {}.", conditionId); 732 * Extracts date time information from the FHIR Condition resource. 734 * @param srcCondition FHIR Condition resource 735 * @return start date time and end date time of the FHIR Condition resource 737 private ResourceOnset getConditionOnset(Condition srcCondition) { 738 var resourceOnset = new ResourceOnset(); 740 if (srcCondition.hasOnsetDateTimeType()) { 741 var onsetDateTimeType = srcCondition.getOnsetDateTimeType(); 742 if (!onsetDateTimeType.isEmpty()) { 743 resourceOnset.setStartDateTime( 744 new Timestamp(onsetDateTimeType.getValue().getTime()).toLocalDateTime()); 745 return resourceOnset; 749 if (srcCondition.hasOnsetPeriod()) { 750 var onsetPeriod = srcCondition.getOnsetPeriod(); 751 if (!onsetPeriod.isEmpty()) { 752 if (onsetPeriod.getStart() != null) { 753 resourceOnset.setStartDateTime( 754 new Timestamp(onsetPeriod.getStart().getTime()).toLocalDateTime()); 756 if (onsetPeriod.getEnd() != null) { 757 resourceOnset.setEndDateTime( 758 new Timestamp(onsetPeriod.getEnd().getTime()).toLocalDateTime()); 760 return resourceOnset; 764 var recordedDateElement = srcCondition.getRecordedDateElement(); 765 if (!recordedDateElement.isEmpty()) { 766 var recordedDate = checkDataAbsentReason.getValue(recordedDateElement); 767 if (recordedDate != null) { 768 resourceOnset.setStartDateTime(recordedDate); 769 return resourceOnset; 772 return resourceOnset; 776 * Separates primary and secondary ICD codes. 778 * @param icdSourceCodes string which contains both primary and secondary ICD codes 779 * @return list of primary and secondary ICD codes as FHIR Coding-Type 781 private List<Coding> splitDiagnoseCodes(Coding diagnoseSourceCoding, StringType version) { 782 List<Coding> uncheckedDiagnoseCodes = new ArrayList<>(); 783 var vocabularyId = findOmopConcepts.getOmopVocabularyId(diagnoseSourceCoding.getSystem()); 784 if (vocabularyId.equals(VOCABULARY_ICD10GM) && diagnoseSourceCoding.getCode() != null) { 785 var sourceCodes = diagnoseSourceCoding.getCode().strip(); 787 if (sourceCodes.contains(" ")) { 788 var codeArr = Arrays.asList(sourceCodes.split(" ", 2)); 789 for (var code : codeArr) { 793 .setSystem(diagnoseSourceCoding.getSystem()) 794 .setVersionElement(version) 795 .setExtension(diagnoseSourceCoding.getExtension()); 796 var singleCoding = element.castToCoding(element); 797 uncheckedDiagnoseCodes.add(singleCoding); 801 uncheckedDiagnoseCodes.add(diagnoseSourceCoding); 804 uncheckedDiagnoseCodes.add(diagnoseSourceCoding); 806 return uncheckedDiagnoseCodes; 810 * Processes information from FHIR Condition resource and transforms them into records OMOP CDM 813 * @param singlePair one pair of ICD code and its OMOP concept_id and domain information 814 * @param omopConcept extracted Concept from OMOP 815 * @param orphaSnomedPair one pair of Orpha code and its SNOMED concept_id and domain information 816 * @param wrapper the OMOP model wrapper 817 * @param diagnoseOnset start date time and end date time of the FHIR Condition resource 818 * @param diagnosticConfidenceConcept 819 * @param conditionLogicId logical id of the FHIR Condition resource 820 * @param conditionSourceIdentifier identifier of the FHIR Condition resource 821 * @param personId person_id of the referenced FHIR Patient resource 822 * @param visiOccId visit_occurrence_id of the referenced FHIR Encounter resource 824 private void icdProcessor( 825 @Nullable Pair<String, List<IcdSnomedDomainLookup>> singlePair, 826 @Nullable Concept omopConcept, 827 @Nullable Pair<String, List<OrphaSnomedMapping>> orphaSnomedPair, 828 OmopModelWrapper wrapper, 829 ResourceOnset diagnoseOnset, 830 SourceToConceptMap diagnosticConfidenceConcept, 831 String conditionLogicId, 832 String conditionSourceIdentifier, 836 if (singlePair == null && omopConcept == null && orphaSnomedPair == null) { 840 if (orphaSnomedPair != null) { 841 var orphaCode = orphaSnomedPair.getLeft(); 842 var orphaSnomedMaps = orphaSnomedPair.getRight(); 844 for (var orphaSnomedMap : orphaSnomedMaps) { 845 var domain = orphaSnomedMap.getSnomedDomainId(); 847 diagnosticConfidenceConcept, 851 conditionSourceIdentifier, 855 orphaSnomedMap.getSnomedConceptId(), 856 orphaSnomedMap.getOrphaConceptId(), 860 } else if (singlePair != null) { 861 var rawIcdCode = singlePair.getLeft(); 862 var icdSnomedMaps = singlePair.getRight(); 864 for (var icdCodeCheck : icdSnomedMaps) { 865 var domain = icdCodeCheck.getSnomedDomainId(); 867 diagnosticConfidenceConcept, 871 conditionSourceIdentifier, 875 icdCodeCheck.getSnomedConceptId(), 876 icdCodeCheck.getIcdGmConceptId(), 881 diagnosticConfidenceConcept, 885 conditionSourceIdentifier, 888 omopConcept.getConceptCode(), 889 omopConcept.getConceptId(), 890 omopConcept.getConceptId(), 891 omopConcept.getDomainId()); 896 * Write diagnosis information into corrected OMOP tables based on their domains. 898 * @param diagnosticConfidenceConcept OMOP concept for diagnostic confidence 899 * @param wrapper the OMOP model wrapper 900 * @param diagnoseOnset start date time and end date time of the FHIR Condition resource 901 * @param conditionLogicId logical id of the FHIR Condition resource 902 * @param conditionSourceIdentifier identifier of the FHIR Condition resource 903 * @param personId person_id of the referenced FHIR Patient resource 904 * @param visiOccId visit_occurrence_id of the referenced FHIR Encounter resource 905 * @param diagnosisCode diagnosis code 906 * @param diagnoseConceptId the OMOP concept_id of diagnosis Code as concept_id 907 * @param diagnoseSourceConceptId the OMOP concept_id of diagnosis Code as source_concept_id 908 * @param domain the OMOP domain of the diagnosis code 910 private void setDiagnoses( 911 SourceToConceptMap diagnosticConfidenceConcept, 912 OmopModelWrapper wrapper, 913 ResourceOnset diagnoseOnset, 914 String conditionLogicId, 915 String conditionSourceIdentifier, 918 String diagnosisCode, 919 Integer diagnoseConceptId, 920 Integer diagnoseSourceConceptId, 923 case OMOP_DOMAIN_CONDITION: 928 diagnoseSourceConceptId, 930 diagnosticConfidenceConcept, 934 conditionSourceIdentifier); 936 wrapper.getConditionOccurrence().add(condition); 939 case OMOP_DOMAIN_OBSERVATION: 942 diagnoseOnset.getStartDateTime(), 944 diagnoseSourceConceptId, 946 diagnosticConfidenceConcept, 950 conditionSourceIdentifier); 952 wrapper.getObservation().add(observation); 955 case OMOP_DOMAIN_PROCEDURE: 958 diagnoseOnset.getStartDateTime(), 960 diagnoseSourceConceptId, 962 diagnosticConfidenceConcept, 966 conditionSourceIdentifier); 968 wrapper.getProcedureOccurrence().add(procedure); 971 case OMOP_DOMAIN_MEASUREMENT: 974 diagnoseOnset.getStartDateTime(), 976 diagnoseSourceConceptId, 978 diagnosticConfidenceConcept, 982 conditionSourceIdentifier); 984 wrapper.getMeasurement().add(measurement); 988 throw new UnsupportedOperationException(String.format("Unsupported domain %s", domain)); 993 * Extracts diagnostic confidence information from FHIR Condition resource. 995 * @param icdCoding part of the FHIR Condition resource, which contains ICD codes 996 * @param conditionId logical id of the FHIR Condition resource 997 * @return diagnostic confidence from FHIR Condition resource 999 private Coding getDiagnosticConfidence(Coding icdCoding, String conditionId) { 1000 if (!icdCoding.hasExtension(fhirSystems.getDiagnosticConfidence())) { 1001 log.debug("No [Diagnostic confidence] found for [Condition] {}.", conditionId); 1005 var diagnosticConfidenceType = 1006 icdCoding.getExtensionByUrl(fhirSystems.getDiagnosticConfidence()).getValue(); 1007 var diagnosticConfidence = diagnosticConfidenceType.castToCoding(diagnosticConfidenceType); 1008 if (!diagnosticConfidence.hasCode() || Strings.isNullOrEmpty(diagnosticConfidence.getCode())) { 1009 log.debug("No [Diagnostic confidence] found for [Condition] {}.", conditionId); 1012 return diagnosticConfidence; 1016 * Deletes FHIR Condition resources from OMOP CDM tables using fhir_logical_id and fhir_identifier 1018 * @param conditionLogicId logical id of the FHIR Condition resource 1019 * @param conditionSourceIdentifier identifier of the FHIR Condition resource 1021 private void deleteExistingConditionEntry( 1022 String conditionLogicId, String conditionSourceIdentifier) { 1023 if (!Strings.isNullOrEmpty(conditionLogicId)) { 1024 conditionService.deleteExistingConditionsByFhirLogicalId(conditionLogicId); 1026 conditionService.deleteExistingConditionsByFhirIdentifier(conditionSourceIdentifier); 1031 * Deletes rank and use information from post_process_map table using fhir_logical_id and 1034 * @param conditionLogicId logical id of the FHIR Condition resource 1035 * @param conditionSourceIdentifier identifier of the FHIR Condition resource 1037 private void deleteExistingPostProcessMapEntry( 1038 String conditionLogicId, String conditionSourceIdentifier) { 1039 if (!Strings.isNullOrEmpty(conditionLogicId)) { 1040 conditionService.deleteExistingPpmEntriesByFhirLogicalId(conditionLogicId); 1042 conditionService.deleteExistingPpmEntriesByFhirIdentifier(conditionSourceIdentifier); 1047 * Updates flag for rank and use information in post_process_map table using fhir_logical_id and 1050 * @param conditionLogicId logical id of the FHIR Condition resource 1051 * @param conditionSourceIdentifier identifier of the FHIR Condition resource 1053 private void updateExistingPostProcessMapEntry( 1054 String conditionLogicId, String conditionSourceIdentifier) { 1055 if (!Strings.isNullOrEmpty(conditionLogicId)) { 1056 conditionService.updateExistingPpmEntriesByFhirLogicalId(conditionLogicId); 1058 conditionService.updateExistingPpmEntriesByFhirIdentifier(conditionSourceIdentifier); 1063 * Creates a new record of the condition_occurrence table in OMOP CDM for the processed FHIR 1064 * Condition resource. The extracted ICD code of the FHIR Condition resource belongs to the 1065 * Condition domain in OMOP CDM. 1067 * @param diagnoseOnset start date time and end date time of the FHIR Condition resource 1068 * @param diagnoseConceptId the OMOP concept_id of diagnose Code as concept_id 1069 * @param diagnoseSourceConceptId the OMOP concept_id of diagnose Code as source_concept_id 1070 * @param rawIcdCode ICD code with special characters 1071 * @param diagnosticConfidenceConcept the OMOP concept of diagnostic confidence 1072 * @param personId person_id of the referenced FHIR Patient resource 1073 * @param visitOccId visit_occurrence_id of the referenced FHIR Encounter resource 1074 * @param conditionLogicId logical id of the FHIR Condition resource 1075 * @param conditionSourceIdentifier identifier of the FHIR Condition resource 1076 * @return new record of the condition_occurrence table in OMOP CDM for the processed FHIR 1077 * Condition resource 1079 private ConditionOccurrence setUpCondition( 1080 ResourceOnset diagnoseOnset, 1081 Integer diagnoseConceptId, 1082 Integer diagnoseSourceConceptId, 1084 SourceToConceptMap diagnosticConfidenceConcept, 1087 String conditionLogicId, 1088 String conditionSourceIdentifier) { 1089 var startDatetime = diagnoseOnset.getStartDateTime(); 1090 var endDatetime = diagnoseOnset.getEndDateTime(); 1092 var newConditionOcc = 1093 ConditionOccurrence.builder() 1095 .conditionStartDate(startDatetime.toLocalDate()) 1096 .conditionStartDatetime(startDatetime) 1097 .conditionEndDatetime(endDatetime) 1098 .conditionEndDate(endDatetime != null ? endDatetime.toLocalDate() : null) 1099 .visitOccurrenceId(visitOccId) 1100 .conditionSourceConceptId(diagnoseSourceConceptId) 1101 .conditionConceptId(diagnoseConceptId) 1102 .conditionTypeConceptId(CONCEPT_EHR) 1103 .conditionSourceValue(rawIcdCode) 1104 .fhirLogicalId(conditionLogicId) 1105 .fhirIdentifier(conditionSourceIdentifier) 1108 if (diagnosticConfidenceConcept != null 1109 && diagnosticConfidenceConcept.getTargetConceptId() != null) { 1111 newConditionOcc.setConditionStatusSourceValue(diagnosticConfidenceConcept.getSourceCode()); 1112 newConditionOcc.setConditionStatusConceptId(diagnosticConfidenceConcept.getTargetConceptId()); 1115 return newConditionOcc; 1119 * Find the concept_id of diagnostic confidence. 1121 * @param diagnosticConfidenceCoding Diagnostic confidence of Condition FHIR Resource 1122 * @return a entry of SOURCE_TO_CONCEPT_MAP for diagnostic confidence 1124 private SourceToConceptMap getDiagnosticConfidenceConcept(Coding diagnosticConfidenceCoding) { 1125 if (diagnosticConfidenceCoding == null) { 1129 return findOmopConcepts.getCustomConcepts( 1130 diagnosticConfidenceCoding.getCode(), 1131 SOURCE_VOCABULARY_ID_DIAGNOSTIC_CONFIDENCE, 1136 * Creates a new record of the observation table in OMOP CDM for the processed FHIR Condition 1137 * resource. The extracted ICD code of the FHIR Condition resource belongs to the Observation 1138 * domain in OMOP CDM. 1140 * @param startDatetime start date time of the FHIR Condition resource 1141 * @param diagnoseConceptId the OMOP concept_id of diagnose Code as concept_id 1142 * @param diagnoseSourceConceptId the OMOP concept_id of diagnose Code as source_concept_id 1143 * @param rawIcdCode ICD code with special characters 1144 * @param diagnosticConfidenceConcept the OMOP concept of diagnostic confidence 1145 * @param personId person_id of the referenced FHIR Patient resource 1146 * @param visitOccId visit_occurrence_id of the referenced FHIR Encounter resource 1147 * @param conditionLogicId logical id of the FHIR Condition resource 1148 * @param conditionSourceIdentifier identifier of the FHIR Condition resource 1149 * @return new record of the observation table in OMOP CDM for the processed FHIR Condition 1152 private OmopObservation setUpObservation( 1153 LocalDateTime startDatetime, 1154 Integer diagnoseConceptId, 1155 Integer diagnoseSourceConceptId, 1157 SourceToConceptMap diagnosticConfidenceConcept, 1160 String conditionLogicId, 1161 String conditionSourceIdentifier) { 1163 var newObservation = 1164 OmopObservation.builder() 1166 .observationDate(startDatetime.toLocalDate()) 1167 .observationDatetime(startDatetime) 1168 .visitOccurrenceId(visitOccId) 1169 .observationSourceConceptId(diagnoseSourceConceptId) 1170 .observationConceptId(diagnoseConceptId) 1171 .observationTypeConceptId(CONCEPT_EHR) 1172 .observationSourceValue(rawIcdCode) 1173 .fhirLogicalId(conditionLogicId) 1174 .fhirIdentifier(conditionSourceIdentifier) 1177 if (diagnosticConfidenceConcept != null) { 1179 newObservation.setQualifierSourceValue(diagnosticConfidenceConcept.getSourceCode()); 1181 newObservation.setQualifierConceptId(diagnosticConfidenceConcept.getTargetConceptId()); 1184 return newObservation; 1188 * Creates a new record of the procedure_occurrence table in OMOP CDM for the processed FHIR 1189 * Condition resource. The extracted ICD code of the FHIR Condition resource belongs to the 1190 * Procedure domain in OMOP CDM. 1192 * @param startDatetime start date time of the FHIR Condition resource 1193 * @param diagnoseConceptId the OMOP concept_id of diagnose Code as concept_id 1194 * @param diagnoseSourceConceptId the OMOP concept_id of diagnose Code as source_concept_id 1195 * @param rawIcdCode ICD code with special characters 1196 * @param diagnosticConfidenceConcept the OMOP concept of diagnostic confidence 1197 * @param personId person_id of the referenced FHIR Patient resource 1198 * @param visitOccId visit_occurrence_id of the referenced FHIR Encounter resource 1199 * @param conditionLogicId logical id of the FHIR Condition resource 1200 * @param conditionSourceIdentifier identifier of the FHIR Condition resource 1201 * @return new record of the procedure_occurrence table in OMOP CDM for the processed FHIR 1202 * Condition resource 1204 private ProcedureOccurrence setUpProcedure( 1205 LocalDateTime startDatetime, 1206 Integer diagnoseConceptId, 1207 Integer diagnoseSourceConceptId, 1209 SourceToConceptMap diagnosticConfidenceConcept, 1212 String conditionLogicId, 1213 String conditionSourceIdentifier) { 1215 var newProcedureOcc = 1216 ProcedureOccurrence.builder() 1218 .procedureDate(startDatetime.toLocalDate()) 1219 .procedureDatetime(startDatetime) 1220 .visitOccurrenceId(visitOccId) 1221 .procedureSourceConceptId(diagnoseSourceConceptId) 1222 .procedureConceptId(diagnoseConceptId) 1223 .procedureTypeConceptId(CONCEPT_EHR) 1224 .procedureSourceValue(rawIcdCode) 1225 .fhirLogicalId(conditionLogicId) 1226 .fhirIdentifier(conditionSourceIdentifier) 1229 if (diagnosticConfidenceConcept != null) { 1230 newProcedureOcc.setModifierSourceValue(diagnosticConfidenceConcept.getSourceCode()); 1232 newProcedureOcc.setModifierConceptId(diagnosticConfidenceConcept.getTargetConceptId()); 1235 return newProcedureOcc; 1239 * Creates a new record of the measurement table in OMOP CDM for the processed FHIR Condition 1240 * resource. The extracted ICD code of the FHIR Condition resource belongs to the Measurement 1241 * domain in OMOP CDM. 1243 * @param startDatetime start date time of the FHIR Condition resource 1244 * @param diagnoseConceptId the OMOP concept_id of diagnose Code as concept_id 1245 * @param diagnoseSourceConceptId the OMOP concept_id of diagnose Code as source_concept_id 1246 * @param rawIcdCode ICD code with special characters 1247 * @param diagnosticConfidenceConcept the OMOP concept of diagnostic confidence 1248 * @param personId person_id of the referenced FHIR Patient resource 1249 * @param visitOccId visit_occurrence_id of the referenced FHIR Encounter resource 1250 * @param conditionLogicId logical id of the FHIR Condition resource 1251 * @param conditionSourceIdentifier identifier of the FHIR Condition resource 1252 * @return new record of the measurement table in OMOP CDM for the processed FHIR Condition 1255 private Measurement setUpMeasurement( 1256 LocalDateTime startDatetime, 1257 Integer diagnoseConceptId, 1258 Integer diagnoseSourceConceptId, 1260 SourceToConceptMap diagnosticConfidenceConcept, 1263 String conditionLogicId, 1264 String conditionSourceIdentifier) { 1266 var newMeasurement = 1267 Measurement.builder() 1269 .measurementDate(startDatetime.toLocalDate()) 1270 .measurementDatetime(startDatetime) 1271 .visitOccurrenceId(visitOccId) 1272 .measurementSourceConceptId(diagnoseSourceConceptId) 1273 .measurementConceptId(diagnoseConceptId) 1274 .measurementTypeConceptId(CONCEPT_EHR) 1275 .measurementSourceValue(rawIcdCode) 1276 .fhirLogicalId(conditionLogicId) 1277 .fhirIdentifier(conditionSourceIdentifier) 1280 if (diagnosticConfidenceConcept != null) { 1281 newMeasurement.setValueSourceValue(diagnosticConfidenceConcept.getSourceCode()); 1283 newMeasurement.setValueAsConceptId(diagnosticConfidenceConcept.getTargetConceptId()); 1286 return newMeasurement; 1290 * Creates new records of the post_process_map table in OMOP CDM for ICD pairs. 1292 * @param icdSnomedPairMaps a list of valid pairs of ICD code and its OMOP concept_id and domain 1294 * @param personIdperson_id of the referenced FHIR Patient resource 1295 * @param conditionLogicId logical id of the FHIR Condition resource 1296 * @param conditionSourceIdentifier identifier of the FHIR Condition resource 1297 * @return list of new records of the post_process_map table in OMOP CDM for the processed FHIR 1298 * Condition resource 1300 private List<PostProcessMap> setIcdPairs( 1301 List<Pair<String, List<IcdSnomedDomainLookup>>> icdSnomedPairMaps, 1302 String conditionLogicId, 1303 String conditionSourceIdentifier) { 1305 var primary = icdSnomedPairMaps.get(0); 1306 var secondary = icdSnomedPairMaps.get(1); 1308 var primaryIcdCode = primary.getLeft(); 1309 var secondaryIcdCode = secondary.getLeft(); 1311 var primaryIcdSnomedMap = primary.getRight(); 1312 var secondaryIcdSnomedMap = secondary.getRight(); 1314 ArrayList<PostProcessMap> icdPairs = new ArrayList<>(); 1316 for (var pri : primaryIcdSnomedMap) { 1318 for (var sec : secondaryIcdSnomedMap) { 1320 PostProcessMap.builder() 1321 .type(ResourceType.CONDITION.name()) 1322 .dataOne(primaryIcdCode + ":" + pri.getSnomedDomainId()) 1323 .dataTwo(secondaryIcdCode + ":" + sec.getSnomedDomainId()) 1325 .omopTable("primary_secondary_icd") 1326 .fhirLogicalId(conditionLogicId) 1327 .fhirIdentifier(conditionSourceIdentifier) 1329 if (!icdPairs.contains(ppmIcdPairs)) { 1330 icdPairs.add(ppmIcdPairs); 1338 * * Creates new record of the post_process_map table in OMOP CDM for extracted site localization 1339 * information from the processed FHIR Condition resource. 1341 * @param icdSnomedMapList a list of valid pairs of ICD code and its OMOP concept_id and domain 1343 * @param omopConcept extracted Concept from OMOP 1344 * @param personId person_id of the referenced FHIR Patient resource 1345 * @param siteLocalization site localization information as OMOP observation from the processed 1346 * FHIR Condition resource 1347 * @param conditionLogicId logical id of the FHIR Condition resource 1348 * @param conditionSourceIdentifier identifier of the FHIR Condition resource 1349 * @return new record of the post_process_map table in OMOP CDM for the processed FHIR Condition 1352 private PostProcessMap setBodySiteLocalizationReference( 1353 @Nullable List<Pair<String, List<IcdSnomedDomainLookup>>> icdSnomedMapList, 1354 @Nullable Concept omopConcept, 1356 OmopObservation siteLocalization, 1357 String conditionLogicId, 1358 String conditionSourceIdentifier) { 1360 if ((icdSnomedMapList == null && omopConcept == null) || icdSnomedMapList == null) { 1364 return PostProcessMap.builder() 1365 .type(ResourceType.CONDITION.name()) 1366 .dataOne(siteLocalization.getObservationSourceValue() + ":27") 1367 .dataTwo(Integer.toString(siteLocalization.getObservationConceptId())) 1369 .omopTable("site_localization") 1370 .fhirLogicalId(conditionLogicId) 1371 .fhirIdentifier(conditionSourceIdentifier) 1376 * Create a new record of the post_process_map table in OMOP CDM for extracted severity or stage 1377 * information from the processed FHIR Condition resource. 1379 * @param icdSnomedMapList a list of valid pairs of ICD code and its OMOP concept_id and domain 1381 * @param omopConcept extracted Concept from OMOP 1382 * @param personId person_id of the referenced FHIR Patient resource 1383 * @param diagnoseMetaInfo severity or stage information as OMOP observation from the processed 1384 * FHIR Condition resource 1385 * @param conditionLogicId logical id of the FHIR Condition resource 1386 * @param conditionSourceIdentifier identifier of the FHIR Condition resource 1387 * @return new record of the post_process_map table in OMOP CDM for the processed FHIR Condition 1390 private PostProcessMap setDiagnoseMetaInfoReference( 1391 @Nullable List<Pair<String, List<IcdSnomedDomainLookup>>> icdSnomedMapList, 1392 @Nullable Concept omopConcept, 1394 OmopObservation diagnoseMetaInfo, 1395 String conditionLogicId, 1396 String conditionSourceIdentifier, 1397 String metaInfoType) { 1399 if ((icdSnomedMapList == null && omopConcept == null) || icdSnomedMapList == null) { 1403 return PostProcessMap.builder() 1404 .type(ResourceType.CONDITION.name()) 1405 .dataOne(diagnoseMetaInfo.getObservationSourceValue() + ":27") 1406 .dataTwo(Integer.toString(diagnoseMetaInfo.getObservationConceptId())) 1408 .omopTable(metaInfoType) 1409 .fhirLogicalId(conditionLogicId) 1410 .fhirIdentifier(conditionSourceIdentifier) 1415 * Creates a new record of the observation table in OMOP CDM for extracted site localization 1416 * information from the processed FHIR Condition resource. 1418 * @param icdBodyLocalization a pair of the body site or site localization name and OMOP 1420 * @param conditionLogicId logical id of FHIR Condition resource 1421 * @param conditionSourceIdentifier identifier of FHIR Condition resource 1422 * @param personId person_id of the referenced FHIR Patient resource 1423 * @param visitOccId visit_occurrence_id of the referenced FHIR Encounter resource 1424 * @param diagnoseOnset start date time and end date time of the FHIR Condition resource 1425 * @return new record of the observation table in OMOP CDM for extracted site localization 1426 * information from the processed FHIR Condition resource 1428 private OmopObservation createSiteLocalization( 1429 Pair<String, Integer> icdBodyLocalization, 1430 String conditionLogicId, 1431 String conditionSourceIdentifier, 1434 ResourceOnset diagnoseOnset) { 1436 if (icdBodyLocalization != null && !Strings.isNullOrEmpty(icdBodyLocalization.getLeft())) { 1438 return OmopObservation.builder() 1440 .observationDate(diagnoseOnset.getStartDateTime().toLocalDate()) 1441 .observationDatetime(diagnoseOnset.getStartDateTime()) 1442 .observationTypeConceptId(CONCEPT_EHR) 1443 .observationConceptId(icdBodyLocalization.getRight()) 1444 .valueAsString(icdBodyLocalization.getLeft()) 1445 .observationSourceValue(icdBodyLocalization.getLeft()) 1446 .observationSourceConceptId(icdBodyLocalization.getRight()) 1447 .qualifierConceptId(CONCEPT_FINDING_SITE) 1448 .visitOccurrenceId(visitOccId) 1449 .fhirLogicalId(conditionLogicId) 1450 .fhirIdentifier(conditionSourceIdentifier) 1457 * Creates a new record of the observation table in OMOP CDM for extracted severity information 1458 * from the processed FHIR Condition resource. 1460 * @param diagnoseMetaInfoConcept concept of diagnose meta information 1461 * @param conditionLogicId logical id of FHIR Condition resource 1462 * @param conditionSourceIdentifier identifier of FHIR Condition resource 1463 * @param personId person_id of the referenced FHIR Patient resource 1464 * @param visitOccId visit_occurrence_id of the referenced FHIR Encounter resource 1465 * @param diagnoseOnset start date time and end date time of the FHIR Condition resource 1466 * @return new record of the observation table in OMOP CDM for extracted site localization 1467 * information from the processed FHIR Condition resource 1469 private OmopObservation createDiagnoseMetaInfo( 1470 Concept diagnoseMetaInfoConcept, 1471 String conditionLogicId, 1472 String conditionSourceIdentifier, 1475 ResourceOnset diagnoseOnset, 1476 String metaInfoType) { 1478 if (diagnoseMetaInfoConcept == null) { 1482 return OmopObservation.builder() 1484 .observationDate(diagnoseOnset.getStartDateTime().toLocalDate()) 1485 .observationDatetime(diagnoseOnset.getStartDateTime()) 1486 .observationTypeConceptId(CONCEPT_EHR) 1487 .observationConceptId(diagnoseMetaInfoConcept.getConceptId()) 1488 .valueAsString(diagnoseMetaInfoConcept.getConceptCode()) 1489 .observationSourceValue(diagnoseMetaInfoConcept.getConceptCode()) 1490 .observationSourceConceptId(diagnoseMetaInfoConcept.getConceptId()) 1491 .qualifierConceptId(metaInfoType.equals("stage") ? CONCEPT_STAGE : CONCEPT_SEVERITY) 1492 .visitOccurrenceId(visitOccId) 1493 .fhirLogicalId(conditionLogicId) 1494 .fhirIdentifier(conditionSourceIdentifier) 1499 * Extract the site localization name and its OMOP concept_id 1501 * @param icdCoding part of the FHIR Condition resource, which contains ICD codes 1502 * @param srcCondition FHIR Condition resource 1503 * @param diagnoseDate start date time of the FHIR Condition resource 1504 * @return a pair of the site localization name and its OMOP concept_id 1506 private Pair<String, Integer> getBodySiteLocalizationConcepts( 1507 Coding icdCoding, Condition srcCondition, LocalDate diagnoseDate, String conditionId) { 1508 var icdSiteLocalization = getSiteLocalization(icdCoding); 1509 var diagnoseBodySite = getBodySite(srcCondition); 1511 if (icdSiteLocalization == null && diagnoseBodySite == null) { 1513 } else if (icdSiteLocalization != null) { 1514 var icdSiteLocalizationConcept = 1515 findOmopConcepts.getCustomConcepts( 1516 icdSiteLocalization.getCode(), SOURCE_VOCABULARY_ID_ICD_LOCALIZATION, dbMappings); 1518 icdSiteLocalization.getCode(), icdSiteLocalizationConcept.getTargetConceptId()); 1520 var diagnoseBodySiteConcept = 1521 findOmopConcepts.getConcepts( 1522 diagnoseBodySite, diagnoseDate, bulkload, dbMappings, conditionId); 1523 if (diagnoseBodySiteConcept != null) { 1524 return Pair.of(diagnoseBodySite.getCode(), diagnoseBodySiteConcept.getConceptId()); 1531 * Extracts site localization information from the processed FHIR Condition resource. 1533 * @param icdCoding part of the FHIR Condition resource, which contains ICD codes 1534 * @return site localization from FHIR Condition resource 1536 private Coding getSiteLocalization(Coding icdCoding) { 1537 var siteLocalizationCodingExtension = 1538 icdCoding.getExtensionByUrl(fhirSystems.getSiteLocalizationExtension()); 1539 if (siteLocalizationCodingExtension == null) { 1542 var siteLocalizationCoding = 1543 siteLocalizationCodingExtension 1545 .castToCoding(siteLocalizationCodingExtension.getValue()); 1546 var siteLocalizationCode = siteLocalizationCoding.getCode(); 1547 if (Strings.isNullOrEmpty(siteLocalizationCode)) { 1551 return siteLocalizationCoding; 1555 * Extracts body site information from the processed FHIR Condition resource. 1557 * @param srcCondition FHIR Condition resource 1558 * @return body site from FHIR Condition resource 1560 private Coding getBodySite(Condition srcCondition) { 1561 var bodySiteCodeable = srcCondition.getBodySite(); 1562 if (bodySiteCodeable.isEmpty()) { 1566 var bodySiteCoding = 1567 bodySiteCodeable.stream().filter(codeable -> !codeable.getCoding().isEmpty()).findFirst(); 1568 if (bodySiteCoding.isEmpty()) { 1573 bodySiteCoding.get().getCoding().stream() 1574 .filter(coding -> coding.getSystem().equals(fhirSystems.getSnomed())) 1576 if (!bodySite.isPresent()) { 1579 var bodySiteCode = bodySite.get().getCode(); 1580 if (Strings.isNullOrEmpty(bodySiteCode)) { 1583 return bodySite.get(); 1587 * Extracts stage information from the processed FHIR Condition resource. 1589 * @param srcCondition FHIR Condition resource 1590 * @return stage from FHIR Condition resource 1592 private Coding getStage(Condition srcCondition) { 1594 if (!srcCondition.hasStage() || srcCondition.getStage().isEmpty()) { 1597 var stage = srcCondition.getStage(); 1599 var stageComponent = 1600 stage.stream().filter(summary -> !summary.getSummary().isEmpty()).findFirst(); 1601 if (stageComponent.isEmpty() 1602 || !stageComponent.get().hasSummary() 1603 || stageComponent.get().getSummary() == null) { 1607 var stageSummaryCodeable = stageComponent.get().getSummary(); 1608 if (stageSummaryCodeable.isEmpty() || !stageSummaryCodeable.hasCoding()) { 1613 stageSummaryCodeable.getCoding().stream() 1614 .filter(coding -> coding.getSystem().equals(fhirSystems.getSnomed())) 1616 if (!stageSummary.isPresent()) { 1619 var stageCode = stageSummary.get().getCode(); 1620 if (Strings.isNullOrEmpty(stageCode)) { 1623 return stageSummary.get(); 1627 * Extracts severity information from the processed FHIR Condition resource. 1629 * @param srcCondition FHIR Condition resource 1630 * @return severity from FHIR Condition resource 1632 private Coding getSeverity(Condition srcCondition) { 1633 if (!srcCondition.hasSeverity()) { 1636 var severityCodeable = srcCondition.getSeverity(); 1637 if (severityCodeable.isEmpty() || !severityCodeable.hasCoding()) { 1642 severityCodeable.getCoding().stream() 1643 .filter(coding -> coding.getSystem().equals(fhirSystems.getSnomed())) 1645 if (!severity.isPresent()) { 1648 var severityCode = severity.get().getCode(); 1649 if (Strings.isNullOrEmpty(severityCode)) { 1652 return severity.get();