Loinc uploader updates

This commit is contained in:
James Agnew 2018-04-21 14:32:17 -04:00
parent 8c889267e5
commit 488890155c
25 changed files with 493 additions and 167 deletions

View File

@ -717,10 +717,10 @@
</plugins> </plugins>
<resources> <resources>
<resource> <resource>
<directory>${basedir}/src/main/resources</directory> <directory>${project.basedir}/src/main/resources</directory>
</resource> </resource>
<resource> <resource>
<directory>${basedir}/target/generated-resources/tinder</directory> <directory>${project.basedir}/target/generated-resources/tinder</directory>
</resource> </resource>
</resources> </resources>
</build> </build>

View File

@ -8,7 +8,10 @@ import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.hl7.fhir.r4.model.*; import org.hl7.fhir.r4.model.*;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
@ -122,7 +125,7 @@ public interface IFhirResourceDaoCodeSystem<T extends IBaseResource, CD, CC> ext
} }
} }
public Parameters toParameters() { public Parameters toParameters(List<? extends IPrimitiveType<String>> theProperties) {
Parameters retVal = new Parameters(); Parameters retVal = new Parameters();
retVal.addParameter().setName("name").setValue(new StringType(getCodeSystemDisplayName())); retVal.addParameter().setName("name").setValue(new StringType(getCodeSystemDisplayName()));
@ -133,7 +136,23 @@ public interface IFhirResourceDaoCodeSystem<T extends IBaseResource, CD, CC> ext
retVal.addParameter().setName("abstract").setValue(new BooleanType(isCodeIsAbstract())); retVal.addParameter().setName("abstract").setValue(new BooleanType(isCodeIsAbstract()));
if (myProperties != null) { if (myProperties != null) {
Set<String> properties = Collections.emptySet();
if (theProperties != null) {
properties = theProperties
.stream()
.map(IPrimitiveType::getValueAsString)
.collect(Collectors.toSet());
}
for (IContextValidationSupport.BaseConceptProperty next : myProperties) { for (IContextValidationSupport.BaseConceptProperty next : myProperties) {
if (!properties.isEmpty()) {
if (!properties.contains(next.getPropertyName())) {
continue;
}
}
Parameters.ParametersParameterComponent property = retVal.addParameter().setName("property"); Parameters.ParametersParameterComponent property = retVal.addParameter().setName("property");
property property
.addPart() .addPart()

View File

@ -53,6 +53,11 @@ public class TermConceptPropertyFieldBridge implements FieldBridge, StringBridge
for (TermConceptProperty next : properties) { for (TermConceptProperty next : properties) {
String propValue = next.getKey() + "=" + next.getValue(); String propValue = next.getKey() + "=" + next.getValue();
theLuceneOptions.addFieldToDocument(theName, propValue, theDocument); theLuceneOptions.addFieldToDocument(theName, propValue, theDocument);
if (next.getType() == TermConceptPropertyTypeEnum.CODING) {
propValue = next.getKey() + "=" + next.getDisplay();
theLuceneOptions.addFieldToDocument(theName, propValue, theDocument);
}
} }
} }
} }

View File

@ -20,25 +20,21 @@ package ca.uhn.fhir.jpa.provider.dstu3;
* #L% * #L%
*/ */
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.hl7.fhir.convertors.VersionConvertor_30_40;
import org.hl7.fhir.dstu3.model.*;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem; import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem.LookupCodeResult; import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem.LookupCodeResult;
import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.hl7.fhir.convertors.VersionConvertor_30_40;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
public class BaseJpaResourceProviderCodeSystemDstu3 extends JpaResourceProviderDstu3<CodeSystem> { public class BaseJpaResourceProviderCodeSystemDstu3 extends JpaResourceProviderDstu3<CodeSystem> {
//@formatter:off
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Operation(name = "$lookup", idempotent = true, returnParameters= { @Operation(name = "$lookup", idempotent = true, returnParameters= {
@OperationParam(name="name", type=StringType.class, min=1), @OperationParam(name="name", type=StringType.class, min=1),
@ -51,16 +47,16 @@ public class BaseJpaResourceProviderCodeSystemDstu3 extends JpaResourceProviderD
@OperationParam(name="code", min=0, max=1) CodeType theCode, @OperationParam(name="code", min=0, max=1) CodeType theCode,
@OperationParam(name="system", min=0, max=1) UriType theSystem, @OperationParam(name="system", min=0, max=1) UriType theSystem,
@OperationParam(name="coding", min=0, max=1) Coding theCoding, @OperationParam(name="coding", min=0, max=1) Coding theCoding,
@OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) List<CodeType> theProperties,
RequestDetails theRequestDetails RequestDetails theRequestDetails
) { ) {
//@formatter:on
startRequest(theServletRequest); startRequest(theServletRequest);
try { try {
IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> dao = (IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept>) getDao(); IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> dao = (IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept>) getDao();
LookupCodeResult result = dao.lookupCode(theCode, theSystem, theCoding, theRequestDetails); LookupCodeResult result = dao.lookupCode(theCode, theSystem, theCoding, theRequestDetails);
result.throwNotFoundIfAppropriate(); result.throwNotFoundIfAppropriate();
org.hl7.fhir.r4.model.Parameters parametersR4 = result.toParameters(); org.hl7.fhir.r4.model.Parameters parametersR4 = result.toParameters(theProperties);
return VersionConvertor_30_40.convertParameters(parametersR4); return VersionConvertor_30_40.convertParameters(parametersR4);
} catch (FHIRException e) { } catch (FHIRException e) {
throw new InternalErrorException(e); throw new InternalErrorException(e);

View File

@ -20,22 +20,18 @@ package ca.uhn.fhir.jpa.provider.r4;
* #L% * #L%
*/ */
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import javax.servlet.http.HttpServletRequest;
import org.hl7.fhir.r4.model.*;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem; import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem.LookupCodeResult; import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem.LookupCodeResult;
import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import org.hl7.fhir.r4.model.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
public class BaseJpaResourceProviderCodeSystemR4 extends JpaResourceProviderR4<CodeSystem> { public class BaseJpaResourceProviderCodeSystemR4 extends JpaResourceProviderR4<CodeSystem> {
//@formatter:off
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Operation(name = "$lookup", idempotent = true, returnParameters= { @Operation(name = "$lookup", idempotent = true, returnParameters= {
@OperationParam(name="name", type=StringType.class, min=1), @OperationParam(name="name", type=StringType.class, min=1),
@ -48,16 +44,16 @@ public class BaseJpaResourceProviderCodeSystemR4 extends JpaResourceProviderR4<C
@OperationParam(name="code", min=0, max=1) CodeType theCode, @OperationParam(name="code", min=0, max=1) CodeType theCode,
@OperationParam(name="system", min=0, max=1) UriType theSystem, @OperationParam(name="system", min=0, max=1) UriType theSystem,
@OperationParam(name="coding", min=0, max=1) Coding theCoding, @OperationParam(name="coding", min=0, max=1) Coding theCoding,
@OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) List<CodeType> theProperties,
RequestDetails theRequestDetails RequestDetails theRequestDetails
) { ) {
//@formatter:on
startRequest(theServletRequest); startRequest(theServletRequest);
try { try {
IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> dao = (IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept>) getDao(); IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> dao = (IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept>) getDao();
LookupCodeResult result = dao.lookupCode(theCode, theSystem, theCoding, theRequestDetails); LookupCodeResult result = dao.lookupCode(theCode, theSystem, theCoding, theRequestDetails);
result.throwNotFoundIfAppropriate(); result.throwNotFoundIfAppropriate();
return result.toParameters(); return result.toParameters(theProperties);
} finally { } finally {
endRequest(theServletRequest); endRequest(theServletRequest);
} }

View File

@ -292,7 +292,6 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
} else { } else {
// bool.must(qb.keyword().onField("myProperties").matching(nextFilter.getStringProperty()+"="+nextFilter.getValue()).createQuery());
bool.must(qb.phrase().onField("myProperties").sentence(nextFilter.getProperty() + "=" + nextFilter.getValue()).createQuery()); bool.must(qb.phrase().onField("myProperties").sentence(nextFilter.getProperty() + "=" + nextFilter.getValue()).createQuery());
} }

View File

@ -64,6 +64,7 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
public static final String LOINC_ANSWERLIST_FILE = "AnswerList_Beta_1.csv"; public static final String LOINC_ANSWERLIST_FILE = "AnswerList_Beta_1.csv";
public static final String LOINC_ANSWERLIST_LINK_FILE = "LoincAnswerListLink_Beta_1.csv"; public static final String LOINC_ANSWERLIST_LINK_FILE = "LoincAnswerListLink_Beta_1.csv";
public static final String LOINC_DOCUMENT_ONTOLOGY_FILE = "DocumentOntology.csv"; public static final String LOINC_DOCUMENT_ONTOLOGY_FILE = "DocumentOntology.csv";
public static final String LOINC_UPLOAD_PROPERTIES_FILE = "loincupload.properties";
public static final String LOINC_FILE = "loinc.csv"; public static final String LOINC_FILE = "loinc.csv";
public static final String LOINC_HIERARCHY_FILE = "MULTI-AXIAL_HIERARCHY.CSV"; public static final String LOINC_HIERARCHY_FILE = "MULTI-AXIAL_HIERARCHY.CSV";
public static final String LOINC_PART_FILE = "Part_Beta_1.csv"; public static final String LOINC_PART_FILE = "Part_Beta_1.csv";
@ -173,6 +174,7 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
descriptors.verifyMandatoryFilesExist(mandatoryFilenameFragments); descriptors.verifyMandatoryFilesExist(mandatoryFilenameFragments);
List<String> optionalFilenameFragments = Arrays.asList( List<String> optionalFilenameFragments = Arrays.asList(
LOINC_UPLOAD_PROPERTIES_FILE,
LOINC_ANSWERLIST_FILE, LOINC_ANSWERLIST_FILE,
LOINC_ANSWERLIST_LINK_FILE, LOINC_ANSWERLIST_LINK_FILE,
LOINC_PART_FILE, LOINC_PART_FILE,
@ -222,17 +224,37 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
throw new InternalErrorException("Failed to load loinc.xml", e); throw new InternalErrorException("Failed to load loinc.xml", e);
} }
Set<String> propertyNames = new HashSet<>(); Map<String, CodeSystem.PropertyType> propertyNamesToTypes = new HashMap<>();
for (CodeSystem.PropertyComponent nextProperty : loincCs.getProperty()) { for (CodeSystem.PropertyComponent nextProperty : loincCs.getProperty()) {
if (isNotBlank(nextProperty.getCode())) { String nextPropertyCode = nextProperty.getCode();
propertyNames.add(nextProperty.getCode()); CodeSystem.PropertyType nextPropertyType = nextProperty.getType();
if (isNotBlank(nextPropertyCode)) {
propertyNamesToTypes.put(nextPropertyCode, nextPropertyType);
} }
} }
IRecordHandler handler; IRecordHandler handler;
Properties uploadProperties = new Properties();
for (FileDescriptor next : theDescriptors.getUncompressedFileDescriptors()) {
if (next.getFilename().endsWith("loincupload.properties")) {
try {
try (InputStream inputStream = next.getInputStream()) {
uploadProperties.load(inputStream);
}
} catch (IOException e) {
throw new InternalErrorException("Failed to read loincupload.properties", e);
}
}
}
// Part file
handler = new LoincPartHandler(codeSystemVersion, code2concept);
iterateOverZipFile(theDescriptors, LOINC_PART_FILE, handler, ',', QuoteMode.NON_NUMERIC);
Map<PartTypeAndPartName, String> partTypeAndPartNameToPartNumber = ((LoincPartHandler) handler).getPartTypeAndPartNameToPartNumber();
// Loinc Codes // Loinc Codes
handler = new LoincHandler(codeSystemVersion, code2concept, propertyNames); handler = new LoincHandler(codeSystemVersion, code2concept, propertyNamesToTypes, partTypeAndPartNameToPartNumber);
iterateOverZipFile(theDescriptors, LOINC_FILE, handler, ',', QuoteMode.NON_NUMERIC); iterateOverZipFile(theDescriptors, LOINC_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Loinc Hierarchy // Loinc Hierarchy
@ -240,51 +262,47 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
iterateOverZipFile(theDescriptors, LOINC_HIERARCHY_FILE, handler, ',', QuoteMode.NON_NUMERIC); iterateOverZipFile(theDescriptors, LOINC_HIERARCHY_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Answer lists (ValueSets of potential answers/values for loinc "questions") // Answer lists (ValueSets of potential answers/values for loinc "questions")
handler = new LoincAnswerListHandler(codeSystemVersion, code2concept, propertyNames, valueSets, conceptMaps); handler = new LoincAnswerListHandler(codeSystemVersion, code2concept, valueSets, conceptMaps, uploadProperties);
iterateOverZipFile(theDescriptors, LOINC_ANSWERLIST_FILE, handler, ',', QuoteMode.NON_NUMERIC); iterateOverZipFile(theDescriptors, LOINC_ANSWERLIST_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Answer list links (connects loinc observation codes to answerlist codes) // Answer list links (connects loinc observation codes to answerlist codes)
handler = new LoincAnswerListLinkHandler(code2concept, valueSets); handler = new LoincAnswerListLinkHandler(code2concept, valueSets);
iterateOverZipFile(theDescriptors, LOINC_ANSWERLIST_LINK_FILE, handler, ',', QuoteMode.NON_NUMERIC); iterateOverZipFile(theDescriptors, LOINC_ANSWERLIST_LINK_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Part file
handler = new LoincPartHandler(codeSystemVersion, code2concept);
iterateOverZipFile(theDescriptors, LOINC_PART_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Part link file // Part link file
handler = new LoincPartLinkHandler(codeSystemVersion, code2concept); handler = new LoincPartLinkHandler(codeSystemVersion, code2concept);
iterateOverZipFile(theDescriptors, LOINC_PART_LINK_FILE, handler, ',', QuoteMode.NON_NUMERIC); iterateOverZipFile(theDescriptors, LOINC_PART_LINK_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Part related code mapping // Part related code mapping
handler = new LoincPartRelatedCodeMappingHandler(codeSystemVersion, code2concept, valueSets, conceptMaps); handler = new LoincPartRelatedCodeMappingHandler(codeSystemVersion, code2concept, valueSets, conceptMaps, uploadProperties);
iterateOverZipFile(theDescriptors, LOINC_PART_RELATED_CODE_MAPPING_FILE, handler, ',', QuoteMode.NON_NUMERIC); iterateOverZipFile(theDescriptors, LOINC_PART_RELATED_CODE_MAPPING_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Document Ontology File // Document Ontology File
handler = new LoincDocumentOntologyHandler(codeSystemVersion, code2concept, propertyNames, valueSets, conceptMaps); handler = new LoincDocumentOntologyHandler(code2concept, propertyNamesToTypes, valueSets, conceptMaps, uploadProperties);
iterateOverZipFile(theDescriptors, LOINC_DOCUMENT_ONTOLOGY_FILE, handler, ',', QuoteMode.NON_NUMERIC); iterateOverZipFile(theDescriptors, LOINC_DOCUMENT_ONTOLOGY_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// RSNA Playbook file // RSNA Playbook file
handler = new LoincRsnaPlaybookHandler(codeSystemVersion, code2concept, propertyNames, valueSets, conceptMaps); handler = new LoincRsnaPlaybookHandler(code2concept, valueSets, conceptMaps, uploadProperties);
iterateOverZipFile(theDescriptors, LOINC_RSNA_PLAYBOOK_FILE, handler, ',', QuoteMode.NON_NUMERIC); iterateOverZipFile(theDescriptors, LOINC_RSNA_PLAYBOOK_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Top 2000 Codes - US // Top 2000 Codes - US
handler = new LoincTop2000LabResultsUsHandler(code2concept, valueSets, conceptMaps); handler = new LoincTop2000LabResultsUsHandler(code2concept, valueSets, conceptMaps, uploadProperties);
iterateOverZipFile(theDescriptors, LOINC_TOP2000_COMMON_LAB_RESULTS_US_FILE, handler, ',', QuoteMode.NON_NUMERIC); iterateOverZipFile(theDescriptors, LOINC_TOP2000_COMMON_LAB_RESULTS_US_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Top 2000 Codes - SI // Top 2000 Codes - SI
handler = new LoincTop2000LabResultsSiHandler(code2concept, valueSets, conceptMaps); handler = new LoincTop2000LabResultsSiHandler(code2concept, valueSets, conceptMaps, uploadProperties);
iterateOverZipFile(theDescriptors, LOINC_TOP2000_COMMON_LAB_RESULTS_SI_FILE, handler, ',', QuoteMode.NON_NUMERIC); iterateOverZipFile(theDescriptors, LOINC_TOP2000_COMMON_LAB_RESULTS_SI_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Universal Lab Order ValueSet // Universal Lab Order ValueSet
handler = new LoincUniversalOrderSetHandler(code2concept, valueSets, conceptMaps); handler = new LoincUniversalOrderSetHandler(code2concept, valueSets, conceptMaps, uploadProperties);
iterateOverZipFile(theDescriptors, LOINC_UNIVERSAL_LAB_ORDER_VALUESET_FILE, handler, ',', QuoteMode.NON_NUMERIC); iterateOverZipFile(theDescriptors, LOINC_UNIVERSAL_LAB_ORDER_VALUESET_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// IEEE Medical Device Codes // IEEE Medical Device Codes
handler = new LoincIeeeMedicalDeviceCodeHandler(code2concept, valueSets, conceptMaps); handler = new LoincIeeeMedicalDeviceCodeHandler(code2concept, valueSets, conceptMaps, uploadProperties);
iterateOverZipFile(theDescriptors, LOINC_IEEE_MEDICAL_DEVICE_CODE_MAPPING_TABLE_CSV, handler, ',', QuoteMode.NON_NUMERIC); iterateOverZipFile(theDescriptors, LOINC_IEEE_MEDICAL_DEVICE_CODE_MAPPING_TABLE_CSV, handler, ',', QuoteMode.NON_NUMERIC);
// Imaging Document Codes // Imaging Document Codes
handler = new LoincImagingDocumentCodeHandler(code2concept, valueSets, conceptMaps); handler = new LoincImagingDocumentCodeHandler(code2concept, valueSets, conceptMaps, uploadProperties);
iterateOverZipFile(theDescriptors, LOINC_IMAGING_DOCUMENT_CODES_FILE, handler, ',', QuoteMode.NON_NUMERIC); iterateOverZipFile(theDescriptors, LOINC_IMAGING_DOCUMENT_CODES_FILE, handler, ',', QuoteMode.NON_NUMERIC);
IOUtils.closeQuietly(theDescriptors); IOUtils.closeQuietly(theDescriptors);
@ -367,8 +385,8 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
private void storeCodeSystem(RequestDetails theRequestDetails, final TermCodeSystemVersion theCodeSystemVersion, CodeSystem theCodeSystem, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) { private void storeCodeSystem(RequestDetails theRequestDetails, final TermCodeSystemVersion theCodeSystemVersion, CodeSystem theCodeSystem, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) {
Validate.isTrue(theCodeSystem.getContent() == CodeSystem.CodeSystemContentMode.NOTPRESENT); Validate.isTrue(theCodeSystem.getContent() == CodeSystem.CodeSystemContentMode.NOTPRESENT);
List<ValueSet> valueSets = ObjectUtils.defaultIfNull(theValueSets, Collections.<ValueSet>emptyList()); List<ValueSet> valueSets = ObjectUtils.defaultIfNull(theValueSets, Collections.emptyList());
List<ConceptMap> conceptMaps = ObjectUtils.defaultIfNull(theConceptMaps, Collections.<ConceptMap>emptyList()); List<ConceptMap> conceptMaps = ObjectUtils.defaultIfNull(theConceptMaps, Collections.emptyList());
myTermSvc.setProcessDeferred(false); myTermSvc.setProcessDeferred(false);
if (myTermSvcDstu3 != null) { if (myTermSvcDstu3 != null) {

View File

@ -30,21 +30,31 @@ import org.hl7.fhir.r4.model.ValueSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import static org.apache.commons.lang3.StringUtils.*; import static org.apache.commons.lang3.StringUtils.*;
abstract class BaseHandler implements IRecordHandler { public abstract class BaseLoincHandler implements IRecordHandler {
public static final String LOINC_COPYRIGHT_STATEMENT = "This content from LOINC® is copyright © 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at https://loinc.org/license/";
/**
* This is <b>NOT</b> the LOINC CodeSystem URI! It is just
* the website URL to LOINC.
*/
public static final String LOINC_WEBSITE_URL = "https://loinc.org";
public static final String REGENSTRIEF_INSTITUTE_INC = "Regenstrief Institute, Inc.";
private final List<ConceptMap> myConceptMaps; private final List<ConceptMap> myConceptMaps;
private final Map<String, ConceptMap> myIdToConceptMaps = new HashMap<>(); private final Map<String, ConceptMap> myIdToConceptMaps = new HashMap<>();
private final List<ValueSet> myValueSets; private final List<ValueSet> myValueSets;
private final Map<String, ValueSet> myIdToValueSet = new HashMap<>(); private final Map<String, ValueSet> myIdToValueSet = new HashMap<>();
private final Map<String, TermConcept> myCode2Concept; private final Map<String, TermConcept> myCode2Concept;
private final Properties myUploadProperties;
BaseHandler(Map<String, TermConcept> theCode2Concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) { BaseLoincHandler(Map<String, TermConcept> theCode2Concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps, Properties theUploadProperties) {
myValueSets = theValueSets; myValueSets = theValueSets;
myCode2Concept = theCode2Concept; myCode2Concept = theCode2Concept;
myConceptMaps = theConceptMaps; myConceptMaps = theConceptMaps;
myUploadProperties = theUploadProperties;
} }
void addCodeAsIncludeToValueSet(ValueSet theVs, String theCodeSystemUrl, String theCode, String theDisplayName) { void addCodeAsIncludeToValueSet(ValueSet theVs, String theCodeSystemUrl, String theCode, String theDisplayName) {
@ -100,20 +110,25 @@ abstract class BaseHandler implements IRecordHandler {
conceptMap.setId(theMapping.getConceptMapId()); conceptMap.setId(theMapping.getConceptMapId());
conceptMap.setUrl(theMapping.getConceptMapUri()); conceptMap.setUrl(theMapping.getConceptMapUri());
conceptMap.setName(theMapping.getConceptMapName()); conceptMap.setName(theMapping.getConceptMapName());
conceptMap.setPublisher("Regentrief Institute, Inc."); conceptMap.setVersion(myUploadProperties.getProperty("conceptmap.version"));
conceptMap.setPublisher(REGENSTRIEF_INSTITUTE_INC);
conceptMap.addContact() conceptMap.addContact()
.setName("Regentrief Institute, Inc.") .setName(REGENSTRIEF_INSTITUTE_INC)
.addTelecom() .addTelecom()
.setSystem(ContactPoint.ContactPointSystem.URL) .setSystem(ContactPoint.ContactPointSystem.URL)
.setValue("https://loinc.org"); .setValue(LOINC_WEBSITE_URL);
conceptMap.setCopyright(theCopyright); String copyright = theCopyright;
if (!copyright.contains("LOINC")) {
copyright = LOINC_COPYRIGHT_STATEMENT + ". " + copyright;
}
conceptMap.setCopyright(copyright);
myIdToConceptMaps.put(theMapping.getConceptMapId(), conceptMap); myIdToConceptMaps.put(theMapping.getConceptMapId(), conceptMap);
myConceptMaps.add(conceptMap); myConceptMaps.add(conceptMap);
} else { } else {
conceptMap = myIdToConceptMaps.get(theMapping.getConceptMapId()); conceptMap = myIdToConceptMaps.get(theMapping.getConceptMapId());
} }
if (isNotBlank(theMapping.getCopyright())) { if (isBlank(theMapping.getCopyright())) {
conceptMap.setCopyright(theMapping.getCopyright()); conceptMap.setCopyright(theMapping.getCopyright());
} }
@ -164,21 +179,28 @@ abstract class BaseHandler implements IRecordHandler {
} }
} }
ValueSet getValueSet(String theValueSetId, String theValueSetUri, String theValueSetName) { ValueSet getValueSet(String theValueSetId, String theValueSetUri, String theValueSetName, String theVersionPropertyName) {
String version = null;
if (isNotBlank(theVersionPropertyName)) {
version = myUploadProperties.getProperty(theVersionPropertyName);
}
ValueSet vs; ValueSet vs;
if (!myIdToValueSet.containsKey(theValueSetId)) { if (!myIdToValueSet.containsKey(theValueSetId)) {
vs = new ValueSet(); vs = new ValueSet();
vs.setUrl(theValueSetUri); vs.setUrl(theValueSetUri);
vs.setId(theValueSetId); vs.setId(theValueSetId);
vs.setVersion(version);
vs.setName(theValueSetName); vs.setName(theValueSetName);
vs.setStatus(Enumerations.PublicationStatus.ACTIVE); vs.setStatus(Enumerations.PublicationStatus.ACTIVE);
vs.setPublisher("Regenstrief Institute, Inc."); vs.setPublisher(REGENSTRIEF_INSTITUTE_INC);
vs.addContact() vs.addContact()
.setName("Regenstrief Institute, Inc.") .setName(REGENSTRIEF_INSTITUTE_INC)
.addTelecom() .addTelecom()
.setSystem(ContactPoint.ContactPointSystem.URL) .setSystem(ContactPoint.ContactPointSystem.URL)
.setValue("https://loinc.org"); .setValue(LOINC_WEBSITE_URL);
vs.setCopyright("This content from LOINC® is copyright © 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at https://loinc.org/license/"); vs.setCopyright(LOINC_COPYRIGHT_STATEMENT);
myIdToValueSet.put(theValueSetId, vs); myIdToValueSet.put(theValueSetId, vs);
myValueSets.add(vs); myValueSets.add(vs);
} else { } else {

View File

@ -29,17 +29,18 @@ import org.hl7.fhir.r4.model.ValueSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import static org.apache.commons.lang3.StringUtils.trim; import static org.apache.commons.lang3.StringUtils.trim;
public class BaseLoincTop2000LabResultsHandler extends BaseHandler implements IRecordHandler { public class BaseLoincTop2000LabResultsHandler extends BaseLoincHandler implements IRecordHandler {
private String myValueSetId; private String myValueSetId;
private String myValueSetUri; private String myValueSetUri;
private String myValueSetName; private String myValueSetName;
public BaseLoincTop2000LabResultsHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, String theValueSetId, String theValueSetUri, String theValueSetName, List<ConceptMap> theConceptMaps) { public BaseLoincTop2000LabResultsHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, String theValueSetId, String theValueSetUri, String theValueSetName, List<ConceptMap> theConceptMaps, Properties theUploadProperties) {
super(theCode2concept, theValueSets, theConceptMaps); super(theCode2concept, theValueSets, theConceptMaps, theUploadProperties);
myValueSetId = theValueSetId; myValueSetId = theValueSetId;
myValueSetUri = theValueSetUri; myValueSetUri = theValueSetUri;
myValueSetName = theValueSetName; myValueSetName = theValueSetName;
@ -50,7 +51,7 @@ public class BaseLoincTop2000LabResultsHandler extends BaseHandler implements IR
String loincNumber = trim(theRecord.get("LOINC #")); String loincNumber = trim(theRecord.get("LOINC #"));
String displayName = trim(theRecord.get("Long Common Name")); String displayName = trim(theRecord.get("Long Common Name"));
ValueSet valueSet = getValueSet(myValueSetId, myValueSetUri, myValueSetName); ValueSet valueSet = getValueSet(myValueSetId, myValueSetUri, myValueSetName, null);
addCodeAsIncludeToValueSet(valueSet, IHapiTerminologyLoaderSvc.LOINC_URI, loincNumber, displayName); addCodeAsIncludeToValueSet(valueSet, IHapiTerminologyLoaderSvc.LOINC_URI, loincNumber, displayName);
} }

View File

@ -27,27 +27,21 @@ import org.apache.commons.csv.CSVRecord;
import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.model.ValueSet;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Properties;
import static org.apache.commons.lang3.StringUtils.*; import static org.apache.commons.lang3.StringUtils.*;
public class LoincAnswerListHandler extends BaseHandler { public class LoincAnswerListHandler extends BaseLoincHandler {
private final Map<String, TermConcept> myCode2Concept; private final Map<String, TermConcept> myCode2Concept;
private final TermCodeSystemVersion myCodeSystemVersion; private final TermCodeSystemVersion myCodeSystemVersion;
private final Set<String> myPropertyNames;
private final List<ValueSet> myValueSets;
private final Map<String, ValueSet> myIdToValueSet = new HashMap<>();
public LoincAnswerListHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, Set<String> thePropertyNames, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) { public LoincAnswerListHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps, Properties theUploadProperties) {
super(theCode2concept, theValueSets, theConceptMaps); super(theCode2concept, theValueSets, theConceptMaps, theUploadProperties);
myCodeSystemVersion = theCodeSystemVersion; myCodeSystemVersion = theCodeSystemVersion;
myCode2Concept = theCode2concept; myCode2Concept = theCode2concept;
myPropertyNames = thePropertyNames;
myValueSets = theValueSets;
} }
@Override @Override
@ -91,11 +85,11 @@ public class LoincAnswerListHandler extends BaseHandler {
} }
// Answer list ValueSet // Answer list ValueSet
ValueSet vs = getValueSet(answerListId, "urn:oid:" + answerListOid, answerListName); ValueSet vs = getValueSet(answerListId, "http://loinc.org/vs/" + answerListId, answerListName, "answerlist.version");
if (vs.getIdentifier().isEmpty()) { if (vs.getIdentifier().isEmpty()) {
vs.addIdentifier() vs.addIdentifier()
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URI) .setSystem("urn:ietf:rfc:3986")
.setValue(answerListId); .setValue("urn:oid:" + answerListOid);
} }
vs vs

View File

@ -20,33 +20,31 @@ package ca.uhn.fhir.jpa.term.loinc;
* #L% * #L%
*/ */
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept; import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc; import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IRecordHandler; import ca.uhn.fhir.jpa.term.IRecordHandler;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.commons.csv.CSVRecord; import org.apache.commons.csv.CSVRecord;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.model.ValueSet;
import java.util.*; import java.util.List;
import java.util.Map;
import java.util.Properties;
import static org.apache.commons.lang3.StringUtils.trim; import static org.apache.commons.lang3.StringUtils.trim;
public class LoincDocumentOntologyHandler extends BaseHandler implements IRecordHandler { public class LoincDocumentOntologyHandler extends BaseLoincHandler implements IRecordHandler {
public static final String DOCUMENT_ONTOLOGY_CODES_VS_ID = "loinc-document-ontology"; public static final String DOCUMENT_ONTOLOGY_CODES_VS_ID = "loinc-document-ontology";
public static final String DOCUMENT_ONTOLOGY_CODES_VS_URI = "http://loinc.org/vs/loinc-document-ontology"; public static final String DOCUMENT_ONTOLOGY_CODES_VS_URI = "http://loinc.org/vs/loinc-document-ontology";
public static final String DOCUMENT_ONTOLOGY_CODES_VS_NAME = "LOINC Document Ontology Codes"; public static final String DOCUMENT_ONTOLOGY_CODES_VS_NAME = "LOINC Document Ontology Codes";
private final Map<String, TermConcept> myCode2Concept; private final Map<String, TermConcept> myCode2Concept;
private final TermCodeSystemVersion myCodeSystemVersion;
private final Set<String> myPropertyNames;
public LoincDocumentOntologyHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, Set<String> thePropertyNames, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) { public LoincDocumentOntologyHandler(Map<String, TermConcept> theCode2concept, Map<String, CodeSystem.PropertyType> thePropertyNames, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps, Properties theUploadProperties) {
super(theCode2concept, theValueSets, theConceptMaps); super(theCode2concept, theValueSets, theConceptMaps, theUploadProperties);
myCodeSystemVersion = theCodeSystemVersion;
myCode2Concept = theCode2concept; myCode2Concept = theCode2concept;
myPropertyNames = thePropertyNames;
} }
@Override @Override
@ -59,7 +57,7 @@ public class LoincDocumentOntologyHandler extends BaseHandler implements IRecord
String partName = trim(theRecord.get("PartName")); String partName = trim(theRecord.get("PartName"));
// RSNA Codes VS // RSNA Codes VS
ValueSet vs = getValueSet(DOCUMENT_ONTOLOGY_CODES_VS_ID, DOCUMENT_ONTOLOGY_CODES_VS_URI, DOCUMENT_ONTOLOGY_CODES_VS_NAME); ValueSet vs = getValueSet(DOCUMENT_ONTOLOGY_CODES_VS_ID, DOCUMENT_ONTOLOGY_CODES_VS_URI, DOCUMENT_ONTOLOGY_CODES_VS_NAME, null);
addCodeAsIncludeToValueSet(vs, IHapiTerminologyLoaderSvc.LOINC_URI, loincNumber, null); addCodeAsIncludeToValueSet(vs, IHapiTerminologyLoaderSvc.LOINC_URI, loincNumber, null);
// Part Properties // Part Properties

View File

@ -22,13 +22,17 @@ package ca.uhn.fhir.jpa.term.loinc;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept; import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IRecordHandler; import ca.uhn.fhir.jpa.term.IRecordHandler;
import ca.uhn.fhir.jpa.term.TerminologyLoaderSvcImpl; import ca.uhn.fhir.jpa.term.TerminologyLoaderSvcImpl;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.commons.csv.CSVRecord; import org.apache.commons.csv.CSVRecord;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.hl7.fhir.r4.model.CodeSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map; import java.util.Map;
import java.util.Set;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trim; import static org.apache.commons.lang3.StringUtils.trim;
@ -37,12 +41,14 @@ public class LoincHandler implements IRecordHandler {
private final Map<String, TermConcept> myCode2Concept; private final Map<String, TermConcept> myCode2Concept;
private final TermCodeSystemVersion myCodeSystemVersion; private final TermCodeSystemVersion myCodeSystemVersion;
private final Set<String> myPropertyNames; private final Map<String, CodeSystem.PropertyType> myPropertyNames;
private final Map<PartTypeAndPartName, String> myPartTypeAndPartNameToPartNumber;
public LoincHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, Set<String> thePropertyNames) { public LoincHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, Map<String, CodeSystem.PropertyType> thePropertyNames, Map<PartTypeAndPartName, String> thePartTypeAndPartNameToPartNumber) {
myCodeSystemVersion = theCodeSystemVersion; myCodeSystemVersion = theCodeSystemVersion;
myCode2Concept = theCode2concept; myCode2Concept = theCode2concept;
myPropertyNames = thePropertyNames; myPropertyNames = thePropertyNames;
myPartTypeAndPartNameToPartNumber = thePartTypeAndPartNameToPartNumber;
} }
@Override @Override
@ -64,13 +70,57 @@ public class LoincHandler implements IRecordHandler {
.setValue(shortName); .setValue(shortName);
} }
for (String nextPropertyName : myPropertyNames) { for (String nextPropertyName : myPropertyNames.keySet()) {
if (!theRecord.toMap().containsKey(nextPropertyName)) { if (!theRecord.toMap().containsKey(nextPropertyName)) {
continue; continue;
} }
CodeSystem.PropertyType nextPropertyType = myPropertyNames.get(nextPropertyName);
String nextPropertyValue = theRecord.get(nextPropertyName); String nextPropertyValue = theRecord.get(nextPropertyName);
if (isNotBlank(nextPropertyValue)) { if (isNotBlank(nextPropertyValue)) {
nextPropertyValue = trim(nextPropertyValue);
switch (nextPropertyType) {
case STRING:
concept.addPropertyString(nextPropertyName, nextPropertyValue); concept.addPropertyString(nextPropertyName, nextPropertyValue);
break;
case CODING:
PartTypeAndPartName key = new PartTypeAndPartName(nextPropertyName, nextPropertyValue);
String partNumber = myPartTypeAndPartNameToPartNumber.get(key);
if (partNumber == null && nextPropertyName.equals("TIME_ASPCT")) {
key = new PartTypeAndPartName("TIME", nextPropertyValue);
partNumber = myPartTypeAndPartNameToPartNumber.get(key);
}
if (partNumber == null && nextPropertyName.equals("METHOD_TYP")) {
key = new PartTypeAndPartName("METHOD", nextPropertyValue);
partNumber = myPartTypeAndPartNameToPartNumber.get(key);
}
if (partNumber == null && nextPropertyName.equals("SCALE_TYP")) {
key = new PartTypeAndPartName("SCALE", nextPropertyValue);
partNumber = myPartTypeAndPartNameToPartNumber.get(key);
}
if (partNumber == null && nextPropertyName.equals("SYSTEM") && nextPropertyValue.startsWith("^")) {
continue;
}
// Validate.notBlank(partNumber, "Unknown part: " + key);
if (isNotBlank(partNumber)) {
concept.addPropertyCoding(nextPropertyName, IHapiTerminologyLoaderSvc.LOINC_URI, partNumber, nextPropertyValue);
} else {
ourLog.warn("Unable to find part code with TYPE[{}] and NAME[{}]", key.getPartType(), key.getPartName());
}
break;
case CODE:
case INTEGER:
case BOOLEAN:
case DATETIME:
case NULL:
throw new InternalErrorException("Don't know how to handle LOINC property of type: " + nextPropertyType);
}
} }
} }
@ -78,5 +128,5 @@ public class LoincHandler implements IRecordHandler {
myCode2Concept.put(code, concept); myCode2Concept.put(code, concept);
} }
} }
private static final Logger ourLog = LoggerFactory.getLogger(LoincHandler.class);
} }

View File

@ -30,10 +30,11 @@ import org.hl7.fhir.r4.model.ValueSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import static org.apache.commons.lang3.StringUtils.trim; import static org.apache.commons.lang3.StringUtils.trim;
public class LoincIeeeMedicalDeviceCodeHandler extends BaseHandler implements IRecordHandler { public class LoincIeeeMedicalDeviceCodeHandler extends BaseLoincHandler implements IRecordHandler {
public static final String LOINC_IEEE_CM_ID = "LOINC-IEEE-MEDICAL-DEVICE-CM"; public static final String LOINC_IEEE_CM_ID = "LOINC-IEEE-MEDICAL-DEVICE-CM";
public static final String LOINC_IEEE_CM_URI = "http://loinc.org/fhir/loinc-ieee-device-code-mappings"; public static final String LOINC_IEEE_CM_URI = "http://loinc.org/fhir/loinc-ieee-device-code-mappings";
@ -43,8 +44,8 @@ public class LoincIeeeMedicalDeviceCodeHandler extends BaseHandler implements IR
/** /**
* Constructor * Constructor
*/ */
public LoincIeeeMedicalDeviceCodeHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) { public LoincIeeeMedicalDeviceCodeHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps, Properties theUploadProperties) {
super(theCode2concept, theValueSets, theConceptMaps); super(theCode2concept, theValueSets, theConceptMaps, theUploadProperties);
} }
@Override @Override

View File

@ -29,17 +29,18 @@ import org.hl7.fhir.r4.model.ValueSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import static org.apache.commons.lang3.StringUtils.trim; import static org.apache.commons.lang3.StringUtils.trim;
public class LoincImagingDocumentCodeHandler extends BaseHandler implements IRecordHandler { public class LoincImagingDocumentCodeHandler extends BaseLoincHandler implements IRecordHandler {
public static final String VS_ID = "loinc-imaging-document-codes"; public static final String VS_ID = "loinc-imaging-document-codes";
public static final String VS_URI = "http://loinc.org/fhir/loinc-imaging-document-codes"; public static final String VS_URI = "http://loinc.org/fhir/loinc-imaging-document-codes";
public static final String VS_NAME = "LOINC Imaging Document Codes"; public static final String VS_NAME = "LOINC Imaging Document Codes";
public LoincImagingDocumentCodeHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) { public LoincImagingDocumentCodeHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps, Properties theUploadProperties) {
super(theCode2concept, theValueSets, theConceptMaps); super(theCode2concept, theValueSets, theConceptMaps, theUploadProperties);
} }
@Override @Override
@ -47,7 +48,7 @@ public class LoincImagingDocumentCodeHandler extends BaseHandler implements IRec
String loincNumber = trim(theRecord.get("LOINC_NUM")); String loincNumber = trim(theRecord.get("LOINC_NUM"));
String displayName = trim(theRecord.get("LONG_COMMON_NAME")); String displayName = trim(theRecord.get("LONG_COMMON_NAME"));
ValueSet valueSet = getValueSet(VS_ID, VS_URI, VS_NAME); ValueSet valueSet = getValueSet(VS_ID, VS_URI, VS_NAME,null);
addCodeAsIncludeToValueSet(valueSet, IHapiTerminologyLoaderSvc.LOINC_URI, loincNumber, displayName); addCodeAsIncludeToValueSet(valueSet, IHapiTerminologyLoaderSvc.LOINC_URI, loincNumber, displayName);
} }

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept; import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.term.IRecordHandler; import ca.uhn.fhir.jpa.term.IRecordHandler;
import org.apache.commons.csv.CSVRecord; import org.apache.commons.csv.CSVRecord;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.model.ValueSet;
import java.util.HashMap; import java.util.HashMap;
@ -37,6 +38,7 @@ public class LoincPartHandler implements IRecordHandler {
private final Map<String, TermConcept> myCode2Concept; private final Map<String, TermConcept> myCode2Concept;
private final TermCodeSystemVersion myCodeSystemVersion; private final TermCodeSystemVersion myCodeSystemVersion;
private final Map<String, ValueSet> myIdToValueSet = new HashMap<>(); private final Map<String, ValueSet> myIdToValueSet = new HashMap<>();
private final Map<PartTypeAndPartName, String> myPartTypeAndPartNameToPartNumber = new HashMap<>();
public LoincPartHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept) { public LoincPartHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept) {
myCodeSystemVersion = theCodeSystemVersion; myCodeSystemVersion = theCodeSystemVersion;
@ -58,6 +60,10 @@ public class LoincPartHandler implements IRecordHandler {
// return; // return;
// } // }
PartTypeAndPartName partTypeAndPartName = new PartTypeAndPartName(partTypeName, partName);
String previousValue = myPartTypeAndPartNameToPartNumber.put(partTypeAndPartName, partNumber);
Validate.isTrue(previousValue == null, "Already had part: " + partTypeAndPartName);
TermConcept concept = myCode2Concept.get(partNumber); TermConcept concept = myCode2Concept.get(partNumber);
if (concept == null) { if (concept == null) {
concept = new TermConcept(myCodeSystemVersion, partNumber); concept = new TermConcept(myCodeSystemVersion, partNumber);
@ -74,4 +80,9 @@ public class LoincPartHandler implements IRecordHandler {
} }
public Map<PartTypeAndPartName, String> getPartTypeAndPartNameToPartNumber() {
return myPartTypeAndPartNameToPartNumber;
}
} }

View File

@ -32,22 +32,23 @@ import org.hl7.fhir.r4.model.ValueSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import static org.apache.commons.lang3.StringUtils.defaultString; import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.trim; import static org.apache.commons.lang3.StringUtils.trim;
public class LoincPartRelatedCodeMappingHandler extends BaseHandler implements IRecordHandler { public class LoincPartRelatedCodeMappingHandler extends BaseLoincHandler implements IRecordHandler {
public static final String LOINC_PART_MAP_ID = "LOINC-PART-MAP"; public static final String LOINC_SCT_PART_MAP_ID = "loinc-parts-to-snomed-ct";
public static final String LOINC_PART_MAP_URI = "http://loinc.org/cm/loinc-parts-to-snomed-ct"; public static final String LOINC_SCT_PART_MAP_URI = "http://loinc.org/cm/loinc-parts-to-snomed-ct";
public static final String LOINC_PART_MAP_NAME = "LOINC Part Map"; public static final String LOINC_SCT_PART_MAP_NAME = "LOINC Part Map to SNOMED CT";
private static final String CM_COPYRIGHT = "This content from LOINC® is copyright © 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at https://loinc.org/license/. The LOINC Part File, LOINC/SNOMED CT Expression Association and Map Sets File, RELMA database and associated search index files include SNOMED Clinical Terms (SNOMED CT®) which is used by permission of the International Health Terminology Standards Development Organisation (IHTSDO) under license. All rights are reserved. SNOMED CT® was originally created by The College of American Pathologists. “SNOMED” and “SNOMED CT” are registered trademarks of the IHTSDO. Use of SNOMED CT content is subject to the terms and conditions set forth in the SNOMED CT Affiliate License Agreement. It is the responsibility of those implementing this product to ensure they are appropriately licensed and for more information on the license, including how to register as an Affiliate Licensee, please refer to http://www.snomed.org/snomed-ct/get-snomed-ct or info@snomed.org. Under the terms of the Affiliate License, use of SNOMED CT in countries that are not IHTSDO Members is subject to reporting and fee payment obligations. However, IHTSDO agrees to waive the requirements to report and pay fees for use of SNOMED CT content included in the LOINC Part Mapping and LOINC Term Associations for purposes that support or enable more effective use of LOINC. This material includes content from the US Edition to SNOMED CT, which is developed and maintained by the U.S. National Library of Medicine and is available to authorized UMLS Metathesaurus Licensees from the UTS Downloads site at https://uts.nlm.nih.gov."; private static final String CM_COPYRIGHT = "This content from LOINC® is copyright © 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at https://loinc.org/license/. The LOINC Part File, LOINC/SNOMED CT Expression Association and Map Sets File, RELMA database and associated search index files include SNOMED Clinical Terms (SNOMED CT®) which is used by permission of the International Health Terminology Standards Development Organisation (IHTSDO) under license. All rights are reserved. SNOMED CT® was originally created by The College of American Pathologists. “SNOMED” and “SNOMED CT” are registered trademarks of the IHTSDO. Use of SNOMED CT content is subject to the terms and conditions set forth in the SNOMED CT Affiliate License Agreement. It is the responsibility of those implementing this product to ensure they are appropriately licensed and for more information on the license, including how to register as an Affiliate Licensee, please refer to http://www.snomed.org/snomed-ct/get-snomed-ct or info@snomed.org. Under the terms of the Affiliate License, use of SNOMED CT in countries that are not IHTSDO Members is subject to reporting and fee payment obligations. However, IHTSDO agrees to waive the requirements to report and pay fees for use of SNOMED CT content included in the LOINC Part Mapping and LOINC Term Associations for purposes that support or enable more effective use of LOINC. This material includes content from the US Edition to SNOMED CT, which is developed and maintained by the U.S. National Library of Medicine and is available to authorized UMLS Metathesaurus Licensees from the UTS Downloads site at https://uts.nlm.nih.gov.";
private final Map<String, TermConcept> myCode2Concept; private final Map<String, TermConcept> myCode2Concept;
private final TermCodeSystemVersion myCodeSystemVersion; private final TermCodeSystemVersion myCodeSystemVersion;
private final List<ConceptMap> myConceptMaps; private final List<ConceptMap> myConceptMaps;
public LoincPartRelatedCodeMappingHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) { public LoincPartRelatedCodeMappingHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps, Properties theUploadProperties) {
super(theCode2concept, theValueSets, theConceptMaps); super(theCode2concept, theValueSets, theConceptMaps, theUploadProperties);
myCodeSystemVersion = theCodeSystemVersion; myCodeSystemVersion = theCodeSystemVersion;
myCode2Concept = theCode2concept; myCode2Concept = theCode2concept;
myConceptMaps = theConceptMaps; myConceptMaps = theConceptMaps;
@ -86,11 +87,24 @@ public class LoincPartRelatedCodeMappingHandler extends BaseHandler implements I
throw new InternalErrorException("Unknown MapType '" + mapType + "' for PartNumber: " + partNumber); throw new InternalErrorException("Unknown MapType '" + mapType + "' for PartNumber: " + partNumber);
} }
String loincPartMapId;
String loincPartMapUri;
String loincPartMapName;
switch (extCodeSystem) {
case IHapiTerminologyLoaderSvc.SCT_URI:
loincPartMapId = LOINC_SCT_PART_MAP_ID;
loincPartMapUri = LOINC_SCT_PART_MAP_URI;
loincPartMapName = LOINC_SCT_PART_MAP_NAME;
break;
default:
throw new InternalErrorException("Don't know how to handle mapping to system: " + extCodeSystem);
}
addConceptMapEntry( addConceptMapEntry(
new ConceptMapping() new ConceptMapping()
.setConceptMapId(LOINC_PART_MAP_ID) .setConceptMapId(loincPartMapId)
.setConceptMapUri(LOINC_PART_MAP_URI) .setConceptMapUri(loincPartMapUri)
.setConceptMapName(LOINC_PART_MAP_NAME) .setConceptMapName(loincPartMapName)
.setSourceCodeSystem(IHapiTerminologyLoaderSvc.LOINC_URI) .setSourceCodeSystem(IHapiTerminologyLoaderSvc.LOINC_URI)
.setSourceCode(partNumber) .setSourceCode(partNumber)
.setSourceDisplay(partName) .setSourceDisplay(partName)

View File

@ -20,7 +20,6 @@ package ca.uhn.fhir.jpa.term.loinc;
* #L% * #L%
*/ */
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept; import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc; import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IRecordHandler; import ca.uhn.fhir.jpa.term.IRecordHandler;
@ -35,7 +34,7 @@ import java.util.*;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trim; import static org.apache.commons.lang3.StringUtils.trim;
public class LoincRsnaPlaybookHandler extends BaseHandler implements IRecordHandler { public class LoincRsnaPlaybookHandler extends BaseLoincHandler implements IRecordHandler {
public static final String RSNA_CODES_VS_ID = "loinc-rsna-radiology-playbook"; public static final String RSNA_CODES_VS_ID = "loinc-rsna-radiology-playbook";
public static final String RSNA_CODES_VS_URI = "http://loinc.org/vs/loinc-rsna-radiology-playbook"; public static final String RSNA_CODES_VS_URI = "http://loinc.org/vs/loinc-rsna-radiology-playbook";
@ -59,8 +58,6 @@ public class LoincRsnaPlaybookHandler extends BaseHandler implements IRecordHand
public static final String RPID_CS_URI = RID_CS_URI; public static final String RPID_CS_URI = RID_CS_URI;
private static final String CM_COPYRIGHT = "This content from LOINC® is copyright © 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at https://loinc.org/license/. The LOINC/RSNA Radiology Playbook and the LOINC Part File contain content from RadLex® (http://rsna.org/RadLex.aspx), copyright © 2005-2017, The Radiological Society of North America, Inc., available at no cost under the license at http://www.rsna.org/uploadedFiles/RSNA/Content/Informatics/RadLex_License_Agreement_and_Terms_of_Use_V2_Final.pdf."; private static final String CM_COPYRIGHT = "This content from LOINC® is copyright © 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at https://loinc.org/license/. The LOINC/RSNA Radiology Playbook and the LOINC Part File contain content from RadLex® (http://rsna.org/RadLex.aspx), copyright © 2005-2017, The Radiological Society of North America, Inc., available at no cost under the license at http://www.rsna.org/uploadedFiles/RSNA/Content/Informatics/RadLex_License_Agreement_and_Terms_of_Use_V2_Final.pdf.";
private final Map<String, TermConcept> myCode2Concept; private final Map<String, TermConcept> myCode2Concept;
private final TermCodeSystemVersion myCodeSystemVersion;
private final Set<String> myPropertyNames;
private final List<ValueSet> myValueSets; private final List<ValueSet> myValueSets;
private final Map<String, ValueSet> myIdToValueSet = new HashMap<>(); private final Map<String, ValueSet> myIdToValueSet = new HashMap<>();
private final Set<String> myCodesInRsnaPlaybookValueSet = new HashSet<>(); private final Set<String> myCodesInRsnaPlaybookValueSet = new HashSet<>();
@ -68,11 +65,9 @@ public class LoincRsnaPlaybookHandler extends BaseHandler implements IRecordHand
/** /**
* Constructor * Constructor
*/ */
public LoincRsnaPlaybookHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, Set<String> thePropertyNames, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) { public LoincRsnaPlaybookHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps, Properties theUploadProperties) {
super(theCode2concept, theValueSets, theConceptMaps); super(theCode2concept, theValueSets, theConceptMaps, theUploadProperties);
myCodeSystemVersion = theCodeSystemVersion;
myCode2Concept = theCode2concept; myCode2Concept = theCode2concept;
myPropertyNames = thePropertyNames;
myValueSets = theValueSets; myValueSets = theValueSets;
} }

View File

@ -26,6 +26,7 @@ import org.hl7.fhir.r4.model.ValueSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
public class LoincTop2000LabResultsSiHandler extends BaseLoincTop2000LabResultsHandler { public class LoincTop2000LabResultsSiHandler extends BaseLoincTop2000LabResultsHandler {
@ -33,8 +34,8 @@ public class LoincTop2000LabResultsSiHandler extends BaseLoincTop2000LabResultsH
public static final String TOP_2000_SI_VS_URI = "http://loinc.org/vs/top-2000-lab-observations-si"; public static final String TOP_2000_SI_VS_URI = "http://loinc.org/vs/top-2000-lab-observations-si";
public static final String TOP_2000_SI_VS_NAME = "Top 2000 Lab Results SI"; public static final String TOP_2000_SI_VS_NAME = "Top 2000 Lab Results SI";
public LoincTop2000LabResultsSiHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) { public LoincTop2000LabResultsSiHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps, Properties theUploadProperties) {
super(theCode2concept, theValueSets, TOP_2000_SI_VS_ID, TOP_2000_SI_VS_URI, TOP_2000_SI_VS_NAME, theConceptMaps); super(theCode2concept, theValueSets, TOP_2000_SI_VS_ID, TOP_2000_SI_VS_URI, TOP_2000_SI_VS_NAME, theConceptMaps, theUploadProperties);
} }

View File

@ -26,6 +26,7 @@ import org.hl7.fhir.r4.model.ValueSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
public class LoincTop2000LabResultsUsHandler extends BaseLoincTop2000LabResultsHandler { public class LoincTop2000LabResultsUsHandler extends BaseLoincTop2000LabResultsHandler {
@ -33,8 +34,8 @@ public class LoincTop2000LabResultsUsHandler extends BaseLoincTop2000LabResultsH
public static final String TOP_2000_US_VS_URI = "http://loinc.org/vs/top-2000-lab-observations-us"; public static final String TOP_2000_US_VS_URI = "http://loinc.org/vs/top-2000-lab-observations-us";
public static final String TOP_2000_US_VS_NAME = "Top 2000 Lab Results US"; public static final String TOP_2000_US_VS_NAME = "Top 2000 Lab Results US";
public LoincTop2000LabResultsUsHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) { public LoincTop2000LabResultsUsHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps, Properties theUploadProperties) {
super(theCode2concept, theValueSets, TOP_2000_US_VS_ID, TOP_2000_US_VS_URI, TOP_2000_US_VS_NAME, theConceptMaps); super(theCode2concept, theValueSets, TOP_2000_US_VS_ID, TOP_2000_US_VS_URI, TOP_2000_US_VS_NAME, theConceptMaps, theUploadProperties);
} }

View File

@ -31,14 +31,14 @@ import java.util.*;
import static org.apache.commons.lang3.StringUtils.trim; import static org.apache.commons.lang3.StringUtils.trim;
public class LoincUniversalOrderSetHandler extends BaseHandler implements IRecordHandler { public class LoincUniversalOrderSetHandler extends BaseLoincHandler implements IRecordHandler {
public static final String VS_ID = "loinc-universal-order-set-vs"; public static final String VS_ID = "loinc-universal-order-set-vs";
public static final String VS_URI = "http://loinc.org/fhir/loinc-universal-order-set"; public static final String VS_URI = "http://loinc.org/fhir/loinc-universal-order-set";
public static final String VS_NAME = "LOINC Universal Order Set"; public static final String VS_NAME = "LOINC Universal Order Set";
public LoincUniversalOrderSetHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) { public LoincUniversalOrderSetHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps, Properties theUploadProperties) {
super(theCode2concept, theValueSets, theConceptMaps); super(theCode2concept, theValueSets, theConceptMaps, theUploadProperties);
} }
@Override @Override
@ -47,7 +47,7 @@ public class LoincUniversalOrderSetHandler extends BaseHandler implements IRecor
String displayName = trim(theRecord.get("LONG_COMMON_NAME")); String displayName = trim(theRecord.get("LONG_COMMON_NAME"));
String orderObs = trim(theRecord.get("ORDER_OBS")); String orderObs = trim(theRecord.get("ORDER_OBS"));
ValueSet valueSet = getValueSet(VS_ID, VS_URI, VS_NAME); ValueSet valueSet = getValueSet(VS_ID, VS_URI, VS_NAME, null);
addCodeAsIncludeToValueSet(valueSet, IHapiTerminologyLoaderSvc.LOINC_URI, loincNumber, displayName); addCodeAsIncludeToValueSet(valueSet, IHapiTerminologyLoaderSvc.LOINC_URI, loincNumber, displayName);
} }

View File

@ -0,0 +1,57 @@
package ca.uhn.fhir.jpa.term.loinc;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
public class PartTypeAndPartName {
private final String myPartType;
private final String myPartName;
public PartTypeAndPartName(String thePartType, String thePartName) {
myPartType = thePartType;
myPartName = thePartName;
}
@Override
public boolean equals(Object theO) {
if (this == theO) {
return true;
}
if (theO == null || getClass() != theO.getClass()) {
return false;
}
PartTypeAndPartName that = (PartTypeAndPartName) theO;
return new EqualsBuilder()
.append(myPartType, that.myPartType)
.append(myPartName, that.myPartName)
.isEquals();
}
public String getPartName() {
return myPartName;
}
public String getPartType() {
return myPartType;
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(myPartType)
.append(myPartName)
.toHashCode();
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("partType", myPartType)
.append("partName", myPartName)
.toString();
}
}

View File

@ -4,8 +4,10 @@ import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem; import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test; import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import com.google.common.collect.Lists;
import org.hl7.fhir.convertors.VersionConvertor_30_40; import org.hl7.fhir.convertors.VersionConvertor_30_40;
import org.hl7.fhir.dstu3.model.*; import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
@ -14,13 +16,14 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertEquals; import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertThat; import static org.junit.Assert.*;
public class TerminologyLoaderSvcIntegrationDstu3Test extends BaseJpaDstu3Test { public class TerminologyLoaderSvcIntegrationDstu3Test extends BaseJpaDstu3Test {
@ -39,44 +42,14 @@ public class TerminologyLoaderSvcIntegrationDstu3Test extends BaseJpaDstu3Test {
myDaoConfig.setDeferIndexingForCodesystemsOfSize(20000); myDaoConfig.setDeferIndexingForCodesystemsOfSize(20000);
} }
@Test private <T extends Type> Optional<T> findProperty(Parameters theParameters, String thePropertyName) {
public void testExpandWithProperty() throws Exception { return theParameters
ZipCollectionBuilder files = new ZipCollectionBuilder(); .getParameter()
TerminologyLoaderSvcLoincTest.addLoincMandatoryFilesToZip(files); .stream()
TerminologyLoaderSvcLoincTest.addLoincOptionalFilesToZip(files); .filter(t -> t.getName().equals("property"))
myLoader.loadLoinc(files.getFiles(), mySrd); .filter(t -> ((PrimitiveType<?>) t.getPart().get(0).getValue()).getValueAsString().equals(thePropertyName))
.map(t -> (T) t.getPart().get(1).getValue())
ValueSet input = new ValueSet(); .findFirst();
input
.getCompose()
.addInclude()
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URI)
.addFilter()
.setProperty("SCALE_TYP")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("Ord");
ValueSet expanded = myValueSetDao.expand(input, null);
Set<String> codes = toExpandedCodes(expanded);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded));
assertThat(codes, containsInAnyOrder("1001-7", "61438-8"));
}
@Test
public void testLookupWithProperties() throws Exception {
ZipCollectionBuilder files = new ZipCollectionBuilder();
TerminologyLoaderSvcLoincTest.addLoincMandatoryFilesToZip(files);
TerminologyLoaderSvcLoincTest.addLoincOptionalFilesToZip(files);
myLoader.loadLoinc(files.getFiles(), mySrd);
IFhirResourceDaoCodeSystem.LookupCodeResult result = myCodeSystemDao.lookupCode(new StringType("10013-1"), new StringType(IHapiTerminologyLoaderSvc.LOINC_URI), null, mySrd);
org.hl7.fhir.r4.model.Parameters parametersR4 = result.toParameters();
Parameters parameters = VersionConvertor_30_40.convertParameters(parametersR4);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(parameters));
assertEquals("SYSTEM", this.<CodeType>getPropertyPart(parameters, "property", "code").get().getValueAsString());
assertEquals("Heart", this.<StringType>getPropertyPart(parameters, "property", "value").get().getValueAsString());
} }
private <T extends Type> Optional<T> getPropertyPart(Parameters theParameters, String thePropName, String thePart) { private <T extends Type> Optional<T> getPropertyPart(Parameters theParameters, String thePropName, String thePart) {
@ -90,6 +63,140 @@ public class TerminologyLoaderSvcIntegrationDstu3Test extends BaseJpaDstu3Test {
.findFirst(); .findFirst();
} }
@Test
public void testExpandWithPropertyCoding() throws Exception {
ZipCollectionBuilder files = new ZipCollectionBuilder();
TerminologyLoaderSvcLoincTest.addLoincMandatoryFilesToZip(files);
TerminologyLoaderSvcLoincTest.addLoincOptionalFilesToZip(files);
myLoader.loadLoinc(files.getFiles(), mySrd);
// Search by code
ValueSet input = new ValueSet();
input
.getCompose()
.addInclude()
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URI)
.addFilter()
.setProperty("SCALE_TYP")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("LP7753-9");
ValueSet expanded = myValueSetDao.expand(input, null);
Set<String> codes = toExpandedCodes(expanded);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded));
ourLog.info("Codes: {}", codes);
assertThat(codes, containsInAnyOrder("10019-8", "10013-1", "10014-9", "10016-4", "17788-1", "10000-8", "10017-2", "10015-6", "10020-6", "10018-0"));
// Search by display name
input = new ValueSet();
input
.getCompose()
.addInclude()
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URI)
.addFilter()
.setProperty("SCALE_TYP")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("Qn");
expanded = myValueSetDao.expand(input, null);
codes = toExpandedCodes(expanded);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded));
assertThat(codes, containsInAnyOrder("10019-8", "10013-1", "10014-9", "10016-4", "17788-1", "10000-8", "10017-2", "10015-6", "10020-6", "10018-0"));
// Search by something that doesn't match
input = new ValueSet();
input
.getCompose()
.addInclude()
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URI)
.addFilter()
.setProperty("SCALE_TYP")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("Qn999");
expanded = myValueSetDao.expand(input, null);
codes = toExpandedCodes(expanded);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded));
assertThat(codes, empty());
}
@Test
public void testExpandWithPropertyString() throws Exception {
ZipCollectionBuilder files = new ZipCollectionBuilder();
TerminologyLoaderSvcLoincTest.addLoincMandatoryFilesToZip(files);
TerminologyLoaderSvcLoincTest.addLoincOptionalFilesToZip(files);
myLoader.loadLoinc(files.getFiles(), mySrd);
ValueSet input = new ValueSet();
input
.getCompose()
.addInclude()
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URI)
.addFilter()
.setProperty("CLASS")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("EKG.MEAS");
ValueSet expanded = myValueSetDao.expand(input, null);
Set<String> codes = toExpandedCodes(expanded);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded));
ourLog.info("Codes: {}", codes);
assertThat(codes, containsInAnyOrder("10019-8", "10013-1", "10014-9", "10000-8", "10016-4", "10017-2", "10015-6", "10020-6", "10018-0"));
}
@Test
public void testLookupWithProperties() throws Exception {
ZipCollectionBuilder files = new ZipCollectionBuilder();
TerminologyLoaderSvcLoincTest.addLoincMandatoryFilesToZip(files);
TerminologyLoaderSvcLoincTest.addLoincOptionalFilesToZip(files);
myLoader.loadLoinc(files.getFiles(), mySrd);
IFhirResourceDaoCodeSystem.LookupCodeResult result = myCodeSystemDao.lookupCode(new StringType("10013-1"), new StringType(IHapiTerminologyLoaderSvc.LOINC_URI), null, mySrd);
org.hl7.fhir.r4.model.Parameters parametersR4 = result.toParameters(null);
Parameters parameters = VersionConvertor_30_40.convertParameters(parametersR4);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(parameters));
Optional<Coding> propertyValue = findProperty(parameters, "SCALE_TYP");
assertTrue(propertyValue.isPresent());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, propertyValue.get().getSystem());
assertEquals("LP7753-9", propertyValue.get().getCode());
assertEquals("Qn", propertyValue.get().getDisplay());
propertyValue = findProperty(parameters, "COMPONENT");
assertTrue(propertyValue.isPresent());
Optional<StringType> propertyValueString = findProperty(parameters, "ORDER_OBS");
assertTrue(propertyValueString.isPresent());
assertEquals("Observation", propertyValueString.get().getValue());
propertyValueString = findProperty(parameters, "CLASSTYPE");
assertTrue(propertyValueString.isPresent());
assertEquals("2", propertyValueString.get().getValue());
}
@Test
public void testLookupWithPropertiesExplicit() throws Exception {
ZipCollectionBuilder files = new ZipCollectionBuilder();
TerminologyLoaderSvcLoincTest.addLoincMandatoryFilesToZip(files);
TerminologyLoaderSvcLoincTest.addLoincOptionalFilesToZip(files);
myLoader.loadLoinc(files.getFiles(), mySrd);
IFhirResourceDaoCodeSystem.LookupCodeResult result = myCodeSystemDao.lookupCode(new StringType("10013-1"), new StringType(IHapiTerminologyLoaderSvc.LOINC_URI), null, mySrd);
List<? extends IPrimitiveType<String>> properties = Lists.newArrayList(new CodeType("SCALE_TYP"));
org.hl7.fhir.r4.model.Parameters parametersR4 = result.toParameters(properties);
Parameters parameters = VersionConvertor_30_40.convertParameters(parametersR4);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(parameters));
Optional<Coding> propertyValueCoding = findProperty(parameters, "SCALE_TYP");
assertTrue(propertyValueCoding.isPresent());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, propertyValueCoding.get().getSystem());
assertEquals("LP7753-9", propertyValueCoding.get().getCode());
assertEquals("Qn", propertyValueCoding.get().getDisplay());
propertyValueCoding = findProperty(parameters, "COMPONENT");
assertFalse(propertyValueCoding.isPresent());
}
private Set<String> toExpandedCodes(ValueSet theExpanded) { private Set<String> toExpandedCodes(ValueSet theExpanded) {
return theExpanded return theExpanded
.getExpansion() .getExpansion()

View File

@ -110,8 +110,10 @@ public class TerminologyLoaderSvcLoincTest {
// Normal loinc code // Normal loinc code
code = concepts.get("10013-1"); code = concepts.get("10013-1");
assertEquals("10013-1", code.getCode()); assertEquals("10013-1", code.getCode());
assertEquals("Elpot", code.getStringProperty("PROPERTY")); assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, code.getCodingProperties("PROPERTY").get(0).getSystem());
assertEquals("Pt", code.getStringProperty("TIME_ASPCT")); assertEquals("LP6802-5", code.getCodingProperties("PROPERTY").get(0).getCode());
assertEquals("Elpot", code.getCodingProperties("PROPERTY").get(0).getDisplay());
assertEquals("EKG.MEAS", code.getStringProperty("CLASS"));
assertEquals("R' wave amplitude in lead I", code.getDisplay()); assertEquals("R' wave amplitude in lead I", code.getDisplay());
// Loinc code with answer // Loinc code with answer
@ -135,10 +137,11 @@ public class TerminologyLoaderSvcLoincTest {
// AnswerList valueSet // AnswerList valueSet
vs = valueSets.get("LL1001-8"); vs = valueSets.get("LL1001-8");
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, vs.getIdentifier().get(0).getSystem()); assertEquals("Beta.1", vs.getVersion());
assertEquals("LL1001-8", vs.getIdentifier().get(0).getValue()); assertEquals("urn:ietf:rfc:3986", vs.getIdentifier().get(0).getSystem());
assertEquals("urn:oid:1.3.6.1.4.1.12009.10.1.166", vs.getIdentifier().get(0).getValue());
assertEquals("PhenX05_14_30D freq amts", vs.getName()); assertEquals("PhenX05_14_30D freq amts", vs.getName());
assertEquals("urn:oid:1.3.6.1.4.1.12009.10.1.166", vs.getUrl()); assertEquals("http://loinc.org/vs/LL1001-8", vs.getUrl());
assertEquals(1, vs.getCompose().getInclude().size()); assertEquals(1, vs.getCompose().getInclude().size());
assertEquals(7, vs.getCompose().getInclude().get(0).getConcept().size()); assertEquals(7, vs.getCompose().getInclude().get(0).getConcept().size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, vs.getCompose().getInclude().get(0).getSystem()); assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, vs.getCompose().getInclude().get(0).getSystem());
@ -151,10 +154,12 @@ public class TerminologyLoaderSvcLoincTest {
assertEquals("adjusted for maternal weight", code.getDisplay()); assertEquals("adjusted for maternal weight", code.getDisplay());
// Part Mappings // Part Mappings
conceptMap = conceptMaps.get(LoincPartRelatedCodeMappingHandler.LOINC_PART_MAP_ID); conceptMap = conceptMaps.get(LoincPartRelatedCodeMappingHandler.LOINC_SCT_PART_MAP_ID);
assertEquals(null, conceptMap.getSource()); assertEquals(null, conceptMap.getSource());
assertEquals(null, conceptMap.getTarget()); assertEquals(null, conceptMap.getTarget());
assertEquals("This material includes SNOMED Clinical Terms® (SNOMED CT®) which is used by permission of the International Health Terminology Standards Development Organisation (IHTSDO) under license. All rights reserved. SNOMED CT® was originally created by The College of American Pathologists. “SNOMED” and “SNOMED CT” are registered trademarks of the IHTSDO.This material includes content from the US Edition to SNOMED CT, which is developed and maintained by the U.S. National Library of Medicine and is available to authorized UMLS Metathesaurus Licensees from the UTS Downloads site at https://uts.nlm.nih.gov.Use of SNOMED CT content is subject to the terms and conditions set forth in the SNOMED CT Affiliate License Agreement. It is the responsibility of those implementing this product to ensure they are appropriately licensed and for more information on the license, including how to register as an Affiliate Licensee, please refer to http://www.snomed.org/snomed-ct/get-snomed-ct or info@snomed.org<mailto:info@snomed.org>. This may incur a fee in SNOMED International non-Member countries.", conceptMap.getCopyright()); assertEquals(LoincPartRelatedCodeMappingHandler.LOINC_SCT_PART_MAP_URI, conceptMap.getUrl());
assertEquals("This content from LOINC® is copyright © 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at https://loinc.org/license/. The LOINC Part File, LOINC/SNOMED CT Expression Association and Map Sets File, RELMA database and associated search index files include SNOMED Clinical Terms (SNOMED CT®) which is used by permission of the International Health Terminology Standards Development Organisation (IHTSDO) under license. All rights are reserved. SNOMED CT® was originally created by The College of American Pathologists. “SNOMED” and “SNOMED CT” are registered trademarks of the IHTSDO. Use of SNOMED CT content is subject to the terms and conditions set forth in the SNOMED CT Affiliate License Agreement. It is the responsibility of those implementing this product to ensure they are appropriately licensed and for more information on the license, including how to register as an Affiliate Licensee, please refer to http://www.snomed.org/snomed-ct/get-snomed-ct or info@snomed.org. Under the terms of the Affiliate License, use of SNOMED CT in countries that are not IHTSDO Members is subject to reporting and fee payment obligations. However, IHTSDO agrees to waive the requirements to report and pay fees for use of SNOMED CT content included in the LOINC Part Mapping and LOINC Term Associations for purposes that support or enable more effective use of LOINC. This material includes content from the US Edition to SNOMED CT, which is developed and maintained by the U.S. National Library of Medicine and is available to authorized UMLS Metathesaurus Licensees from the UTS Downloads site at https://uts.nlm.nih.gov.", conceptMap.getCopyright());
assertEquals("Beta.1", conceptMap.getVersion());
assertEquals(1, conceptMap.getGroup().size()); assertEquals(1, conceptMap.getGroup().size());
group = conceptMap.getGroup().get(0); group = conceptMap.getGroup().get(0);
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, group.getSource()); assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, group.getSource());
@ -320,9 +325,6 @@ public class TerminologyLoaderSvcLoincTest {
// Normal loinc code // Normal loinc code
TermConcept code = concepts.get("10013-1"); TermConcept code = concepts.get("10013-1");
assertEquals("10013-1", code.getCode()); assertEquals("10013-1", code.getCode());
assertEquals("Elpot", code.getStringProperty("PROPERTY"));
assertEquals("Pt", code.getStringProperty("TIME_ASPCT"));
assertEquals("R' wave amplitude in lead I", code.getDisplay());
// No valuesets or conceptmaps get created // No valuesets or conceptmaps get created
assertThat(valueSets.keySet(), empty()); assertThat(valueSets.keySet(), empty());
@ -350,6 +352,7 @@ public class TerminologyLoaderSvcLoincTest {
} }
static void addLoincOptionalFilesToZip(ZipCollectionBuilder theFiles) throws IOException { static void addLoincOptionalFilesToZip(ZipCollectionBuilder theFiles) throws IOException {
theFiles.addFileZip("/loinc/", "loincupload.properties");
theFiles.addFileZip("/loinc/", "AnswerList_Beta_1.csv", TerminologyLoaderSvcImpl.LOINC_ANSWERLIST_FILE); theFiles.addFileZip("/loinc/", "AnswerList_Beta_1.csv", TerminologyLoaderSvcImpl.LOINC_ANSWERLIST_FILE);
theFiles.addFileZip("/loinc/", TerminologyLoaderSvcImpl.LOINC_ANSWERLIST_LINK_FILE, TerminologyLoaderSvcImpl.LOINC_ANSWERLIST_LINK_FILE); theFiles.addFileZip("/loinc/", TerminologyLoaderSvcImpl.LOINC_ANSWERLIST_LINK_FILE, TerminologyLoaderSvcImpl.LOINC_ANSWERLIST_LINK_FILE);
theFiles.addFileZip("/loinc/", TerminologyLoaderSvcImpl.LOINC_PART_FILE, TerminologyLoaderSvcImpl.LOINC_PART_FILE); theFiles.addFileZip("/loinc/", TerminologyLoaderSvcImpl.LOINC_PART_FILE, TerminologyLoaderSvcImpl.LOINC_PART_FILE);

View File

@ -8,3 +8,33 @@
"LP173484-9","ADJUSTMENT","W hyperextension)",,"ACTIVE" "LP173484-9","ADJUSTMENT","W hyperextension)",,"ACTIVE"
"LP6244-0","METHOD","EKG","Electrocardiogram (EKG)","ACTIVE" "LP6244-0","METHOD","EKG","Electrocardiogram (EKG)","ACTIVE"
"LP18172-4","COMPONENT","Interferon.beta","Interferon beta","ACTIVE" "LP18172-4","COMPONENT","Interferon.beta","Interferon beta","ACTIVE"
"LP7289-4","SYSTEM","Heart","Heart","ACTIVE"
"LP6960-1","TIME","Pt","Point in time (spot)","ACTIVE"
"LP6802-5","PROPERTY","Elpot","Electrical Potential (Voltage)","ACTIVE"
"LP7753-9","SCALE","Qn","Qn","ACTIVE"
"LP31101-6","COMPONENT","R' wave amplitude.lead I","R' wave amplitude.lead I","ACTIVE"
"LP31102-4","COMPONENT","R' wave amplitude.lead II","R' wave amplitude.lead II","ACTIVE"
"LP31103-2","COMPONENT","R' wave amplitude.lead III","R' wave amplitude.lead III","ACTIVE"
"LP31104-0","COMPONENT","R' wave amplitude.lead V1","R' wave amplitude.lead V1","ACTIVE"
"LP31105-7","COMPONENT","R' wave amplitude.lead V2","R' wave amplitude.lead V2","ACTIVE"
"LP31106-5","COMPONENT","R' wave amplitude.lead V3","R' wave amplitude.lead V3","ACTIVE"
"LP31107-3","COMPONENT","R' wave amplitude.lead V4","R' wave amplitude.lead V4","ACTIVE"
"LP31108-1","COMPONENT","R' wave amplitude.lead V5","R' wave amplitude.lead V5","ACTIVE"
"LP31109-9","COMPONENT","R' wave amplitude.lead V6","R' wave amplitude.lead V6","ACTIVE"
"LP31110-7","COMPONENT","R' wave duration.lead AVF","R' wave duration.lead AVF","ACTIVE"
"LP30269-2","SYSTEM","Ser/Plas^donor",,"ACTIVE"
"LP149220-8","PROPERTY","Pr","Presence","ACTIVE"
"LP7751-3","SCALE","Ord","Ord","ACTIVE"
"LP37904-7","COMPONENT","DBG Ab","DBG Ab","ACTIVE"
"LP6813-2","PROPERTY","Find","Finding","ACTIVE"
"LP95333-8","METHOD","PhenX","PhenX","ACTIVE"
"LP102627-9","COMPONENT","Each time you ate bread, toast or dinner rolls, how much did you usually eat in the past 30D","Each time you ate bread, toast or dinner rolls, how much did you usually eat in the past 30 days","ACTIVE"
"LP6879-3","PROPERTY","Time","Time (e.g. seconds)","ACTIVE"
"LP31088-5","COMPONENT","R wave duration.lead AVR","R wave duration.lead AVR","ACTIVE"
"LP206647-2","SYSTEM","Neck>Thyroid gland","Thyroid gland","ACTIVE"
"LP208655-3","METHOD","NM","NM","ACTIVE"
"LP32888-7","SCALE","Doc","Doc","ACTIVE"
"LP31534-8","COMPONENT","Study report","Study report","ACTIVE"
"LP7057-5","SYSTEM","Bld","Blood","ACTIVE"
"LP6838-9","PROPERTY","NFr","Number Fraction","ACTIVE"
"LP6141-8","METHOD","Automated count","Automated count","ACTIVE"

1 PartNumber PartTypeName PartName PartDisplayName Status
8 LP173484-9 ADJUSTMENT W hyperextension) ACTIVE
9 LP6244-0 METHOD EKG Electrocardiogram (EKG) ACTIVE
10 LP18172-4 COMPONENT Interferon.beta Interferon beta ACTIVE
11 LP7289-4 SYSTEM Heart Heart ACTIVE
12 LP6960-1 TIME Pt Point in time (spot) ACTIVE
13 LP6802-5 PROPERTY Elpot Electrical Potential (Voltage) ACTIVE
14 LP7753-9 SCALE Qn Qn ACTIVE
15 LP31101-6 COMPONENT R' wave amplitude.lead I R' wave amplitude.lead I ACTIVE
16 LP31102-4 COMPONENT R' wave amplitude.lead II R' wave amplitude.lead II ACTIVE
17 LP31103-2 COMPONENT R' wave amplitude.lead III R' wave amplitude.lead III ACTIVE
18 LP31104-0 COMPONENT R' wave amplitude.lead V1 R' wave amplitude.lead V1 ACTIVE
19 LP31105-7 COMPONENT R' wave amplitude.lead V2 R' wave amplitude.lead V2 ACTIVE
20 LP31106-5 COMPONENT R' wave amplitude.lead V3 R' wave amplitude.lead V3 ACTIVE
21 LP31107-3 COMPONENT R' wave amplitude.lead V4 R' wave amplitude.lead V4 ACTIVE
22 LP31108-1 COMPONENT R' wave amplitude.lead V5 R' wave amplitude.lead V5 ACTIVE
23 LP31109-9 COMPONENT R' wave amplitude.lead V6 R' wave amplitude.lead V6 ACTIVE
24 LP31110-7 COMPONENT R' wave duration.lead AVF R' wave duration.lead AVF ACTIVE
25 LP30269-2 SYSTEM Ser/Plas^donor ACTIVE
26 LP149220-8 PROPERTY Pr Presence ACTIVE
27 LP7751-3 SCALE Ord Ord ACTIVE
28 LP37904-7 COMPONENT DBG Ab DBG Ab ACTIVE
29 LP6813-2 PROPERTY Find Finding ACTIVE
30 LP95333-8 METHOD PhenX PhenX ACTIVE
31 LP102627-9 COMPONENT Each time you ate bread, toast or dinner rolls, how much did you usually eat in the past 30D Each time you ate bread, toast or dinner rolls, how much did you usually eat in the past 30 days ACTIVE
32 LP6879-3 PROPERTY Time Time (e.g. seconds) ACTIVE
33 LP31088-5 COMPONENT R wave duration.lead AVR R wave duration.lead AVR ACTIVE
34 LP206647-2 SYSTEM Neck>Thyroid gland Thyroid gland ACTIVE
35 LP208655-3 METHOD NM NM ACTIVE
36 LP32888-7 SCALE Doc Doc ACTIVE
37 LP31534-8 COMPONENT Study report Study report ACTIVE
38 LP7057-5 SYSTEM Bld Blood ACTIVE
39 LP6838-9 PROPERTY NFr Number Fraction ACTIVE
40 LP6141-8 METHOD Automated count Automated count ACTIVE

View File

@ -0,0 +1,7 @@
# This is the version identifier for the AnswerList file
answerlist.version=Beta.1
# This is the version identifier for uploaded ConceptMap resources
conceptmap.version=Beta.1