Initial changes to support multiple versions for code system.
This commit is contained in:
parent
63ef2ce006
commit
d39348d7bd
|
@ -183,6 +183,24 @@ public interface IValidationSupport {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates that the given code exists and if possible returns a display
|
||||||
|
* name. This method is called to check codes which are found in "example"
|
||||||
|
* binding fields (e.g. <code>Observation.code</code> in the default profile.
|
||||||
|
*
|
||||||
|
* @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to
|
||||||
|
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||||
|
* @param theOptions Provides options controlling the validation
|
||||||
|
* @param theCodeSystem The code system, e.g. "<code>http://loinc.org</code>"
|
||||||
|
* @param theCode The code, e.g. "<code>1234-5</code>"
|
||||||
|
* @param theDisplay The display name, if it should also be validated
|
||||||
|
* @param theSystemVersion The code system version.
|
||||||
|
* @return Returns a validation result object
|
||||||
|
*/
|
||||||
|
default CodeValidationResult validateCode(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl, String theSystemVersion) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates that the given code exists and if possible returns a display
|
* Validates that the given code exists and if possible returns a display
|
||||||
* name. This method is called to check codes which are found in "example"
|
* name. This method is called to check codes which are found in "example"
|
||||||
|
@ -212,6 +230,19 @@ public interface IValidationSupport {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up a code using the system, system version and code value
|
||||||
|
*
|
||||||
|
* @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to
|
||||||
|
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||||
|
* @param theSystem The CodeSystem URL
|
||||||
|
* @param theCode The code
|
||||||
|
* @param theSystemVersion The CodeSystem version
|
||||||
|
*/
|
||||||
|
default LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode, String theSystemVersion) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns <code>true</code> if the given valueset can be validated by the given
|
* Returns <code>true</code> if the given valueset can be validated by the given
|
||||||
* validation support module
|
* validation support module
|
||||||
|
|
|
@ -227,6 +227,11 @@ public class DaoConfig {
|
||||||
*/
|
*/
|
||||||
private boolean myPreloadBlobFromInputStream = false;
|
private boolean myPreloadBlobFromInputStream = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 5.1.0
|
||||||
|
*/
|
||||||
|
private boolean myMultipleCodeSystemVersionsEnabled = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
|
@ -2126,4 +2131,34 @@ public class DaoConfig {
|
||||||
myPreloadBlobFromInputStream = thePreloadBlobFromInputStream;
|
myPreloadBlobFromInputStream = thePreloadBlobFromInputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* This determines whether multiple code system versions will be enabled. If not enabled, existing code systems will be
|
||||||
|
* deleted when a new version is uploaded.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The default value for this setting is {@code false}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*/
|
||||||
|
public boolean isMultipleCodeSystemVersionsEnabled() {
|
||||||
|
return myMultipleCodeSystemVersionsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* This determines whether multiple code system versions will be enabled. If not enabled, existing code systems will be
|
||||||
|
* deleted when a new version is uploaded.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The default value for this setting is {@code false}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*/
|
||||||
|
public void setMultipleCodeSystemVersionsEnabled(Boolean theMultipleCodeSystemVersionsEnabled) {
|
||||||
|
myMultipleCodeSystemVersionsEnabled = theMultipleCodeSystemVersionsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,11 @@ public interface IFhirResourceDaoCodeSystem<T extends IBaseResource, CD, CC> ext
|
||||||
|
|
||||||
SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, CD theCodingA, CD theCodingB, RequestDetails theRequestDetails);
|
SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, CD theCodingA, CD theCodingB, RequestDetails theRequestDetails);
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, CD theCoding, IPrimitiveType<String> theVersion, RequestDetails theRequestDetails);
|
||||||
|
|
||||||
|
SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, CD theCodingA, CD theCodingB, IPrimitiveType<String> theVersion, RequestDetails theRequestDetails);
|
||||||
|
|
||||||
class SubsumesResult {
|
class SubsumesResult {
|
||||||
|
|
||||||
private final ConceptSubsumptionOutcome myOutcome;
|
private final ConceptSubsumptionOutcome myOutcome;
|
||||||
|
|
|
@ -48,6 +48,7 @@ import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
|
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
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.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
|
||||||
|
@ -235,6 +236,12 @@ public class FhirResourceDaoValueSetDstu2 extends BaseHapiFhirResourceDao<ValueS
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, CodingDt theCoding, IPrimitiveType<String> theVersion, RequestDetails theRequestDetails) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, CodingDt theCoding, RequestDetails theRequest) {
|
public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, CodingDt theCoding, RequestDetails theRequest) {
|
||||||
boolean haveCoding = theCoding != null && isNotBlank(theCoding.getSystem()) && isNotBlank(theCoding.getCode());
|
boolean haveCoding = theCoding != null && isNotBlank(theCoding.getSystem()) && isNotBlank(theCoding.getCode());
|
||||||
|
@ -280,6 +287,11 @@ public class FhirResourceDaoValueSetDstu2 extends BaseHapiFhirResourceDao<ValueS
|
||||||
return myTerminologySvc.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB);
|
return myTerminologySvc.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, CodingDt theCodingA, CodingDt theCodingB, IPrimitiveType<String> theVersion, RequestDetails theRequestDetails) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void postConstruct() {
|
public void postConstruct() {
|
||||||
|
|
|
@ -35,9 +35,19 @@ public interface ITermCodeSystemVersionDao extends JpaRepository<TermCodeSystemV
|
||||||
@Query("DELETE FROM TermCodeSystemVersion csv WHERE csv.myCodeSystem = :cs")
|
@Query("DELETE FROM TermCodeSystemVersion csv WHERE csv.myCodeSystem = :cs")
|
||||||
void deleteForCodeSystem(@Param("cs") TermCodeSystem theCodeSystem);
|
void deleteForCodeSystem(@Param("cs") TermCodeSystem theCodeSystem);
|
||||||
|
|
||||||
|
@Modifying
|
||||||
|
@Query("DELETE FROM TermCodeSystemVersion csv WHERE csv.myId = :pid")
|
||||||
|
void delete(@Param("pid") Long codesystemversion_pid);
|
||||||
|
|
||||||
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myCodeSystemPid = :codesystem_pid")
|
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myCodeSystemPid = :codesystem_pid")
|
||||||
List<TermCodeSystemVersion> findByCodeSystemPid(@Param("codesystem_pid") Long theCodeSystemPid);
|
List<TermCodeSystemVersion> findByCodeSystemPid(@Param("codesystem_pid") Long theCodeSystemPid);
|
||||||
|
|
||||||
|
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myCodeSystemPid = :codesystem_pid AND cs.myCodeSystemVersionId = :codesystem_version_id")
|
||||||
|
TermCodeSystemVersion findByCodeSystemPidAndVersion(@Param("codesystem_pid") Long theCodeSystemPid, @Param("codesystem_version_id") String theCodeSystemVersionId);
|
||||||
|
|
||||||
|
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myCodeSystemPid = :codesystem_pid AND cs.myCodeSystemVersionId IS NULL")
|
||||||
|
TermCodeSystemVersion findByCodeSystemPidVersionIsNull(@Param("codesystem_pid") Long theCodeSystemPid);
|
||||||
|
|
||||||
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myResourcePid = :resource_id")
|
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myResourcePid = :resource_id")
|
||||||
List<TermCodeSystemVersion> findByCodeSystemResourcePid(@Param("resource_id") Long theCodeSystemResourcePid);
|
List<TermCodeSystemVersion> findByCodeSystemResourcePid(@Param("resource_id") Long theCodeSystemResourcePid);
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ import org.hl7.fhir.dstu3.model.Coding;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
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.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
@ -86,9 +87,15 @@ public class FhirResourceDaoCodeSystemDstu3 extends BaseHapiFhirResourceDao<Code
|
||||||
return valueSetIds;
|
return valueSetIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, Coding theCoding, RequestDetails theRequestDetails) {
|
public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, Coding theCoding, RequestDetails theRequestDetails) {
|
||||||
|
return lookupCode(theCode, theSystem, theCoding, null, theRequestDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, Coding theCoding, IPrimitiveType<String> theVersion, RequestDetails theRequestDetails) {
|
||||||
boolean haveCoding = theCoding != null && isNotBlank(theCoding.getSystem()) && isNotBlank(theCoding.getCode());
|
boolean haveCoding = theCoding != null && isNotBlank(theCoding.getSystem()) && isNotBlank(theCoding.getCode());
|
||||||
boolean haveCode = theCode != null && theCode.isEmpty() == false;
|
boolean haveCode = theCode != null && theCode.isEmpty() == false;
|
||||||
boolean haveSystem = theSystem != null && theSystem.isEmpty() == false;
|
boolean haveSystem = theSystem != null && theSystem.isEmpty() == false;
|
||||||
|
@ -109,12 +116,16 @@ public class FhirResourceDaoCodeSystemDstu3 extends BaseHapiFhirResourceDao<Code
|
||||||
code = theCode.getValue();
|
code = theCode.getValue();
|
||||||
system = theSystem.getValue();
|
system = theSystem.getValue();
|
||||||
}
|
}
|
||||||
|
String codeSystemVersion = null;
|
||||||
|
if (theVersion != null) {
|
||||||
|
codeSystemVersion = theVersion.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
ourLog.debug("Looking up {} / {}", system, code);
|
ourLog.info("Looking up {} / {}, version {}", system, code, codeSystemVersion);
|
||||||
|
|
||||||
if (myValidationSupport.isCodeSystemSupported(new ValidationSupportContext(myValidationSupport), system)) {
|
if (myValidationSupport.isCodeSystemSupported(new ValidationSupportContext(myValidationSupport), system)) {
|
||||||
ourLog.debug("Code system {} is supported", system);
|
ourLog.debug("Code system {} is supported", system);
|
||||||
IValidationSupport.LookupCodeResult result = myValidationSupport.lookupCode(new ValidationSupportContext(myValidationSupport), system, code);
|
IValidationSupport.LookupCodeResult result = myValidationSupport.lookupCode(new ValidationSupportContext(myValidationSupport), system, code, codeSystemVersion);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -124,6 +135,11 @@ public class FhirResourceDaoCodeSystemDstu3 extends BaseHapiFhirResourceDao<Code
|
||||||
return IValidationSupport.LookupCodeResult.notFound(system, code);
|
return IValidationSupport.LookupCodeResult.notFound(system, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, Coding theCodingA, Coding theCodingB, IPrimitiveType<String> theVersion, RequestDetails theRequestDetails) {
|
||||||
|
return myTerminologySvc.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB, theVersion);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, Coding theCodingA, Coding theCodingB, RequestDetails theRequestDetails) {
|
public SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, Coding theCodingA, Coding theCodingB, RequestDetails theRequestDetails) {
|
||||||
return myTerminologySvc.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB);
|
return myTerminologySvc.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB);
|
||||||
|
|
|
@ -44,6 +44,7 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.hl7.fhir.r4.model.CodeSystem;
|
import org.hl7.fhir.r4.model.CodeSystem;
|
||||||
import org.hl7.fhir.r4.model.CodeableConcept;
|
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||||
import org.hl7.fhir.r4.model.Coding;
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
@ -81,9 +82,15 @@ public class FhirResourceDaoCodeSystemR4 extends BaseHapiFhirResourceDao<CodeSys
|
||||||
return valueSetIds;
|
return valueSetIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, Coding theCoding, RequestDetails theRequestDetails) {
|
public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, Coding theCoding, RequestDetails theRequestDetails) {
|
||||||
|
return lookupCode(theCode, theSystem, theCoding, null, theRequestDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, Coding theCoding, IPrimitiveType<String> theVersion, RequestDetails theRequestDetails) {
|
||||||
boolean haveCoding = theCoding != null && isNotBlank(theCoding.getSystem()) && isNotBlank(theCoding.getCode());
|
boolean haveCoding = theCoding != null && isNotBlank(theCoding.getSystem()) && isNotBlank(theCoding.getCode());
|
||||||
boolean haveCode = theCode != null && theCode.isEmpty() == false;
|
boolean haveCode = theCode != null && theCode.isEmpty() == false;
|
||||||
boolean haveSystem = theSystem != null && theSystem.isEmpty() == false;
|
boolean haveSystem = theSystem != null && theSystem.isEmpty() == false;
|
||||||
|
@ -104,13 +111,17 @@ public class FhirResourceDaoCodeSystemR4 extends BaseHapiFhirResourceDao<CodeSys
|
||||||
code = theCode.getValue();
|
code = theCode.getValue();
|
||||||
system = theSystem.getValue();
|
system = theSystem.getValue();
|
||||||
}
|
}
|
||||||
|
String codeSystemVersion = null;
|
||||||
|
if (theVersion != null) {
|
||||||
|
codeSystemVersion = theVersion.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
ourLog.debug("Looking up {} / {}", system, code);
|
ourLog.info("Looking up {} / {}, version {}", system, code, codeSystemVersion);
|
||||||
|
|
||||||
if (myValidationSupport.isCodeSystemSupported(new ValidationSupportContext(myValidationSupport), system)) {
|
if (myValidationSupport.isCodeSystemSupported(new ValidationSupportContext(myValidationSupport), system)) {
|
||||||
|
|
||||||
ourLog.debug("Code system {} is supported", system);
|
ourLog.debug("Code system {} is supported", system);
|
||||||
IValidationSupport.LookupCodeResult retVal = myValidationSupport.lookupCode(new ValidationSupportContext(myValidationSupport), system, code);
|
IValidationSupport.LookupCodeResult retVal = myValidationSupport.lookupCode(new ValidationSupportContext(myValidationSupport), system, code, codeSystemVersion);
|
||||||
if (retVal != null) {
|
if (retVal != null) {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
@ -122,6 +133,11 @@ public class FhirResourceDaoCodeSystemR4 extends BaseHapiFhirResourceDao<CodeSys
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, Coding theCodingA, Coding theCodingB, IPrimitiveType<String> theVersion, RequestDetails theRequestDetails) {
|
||||||
|
return myTerminologySvc.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB, theVersion);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, Coding theCodingA, Coding theCodingB, RequestDetails theRequestDetails) {
|
public SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, Coding theCodingA, Coding theCodingB, RequestDetails theRequestDetails) {
|
||||||
return myTerminologySvc.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB);
|
return myTerminologySvc.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB);
|
||||||
|
|
|
@ -113,14 +113,17 @@ public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet>
|
||||||
ValueSet source = new ValueSet();
|
ValueSet source = new ValueSet();
|
||||||
source.setUrl(theUri);
|
source.setUrl(theUri);
|
||||||
|
|
||||||
source.getCompose().addInclude().addValueSet(theUri);
|
// source.getCompose().addInclude().addValueSet(theUri);
|
||||||
|
|
||||||
if (isNotBlank(theFilter)) {
|
if (isNotBlank(theFilter)) {
|
||||||
ConceptSetComponent include = source.getCompose().addInclude();
|
// ConceptSetComponent include = source.getCompose().addInclude();
|
||||||
ConceptSetFilterComponent filter = include.addFilter();
|
// ConceptSetFilterComponent filter = include.addFilter();
|
||||||
|
ConceptSetFilterComponent filter = source.getCompose().addInclude().addValueSet(theUri).addFilter();
|
||||||
filter.setProperty("display");
|
filter.setProperty("display");
|
||||||
filter.setOp(FilterOperator.EQUAL);
|
filter.setOp(FilterOperator.EQUAL);
|
||||||
filter.setValue(theFilter);
|
filter.setValue(theFilter);
|
||||||
|
} else {
|
||||||
|
source.getCompose().addInclude().addValueSet(theUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueSet retVal = doExpand(source);
|
ValueSet retVal = doExpand(source);
|
||||||
|
@ -148,14 +151,17 @@ public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet>
|
||||||
ValueSet source = new ValueSet();
|
ValueSet source = new ValueSet();
|
||||||
source.setUrl(theUri);
|
source.setUrl(theUri);
|
||||||
|
|
||||||
source.getCompose().addInclude().addValueSet(theUri);
|
// source.getCompose().addInclude().addValueSet(theUri);
|
||||||
|
|
||||||
if (isNotBlank(theFilter)) {
|
if (isNotBlank(theFilter)) {
|
||||||
ConceptSetComponent include = source.getCompose().addInclude();
|
// ConceptSetComponent include = source.getCompose().addInclude();
|
||||||
ConceptSetFilterComponent filter = include.addFilter();
|
// ConceptSetFilterComponent filter = include.addFilter();
|
||||||
|
ConceptSetFilterComponent filter = source.getCompose().addInclude().addValueSet(theUri).addFilter();
|
||||||
filter.setProperty("display");
|
filter.setProperty("display");
|
||||||
filter.setOp(FilterOperator.EQUAL);
|
filter.setOp(FilterOperator.EQUAL);
|
||||||
filter.setValue(theFilter);
|
filter.setValue(theFilter);
|
||||||
|
} else {
|
||||||
|
source.getCompose().addInclude().addValueSet(theUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueSet retVal = doExpand(source, theOffset, theCount);
|
ValueSet retVal = doExpand(source, theOffset, theCount);
|
||||||
|
|
|
@ -45,6 +45,7 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.hl7.fhir.r5.model.CodeSystem;
|
import org.hl7.fhir.r5.model.CodeSystem;
|
||||||
import org.hl7.fhir.r5.model.CodeableConcept;
|
import org.hl7.fhir.r5.model.CodeableConcept;
|
||||||
import org.hl7.fhir.r5.model.Coding;
|
import org.hl7.fhir.r5.model.Coding;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
@ -83,9 +84,15 @@ public class FhirResourceDaoCodeSystemR5 extends BaseHapiFhirResourceDao<CodeSys
|
||||||
return valueSetIds;
|
return valueSetIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, Coding theCoding, RequestDetails theRequestDetails) {
|
public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, Coding theCoding, RequestDetails theRequestDetails) {
|
||||||
|
return lookupCode(theCode, theSystem, theCoding, null, theRequestDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, Coding theCoding, IPrimitiveType<String> theVersion, RequestDetails theRequestDetails) {
|
||||||
boolean haveCoding = theCoding != null && isNotBlank(theCoding.getSystem()) && isNotBlank(theCoding.getCode());
|
boolean haveCoding = theCoding != null && isNotBlank(theCoding.getSystem()) && isNotBlank(theCoding.getCode());
|
||||||
boolean haveCode = theCode != null && theCode.isEmpty() == false;
|
boolean haveCode = theCode != null && theCode.isEmpty() == false;
|
||||||
boolean haveSystem = theSystem != null && theSystem.isEmpty() == false;
|
boolean haveSystem = theSystem != null && theSystem.isEmpty() == false;
|
||||||
|
@ -106,13 +113,17 @@ public class FhirResourceDaoCodeSystemR5 extends BaseHapiFhirResourceDao<CodeSys
|
||||||
code = theCode.getValue();
|
code = theCode.getValue();
|
||||||
system = theSystem.getValue();
|
system = theSystem.getValue();
|
||||||
}
|
}
|
||||||
|
String codeSystemVersion = null;
|
||||||
|
if (theVersion != null) {
|
||||||
|
codeSystemVersion = theVersion.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
ourLog.info("Looking up {} / {}", system, code);
|
ourLog.info("Looking up {} / {}, version {}", system, code, codeSystemVersion);
|
||||||
|
|
||||||
if (myValidationSupport.isCodeSystemSupported(new ValidationSupportContext(myValidationSupport), system)) {
|
if (myValidationSupport.isCodeSystemSupported(new ValidationSupportContext(myValidationSupport), system)) {
|
||||||
|
|
||||||
ourLog.info("Code system {} is supported", system);
|
ourLog.info("Code system {} is supported", system);
|
||||||
IValidationSupport.LookupCodeResult retVal = myValidationSupport.lookupCode(new ValidationSupportContext(myValidationSupport), system, code);
|
IValidationSupport.LookupCodeResult retVal = myValidationSupport.lookupCode(new ValidationSupportContext(myValidationSupport), system, code, codeSystemVersion);
|
||||||
if (retVal != null) {
|
if (retVal != null) {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
@ -124,6 +135,11 @@ public class FhirResourceDaoCodeSystemR5 extends BaseHapiFhirResourceDao<CodeSys
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, Coding theCodingA, Coding theCodingB, IPrimitiveType<String> theVersion, RequestDetails theRequestDetails) {
|
||||||
|
return myTerminologySvc.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB, theVersion);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, Coding theCodingA, Coding theCodingB, RequestDetails theRequestDetails) {
|
public SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, Coding theCodingA, Coding theCodingB, RequestDetails theRequestDetails) {
|
||||||
return myTerminologySvc.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB);
|
return myTerminologySvc.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB);
|
||||||
|
|
|
@ -40,17 +40,21 @@ import javax.persistence.OneToMany;
|
||||||
import javax.persistence.OneToOne;
|
import javax.persistence.OneToOne;
|
||||||
import javax.persistence.SequenceGenerator;
|
import javax.persistence.SequenceGenerator;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.UniqueConstraint;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.length;
|
import static org.apache.commons.lang3.StringUtils.length;
|
||||||
|
|
||||||
@Table(name = "TRM_CODESYSTEM_VER"
|
@Table(name = "TRM_CODESYSTEM_VER",
|
||||||
// Note, we used to have a constraint named IDX_CSV_RESOURCEPID_AND_VER (don't reuse this)
|
// Note, we used to have a constraint named IDX_CSV_RESOURCEPID_AND_VER (don't reuse this)
|
||||||
)
|
uniqueConstraints = {
|
||||||
|
@UniqueConstraint(name = TermCodeSystemVersion.IDX_CODESYSTEM_AND_VER, columnNames = {"CODESYSTEM_PID", "CS_VERSION_ID"})
|
||||||
|
})
|
||||||
@Entity()
|
@Entity()
|
||||||
public class TermCodeSystemVersion implements Serializable {
|
public class TermCodeSystemVersion implements Serializable {
|
||||||
|
public static final String IDX_CODESYSTEM_AND_VER = "IDX_CODESYSTEM_AND_VER";
|
||||||
public static final int MAX_VERSION_LENGTH = 200;
|
public static final int MAX_VERSION_LENGTH = 200;
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@OneToMany(fetch = FetchType.LAZY, mappedBy = "myCodeSystem")
|
@OneToMany(fetch = FetchType.LAZY, mappedBy = "myCodeSystem")
|
||||||
|
|
|
@ -53,6 +53,7 @@ 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="version", min=0, max=1) StringType theVersion,
|
||||||
@OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) List<CodeType> theProperties,
|
@OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) List<CodeType> theProperties,
|
||||||
RequestDetails theRequestDetails
|
RequestDetails theRequestDetails
|
||||||
) {
|
) {
|
||||||
|
@ -60,7 +61,7 @@ public class BaseJpaResourceProviderCodeSystemDstu3 extends JpaResourceProviderD
|
||||||
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();
|
||||||
IValidationSupport.LookupCodeResult result = dao.lookupCode(theCode, theSystem, theCoding, theRequestDetails);
|
IValidationSupport.LookupCodeResult result = dao.lookupCode(theCode, theSystem, theCoding, theVersion, theRequestDetails);
|
||||||
result.throwNotFoundIfAppropriate();
|
result.throwNotFoundIfAppropriate();
|
||||||
return (Parameters) result.toParameters(theRequestDetails.getFhirContext(), theProperties);
|
return (Parameters) result.toParameters(theRequestDetails.getFhirContext(), theProperties);
|
||||||
} catch (FHIRException e) {
|
} catch (FHIRException e) {
|
||||||
|
|
|
@ -55,6 +55,7 @@ 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="version", min=0, max=1) StringType theVersion,
|
||||||
@OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) List<CodeType> theProperties,
|
@OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) List<CodeType> theProperties,
|
||||||
RequestDetails theRequestDetails
|
RequestDetails theRequestDetails
|
||||||
) {
|
) {
|
||||||
|
@ -62,7 +63,7 @@ public class BaseJpaResourceProviderCodeSystemR4 extends JpaResourceProviderR4<C
|
||||||
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();
|
||||||
IValidationSupport.LookupCodeResult result = dao.lookupCode(theCode, theSystem, theCoding, theRequestDetails);
|
IValidationSupport.LookupCodeResult result = dao.lookupCode(theCode, theSystem, theCoding, theVersion, theRequestDetails);
|
||||||
result.throwNotFoundIfAppropriate();
|
result.throwNotFoundIfAppropriate();
|
||||||
return (Parameters) result.toParameters(theRequestDetails.getFhirContext(), theProperties);
|
return (Parameters) result.toParameters(theRequestDetails.getFhirContext(), theProperties);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -55,6 +55,7 @@ public class BaseJpaResourceProviderCodeSystemR5 extends JpaResourceProviderR5<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="version", min=0, max=1) org.hl7.fhir.r4.model.StringType theVersion,
|
||||||
@OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) List<CodeType> theProperties,
|
@OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) List<CodeType> theProperties,
|
||||||
RequestDetails theRequestDetails
|
RequestDetails theRequestDetails
|
||||||
) {
|
) {
|
||||||
|
@ -62,7 +63,7 @@ public class BaseJpaResourceProviderCodeSystemR5 extends JpaResourceProviderR5<C
|
||||||
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();
|
||||||
IValidationSupport.LookupCodeResult result = dao.lookupCode(theCode, theSystem, theCoding, theRequestDetails);
|
IValidationSupport.LookupCodeResult result = dao.lookupCode(theCode, theSystem, theCoding, theVersion, theRequestDetails);
|
||||||
result.throwNotFoundIfAppropriate();
|
result.throwNotFoundIfAppropriate();
|
||||||
return (Parameters) result.toParameters(theRequestDetails.getFhirContext(), theProperties);
|
return (Parameters) result.toParameters(theRequestDetails.getFhirContext(), theProperties);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -244,7 +244,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) {
|
public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) {
|
||||||
TermCodeSystemVersion cs = getCurrentCodeSystemVersion(theSystem);
|
TermCodeSystemVersion cs = getCurrentCodeSystemVersionForVersion(theSystem,null);
|
||||||
return cs != null;
|
return cs != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -616,6 +616,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
private Boolean expandValueSetHandleIncludeOrExclude(@Nullable ValueSetExpansionOptions theExpansionOptions, IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theIncludeOrExclude, boolean theAdd, AtomicInteger theCodeCounter, int theQueryIndex, VersionIndependentConcept theWantConceptOrNull) {
|
private Boolean expandValueSetHandleIncludeOrExclude(@Nullable ValueSetExpansionOptions theExpansionOptions, IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theIncludeOrExclude, boolean theAdd, AtomicInteger theCodeCounter, int theQueryIndex, VersionIndependentConcept theWantConceptOrNull) {
|
||||||
|
|
||||||
String system = theIncludeOrExclude.getSystem();
|
String system = theIncludeOrExclude.getSystem();
|
||||||
|
String systemVersion = theIncludeOrExclude.getVersion();
|
||||||
boolean hasSystem = isNotBlank(system);
|
boolean hasSystem = isNotBlank(system);
|
||||||
boolean hasValueSet = theIncludeOrExclude.getValueSet().size() > 0;
|
boolean hasValueSet = theIncludeOrExclude.getValueSet().size() > 0;
|
||||||
|
|
||||||
|
@ -630,7 +631,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system);
|
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system);
|
||||||
if (cs != null) {
|
if (cs != null) {
|
||||||
|
|
||||||
return expandValueSetHandleIncludeOrExcludeUsingDatabase(theValueSetCodeAccumulator, theAddedCodes, theIncludeOrExclude, theAdd, theCodeCounter, theQueryIndex, theWantConceptOrNull, system, cs);
|
return expandValueSetHandleIncludeOrExcludeUsingDatabase(theValueSetCodeAccumulator, theAddedCodes, theIncludeOrExclude, theAdd, theCodeCounter, theQueryIndex, theWantConceptOrNull, system, cs, systemVersion);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -671,7 +672,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
nextSystem = system;
|
nextSystem = system;
|
||||||
}
|
}
|
||||||
|
|
||||||
LookupCodeResult lookup = myValidationSupport.lookupCode(new ValidationSupportContext(provideValidationSupport()), nextSystem, next.getCode());
|
LookupCodeResult lookup = myValidationSupport.lookupCode(new ValidationSupportContext(provideValidationSupport()), nextSystem, next.getCode(), systemVersion);
|
||||||
if (lookup != null && lookup.isFound()) {
|
if (lookup != null && lookup.isFound()) {
|
||||||
addOrRemoveCode(theValueSetCodeAccumulator, theAddedCodes, theAdd, nextSystem, next.getCode(), lookup.getCodeDisplay());
|
addOrRemoveCode(theValueSetCodeAccumulator, theAddedCodes, theAdd, nextSystem, next.getCode(), lookup.getCodeDisplay());
|
||||||
foundCount++;
|
foundCount++;
|
||||||
|
@ -765,7 +766,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private Boolean expandValueSetHandleIncludeOrExcludeUsingDatabase(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theIncludeOrExclude, boolean theAdd, AtomicInteger theCodeCounter, int theQueryIndex, VersionIndependentConcept theWantConceptOrNull, String theSystem, TermCodeSystem theCs) {
|
private Boolean expandValueSetHandleIncludeOrExcludeUsingDatabase(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theIncludeOrExclude, boolean theAdd, AtomicInteger theCodeCounter, int theQueryIndex, VersionIndependentConcept theWantConceptOrNull, String theSystem, TermCodeSystem theCs, String theSystemVersion) {
|
||||||
TermCodeSystemVersion csv = theCs.getCurrentVersion();
|
TermCodeSystemVersion csv = theCs.getCurrentVersion();
|
||||||
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
|
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
|
||||||
|
|
||||||
|
@ -793,7 +794,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
/*
|
/*
|
||||||
* Filters
|
* Filters
|
||||||
*/
|
*/
|
||||||
handleFilters(bool, theSystem, qb, theIncludeOrExclude);
|
handleFilters(bool, theSystem, qb, theIncludeOrExclude, theSystemVersion);
|
||||||
|
|
||||||
Query luceneQuery = bool.createQuery();
|
Query luceneQuery = bool.createQuery();
|
||||||
|
|
||||||
|
@ -902,15 +903,15 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleFilters(BooleanJunction<?> theBool, String theSystem, QueryBuilder theQb, ValueSet.ConceptSetComponent theIncludeOrExclude) {
|
private void handleFilters(BooleanJunction<?> theBool, String theSystem, QueryBuilder theQb, ValueSet.ConceptSetComponent theIncludeOrExclude, String theSystemVersion) {
|
||||||
if (theIncludeOrExclude.getFilter().size() > 0) {
|
if (theIncludeOrExclude.getFilter().size() > 0) {
|
||||||
for (ValueSet.ConceptSetFilterComponent nextFilter : theIncludeOrExclude.getFilter()) {
|
for (ValueSet.ConceptSetFilterComponent nextFilter : theIncludeOrExclude.getFilter()) {
|
||||||
handleFilter(theSystem, theQb, theBool, nextFilter);
|
handleFilter(theSystem, theQb, theBool, nextFilter, theSystemVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleFilter(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
private void handleFilter(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter, String theSystemVersion) {
|
||||||
if (isBlank(theFilter.getValue()) && theFilter.getOp() == null && isBlank(theFilter.getProperty())) {
|
if (isBlank(theFilter.getValue()) && theFilter.getOp() == null && isBlank(theFilter.getProperty())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -926,7 +927,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
break;
|
break;
|
||||||
case "concept":
|
case "concept":
|
||||||
case "code":
|
case "code":
|
||||||
handleFilterConceptAndCode(theSystem, theQb, theBool, theFilter);
|
handleFilterConceptAndCode(theSystem, theQb, theBool, theFilter, theSystemVersion);
|
||||||
break;
|
break;
|
||||||
case "parent":
|
case "parent":
|
||||||
case "child":
|
case "child":
|
||||||
|
@ -935,11 +936,11 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
break;
|
break;
|
||||||
case "ancestor":
|
case "ancestor":
|
||||||
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
|
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
|
||||||
handleFilterLoincAncestor(theSystem, theQb, theBool, theFilter);
|
handleFilterLoincAncestor(theSystem, theQb, theBool, theFilter, theSystemVersion);
|
||||||
break;
|
break;
|
||||||
case "descendant":
|
case "descendant":
|
||||||
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
|
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
|
||||||
handleFilterLoincDescendant(theSystem, theQb, theBool, theFilter);
|
handleFilterLoincDescendant(theSystem, theQb, theBool, theFilter, theSystemVersion);
|
||||||
break;
|
break;
|
||||||
case "copyright":
|
case "copyright":
|
||||||
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
|
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
|
||||||
|
@ -990,8 +991,8 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
bool.must(textQuery);
|
bool.must(textQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleFilterConceptAndCode(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
private void handleFilterConceptAndCode(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter, String theSystemVersion) {
|
||||||
TermConcept code = findCode(theSystem, theFilter.getValue())
|
TermConcept code = findCode(theSystem, theFilter.getValue(), theSystemVersion)
|
||||||
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + Constants.codeSystemWithDefaultDescription(theSystem) + "}" + theFilter.getValue()));
|
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + Constants.codeSystemWithDefaultDescription(theSystem) + "}" + theFilter.getValue()));
|
||||||
|
|
||||||
if (theFilter.getOp() == ValueSet.FilterOperator.ISA) {
|
if (theFilter.getOp() == ValueSet.FilterOperator.ISA) {
|
||||||
|
@ -1036,41 +1037,41 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
|
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
|
||||||
private void handleFilterLoincAncestor(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
private void handleFilterLoincAncestor(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter, String theSystemVersion) {
|
||||||
switch (theFilter.getOp()) {
|
switch (theFilter.getOp()) {
|
||||||
case EQUAL:
|
case EQUAL:
|
||||||
addLoincFilterAncestorEqual(theSystem, theQb, theBool, theFilter);
|
addLoincFilterAncestorEqual(theSystem, theQb, theBool, theFilter, theSystemVersion);
|
||||||
break;
|
break;
|
||||||
case IN:
|
case IN:
|
||||||
addLoincFilterAncestorIn(theSystem, theQb, theBool, theFilter);
|
addLoincFilterAncestorIn(theSystem, theQb, theBool, theFilter, theSystemVersion);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty());
|
throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addLoincFilterAncestorEqual(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
private void addLoincFilterAncestorEqual(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter, String theSystemVersion) {
|
||||||
addLoincFilterAncestorEqual(theSystem, theQb, theBool, theFilter.getProperty(), theFilter.getValue());
|
addLoincFilterAncestorEqual(theSystem, theQb, theBool, theFilter.getProperty(), theFilter.getValue(), theSystemVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addLoincFilterAncestorEqual(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, String theProperty, String theValue) {
|
private void addLoincFilterAncestorEqual(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, String theProperty, String theValue, String theSystemVersion) {
|
||||||
List<Term> terms = getAncestorTerms(theSystem, theProperty, theValue);
|
List<Term> terms = getAncestorTerms(theSystem, theProperty, theValue, theSystemVersion);
|
||||||
theBool.must(new TermsQuery(terms));
|
theBool.must(new TermsQuery(terms));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addLoincFilterAncestorIn(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
private void addLoincFilterAncestorIn(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter, String theSystemVersion) {
|
||||||
String[] values = theFilter.getValue().split(",");
|
String[] values = theFilter.getValue().split(",");
|
||||||
List<Term> terms = new ArrayList<>();
|
List<Term> terms = new ArrayList<>();
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
terms.addAll(getAncestorTerms(theSystem, theFilter.getProperty(), value));
|
terms.addAll(getAncestorTerms(theSystem, theFilter.getProperty(), value, theSystemVersion));
|
||||||
}
|
}
|
||||||
theBool.must(new TermsQuery(terms));
|
theBool.must(new TermsQuery(terms));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Term> getAncestorTerms(String theSystem, String theProperty, String theValue) {
|
private List<Term> getAncestorTerms(String theSystem, String theProperty, String theValue, String theSystemVersion) {
|
||||||
List<Term> retVal = new ArrayList<>();
|
List<Term> retVal = new ArrayList<>();
|
||||||
|
|
||||||
TermConcept code = findCode(theSystem, theValue)
|
TermConcept code = findCode(theSystem, theValue, theSystemVersion)
|
||||||
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + Constants.codeSystemWithDefaultDescription(theSystem) + "}" + theValue));
|
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + Constants.codeSystemWithDefaultDescription(theSystem) + "}" + theValue));
|
||||||
|
|
||||||
retVal.add(new Term("myParentPids", "" + code.getId()));
|
retVal.add(new Term("myParentPids", "" + code.getId()));
|
||||||
|
@ -1080,41 +1081,41 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
|
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
|
||||||
private void handleFilterLoincDescendant(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
private void handleFilterLoincDescendant(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter, String theSystemVersion) {
|
||||||
switch (theFilter.getOp()) {
|
switch (theFilter.getOp()) {
|
||||||
case EQUAL:
|
case EQUAL:
|
||||||
addLoincFilterDescendantEqual(theSystem, theBool, theFilter);
|
addLoincFilterDescendantEqual(theSystem, theBool, theFilter, theSystemVersion);
|
||||||
break;
|
break;
|
||||||
case IN:
|
case IN:
|
||||||
addLoincFilterDescendantIn(theSystem, theQb, theBool, theFilter);
|
addLoincFilterDescendantIn(theSystem, theQb, theBool, theFilter, theSystemVersion);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty());
|
throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addLoincFilterDescendantEqual(String theSystem, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
private void addLoincFilterDescendantEqual(String theSystem, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter, String theSystemVersion) {
|
||||||
addLoincFilterDescendantEqual(theSystem, theBool, theFilter.getProperty(), theFilter.getValue());
|
addLoincFilterDescendantEqual(theSystem, theBool, theFilter.getProperty(), theFilter.getValue(), theSystemVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addLoincFilterDescendantEqual(String theSystem, BooleanJunction<?> theBool, String theProperty, String theValue) {
|
private void addLoincFilterDescendantEqual(String theSystem, BooleanJunction<?> theBool, String theProperty, String theValue, String theSystemVersion) {
|
||||||
List<Term> terms = getDescendantTerms(theSystem, theProperty, theValue);
|
List<Term> terms = getDescendantTerms(theSystem, theProperty, theValue, theSystemVersion);
|
||||||
theBool.must(new TermsQuery(terms));
|
theBool.must(new TermsQuery(terms));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addLoincFilterDescendantIn(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
private void addLoincFilterDescendantIn(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter, String theSystemVersion) {
|
||||||
String[] values = theFilter.getValue().split(",");
|
String[] values = theFilter.getValue().split(",");
|
||||||
List<Term> terms = new ArrayList<>();
|
List<Term> terms = new ArrayList<>();
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
terms.addAll(getDescendantTerms(theSystem, theFilter.getProperty(), value));
|
terms.addAll(getDescendantTerms(theSystem, theFilter.getProperty(), value, theSystemVersion));
|
||||||
}
|
}
|
||||||
theBool.must(new TermsQuery(terms));
|
theBool.must(new TermsQuery(terms));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Term> getDescendantTerms(String theSystem, String theProperty, String theValue) {
|
private List<Term> getDescendantTerms(String theSystem, String theProperty, String theValue, String theSystemVersion) {
|
||||||
List<Term> retVal = new ArrayList<>();
|
List<Term> retVal = new ArrayList<>();
|
||||||
|
|
||||||
TermConcept code = findCode(theSystem, theValue)
|
TermConcept code = findCode(theSystem, theValue, theSystemVersion)
|
||||||
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + Constants.codeSystemWithDefaultDescription(theSystem) + "}" + theValue));
|
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + Constants.codeSystemWithDefaultDescription(theSystem) + "}" + theValue));
|
||||||
|
|
||||||
String[] parentPids = code.getParentPidsAsString().split(" ");
|
String[] parentPids = code.getParentPidsAsString().split(" ");
|
||||||
|
@ -1363,6 +1364,12 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<TermConcept> findCode(String theCodeSystem, String theCode) {
|
public Optional<TermConcept> findCode(String theCodeSystem, String theCode) {
|
||||||
|
return findCode(theCodeSystem, theCode, null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<TermConcept> findCode(String theCodeSystem, String theCode, String theVersion) {
|
||||||
/*
|
/*
|
||||||
* Loading concepts without a transaction causes issues later on some
|
* Loading concepts without a transaction causes issues later on some
|
||||||
* platforms (e.g. PSQL) so this transactiontemplate is here to make
|
* platforms (e.g. PSQL) so this transactiontemplate is here to make
|
||||||
|
@ -1371,7 +1378,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
|
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
|
||||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_MANDATORY);
|
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_MANDATORY);
|
||||||
return txTemplate.execute(t -> {
|
return txTemplate.execute(t -> {
|
||||||
TermCodeSystemVersion csv = getCurrentCodeSystemVersion(theCodeSystem);
|
TermCodeSystemVersion csv = getCurrentCodeSystemVersionForVersion(theCodeSystem, theVersion);
|
||||||
if (csv == null) {
|
if (csv == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1380,13 +1387,21 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private TermCodeSystemVersion getCurrentCodeSystemVersion(String theUri) {
|
private TermCodeSystemVersion getCurrentCodeSystemVersionForVersion(String theUri, String theVersion) {
|
||||||
TermCodeSystemVersion retVal = myCodeSystemCurrentVersionCache.get(theUri, uri -> myTxTemplate.execute(tx -> {
|
StringBuffer key = new StringBuffer(theUri);
|
||||||
|
if (theVersion != null) {
|
||||||
|
key.append("_").append(theVersion);
|
||||||
|
}
|
||||||
|
TermCodeSystemVersion retVal = myCodeSystemCurrentVersionCache.get(key.toString(), uri -> myTxTemplate.execute(tx -> {
|
||||||
TermCodeSystemVersion csv = null;
|
TermCodeSystemVersion csv = null;
|
||||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(uri);
|
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(uri);
|
||||||
if (cs != null && cs.getCurrentVersion() != null) {
|
if (cs != null) {
|
||||||
|
if (theVersion != null) {
|
||||||
|
csv = myCodeSystemVersionDao.findByCodeSystemPidAndVersion(cs.getPid(), theVersion);
|
||||||
|
} else if (cs.getCurrentVersion() != null) {
|
||||||
csv = cs.getCurrentVersion();
|
csv = cs.getCurrentVersion();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (csv != null) {
|
if (csv != null) {
|
||||||
return csv;
|
return csv;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1804,19 +1819,28 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
|
||||||
public IFhirResourceDaoCodeSystem.SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, IBaseCoding theCodingA, IBaseCoding theCodingB) {
|
public IFhirResourceDaoCodeSystem.SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, IBaseCoding theCodingA, IBaseCoding theCodingB) {
|
||||||
|
return subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public IFhirResourceDaoCodeSystem.SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, IBaseCoding theCodingA, IBaseCoding theCodingB, IPrimitiveType<String> theSystemVersion) {
|
||||||
VersionIndependentConcept conceptA = toConcept(theCodeA, theSystem, theCodingA);
|
VersionIndependentConcept conceptA = toConcept(theCodeA, theSystem, theCodingA);
|
||||||
VersionIndependentConcept conceptB = toConcept(theCodeB, theSystem, theCodingB);
|
VersionIndependentConcept conceptB = toConcept(theCodeB, theSystem, theCodingB);
|
||||||
|
String systemVersion = null;
|
||||||
|
if (theSystemVersion != null) {
|
||||||
|
systemVersion = theSystemVersion.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
if (!StringUtils.equals(conceptA.getSystem(), conceptB.getSystem())) {
|
if (!StringUtils.equals(conceptA.getSystem(), conceptB.getSystem())) {
|
||||||
throw new InvalidRequestException("Unable to test subsumption across different code systems");
|
throw new InvalidRequestException("Unable to test subsumption across different code systems");
|
||||||
}
|
}
|
||||||
|
|
||||||
TermConcept codeA = findCode(conceptA.getSystem(), conceptA.getCode())
|
TermConcept codeA = findCode(conceptA.getSystem(), conceptA.getCode(), systemVersion)
|
||||||
.orElseThrow(() -> new InvalidRequestException("Unknown code: " + conceptA));
|
.orElseThrow(() -> new InvalidRequestException("Unknown code: " + conceptA));
|
||||||
|
|
||||||
TermConcept codeB = findCode(conceptB.getSystem(), conceptB.getCode())
|
TermConcept codeB = findCode(conceptB.getSystem(), conceptB.getCode(), systemVersion)
|
||||||
.orElseThrow(() -> new InvalidRequestException("Unknown code: " + conceptB));
|
.orElseThrow(() -> new InvalidRequestException("Unknown code: " + conceptB));
|
||||||
|
|
||||||
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
|
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
|
||||||
|
@ -1835,10 +1859,10 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
|
|
||||||
protected abstract ValueSet toCanonicalValueSet(IBaseResource theValueSet);
|
protected abstract ValueSet toCanonicalValueSet(IBaseResource theValueSet);
|
||||||
|
|
||||||
protected IValidationSupport.LookupCodeResult lookupCode(String theSystem, String theCode) {
|
protected IValidationSupport.LookupCodeResult lookupCode(String theSystem, String theCode, String theVersion) {
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
|
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
|
||||||
return txTemplate.execute(t -> {
|
return txTemplate.execute(t -> {
|
||||||
Optional<TermConcept> codeOpt = findCode(theSystem, theCode);
|
Optional<TermConcept> codeOpt = findCode(theSystem, theCode, theVersion);
|
||||||
if (codeOpt.isPresent()) {
|
if (codeOpt.isPresent()) {
|
||||||
TermConcept code = codeOpt.get();
|
TermConcept code = codeOpt.get();
|
||||||
|
|
||||||
|
@ -2107,10 +2131,14 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@CoverageIgnore
|
@CoverageIgnore
|
||||||
@Override
|
@Override
|
||||||
public IValidationSupport.CodeValidationResult validateCode(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl) {
|
public IValidationSupport.CodeValidationResult validateCode(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl) {
|
||||||
|
return validateCode(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSetUrl, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IValidationSupport.CodeValidationResult validateCode(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl, String theSystemVersion) {
|
||||||
invokeRunnableForUnitTest();
|
invokeRunnableForUnitTest();
|
||||||
|
|
||||||
if (isNotBlank(theValueSetUrl)) {
|
if (isNotBlank(theValueSetUrl)) {
|
||||||
|
@ -2119,7 +2147,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
|
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
|
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
|
||||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||||
Optional<VersionIndependentConcept> codeOpt = txTemplate.execute(t -> findCode(theCodeSystem, theCode).map(c -> new VersionIndependentConcept(theCodeSystem, c.getCode())));
|
Optional<VersionIndependentConcept> codeOpt = txTemplate.execute(t -> findCode(theCodeSystem, theCode, theSystemVersion).map(c -> new VersionIndependentConcept(theCodeSystem, c.getCode())));
|
||||||
|
|
||||||
if (codeOpt != null && codeOpt.isPresent()) {
|
if (codeOpt != null && codeOpt.isPresent()) {
|
||||||
VersionIndependentConcept code = codeOpt.get();
|
VersionIndependentConcept code = codeOpt.get();
|
||||||
|
|
|
@ -284,18 +284,21 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
|
||||||
ResourcePersistentId codeSystemResourcePid = getCodeSystemResourcePid(theCodeSystem.getIdElement());
|
ResourcePersistentId codeSystemResourcePid = getCodeSystemResourcePid(theCodeSystem.getIdElement());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is a not-present codesystem, we don't want to store a new version if one
|
* If this is a not-present codesystem and codesystem version already exists, we don't want to
|
||||||
* already exists, since that will wipe out the existing concepts. We do create or update
|
* overwrite the existing version since that will wipe out the existing concepts. We do create
|
||||||
* the TermCodeSystem table though, since that allows the DB to reject changes
|
* or update the TermCodeSystem table though, since that allows the DB to reject changes that would
|
||||||
* that would result in duplicate CodeSysten.url values.
|
* result in duplicate CodeSystem.url values.
|
||||||
*/
|
*/
|
||||||
if (theCodeSystem.getContent() == CodeSystem.CodeSystemContentMode.NOTPRESENT) {
|
if (theCodeSystem.getContent() == CodeSystem.CodeSystemContentMode.NOTPRESENT) {
|
||||||
TermCodeSystem codeSystem = myCodeSystemDao.findByCodeSystemUri(theCodeSystem.getUrl());
|
TermCodeSystem termCodeSystem = myCodeSystemDao.findByCodeSystemUri(theCodeSystem.getUrl());
|
||||||
if (codeSystem != null) {
|
if (termCodeSystem != null) {
|
||||||
|
TermCodeSystemVersion codeSystemVersion = getExistingTermCodeSystemVersion(termCodeSystem.getPid(), theCodeSystem.getVersion());
|
||||||
|
if (codeSystemVersion != null) {
|
||||||
getOrCreateTermCodeSystem(codeSystemResourcePid, theCodeSystem.getUrl(), theCodeSystem.getUrl(), theResourceEntity);
|
getOrCreateTermCodeSystem(codeSystemResourcePid, theCodeSystem.getUrl(), theCodeSystem.getUrl(), theResourceEntity);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TermCodeSystemVersion persCs = new TermCodeSystemVersion();
|
TermCodeSystemVersion persCs = new TermCodeSystemVersion();
|
||||||
|
|
||||||
|
@ -338,22 +341,23 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
|
||||||
ValidateUtil.isTrueOrThrowInvalidRequest(theCodeSystemVersion.getResource() != null, "No resource supplied");
|
ValidateUtil.isTrueOrThrowInvalidRequest(theCodeSystemVersion.getResource() != null, "No resource supplied");
|
||||||
ValidateUtil.isNotBlankOrThrowInvalidRequest(theSystemUri, "No system URI supplied");
|
ValidateUtil.isNotBlankOrThrowInvalidRequest(theSystemUri, "No system URI supplied");
|
||||||
|
|
||||||
// Grab the existing versions so we can delete them later
|
// Grab the existing version so we can delete it
|
||||||
List<TermCodeSystemVersion> existing = myCodeSystemVersionDao.findByCodeSystemResourcePid(theCodeSystemResourcePid.getIdAsLong());
|
TermCodeSystem existingCodeSystem = myCodeSystemDao.findByCodeSystemUri(theSystemUri);
|
||||||
|
TermCodeSystemVersion existing = null;
|
||||||
/*
|
if (existingCodeSystem != null) {
|
||||||
* For now we always delete old versions. At some point it would be nice to allow configuration to keep old versions.
|
existing = getExistingTermCodeSystemVersion(existingCodeSystem.getPid(), theSystemVersionId);
|
||||||
*/
|
|
||||||
|
|
||||||
for (TermCodeSystemVersion next : existing) {
|
|
||||||
ourLog.info("Deleting old code system version {}", next.getPid());
|
|
||||||
Long codeSystemVersionPid = next.getPid();
|
|
||||||
deleteCodeSystemVersion(codeSystemVersionPid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.debug("Flushing...");
|
/*
|
||||||
myConceptDao.flush();
|
* Delete version being replaced.
|
||||||
ourLog.debug("Done flushing");
|
*/
|
||||||
|
|
||||||
|
if(existing != null) {
|
||||||
|
ourLog.info("Deleting old code system version {}", existing.getPid());
|
||||||
|
Long codeSystemVersionPid = existing.getPid();
|
||||||
|
deleteCodeSystemVersion(codeSystemVersionPid);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do the upload
|
* Do the upload
|
||||||
|
@ -408,6 +412,17 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TermCodeSystemVersion getExistingTermCodeSystemVersion(Long theCodeSystemVersionPid, String theCodeSystemVersion) {
|
||||||
|
TermCodeSystemVersion existing;
|
||||||
|
if (theCodeSystemVersion == null) {
|
||||||
|
existing = myCodeSystemVersionDao.findByCodeSystemPidVersionIsNull(theCodeSystemVersionPid);
|
||||||
|
} else {
|
||||||
|
existing = myCodeSystemVersionDao.findByCodeSystemPidAndVersion(theCodeSystemVersionPid, theCodeSystemVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
private void deleteCodeSystemVersion(final Long theCodeSystemVersionPid) {
|
private void deleteCodeSystemVersion(final Long theCodeSystemVersionPid) {
|
||||||
ourLog.info(" * Deleting code system version {}", theCodeSystemVersionPid);
|
ourLog.info(" * Deleting code system version {}", theCodeSystemVersionPid);
|
||||||
|
|
||||||
|
@ -457,8 +472,11 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
|
||||||
myCodeSystemDao.save(codeSystem);
|
myCodeSystemDao.save(codeSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
myConceptDao.flush();
|
||||||
|
|
||||||
ourLog.info(" * Deleting code system version");
|
ourLog.info(" * Deleting code system version");
|
||||||
myCodeSystemVersionDao.deleteById(theCodeSystemVersionPid);
|
myCodeSystemVersionDao.delete(theCodeSystemVersionPid);
|
||||||
|
myCodeSystemVersionDao.flush();
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -378,6 +378,10 @@ public class TermLoaderSvcImpl implements ITermLoaderSvc {
|
||||||
try {
|
try {
|
||||||
String loincCsString = IOUtils.toString(BaseTermReadSvcImpl.class.getResourceAsStream("/ca/uhn/fhir/jpa/term/loinc/loinc.xml"), Charsets.UTF_8);
|
String loincCsString = IOUtils.toString(BaseTermReadSvcImpl.class.getResourceAsStream("/ca/uhn/fhir/jpa/term/loinc/loinc.xml"), Charsets.UTF_8);
|
||||||
loincCs = FhirContext.forR4().newXmlParser().parseResource(CodeSystem.class, loincCsString);
|
loincCs = FhirContext.forR4().newXmlParser().parseResource(CodeSystem.class, loincCsString);
|
||||||
|
String codeSystemVersionId = theUploadProperties.getProperty(LOINC_CODESYSTEM_VERSION.getCode());
|
||||||
|
if (codeSystemVersionId != null) {
|
||||||
|
loincCs.setVersion(codeSystemVersionId);
|
||||||
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InternalErrorException("Failed to load loinc.xml", e);
|
throw new InternalErrorException("Failed to load loinc.xml", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,7 +149,12 @@ public class TermReadSvcDstu3 extends BaseTermReadSvcImpl implements IValidation
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
||||||
return super.lookupCode(theSystem, theCode);
|
return super.lookupCode(theSystem, theCode, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode, String theVersion) {
|
||||||
|
return super.lookupCode(theSystem, theCode, theVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -89,9 +89,14 @@ public class TermReadSvcR4 extends BaseTermReadSvcImpl implements ITermReadSvcR4
|
||||||
return (CodeSystem) theCodeSystem;
|
return (CodeSystem) theCodeSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode, String theVersion) {
|
||||||
|
return super.lookupCode(theSystem, theCode, theVersion);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
||||||
return super.lookupCode(theSystem, theCode);
|
return super.lookupCode(theSystem, theCode, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -73,6 +73,8 @@ public interface ITermReadSvc extends IValidationSupport {
|
||||||
|
|
||||||
List<VersionIndependentConcept> expandValueSet(ValueSetExpansionOptions theExpansionOptions, String theValueSet);
|
List<VersionIndependentConcept> expandValueSet(ValueSetExpansionOptions theExpansionOptions, String theValueSet);
|
||||||
|
|
||||||
|
Optional<TermConcept> findCode(String theCodeSystem, String theCode, String theVersion);
|
||||||
|
|
||||||
Optional<TermConcept> findCode(String theCodeSystem, String theCode);
|
Optional<TermConcept> findCode(String theCodeSystem, String theCode);
|
||||||
|
|
||||||
Set<TermConcept> findCodesAbove(Long theCodeSystemResourcePid, Long theCodeSystemResourceVersionPid, String theCode);
|
Set<TermConcept> findCodesAbove(Long theCodeSystemResourcePid, Long theCodeSystemResourceVersionPid, String theCode);
|
||||||
|
@ -103,6 +105,8 @@ public interface ITermReadSvc extends IValidationSupport {
|
||||||
|
|
||||||
IFhirResourceDaoCodeSystem.SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, IBaseCoding theCodingA, IBaseCoding theCodingB);
|
IFhirResourceDaoCodeSystem.SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, IBaseCoding theCodingA, IBaseCoding theCodingB);
|
||||||
|
|
||||||
|
IFhirResourceDaoCodeSystem.SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, IBaseCoding theCodingA, IBaseCoding theCodingB, IPrimitiveType<String> theSystemVersion);
|
||||||
|
|
||||||
void preExpandDeferredValueSetsToTerminologyTables();
|
void preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -96,6 +96,9 @@ public enum LoincUploadPropertiesEnum {
|
||||||
/*
|
/*
|
||||||
* OPTIONAL
|
* OPTIONAL
|
||||||
*/
|
*/
|
||||||
|
// This is the version identifier for the answer list file
|
||||||
|
LOINC_CODESYSTEM_VERSION("loinc.codesystem.version"),
|
||||||
|
|
||||||
// This is the version identifier for the answer list file
|
// This is the version identifier for the answer list file
|
||||||
LOINC_ANSWERLIST_VERSION("loinc.answerlist.version"),
|
LOINC_ANSWERLIST_VERSION("loinc.answerlist.version"),
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,10 @@ loinc.universal.lab.order.valueset.file=AccessoryFiles/LoincUniversalLabOrdersVa
|
||||||
### OPTIONAL ###
|
### OPTIONAL ###
|
||||||
################
|
################
|
||||||
|
|
||||||
|
# This is the version identifier for the LOINC code system
|
||||||
|
## Key may be omitted if only a single version of LOINC is being kept.
|
||||||
|
loinc.codesystem.version=2.68
|
||||||
|
|
||||||
# This is the version identifier for the answer list file
|
# This is the version identifier for the answer list file
|
||||||
## Key may be omitted
|
## Key may be omitted
|
||||||
loinc.answerlist.version=Beta.1
|
loinc.answerlist.version=Beta.1
|
||||||
|
|
|
@ -521,7 +521,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
||||||
myTerminologyDeferredStorageSvc.saveDeferred();
|
myTerminologyDeferredStorageSvc.saveDeferred();
|
||||||
myTerminologyDeferredStorageSvc.saveDeferred();
|
myTerminologyDeferredStorageSvc.saveDeferred();
|
||||||
|
|
||||||
IValidationSupport.LookupCodeResult lookupResults = myCodeSystemDao.lookupCode(new StringType("childAA"), new StringType(URL_MY_CODE_SYSTEM),null, mySrd);
|
IValidationSupport.LookupCodeResult lookupResults = myCodeSystemDao.lookupCode(new StringType("childAA"), new StringType(URL_MY_CODE_SYSTEM), null,null, mySrd);
|
||||||
assertEquals(true, lookupResults.isFound());
|
assertEquals(true, lookupResults.isFound());
|
||||||
|
|
||||||
ValueSet vs = new ValueSet();
|
ValueSet vs = new ValueSet();
|
||||||
|
@ -711,7 +711,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
||||||
|
|
||||||
StringType code = new StringType("ParentA");
|
StringType code = new StringType("ParentA");
|
||||||
StringType system = new StringType("http://snomed.info/sct");
|
StringType system = new StringType("http://snomed.info/sct");
|
||||||
IValidationSupport.LookupCodeResult outcome = myCodeSystemDao.lookupCode(code, system, null, mySrd);
|
IValidationSupport.LookupCodeResult outcome = myCodeSystemDao.lookupCode(code, system, null,null, mySrd);
|
||||||
assertEquals(true, outcome.isFound());
|
assertEquals(true, outcome.isFound());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -828,7 +828,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
StringType code = new StringType("ParentA");
|
StringType code = new StringType("ParentA");
|
||||||
StringType system = new StringType("http://snomed.info/sct");
|
StringType system = new StringType("http://snomed.info/sct");
|
||||||
IValidationSupport.LookupCodeResult outcome = myCodeSystemDao.lookupCode(code, system, null, mySrd);
|
IValidationSupport.LookupCodeResult outcome = myCodeSystemDao.lookupCode(code, system, null,null, mySrd);
|
||||||
assertEquals(true, outcome.isFound());
|
assertEquals(true, outcome.isFound());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
|
import ca.uhn.fhir.util.ParametersUtil;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
@ -415,6 +416,51 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandByValueSetWithFilter() throws IOException {
|
||||||
|
loadAndPersistCodeSystem();
|
||||||
|
|
||||||
|
ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
|
||||||
|
|
||||||
|
Parameters respParam = myClient
|
||||||
|
.operation()
|
||||||
|
.onType(ValueSet.class)
|
||||||
|
.named("expand")
|
||||||
|
.withParameter(Parameters.class, "valueSet", toExpand)
|
||||||
|
.andParameter("filter", new StringType("blood"))
|
||||||
|
.execute();
|
||||||
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
|
ourLog.info(resp);
|
||||||
|
assertThat(resp, stringContainsInOrder(
|
||||||
|
"<code value=\"11378-7\"/>",
|
||||||
|
"<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandByUrlWithFilter() throws Exception {
|
||||||
|
loadAndPersistCodeSystemAndValueSet();
|
||||||
|
|
||||||
|
Parameters respParam = myClient
|
||||||
|
.operation()
|
||||||
|
.onType(ValueSet.class)
|
||||||
|
.named("expand")
|
||||||
|
.withParameter(Parameters.class, "url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
|
||||||
|
.andParameter("filter", new StringType("first"))
|
||||||
|
.execute();
|
||||||
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
|
ourLog.info(resp);
|
||||||
|
assertThat(resp, stringContainsInOrder(
|
||||||
|
"<code value=\"11378-7\"/>",
|
||||||
|
"<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandByValueSetWithPreExpansion() throws IOException {
|
public void testExpandByValueSetWithPreExpansion() throws IOException {
|
||||||
myDaoConfig.setPreExpandValueSets(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
|
@ -13,7 +13,7 @@ public class TermCodeSystemStorageSvcTest extends BaseJpaR4Test {
|
||||||
public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
|
public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStoreNewCodeSystemVersionForExistingCodeSystem() {
|
public void testStoreNewCodeSystemVersionForExistingCodeSystemNoVersionId() {
|
||||||
CodeSystem upload = createCodeSystemWithMoreThan100Concepts();
|
CodeSystem upload = createCodeSystemWithMoreThan100Concepts();
|
||||||
|
|
||||||
// Create CodeSystem resource
|
// Create CodeSystem resource
|
||||||
|
@ -34,15 +34,38 @@ public class TermCodeSystemStorageSvcTest extends BaseJpaR4Test {
|
||||||
assertEquals(125, myTermConceptDao.count());
|
assertEquals(125, myTermConceptDao.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStoreNewCodeSystemVersionForExistingCodeSystemVersionId() {
|
||||||
|
CodeSystem upload = createCodeSystemWithMoreThan100Concepts();
|
||||||
|
upload.setVersion("1");
|
||||||
|
|
||||||
|
// Create CodeSystem resource
|
||||||
|
ResourceTable codeSystemResourceEntity = (ResourceTable) myCodeSystemDao.create(upload, mySrd).getEntity();
|
||||||
|
|
||||||
|
// Update the CodeSystem resource
|
||||||
|
runInTransaction(() -> myTermCodeSystemStorageSvc.storeNewCodeSystemVersionIfNeeded(upload, codeSystemResourceEntity));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Because there are more than 100 concepts in the code system, the first 100 will be persisted immediately and
|
||||||
|
the remaining 25 concepts will be queued up for "deferred save".
|
||||||
|
|
||||||
|
As the CodeSystem was persisted twice, the extra 25 term concepts will be queued twice, each with a different
|
||||||
|
CodeSystem version PID. Only one set of the term concepts should be persisted (i.e. 125 term concepts in total).
|
||||||
|
*/
|
||||||
|
myTerminologyDeferredStorageSvc.setProcessDeferred(true);
|
||||||
|
myTerminologyDeferredStorageSvc.saveDeferred();
|
||||||
|
assertEquals(125, myTermConceptDao.count());
|
||||||
|
}
|
||||||
|
|
||||||
private CodeSystem createCodeSystemWithMoreThan100Concepts() {
|
private CodeSystem createCodeSystemWithMoreThan100Concepts() {
|
||||||
CodeSystem codeSystem = new CodeSystem();
|
CodeSystem codeSystem = new CodeSystem();
|
||||||
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
|
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
|
||||||
codeSystem.setContent(CodeSystem.CodeSystemContentMode.NOTPRESENT);
|
|
||||||
|
|
||||||
for (int i = 0; i < 125; i++) {
|
for (int i = 0; i < 125; i++) {
|
||||||
codeSystem.addConcept(new CodeSystem.ConceptDefinitionComponent(new CodeType("codeA " + i)));
|
codeSystem.addConcept(new CodeSystem.ConceptDefinitionComponent(new CodeType("codeA " + i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
codeSystem.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
|
||||||
return codeSystem;
|
return codeSystem;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,10 @@ import ca.uhn.fhir.jpa.term.loinc.LoincTop2000LabResultsUsHandler;
|
||||||
import ca.uhn.fhir.jpa.term.loinc.LoincUniversalOrderSetHandler;
|
import ca.uhn.fhir.jpa.term.loinc.LoincUniversalOrderSetHandler;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
|
||||||
import org.hl7.fhir.r4.model.CodeSystem;
|
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.Enumerations;
|
import org.hl7.fhir.r4.model.Enumerations;
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -342,6 +340,28 @@ public class TerminologyLoaderSvcLoincTest extends BaseLoaderTest {
|
||||||
assertEquals("13006-2", vs.getCompose().getInclude().get(0).getConcept().get(1).getCode());
|
assertEquals("13006-2", vs.getCompose().getInclude().get(0).getConcept().get(1).getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadLoincMultipleVersions() throws IOException {
|
||||||
|
|
||||||
|
// Load LOINC marked as version 2.67
|
||||||
|
addLoincMandatoryFilesWithPropertiesFileToZip(myFiles, "v267_loincupload.properties");
|
||||||
|
mySvc.loadLoinc(myFiles.getFiles(), mySrd);
|
||||||
|
|
||||||
|
verify(myTermCodeSystemStorageSvc, times(1)).storeNewCodeSystemVersion(mySystemCaptor.capture(), myCsvCaptor.capture(), any(RequestDetails.class), myValueSetsCaptor.capture(), myConceptMapCaptor.capture());
|
||||||
|
CodeSystem loincCS = mySystemCaptor.getValue();
|
||||||
|
assertEquals("2.67", loincCS.getVersion());
|
||||||
|
|
||||||
|
// Load LOINC marked as version 2.68
|
||||||
|
myFiles = new ZipCollectionBuilder();
|
||||||
|
addLoincMandatoryFilesWithPropertiesFileToZip(myFiles, "v268_loincupload.properties");
|
||||||
|
mySvc.loadLoinc(myFiles.getFiles(), mySrd);
|
||||||
|
|
||||||
|
verify(myTermCodeSystemStorageSvc, times(2)).storeNewCodeSystemVersion(mySystemCaptor.capture(), myCsvCaptor.capture(), any(RequestDetails.class), myValueSetsCaptor.capture(), myConceptMapCaptor.capture());
|
||||||
|
loincCS = mySystemCaptor.getValue();
|
||||||
|
assertEquals("2.68", loincCS.getVersion());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Disabled
|
@Disabled
|
||||||
public void testLoadLoincMandatoryFilesOnly() throws IOException {
|
public void testLoadLoincMandatoryFilesOnly() throws IOException {
|
||||||
|
@ -382,7 +402,11 @@ public class TerminologyLoaderSvcLoincTest extends BaseLoaderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addLoincMandatoryFilesToZip(ZipCollectionBuilder theFiles) throws IOException {
|
public static void addLoincMandatoryFilesToZip(ZipCollectionBuilder theFiles) throws IOException {
|
||||||
theFiles.addFileZip("/loinc/", LOINC_UPLOAD_PROPERTIES_FILE.getCode());
|
addLoincMandatoryFilesWithPropertiesFileToZip(theFiles, LOINC_UPLOAD_PROPERTIES_FILE.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addLoincMandatoryFilesWithPropertiesFileToZip(ZipCollectionBuilder theFiles, String thePropertiesFile) throws IOException {
|
||||||
|
theFiles.addFileZip("/loinc/", thePropertiesFile);
|
||||||
theFiles.addFileZip("/loinc/", LOINC_GROUP_FILE_DEFAULT.getCode());
|
theFiles.addFileZip("/loinc/", LOINC_GROUP_FILE_DEFAULT.getCode());
|
||||||
theFiles.addFileZip("/loinc/", LOINC_GROUP_TERMS_FILE_DEFAULT.getCode());
|
theFiles.addFileZip("/loinc/", LOINC_GROUP_TERMS_FILE_DEFAULT.getCode());
|
||||||
theFiles.addFileZip("/loinc/", LOINC_PARENT_GROUP_FILE_DEFAULT.getCode());
|
theFiles.addFileZip("/loinc/", LOINC_PARENT_GROUP_FILE_DEFAULT.getCode());
|
||||||
|
|
|
@ -184,7 +184,7 @@ public class TerminologySvcDeltaR4Test extends BaseJpaR4Test {
|
||||||
assertEquals(2, outcome.getUpdatedConceptCount());
|
assertEquals(2, outcome.getUpdatedConceptCount());
|
||||||
|
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
TermConcept concept = myTermSvc.findCode("http://foo/cs", "ChildAA").orElseThrow(() -> new IllegalStateException());
|
TermConcept concept = myTermSvc.findCode("http://foo/cs", "ChildAA", null).orElseThrow(() -> new IllegalStateException());
|
||||||
assertEquals(2, concept.getParents().size());
|
assertEquals(2, concept.getParents().size());
|
||||||
assertThat(concept.getParentPidsAsString(), matchesPattern("^[0-9]+ [0-9]+$"));
|
assertThat(concept.getParentPidsAsString(), matchesPattern("^[0-9]+ [0-9]+$"));
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,11 +4,15 @@ import ca.uhn.fhir.context.support.ConceptValidationOptions;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
||||||
import ca.uhn.fhir.jpa.api.model.TranslationRequest;
|
import ca.uhn.fhir.jpa.api.model.TranslationRequest;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptMap;
|
import ca.uhn.fhir.jpa.entity.TermConceptMap;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptMapGroup;
|
import ca.uhn.fhir.jpa.entity.TermConceptMapGroup;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement;
|
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget;
|
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget;
|
||||||
import ca.uhn.fhir.jpa.entity.TermValueSet;
|
import ca.uhn.fhir.jpa.entity.TermValueSet;
|
||||||
|
import ca.uhn.fhir.model.dstu2.valueset.ContentTypeEnum;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.CanonicalType;
|
import org.hl7.fhir.r4.model.CanonicalType;
|
||||||
|
@ -30,9 +34,14 @@ import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
@ -1880,4 +1889,109 @@ public class TerminologySvcImplR4Test extends BaseTermR4Test {
|
||||||
assertTrue(result.isOk());
|
assertTrue(result.isOk());
|
||||||
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateCodeSystemTwoVersions() {
|
||||||
|
CodeSystem codeSystem = new CodeSystem();
|
||||||
|
codeSystem.setUrl(CS_URL);
|
||||||
|
codeSystem.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
|
||||||
|
codeSystem
|
||||||
|
.addConcept().setCode("A").setDisplay("Code A");
|
||||||
|
codeSystem
|
||||||
|
.addConcept().setCode("B").setDisplay("Code A");
|
||||||
|
|
||||||
|
codeSystem.setVersion("1");
|
||||||
|
|
||||||
|
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
|
||||||
|
|
||||||
|
Set<TermConcept> codes = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "A");
|
||||||
|
assertThat(toCodes(codes), containsInAnyOrder("A"));
|
||||||
|
|
||||||
|
codes = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "B");
|
||||||
|
assertThat(toCodes(codes), containsInAnyOrder("B"));
|
||||||
|
|
||||||
|
runInTransaction(() -> {
|
||||||
|
List<TermCodeSystemVersion> termCodeSystemVersions = myTermCodeSystemVersionDao.findAll();
|
||||||
|
assertEquals(termCodeSystemVersions.size(), 1);
|
||||||
|
TermCodeSystemVersion termCodeSystemVersion_1 = termCodeSystemVersions.get(0);
|
||||||
|
assertEquals(termCodeSystemVersion_1.getConcepts().size(), 2);
|
||||||
|
Set<TermConcept> termConcepts = new HashSet<>(termCodeSystemVersion_1.getConcepts());
|
||||||
|
assertThat(toCodes(termConcepts), containsInAnyOrder("A", "B"));
|
||||||
|
|
||||||
|
TermCodeSystem termCodeSystem = myTermCodeSystemDao.findByResourcePid(id.getIdPartAsLong());
|
||||||
|
assertEquals("1", termCodeSystem.getCurrentVersion().getCodeSystemVersionId());
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
codeSystem.setVersion("2");
|
||||||
|
codeSystem
|
||||||
|
.addConcept().setCode("C").setDisplay("Code C");
|
||||||
|
|
||||||
|
myCodeSystemDao.update(codeSystem, mySrd).getId().toUnqualified();
|
||||||
|
codes = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "C");
|
||||||
|
assertThat(toCodes(codes), containsInAnyOrder("C"));
|
||||||
|
|
||||||
|
runInTransaction(() -> {
|
||||||
|
List<TermCodeSystemVersion> termCodeSystemVersions_updated = myTermCodeSystemVersionDao.findAll();
|
||||||
|
assertEquals(termCodeSystemVersions_updated.size(), 2);
|
||||||
|
TermCodeSystemVersion termCodeSystemVersion_2 = termCodeSystemVersions_updated.get(1);
|
||||||
|
assertEquals(termCodeSystemVersion_2.getConcepts().size(), 3);
|
||||||
|
Set<TermConcept> termConcepts_updated = new HashSet<>(termCodeSystemVersion_2.getConcepts());
|
||||||
|
assertThat(toCodes(termConcepts_updated), containsInAnyOrder("A", "B", "C"));
|
||||||
|
|
||||||
|
TermCodeSystem termCodeSystem = myTermCodeSystemDao.findByResourcePid(id.getIdPartAsLong());
|
||||||
|
assertEquals("2", termCodeSystem.getCurrentVersion().getCodeSystemVersionId());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateCodeSystemContentModeNotPresent() {
|
||||||
|
CodeSystem codeSystem = new CodeSystem();
|
||||||
|
codeSystem.setUrl(CS_URL);
|
||||||
|
codeSystem.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
|
||||||
|
codeSystem
|
||||||
|
.addConcept().setCode("A").setDisplay("Code A");
|
||||||
|
codeSystem
|
||||||
|
.addConcept().setCode("B").setDisplay("Code A");
|
||||||
|
|
||||||
|
codeSystem.setVersion("1");
|
||||||
|
|
||||||
|
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
|
||||||
|
|
||||||
|
Set<TermConcept> codes = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "A");
|
||||||
|
assertThat(toCodes(codes), containsInAnyOrder("A"));
|
||||||
|
|
||||||
|
codes = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "B");
|
||||||
|
assertThat(toCodes(codes), containsInAnyOrder("B"));
|
||||||
|
|
||||||
|
runInTransaction(() -> {
|
||||||
|
List<TermCodeSystemVersion> termCodeSystemVersions = myTermCodeSystemVersionDao.findAll();
|
||||||
|
assertEquals(termCodeSystemVersions.size(), 1);
|
||||||
|
TermCodeSystemVersion termCodeSystemVersion_1 = termCodeSystemVersions.get(0);
|
||||||
|
assertEquals(termCodeSystemVersion_1.getConcepts().size(), 2);
|
||||||
|
Set<TermConcept> termConcepts = new HashSet<>(termCodeSystemVersion_1.getConcepts());
|
||||||
|
assertThat(toCodes(termConcepts), containsInAnyOrder("A", "B"));
|
||||||
|
|
||||||
|
TermCodeSystem termCodeSystem = myTermCodeSystemDao.findByResourcePid(id.getIdPartAsLong());
|
||||||
|
assertEquals("1", termCodeSystem.getCurrentVersion().getCodeSystemVersionId());
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove concepts and changed ContentMode to NOTPRESENT
|
||||||
|
codeSystem.setConcept(new ArrayList<>());
|
||||||
|
codeSystem.setContent((CodeSystem.CodeSystemContentMode.NOTPRESENT));
|
||||||
|
|
||||||
|
myCodeSystemDao.update(codeSystem, mySrd).getId().toUnqualified();
|
||||||
|
runInTransaction(() -> {
|
||||||
|
List<TermCodeSystemVersion> termCodeSystemVersions_updated = myTermCodeSystemVersionDao.findAll();
|
||||||
|
assertEquals(termCodeSystemVersions_updated.size(), 1);
|
||||||
|
TermCodeSystemVersion termCodeSystemVersion_2 = termCodeSystemVersions_updated.get(0);
|
||||||
|
assertEquals(termCodeSystemVersion_2.getConcepts().size(), 2);
|
||||||
|
Set<TermConcept> termConcepts_updated = new HashSet<>(termCodeSystemVersion_2.getConcepts());
|
||||||
|
assertThat(toCodes(termConcepts_updated), containsInAnyOrder("A", "B"));
|
||||||
|
|
||||||
|
TermCodeSystem termCodeSystem = myTermCodeSystemDao.findByResourcePid(id.getIdPartAsLong());
|
||||||
|
assertEquals("1", termCodeSystem.getCurrentVersion().getCodeSystemVersionId());
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
#################
|
||||||
|
### MANDATORY ###
|
||||||
|
#################
|
||||||
|
|
||||||
|
# Answer lists (ValueSets of potential answers/values for LOINC "questions")
|
||||||
|
## File must be present
|
||||||
|
loinc.answerlist.file=AccessoryFiles/AnswerFile/AnswerList.csv
|
||||||
|
# Answer list links (connects LOINC observation codes to answer list codes)
|
||||||
|
## File must be present
|
||||||
|
loinc.answerlist.link.file=AccessoryFiles/AnswerFile/LoincAnswerListLink.csv
|
||||||
|
|
||||||
|
# Document ontology
|
||||||
|
## File must be present
|
||||||
|
loinc.document.ontology.file=AccessoryFiles/DocumentOntology/DocumentOntology.csv
|
||||||
|
|
||||||
|
# LOINC codes
|
||||||
|
## File must be present
|
||||||
|
loinc.file=LoincTable/Loinc.csv
|
||||||
|
|
||||||
|
# LOINC hierarchy
|
||||||
|
## File must be present
|
||||||
|
loinc.hierarchy.file=AccessoryFiles/MultiAxialHierarchy/MultiAxialHierarchy.csv
|
||||||
|
|
||||||
|
# IEEE medical device codes
|
||||||
|
## File must be present
|
||||||
|
loinc.ieee.medical.device.code.mapping.table.file=AccessoryFiles/LoincIeeeMedicalDeviceCodeMappingTable/LoincIeeeMedicalDeviceCodeMappingTable.csv
|
||||||
|
|
||||||
|
# Imaging document codes
|
||||||
|
## File must be present
|
||||||
|
loinc.imaging.document.codes.file=AccessoryFiles/ImagingDocuments/ImagingDocumentCodes.csv
|
||||||
|
|
||||||
|
# Part
|
||||||
|
## File must be present
|
||||||
|
loinc.part.file=AccessoryFiles/PartFile/Part.csv
|
||||||
|
|
||||||
|
# Part link
|
||||||
|
## File must be present
|
||||||
|
loinc.part.link.primary.file=AccessoryFiles/PartFile/LoincPartLink_Primary.csv
|
||||||
|
loinc.part.link.supplementary.file=AccessoryFiles/PartFile/LoincPartLink_Supplementary.csv
|
||||||
|
|
||||||
|
# Part related code mapping
|
||||||
|
## File must be present
|
||||||
|
loinc.part.related.code.mapping.file=AccessoryFiles/PartFile/PartRelatedCodeMapping.csv
|
||||||
|
|
||||||
|
# RSNA playbook
|
||||||
|
## File must be present
|
||||||
|
loinc.rsna.playbook.file=AccessoryFiles/LoincRsnaRadiologyPlaybook/LoincRsnaRadiologyPlaybook.csv
|
||||||
|
|
||||||
|
# Top 2000 codes - SI
|
||||||
|
## File must be present
|
||||||
|
loinc.top2000.common.lab.results.si.file=AccessoryFiles/Top2000Results/SI/Top2000CommonLabResultsSi.csv
|
||||||
|
# Top 2000 codes - US
|
||||||
|
## File must be present
|
||||||
|
loinc.top2000.common.lab.results.us.file=AccessoryFiles/Top2000Results/US/Top2000CommonLabResultsUs.csv
|
||||||
|
|
||||||
|
# Universal lab order ValueSet
|
||||||
|
## File must be present
|
||||||
|
loinc.universal.lab.order.valueset.file=AccessoryFiles/LoincUniversalLabOrdersValueSet/LoincUniversalLabOrdersValueSet.csv
|
||||||
|
|
||||||
|
################
|
||||||
|
### OPTIONAL ###
|
||||||
|
################
|
||||||
|
|
||||||
|
# This is the version identifier for the LOINC code system
|
||||||
|
## Key may be omitted if only a single version of LOINC is being kept.
|
||||||
|
loinc.codesystem.version=2.67
|
||||||
|
|
||||||
|
# This is the version identifier for the answer list file
|
||||||
|
## Key may be omitted
|
||||||
|
loinc.answerlist.version=Beta.1
|
||||||
|
|
||||||
|
# This is the version identifier for uploaded ConceptMap resources
|
||||||
|
## Key may be omitted
|
||||||
|
loinc.conceptmap.version=Beta.1
|
||||||
|
|
||||||
|
# Group
|
||||||
|
## Default value if key not provided: AccessoryFiles/GroupFile/Group.csv
|
||||||
|
## File may be omitted
|
||||||
|
loinc.group.file=AccessoryFiles/GroupFile/Group.csv
|
||||||
|
# Group terms
|
||||||
|
## Default value if key not provided: AccessoryFiles/GroupFile/GroupLoincTerms.csv
|
||||||
|
## File may be omitted
|
||||||
|
loinc.group.terms.file=AccessoryFiles/GroupFile/GroupLoincTerms.csv
|
||||||
|
# Parent group
|
||||||
|
## Default value if key not provided: AccessoryFiles/GroupFile/ParentGroup.csv
|
||||||
|
## File may be omitted
|
||||||
|
loinc.parent.group.file=AccessoryFiles/GroupFile/ParentGroup.csv
|
|
@ -0,0 +1,87 @@
|
||||||
|
#################
|
||||||
|
### MANDATORY ###
|
||||||
|
#################
|
||||||
|
|
||||||
|
# This is the version identifier for the LOINC code system
|
||||||
|
## Key may be omitted if only a single version of LOINC is being kept.
|
||||||
|
loinc.codesystem.version=2.68
|
||||||
|
|
||||||
|
# Answer lists (ValueSets of potential answers/values for LOINC "questions")
|
||||||
|
## File must be present
|
||||||
|
loinc.answerlist.file=AccessoryFiles/AnswerFile/AnswerList.csv
|
||||||
|
# Answer list links (connects LOINC observation codes to answer list codes)
|
||||||
|
## File must be present
|
||||||
|
loinc.answerlist.link.file=AccessoryFiles/AnswerFile/LoincAnswerListLink.csv
|
||||||
|
|
||||||
|
# Document ontology
|
||||||
|
## File must be present
|
||||||
|
loinc.document.ontology.file=AccessoryFiles/DocumentOntology/DocumentOntology.csv
|
||||||
|
|
||||||
|
# LOINC codes
|
||||||
|
## File must be present
|
||||||
|
loinc.file=LoincTable/Loinc.csv
|
||||||
|
|
||||||
|
# LOINC hierarchy
|
||||||
|
## File must be present
|
||||||
|
loinc.hierarchy.file=AccessoryFiles/MultiAxialHierarchy/MultiAxialHierarchy.csv
|
||||||
|
|
||||||
|
# IEEE medical device codes
|
||||||
|
## File must be present
|
||||||
|
loinc.ieee.medical.device.code.mapping.table.file=AccessoryFiles/LoincIeeeMedicalDeviceCodeMappingTable/LoincIeeeMedicalDeviceCodeMappingTable.csv
|
||||||
|
|
||||||
|
# Imaging document codes
|
||||||
|
## File must be present
|
||||||
|
loinc.imaging.document.codes.file=AccessoryFiles/ImagingDocuments/ImagingDocumentCodes.csv
|
||||||
|
|
||||||
|
# Part
|
||||||
|
## File must be present
|
||||||
|
loinc.part.file=AccessoryFiles/PartFile/Part.csv
|
||||||
|
|
||||||
|
# Part link
|
||||||
|
## File must be present
|
||||||
|
loinc.part.link.primary.file=AccessoryFiles/PartFile/LoincPartLink_Primary.csv
|
||||||
|
loinc.part.link.supplementary.file=AccessoryFiles/PartFile/LoincPartLink_Supplementary.csv
|
||||||
|
|
||||||
|
# Part related code mapping
|
||||||
|
## File must be present
|
||||||
|
loinc.part.related.code.mapping.file=AccessoryFiles/PartFile/PartRelatedCodeMapping.csv
|
||||||
|
|
||||||
|
# RSNA playbook
|
||||||
|
## File must be present
|
||||||
|
loinc.rsna.playbook.file=AccessoryFiles/LoincRsnaRadiologyPlaybook/LoincRsnaRadiologyPlaybook.csv
|
||||||
|
|
||||||
|
# Top 2000 codes - SI
|
||||||
|
## File must be present
|
||||||
|
loinc.top2000.common.lab.results.si.file=AccessoryFiles/Top2000Results/SI/Top2000CommonLabResultsSi.csv
|
||||||
|
# Top 2000 codes - US
|
||||||
|
## File must be present
|
||||||
|
loinc.top2000.common.lab.results.us.file=AccessoryFiles/Top2000Results/US/Top2000CommonLabResultsUs.csv
|
||||||
|
|
||||||
|
# Universal lab order ValueSet
|
||||||
|
## File must be present
|
||||||
|
loinc.universal.lab.order.valueset.file=AccessoryFiles/LoincUniversalLabOrdersValueSet/LoincUniversalLabOrdersValueSet.csv
|
||||||
|
|
||||||
|
################
|
||||||
|
### OPTIONAL ###
|
||||||
|
################
|
||||||
|
|
||||||
|
# This is the version identifier for the answer list file
|
||||||
|
## Key may be omitted
|
||||||
|
loinc.answerlist.version=Beta.1
|
||||||
|
|
||||||
|
# This is the version identifier for uploaded ConceptMap resources
|
||||||
|
## Key may be omitted
|
||||||
|
loinc.conceptmap.version=Beta.1
|
||||||
|
|
||||||
|
# Group
|
||||||
|
## Default value if key not provided: AccessoryFiles/GroupFile/Group.csv
|
||||||
|
## File may be omitted
|
||||||
|
loinc.group.file=AccessoryFiles/GroupFile/Group.csv
|
||||||
|
# Group terms
|
||||||
|
## Default value if key not provided: AccessoryFiles/GroupFile/GroupLoincTerms.csv
|
||||||
|
## File may be omitted
|
||||||
|
loinc.group.terms.file=AccessoryFiles/GroupFile/GroupLoincTerms.csv
|
||||||
|
# Parent group
|
||||||
|
## Default value if key not provided: AccessoryFiles/GroupFile/ParentGroup.csv
|
||||||
|
## File may be omitted
|
||||||
|
loinc.parent.group.file=AccessoryFiles/GroupFile/ParentGroup.csv
|
|
@ -58,6 +58,11 @@ public class BaseValidationSupportWrapper extends BaseValidationSupport {
|
||||||
return myWrap.validateCode(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSetUrl);
|
return myWrap.validateCode(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSetUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode, String theVersion) {
|
||||||
|
return myWrap.lookupCode(theValidationSupportContext, theSystem, theCode, theVersion);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
||||||
return myWrap.lookupCode(theValidationSupportContext, theSystem, theCode);
|
return myWrap.lookupCode(theValidationSupportContext, theSystem, theCode);
|
||||||
|
|
|
@ -83,6 +83,12 @@ public class CachingValidationSupport extends BaseValidationSupportWrapper imple
|
||||||
return loadFromCache(myValidateCodeCache, key, t -> super.validateCode(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSetUrl));
|
return loadFromCache(myValidateCodeCache, key, t -> super.validateCode(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSetUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode, String theVersion) {
|
||||||
|
String key = "lookupCode " + theSystem + " " + theCode + " " + theVersion;
|
||||||
|
return loadFromCache(myLookupCodeCache, key, t -> super.lookupCode(theValidationSupportContext, theSystem, theCode, theVersion));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
||||||
String key = "lookupCode " + theSystem + " " + theCode;
|
String key = "lookupCode " + theSystem + " " + theCode;
|
||||||
|
|
|
@ -145,6 +145,12 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode, String theVersion) {
|
||||||
|
// For now Common Code Systems will not be versioned.
|
||||||
|
return lookupCode(theValidationSupportContext, theSystem, theCode);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
||||||
|
|
||||||
|
|
|
@ -308,6 +308,12 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
|
||||||
.setMessage(message);
|
.setMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode, String theVersion) {
|
||||||
|
// TODO: Add support for validating versioned codes as well.
|
||||||
|
return lookupCode(theValidationSupportContext, theSystem, theCode);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
||||||
return validateCode(theValidationSupportContext, new ConceptValidationOptions(), theSystem, theCode, null, null).asLookupCodeResult(theSystem, theCode);
|
return validateCode(theValidationSupportContext, new ConceptValidationOptions(), theSystem, theCode, null, null).asLookupCodeResult(theSystem, theCode);
|
||||||
|
@ -470,6 +476,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
|
||||||
|
|
||||||
List<VersionIndependentConcept> nextCodeList = new ArrayList<>();
|
List<VersionIndependentConcept> nextCodeList = new ArrayList<>();
|
||||||
String system = nextInclude.getSystem();
|
String system = nextInclude.getSystem();
|
||||||
|
String systemVersion = nextInclude.getVersion();
|
||||||
if (isNotBlank(system)) {
|
if (isNotBlank(system)) {
|
||||||
|
|
||||||
if (theWantSystem != null && !theWantSystem.equals(system)) {
|
if (theWantSystem != null && !theWantSystem.equals(system)) {
|
||||||
|
@ -492,7 +499,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
|
||||||
|
|
||||||
if (theWantCode != null) {
|
if (theWantCode != null) {
|
||||||
if (theValidationSupportContext.getRootValidationSupport().isCodeSystemSupported(theValidationSupportContext, system)) {
|
if (theValidationSupportContext.getRootValidationSupport().isCodeSystemSupported(theValidationSupportContext, system)) {
|
||||||
LookupCodeResult lookup = theValidationSupportContext.getRootValidationSupport().lookupCode(theValidationSupportContext, system, theWantCode);
|
LookupCodeResult lookup = theValidationSupportContext.getRootValidationSupport().lookupCode(theValidationSupportContext, system, theWantCode, systemVersion);
|
||||||
if (lookup != null && lookup.isFound()) {
|
if (lookup != null && lookup.isFound()) {
|
||||||
CodeSystem.ConceptDefinitionComponent conceptDefinition = new CodeSystem.ConceptDefinitionComponent()
|
CodeSystem.ConceptDefinitionComponent conceptDefinition = new CodeSystem.ConceptDefinitionComponent()
|
||||||
.addConcept()
|
.addConcept()
|
||||||
|
|
|
@ -257,6 +257,16 @@ public class ValidationSupportChain implements IValidationSupport {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode, String theVersion) {
|
||||||
|
for (IValidationSupport next : myChain) {
|
||||||
|
if (next.isCodeSystemSupported(theValidationSupportContext, theSystem)) {
|
||||||
|
return next.lookupCode(theValidationSupportContext, theSystem, theCode, theVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
||||||
for (IValidationSupport next : myChain) {
|
for (IValidationSupport next : myChain) {
|
||||||
|
|
Loading…
Reference in New Issue