Validate code changes and new tests.

This commit is contained in:
ianmarshall 2020-09-24 18:51:47 -04:00
parent e5daea17b7
commit 5fe46be41c
18 changed files with 2472 additions and 501 deletions

View File

@ -100,7 +100,11 @@ public class FhirResourceDaoCodeSystemDstu3 extends BaseHapiFhirResourceDao<Code
String system; String system;
if (haveCoding) { if (haveCoding) {
code = theCoding.getCode(); code = theCoding.getCode();
system = theCoding.getSystem(); if (theCoding.hasVersion()) {
system = theCoding.getSystem() + "|" + theCoding.getVersion();
} else {
system = theCoding.getSystem();
}
} else { } else {
code = theCode.getValue(); code = theCode.getValue();
system = theSystem.getValue(); system = theSystem.getValue();

View File

@ -95,7 +95,11 @@ public class FhirResourceDaoCodeSystemR4 extends BaseHapiFhirResourceDao<CodeSys
String system; String system;
if (haveCoding) { if (haveCoding) {
code = theCoding.getCode(); code = theCoding.getCode();
system = theCoding.getSystem(); if (theCoding.hasVersion()) {
system = theCoding.getSystem() + "|" + theCoding.getVersion();
} else {
system = theCoding.getSystem();
}
} else { } else {
code = theCode.getValue(); code = theCode.getValue();
system = theSystem.getValue(); system = theSystem.getValue();

View File

@ -97,7 +97,11 @@ public class FhirResourceDaoCodeSystemR5 extends BaseHapiFhirResourceDao<CodeSys
String system; String system;
if (haveCoding) { if (haveCoding) {
code = theCoding.getCode(); code = theCoding.getCode();
system = theCoding.getSystem(); if (theCoding.hasVersion()) {
system = theCoding.getSystem() + "|" + theCoding.getVersion();
} else {
system = theCoding.getSystem();
}
} else { } else {
code = theCode.getValue(); code = theCode.getValue();
system = theSystem.getValue(); system = theSystem.getValue();

View File

@ -144,8 +144,10 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
@IdParam(optional = true) IdType theId, @IdParam(optional = true) IdType theId,
@OperationParam(name = "identifier", min = 0, max = 1) UriType theValueSetIdentifier, @OperationParam(name = "identifier", min = 0, max = 1) UriType theValueSetIdentifier,
@OperationParam(name = "url", min = 0, max = 1) UriType theValueSetUrl, @OperationParam(name = "url", min = 0, max = 1) UriType theValueSetUrl,
@OperationParam(name = "valueSetVersion", min = 0, max = 1) StringType theValueSetVersion,
@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 = "systemVersion", min = 0, max = 1) StringType theSystemVersion,
@OperationParam(name = "display", min = 0, max = 1) StringType theDisplay, @OperationParam(name = "display", min = 0, max = 1) StringType theDisplay,
@OperationParam(name = "coding", min = 0, max = 1) Coding theCoding, @OperationParam(name = "coding", min = 0, max = 1) Coding theCoding,
@OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConcept theCodeableConcept, @OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConcept theCodeableConcept,
@ -160,7 +162,19 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
startRequest(theServletRequest); startRequest(theServletRequest);
try { try {
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao(); IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
IValidationSupport.CodeValidationResult result = dao.validateCode(url, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept, theRequestDetails); UriType valueSetIdentifier;
if (theValueSetVersion != null) {
valueSetIdentifier = new UriType(theValueSetUrl.getValue() + "|" + theValueSetVersion);
} else {
valueSetIdentifier = theValueSetUrl;
}
UriType codeSystemIdentifier;
if (theSystemVersion != null) {
codeSystemIdentifier = new UriType(theSystem.getValue() + "|" + theSystemVersion);
} else {
codeSystemIdentifier = theSystem;
}
IValidationSupport.CodeValidationResult result = dao.validateCode(valueSetIdentifier, theId, theCode, codeSystemIdentifier, theDisplay, theCoding, theCodeableConcept, theRequestDetails);
return (Parameters) BaseJpaResourceProviderValueSetDstu2.toValidateCodeResult(getContext(), result); return (Parameters) BaseJpaResourceProviderValueSetDstu2.toValidateCodeResult(getContext(), result);
} finally { } finally {
endRequest(theServletRequest); endRequest(theServletRequest);

View File

@ -66,9 +66,6 @@ public class BaseJpaResourceProviderCodeSystemR4 extends JpaResourceProviderR4<C
IValidationSupport.LookupCodeResult result; IValidationSupport.LookupCodeResult result;
if (theVersion != null) { if (theVersion != null) {
result = dao.lookupCode(theCode, new UriType(theSystem.getValue() + "|" + theVersion), theCoding, theRequestDetails); result = dao.lookupCode(theCode, new UriType(theSystem.getValue() + "|" + theVersion), theCoding, theRequestDetails);
} else if (theCoding != null && theCoding.hasVersion()) {
Coding codingWithVersion = new Coding(theCoding.getSystem() + "|" + theCoding.getVersion(), theCoding.getCode(), theCoding.getDisplay());
result = dao.lookupCode(theCode, theSystem, codingWithVersion, theRequestDetails);
} else { } else {
result = dao.lookupCode(theCode, theSystem, theCoding, theRequestDetails); result = dao.lookupCode(theCode, theSystem, theCoding, theRequestDetails);
} }
@ -104,12 +101,6 @@ public class BaseJpaResourceProviderCodeSystemR4 extends JpaResourceProviderR4<C
if (theVersion != null) { if (theVersion != null) {
theSystem = new UriType(theSystem.asStringValue() + "|" + theVersion.toString()); theSystem = new UriType(theSystem.asStringValue() + "|" + theVersion.toString());
} }
if (theCodingA != null && theCodingA.hasVersion()) {
theCodingA.setSystem(theCodingA.getSystemElement().asStringValue() + "|" + theCodingA.getVersion());
}
if (theCodingB != null && theCodingB.hasVersion()) {
theCodingB.setSystem(theCodingB.getSystemElement().asStringValue() + "|" + theCodingB.getVersion());
}
result = dao.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB, theRequestDetails); result = dao.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB, theRequestDetails);
return (Parameters) result.toParameters(theRequestDetails.getFhirContext()); return (Parameters) result.toParameters(theRequestDetails.getFhirContext());
} finally { } finally {

View File

@ -135,8 +135,10 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
HttpServletRequest theServletRequest, HttpServletRequest theServletRequest,
@IdParam(optional = true) IdType theId, @IdParam(optional = true) IdType theId,
@OperationParam(name = "url", min = 0, max = 1) UriType theValueSetUrl, @OperationParam(name = "url", min = 0, max = 1) UriType theValueSetUrl,
@OperationParam(name = "valueSetVersion", min = 0, max = 1) StringType theValueSetVersion,
@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 = "systemVersion", min = 0, max = 1) StringType theSystemVersion,
@OperationParam(name = "display", min = 0, max = 1) StringType theDisplay, @OperationParam(name = "display", min = 0, max = 1) StringType theDisplay,
@OperationParam(name = "coding", min = 0, max = 1) Coding theCoding, @OperationParam(name = "coding", min = 0, max = 1) Coding theCoding,
@OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConcept theCodeableConcept, @OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConcept theCodeableConcept,
@ -146,7 +148,19 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
startRequest(theServletRequest); startRequest(theServletRequest);
try { try {
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao(); IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
IValidationSupport.CodeValidationResult result = dao.validateCode(theValueSetUrl, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept, theRequestDetails); UriType valueSetIdentifier;
if (theValueSetVersion != null) {
valueSetIdentifier = new UriType(theValueSetUrl.getValue() + "|" + theValueSetVersion);
} else {
valueSetIdentifier = theValueSetUrl;
}
UriType codeSystemIdentifier;
if (theSystemVersion != null) {
codeSystemIdentifier = new UriType(theSystem.getValue() + "|" + theSystemVersion);
} else {
codeSystemIdentifier = theSystem;
}
IValidationSupport.CodeValidationResult result = dao.validateCode(valueSetIdentifier, theId, theCode, codeSystemIdentifier, theDisplay, theCoding, theCodeableConcept, theRequestDetails);
return (Parameters) BaseJpaResourceProviderValueSetDstu2.toValidateCodeResult(getContext(), result); return (Parameters) BaseJpaResourceProviderValueSetDstu2.toValidateCodeResult(getContext(), result);
} finally { } finally {
endRequest(theServletRequest); endRequest(theServletRequest);

View File

@ -66,9 +66,6 @@ public class BaseJpaResourceProviderCodeSystemR5 extends JpaResourceProviderR5<C
IValidationSupport.LookupCodeResult result; IValidationSupport.LookupCodeResult result;
if (theVersion != null) { if (theVersion != null) {
result = dao.lookupCode(theCode, new UriType(theSystem.getValue() + "|" + theVersion), theCoding, theRequestDetails); result = dao.lookupCode(theCode, new UriType(theSystem.getValue() + "|" + theVersion), theCoding, theRequestDetails);
} else if (theCoding != null && theCoding.hasVersion()) {
Coding codingWithVersion = new Coding(theCoding.getSystem() + "|" + theCoding.getVersion(), theCoding.getCode(), theCoding.getDisplay());
result = dao.lookupCode(theCode, theSystem, codingWithVersion, theRequestDetails);
} else { } else {
result = dao.lookupCode(theCode, theSystem, theCoding, theRequestDetails); result = dao.lookupCode(theCode, theSystem, theCoding, theRequestDetails);
} }
@ -104,12 +101,6 @@ public class BaseJpaResourceProviderCodeSystemR5 extends JpaResourceProviderR5<C
if (theVersion != null) { if (theVersion != null) {
theSystem = new UriType(theSystem.asStringValue() + "|" + theVersion.toString()); theSystem = new UriType(theSystem.asStringValue() + "|" + theVersion.toString());
} }
if (theCodingA != null && theCodingA.hasVersion()) {
theCodingA.setSystem(theCodingA.getSystemElement().asStringValue() + "|" + theCodingA.getVersion());
}
if (theCodingB != null && theCodingB.hasVersion()) {
theCodingB.setSystem(theCodingB.getSystemElement().asStringValue() + "|" + theCodingB.getVersion());
}
result = dao.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB, theRequestDetails); result = dao.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB, theRequestDetails);
return (Parameters) result.toParameters(theRequestDetails.getFhirContext()); return (Parameters) result.toParameters(theRequestDetails.getFhirContext());
} finally { } finally {

View File

@ -44,7 +44,7 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
@IdParam(optional = true) IdType theId, @IdParam(optional = true) IdType theId,
@OperationParam(name = "valueSet", min = 0, max = 1) ValueSet theValueSet, @OperationParam(name = "valueSet", min = 0, max = 1) ValueSet theValueSet,
@OperationParam(name = "url", min = 0, max = 1) UriType theUrl, @OperationParam(name = "url", min = 0, max = 1) UriType theUrl,
@OperationParam(name = "valueSetVersion", min = 0, max = 1) org.hl7.fhir.r4.model.StringType theValueSetVersion, @OperationParam(name = "valueSetVersion", min = 0, max = 1) StringType theValueSetVersion,
@OperationParam(name = "filter", min = 0, max = 1) StringType theFilter, @OperationParam(name = "filter", min = 0, max = 1) StringType theFilter,
@OperationParam(name = "offset", min = 0, max = 1) IntegerType theOffset, @OperationParam(name = "offset", min = 0, max = 1) IntegerType theOffset,
@OperationParam(name = "count", min = 0, max = 1) IntegerType theCount, @OperationParam(name = "count", min = 0, max = 1) IntegerType theCount,
@ -135,8 +135,10 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
HttpServletRequest theServletRequest, HttpServletRequest theServletRequest,
@IdParam(optional = true) IdType theId, @IdParam(optional = true) IdType theId,
@OperationParam(name = "url", min = 0, max = 1) UriType theValueSetUrl, @OperationParam(name = "url", min = 0, max = 1) UriType theValueSetUrl,
@OperationParam(name = "valueSetVersion", min = 0, max = 1) StringType theValueSetVersion,
@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 = "systemVersion", min = 0, max = 1) StringType theSystemVersion,
@OperationParam(name = "display", min = 0, max = 1) StringType theDisplay, @OperationParam(name = "display", min = 0, max = 1) StringType theDisplay,
@OperationParam(name = "coding", min = 0, max = 1) Coding theCoding, @OperationParam(name = "coding", min = 0, max = 1) Coding theCoding,
@OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConcept theCodeableConcept, @OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConcept theCodeableConcept,
@ -146,7 +148,19 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
startRequest(theServletRequest); startRequest(theServletRequest);
try { try {
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao(); IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
IValidationSupport.CodeValidationResult result = dao.validateCode(theValueSetUrl, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept, theRequestDetails); UriType valueSetIdentifier;
if (theValueSetVersion != null) {
valueSetIdentifier = new UriType(theValueSetUrl.getValue() + "|" + theValueSetVersion);
} else {
valueSetIdentifier = theValueSetUrl;
}
UriType codeSystemIdentifier;
if (theSystemVersion != null) {
codeSystemIdentifier = new UriType(theSystem.getValue() + "|" + theSystemVersion);
} else {
codeSystemIdentifier = theSystem;
}
IValidationSupport.CodeValidationResult result = dao.validateCode(valueSetIdentifier, theId, theCode, codeSystemIdentifier, theDisplay, theCoding, theCodeableConcept, theRequestDetails);
return (Parameters) BaseJpaResourceProviderValueSetDstu2.toValidateCodeResult(getContext(), result); return (Parameters) BaseJpaResourceProviderValueSetDstu2.toValidateCodeResult(getContext(), result);
} finally { } finally {
endRequest(theServletRequest); endRequest(theServletRequest);

View File

@ -651,22 +651,22 @@ 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 includeOrExcludeSystemUrl = theIncludeOrExclude.getSystem();
boolean hasSystem = isNotBlank(system); boolean hasSystem = isNotBlank(includeOrExcludeSystemUrl);
boolean hasValueSet = theIncludeOrExclude.getValueSet().size() > 0; boolean hasValueSet = theIncludeOrExclude.getValueSet().size() > 0;
if (hasSystem) { if (hasSystem) {
if (theWantConceptOrNull != null && theWantConceptOrNull.getSystem() != null && !system.equals(theWantConceptOrNull.getSystem())) { if (theWantConceptOrNull != null && theWantConceptOrNull.getSystem() != null && !includeOrExcludeSystemUrl.equals(theWantConceptOrNull.getSystem())) {
return false; return false;
} }
ourLog.debug("Starting {} expansion around CodeSystem: {}", (theAdd ? "inclusion" : "exclusion"), system); ourLog.debug("Starting {} expansion around CodeSystem: {}", (theAdd ? "inclusion" : "exclusion"), includeOrExcludeSystemUrl);
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system); TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(includeOrExcludeSystemUrl);
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, includeOrExcludeSystemUrl, cs);
} else { } else {
@ -679,7 +679,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
// No CodeSystem matching the URL found in the database. // No CodeSystem matching the URL found in the database.
CodeSystem codeSystemFromContext = fetchCanonicalCodeSystemFromCompleteContext(system); CodeSystem codeSystemFromContext = fetchCanonicalCodeSystemFromCompleteContext(includeOrExcludeSystemUrl);
if (codeSystemFromContext == null) { if (codeSystemFromContext == null) {
// This is a last ditch effort.. We don't have a CodeSystem resource for the desired CS, and we don't have // This is a last ditch effort.. We don't have a CodeSystem resource for the desired CS, and we don't have
@ -704,7 +704,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
for (VersionIndependentConcept next : includedConcepts) { for (VersionIndependentConcept next : includedConcepts) {
String nextSystem = next.getSystem(); String nextSystem = next.getSystem();
if (nextSystem == null) { if (nextSystem == null) {
nextSystem = system; nextSystem = includeOrExcludeSystemUrl;
} }
LookupCodeResult lookup = myValidationSupport.lookupCode(new ValidationSupportContext(provideValidationSupport()), nextSystem, next.getCode()); LookupCodeResult lookup = myValidationSupport.lookupCode(new ValidationSupportContext(provideValidationSupport()), nextSystem, next.getCode());
@ -720,7 +720,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
} }
String msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "expansionRefersToUnknownCs", system); String msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "expansionRefersToUnknownCs", includeOrExcludeSystemUrl);
if (provideExpansionOptions(theExpansionOptions).isFailOnMissingCodeSystem()) { if (provideExpansionOptions(theExpansionOptions).isFailOnMissingCodeSystem()) {
throw new PreconditionFailedException(msg); throw new PreconditionFailedException(msg);
} else { } else {
@ -735,12 +735,12 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
for (ValueSet.ConceptReferenceComponent next : theIncludeOrExclude.getConcept()) { for (ValueSet.ConceptReferenceComponent next : theIncludeOrExclude.getConcept()) {
String nextCode = next.getCode(); String nextCode = next.getCode();
if (theWantConceptOrNull == null || theWantConceptOrNull.getCode().equals(nextCode)) { if (theWantConceptOrNull == null || theWantConceptOrNull.getCode().equals(nextCode)) {
if (isNoneBlank(system, nextCode) && !theAddedCodes.contains(system + "|" + nextCode)) { if (isNoneBlank(includeOrExcludeSystemUrl, nextCode) && !theAddedCodes.contains(includeOrExcludeSystemUrl + "|" + nextCode)) {
CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode); CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode);
if (code != null) { if (code != null) {
String display = code.getDisplay(); String display = code.getDisplay();
addOrRemoveCode(theValueSetCodeAccumulator, theAddedCodes, theAdd, system, nextCode, display); addOrRemoveCode(theValueSetCodeAccumulator, theAddedCodes, theAdd, includeOrExcludeSystemUrl, nextCode, display);
} }
} }
@ -748,7 +748,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
} else { } else {
List<CodeSystem.ConceptDefinitionComponent> concept = codeSystemFromContext.getConcept(); List<CodeSystem.ConceptDefinitionComponent> concept = codeSystemFromContext.getConcept();
addConceptsToList(theValueSetCodeAccumulator, theAddedCodes, system, concept, theAdd, theWantConceptOrNull); addConceptsToList(theValueSetCodeAccumulator, theAddedCodes, includeOrExcludeSystemUrl, concept, theAdd, theWantConceptOrNull);
} }
return false; return false;
@ -841,13 +841,13 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
/* /*
* Filters * Filters
*/ */
String canonicalSystem; String codeSystemIdentifier;
if (codeSystemVersion != null) { if (codeSystemVersion != null) {
canonicalSystem = theSystem + "|" + codeSystemVersion; codeSystemIdentifier = theSystem + "|" + codeSystemVersion;
} else { } else {
canonicalSystem = theSystem; codeSystemIdentifier = theSystem;
} }
handleFilters(bool, canonicalSystem, qb, theIncludeOrExclude); handleFilters(bool, codeSystemIdentifier, qb, theIncludeOrExclude);
Query luceneQuery = bool.createQuery(); Query luceneQuery = bool.createQuery();
@ -956,15 +956,15 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
} }
private void handleFilters(BooleanJunction<?> theBool, String theCanonicalSystem, QueryBuilder theQb, ValueSet.ConceptSetComponent theIncludeOrExclude) { private void handleFilters(BooleanJunction<?> theBool, String theCodeSystemIdentifier, QueryBuilder theQb, ValueSet.ConceptSetComponent theIncludeOrExclude) {
if (theIncludeOrExclude.getFilter().size() > 0) { if (theIncludeOrExclude.getFilter().size() > 0) {
for (ValueSet.ConceptSetFilterComponent nextFilter : theIncludeOrExclude.getFilter()) { for (ValueSet.ConceptSetFilterComponent nextFilter : theIncludeOrExclude.getFilter()) {
handleFilter(theCanonicalSystem, theQb, theBool, nextFilter); handleFilter(theCodeSystemIdentifier, theQb, theBool, nextFilter);
} }
} }
} }
private void handleFilter(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) { private void handleFilter(String theCodeSystemIdentifier, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
if (isBlank(theFilter.getValue()) && theFilter.getOp() == null && isBlank(theFilter.getProperty())) { if (isBlank(theFilter.getValue()) && theFilter.getOp() == null && isBlank(theFilter.getProperty())) {
return; return;
} }
@ -980,23 +980,23 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
break; break;
case "concept": case "concept":
case "code": case "code":
handleFilterConceptAndCode(theSystem, theQb, theBool, theFilter); handleFilterConceptAndCode(theCodeSystemIdentifier, theQb, theBool, theFilter);
break; break;
case "parent": case "parent":
case "child": case "child":
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty()); isCodeSystemLoingOrThrowInvalidRequestException(theCodeSystemIdentifier, theFilter.getProperty());
handleFilterLoincParentChild(theBool, theFilter); handleFilterLoincParentChild(theBool, theFilter);
break; break;
case "ancestor": case "ancestor":
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty()); isCodeSystemLoingOrThrowInvalidRequestException(theCodeSystemIdentifier, theFilter.getProperty());
handleFilterLoincAncestor(theSystem, theBool, theFilter); handleFilterLoincAncestor(theCodeSystemIdentifier, theBool, theFilter);
break; break;
case "descendant": case "descendant":
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty()); isCodeSystemLoingOrThrowInvalidRequestException(theCodeSystemIdentifier, theFilter.getProperty());
handleFilterLoincDescendant(theSystem, theBool, theFilter); handleFilterLoincDescendant(theCodeSystemIdentifier, theBool, theFilter);
break; break;
case "copyright": case "copyright":
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty()); isCodeSystemLoingOrThrowInvalidRequestException(theCodeSystemIdentifier, theFilter.getProperty());
handleFilterLoincCopyright(theBool, theFilter); handleFilterLoincCopyright(theBool, theFilter);
break; break;
default: default:
@ -1005,8 +1005,8 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
} }
private void isCodeSystemLoingOrThrowInvalidRequestException(String theSystem, String theProperty) { private void isCodeSystemLoingOrThrowInvalidRequestException(String theSystemIdentifier, String theProperty) {
String systemUrl = getSystemFromCanonicalUrl(theSystem); String systemUrl = getUrlFromIdentifier(theSystemIdentifier);
if (!isCodeSystemLoinc(systemUrl)) { if (!isCodeSystemLoinc(systemUrl)) {
throw new InvalidRequestException("Invalid filter, property " + theProperty + " is LOINC-specific and cannot be used with system: " + systemUrl); throw new InvalidRequestException("Invalid filter, property " + theProperty + " is LOINC-specific and cannot be used with system: " + systemUrl);
} }
@ -1435,12 +1435,12 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
@Nullable @Nullable
private TermCodeSystemVersion getCurrentCodeSystemVersion(String theUri) { private TermCodeSystemVersion getCurrentCodeSystemVersion(String theCodeSystemIdentifier) {
String myVersion = getVersionFromCanonicalUrl(theUri); String myVersion = getVersionFromIdentifier(theCodeSystemIdentifier);
String key = theUri; String key = theCodeSystemIdentifier;
TermCodeSystemVersion retVal = myCodeSystemCurrentVersionCache.get(key.toString(), t -> myTxTemplate.execute(tx -> { TermCodeSystemVersion retVal = myCodeSystemCurrentVersionCache.get(key.toString(), t -> myTxTemplate.execute(tx -> {
TermCodeSystemVersion csv = null; TermCodeSystemVersion csv = null;
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(getSystemFromCanonicalUrl(theUri)); TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(getUrlFromIdentifier(theCodeSystemIdentifier));
if (cs != null) { if (cs != null) {
if (myVersion != null) { if (myVersion != null) {
csv = myCodeSystemVersionDao.findByCodeSystemPidAndVersion(cs.getPid(), myVersion); csv = myCodeSystemVersionDao.findByCodeSystemPidAndVersion(cs.getPid(), myVersion);
@ -1460,7 +1460,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
return retVal; return retVal;
} }
private String getVersionFromCanonicalUrl(String theUri) { private String getVersionFromIdentifier(String theUri) {
String retVal = null; String retVal = null;
if (StringUtils.isNotEmpty((theUri))) { if (StringUtils.isNotEmpty((theUri))) {
int versionSeparator = theUri.lastIndexOf('|'); int versionSeparator = theUri.lastIndexOf('|');
@ -1471,7 +1471,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
return retVal; return retVal;
} }
private String getSystemFromCanonicalUrl(String theUri) { private String getUrlFromIdentifier(String theUri) {
String retVal = theUri; String retVal = theUri;
if (StringUtils.isNotEmpty((theUri))){ if (StringUtils.isNotEmpty((theUri))){
int versionSeparator = theUri.lastIndexOf('|'); int versionSeparator = theUri.lastIndexOf('|');
@ -1777,15 +1777,15 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
@Override @Override
public CodeValidationResult validateCode(ConceptValidationOptions theOptions, IIdType theValueSetId, String theValueSetUrl, String theSystem, String theCode, String theDisplay, IBaseDatatype theCoding, IBaseDatatype theCodeableConcept) { public CodeValidationResult validateCode(ConceptValidationOptions theOptions, IIdType theValueSetId, String theValueSetIdentifier, String theCodeSystemIdentifierToValidate, String theCodeToValidate, String theDisplayToValidate, IBaseDatatype theCodingToValidate, IBaseDatatype theCodeableConceptToValidate) {
CodeableConcept codeableConcept = toCanonicalCodeableConcept(theCodeableConcept); CodeableConcept codeableConcept = toCanonicalCodeableConcept(theCodeableConceptToValidate);
boolean haveCodeableConcept = codeableConcept != null && codeableConcept.getCoding().size() > 0; boolean haveCodeableConcept = codeableConcept != null && codeableConcept.getCoding().size() > 0;
Coding coding = toCanonicalCoding(theCoding); Coding canonicalCodingToValidate = toCanonicalCoding(theCodingToValidate);
boolean haveCoding = coding != null && coding.isEmpty() == false; boolean haveCoding = canonicalCodingToValidate != null && canonicalCodingToValidate.isEmpty() == false;
boolean haveCode = theCode != null && theCode.isEmpty() == false; boolean haveCode = theCodeToValidate != null && theCodeToValidate.isEmpty() == false;
if (!haveCodeableConcept && !haveCoding && !haveCode) { if (!haveCodeableConcept && !haveCoding && !haveCode) {
throw new InvalidRequestException("No code, coding, or codeableConcept provided to validate"); throw new InvalidRequestException("No code, coding, or codeableConcept provided to validate");
@ -1794,38 +1794,54 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
throw new InvalidRequestException("$validate-code can only validate (system AND code) OR (coding) OR (codeableConcept)"); throw new InvalidRequestException("$validate-code can only validate (system AND code) OR (coding) OR (codeableConcept)");
} }
boolean haveIdentifierParam = isNotBlank(theValueSetUrl); boolean haveIdentifierParam = isNotBlank(theValueSetIdentifier);
String valueSetUrl; String valueSetIdentifier;
if (theValueSetId != null) { if (theValueSetId != null) {
IBaseResource valueSet = myDaoRegistry.getResourceDao("ValueSet").read(theValueSetId); IBaseResource valueSet = myDaoRegistry.getResourceDao("ValueSet").read(theValueSetId);
valueSetUrl = CommonCodeSystemsTerminologyService.getValueSetUrl(valueSet); StringBuilder valueSetIdentifierBuilder = new StringBuilder(CommonCodeSystemsTerminologyService.getValueSetUrl(valueSet));
String valueSetVersion = CommonCodeSystemsTerminologyService.getValueSetVersion(valueSet);
if (valueSetVersion != null) {
valueSetIdentifierBuilder.append("|").append(valueSetVersion);
}
valueSetIdentifier = valueSetIdentifierBuilder.toString();
} else if (haveIdentifierParam) { } else if (haveIdentifierParam) {
valueSetUrl = theValueSetUrl; valueSetIdentifier = theValueSetIdentifier;
} else { } else {
throw new InvalidRequestException("Either ValueSet ID or ValueSet identifier or system and code must be provided. Unable to validate."); throw new InvalidRequestException("Either ValueSet ID or ValueSet identifier or system and code must be provided. Unable to validate.");
} }
ValidationSupportContext validationContext = new ValidationSupportContext(provideValidationSupport()); ValidationSupportContext validationContext = new ValidationSupportContext(provideValidationSupport());
String code = theCode; String codeValueToValidate = theCodeToValidate;
String system = theSystem; String codeSystemIdentifierValueToValidate = theCodeSystemIdentifierToValidate;
String display = theDisplay; String codeDisplayValueToValidate = theDisplayToValidate;
if (haveCodeableConcept) { if (haveCodeableConcept) {
for (int i = 0; i < codeableConcept.getCoding().size(); i++) { for (int i = 0; i < codeableConcept.getCoding().size(); i++) {
Coding nextCoding = codeableConcept.getCoding().get(i); Coding nextCoding = codeableConcept.getCoding().get(i);
CodeValidationResult nextValidation = validateCode(validationContext, theOptions, nextCoding.getSystem(), nextCoding.getCode(), nextCoding.getDisplay(), valueSetUrl); String codeSystemIdentifier;
if (nextCoding.hasVersion()) {
codeSystemIdentifier = nextCoding.getSystem() + "|" + nextCoding.getVersion();
} else {
codeSystemIdentifier = nextCoding.getSystem();
}
CodeValidationResult nextValidation = validateCode(validationContext, theOptions, codeSystemIdentifier, nextCoding.getCode(), nextCoding.getDisplay(), valueSetIdentifier);
if (nextValidation.isOk() || i == codeableConcept.getCoding().size() - 1) { if (nextValidation.isOk() || i == codeableConcept.getCoding().size() - 1) {
return nextValidation; return nextValidation;
} }
} }
} else if (haveCoding) { } else if (haveCoding) {
system = coding.getSystem(); if (canonicalCodingToValidate.hasVersion()) {
code = coding.getCode(); codeSystemIdentifierValueToValidate = canonicalCodingToValidate.getSystem() + "|" + canonicalCodingToValidate.getVersion();
display = coding.getDisplay(); } else {
codeSystemIdentifierValueToValidate = canonicalCodingToValidate.getSystem();
}
codeValueToValidate = canonicalCodingToValidate.getCode();
codeDisplayValueToValidate = canonicalCodingToValidate.getDisplay();
} }
return validateCode(validationContext, theOptions, system, code, display, valueSetUrl); return validateCode(validationContext, theOptions, codeSystemIdentifierValueToValidate, codeValueToValidate, codeDisplayValueToValidate, valueSetIdentifier);
} }
private boolean isNotSafeToPreExpandValueSets() { private boolean isNotSafeToPreExpandValueSets() {
@ -1914,22 +1930,22 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
throw new InvalidRequestException("Unable to test subsumption across different code system versions"); throw new InvalidRequestException("Unable to test subsumption across different code system versions");
} }
String codeACanonicalUrl; String codeASystemIdentifier;
if (StringUtils.isNotEmpty(conceptA.getSystemVersion())) { if (StringUtils.isNotEmpty(conceptA.getSystemVersion())) {
codeACanonicalUrl = conceptA.getSystem() + "|" + conceptA.getSystemVersion(); codeASystemIdentifier = conceptA.getSystem() + "|" + conceptA.getSystemVersion();
} else { } else {
codeACanonicalUrl = conceptA.getSystem(); codeASystemIdentifier = conceptA.getSystem();
} }
TermConcept codeA = findCode(codeACanonicalUrl, conceptA.getCode()) TermConcept codeA = findCode(codeASystemIdentifier, conceptA.getCode())
.orElseThrow(() -> new InvalidRequestException("Unknown code: " + conceptA)); .orElseThrow(() -> new InvalidRequestException("Unknown code: " + conceptA));
String codeBCanonicalUrl; String codeBSystemIdentifier;
if (StringUtils.isNotEmpty(conceptB.getSystemVersion())) { if (StringUtils.isNotEmpty(conceptB.getSystemVersion())) {
codeBCanonicalUrl = conceptB.getSystem() + "|" + conceptB.getSystemVersion(); codeBSystemIdentifier = conceptB.getSystem() + "|" + conceptB.getSystemVersion();
} else { } else {
codeBCanonicalUrl = conceptB.getSystem(); codeBSystemIdentifier = conceptB.getSystem();
} }
TermConcept codeB = findCode(codeBCanonicalUrl, conceptB.getCode()) TermConcept codeB = findCode(codeBSystemIdentifier, conceptB.getCode())
.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);
@ -2405,6 +2421,9 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
@Nullable @Nullable
protected abstract Coding toCanonicalCoding(@Nullable IBaseDatatype theCoding); protected abstract Coding toCanonicalCoding(@Nullable IBaseDatatype theCoding);
@Nullable
protected abstract Coding toCanonicalCoding(@Nullable IBaseCoding theCoding);
@Nullable @Nullable
protected abstract CodeableConcept toCanonicalCodeableConcept(@Nullable IBaseDatatype theCodeableConcept); protected abstract CodeableConcept toCanonicalCodeableConcept(@Nullable IBaseDatatype theCodeableConcept);
@ -2496,14 +2515,15 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
@NotNull @NotNull
private VersionIndependentConcept toConcept(IPrimitiveType<String> theCodeType, IPrimitiveType<String> theSystemType, IBaseCoding theCodingType) { private VersionIndependentConcept toConcept(IPrimitiveType<String> theCodeType, IPrimitiveType<String> theCodeSystemIdentifierType, IBaseCoding theCodingType) {
String code = theCodeType != null ? theCodeType.getValueAsString() : null; String code = theCodeType != null ? theCodeType.getValueAsString() : null;
String system = theSystemType != null ? getSystemFromCanonicalUrl(theSystemType.getValueAsString()): null; String system = theCodeSystemIdentifierType != null ? getUrlFromIdentifier(theCodeSystemIdentifierType.getValueAsString()): null;
String systemVersion = theSystemType != null ? getVersionFromCanonicalUrl(theSystemType.getValueAsString()): null; String systemVersion = theCodeSystemIdentifierType != null ? getVersionFromIdentifier(theCodeSystemIdentifierType.getValueAsString()): null;
if (theCodingType != null) { if (theCodingType != null) {
code = theCodingType.getCode(); Coding canonicalizedCoding = toCanonicalCoding(theCodingType);
system = getSystemFromCanonicalUrl(theCodingType.getSystem()); code = canonicalizedCoding.getCode();
systemVersion = getVersionFromCanonicalUrl(theCodingType.getSystem()); system = canonicalizedCoding.getSystem();
systemVersion = canonicalizedCoding.getVersion();
} }
return new VersionIndependentConcept(system, code, null, systemVersion); return new VersionIndependentConcept(system, code, null, systemVersion);
} }

View File

@ -27,6 +27,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt; import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.CodingDt; import ca.uhn.fhir.model.dstu2.composite.CodingDt;
import ca.uhn.fhir.util.VersionIndependentConcept; import ca.uhn.fhir.util.VersionIndependentConcept;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseDatatype; import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeSystem;
@ -148,6 +149,17 @@ public class TermReadSvcDstu2 extends BaseTermReadSvcImpl {
return retVal; return retVal;
} }
@Nullable
@Override
protected Coding toCanonicalCoding(@Nullable IBaseCoding theCoding) {
Coding retVal = null;
if (theCoding != null) {
CodingDt coding = (CodingDt) theCoding;
retVal = new Coding(coding.getSystem(), coding.getCode(), coding.getDisplay());
}
return retVal;
}
@Nullable @Nullable
@Override @Override
protected CodeableConcept toCanonicalCodeableConcept(@Nullable IBaseDatatype theCodeableConcept) { protected CodeableConcept toCanonicalCodeableConcept(@Nullable IBaseDatatype theCodeableConcept) {
@ -157,7 +169,7 @@ public class TermReadSvcDstu2 extends BaseTermReadSvcImpl {
CodeableConceptDt cc = (CodeableConceptDt) theCodeableConcept; CodeableConceptDt cc = (CodeableConceptDt) theCodeableConcept;
outcome.setText(cc.getText()); outcome.setText(cc.getText());
for (CodingDt next : cc.getCoding()) { for (CodingDt next : cc.getCoding()) {
outcome.addCoding(toCanonicalCoding(next)); outcome.addCoding(toCanonicalCoding((IBaseDatatype)next));
} }
} }
return outcome; return outcome;

View File

@ -20,6 +20,7 @@ import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Coding; import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.ValueSet; import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseDatatype; import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.utilities.validation.ValidationOptions; import org.hl7.fhir.utilities.validation.ValidationOptions;
@ -112,6 +113,12 @@ public class TermReadSvcDstu3 extends BaseTermReadSvcImpl implements IValidation
return VersionConvertor_30_40.convertCoding((org.hl7.fhir.dstu3.model.Coding) theCoding); return VersionConvertor_30_40.convertCoding((org.hl7.fhir.dstu3.model.Coding) theCoding);
} }
@Override
@Nullable
protected org.hl7.fhir.r4.model.Coding toCanonicalCoding(IBaseCoding theCoding) {
return VersionConvertor_30_40.convertCoding((org.hl7.fhir.dstu3.model.Coding) theCoding);
}
@Override @Override
@Nullable @Nullable
protected org.hl7.fhir.r4.model.CodeableConcept toCanonicalCodeableConcept(IBaseDatatype theCoding) { protected org.hl7.fhir.r4.model.CodeableConcept toCanonicalCodeableConcept(IBaseDatatype theCoding) {

View File

@ -8,6 +8,7 @@ import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.term.api.ITermReadSvcR4; import ca.uhn.fhir.jpa.term.api.ITermReadSvcR4;
import ca.uhn.fhir.jpa.term.ex.ExpansionTooCostlyException; import ca.uhn.fhir.jpa.term.ex.ExpansionTooCostlyException;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseDatatype; import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeSystem;
@ -107,6 +108,11 @@ public class TermReadSvcR4 extends BaseTermReadSvcImpl implements ITermReadSvcR4
return (Coding) theCoding; return (Coding) theCoding;
} }
@Override
protected Coding toCanonicalCoding(IBaseCoding theCoding) {
return (Coding) theCoding;
}
@Override @Override
protected CodeableConcept toCanonicalCodeableConcept(IBaseDatatype theCodeableConcept) { protected CodeableConcept toCanonicalCodeableConcept(IBaseDatatype theCodeableConcept) {
return (CodeableConcept) theCodeableConcept; return (CodeableConcept) theCodeableConcept;

View File

@ -12,6 +12,7 @@ import ca.uhn.fhir.jpa.term.ex.ExpansionTooCostlyException;
import ca.uhn.fhir.util.ValidateUtil; import ca.uhn.fhir.util.ValidateUtil;
import org.hl7.fhir.convertors.VersionConvertor_40_50; import org.hl7.fhir.convertors.VersionConvertor_40_50;
import org.hl7.fhir.convertors.conv40_50.CodeSystem40_50; import org.hl7.fhir.convertors.conv40_50.CodeSystem40_50;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseDatatype; import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.CodeSystem;
@ -111,6 +112,12 @@ public class TermReadSvcR5 extends BaseTermReadSvcImpl implements IValidationSup
return VersionConvertor_40_50.convertCoding((Coding) theCoding); return VersionConvertor_40_50.convertCoding((Coding) theCoding);
} }
@Override
@Nullable
protected org.hl7.fhir.r4.model.Coding toCanonicalCoding(IBaseCoding theCoding) {
return VersionConvertor_40_50.convertCoding((Coding) theCoding);
}
@Override @Override
@Nullable @Nullable
protected org.hl7.fhir.r4.model.CodeableConcept toCanonicalCodeableConcept(IBaseDatatype theCoding) { protected org.hl7.fhir.r4.model.CodeableConcept toCanonicalCodeableConcept(IBaseDatatype theCoding) {

View File

@ -29,6 +29,10 @@ import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator; import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
import org.hl7.fhir.dstu3.model.codesystems.HttpVerb; import org.hl7.fhir.dstu3.model.codesystems.HttpVerb;
import org.hl7.fhir.dstu3.model.BooleanType;
import org.hl7.fhir.dstu3.model.CodeType;
import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Coding;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
@ -49,6 +53,7 @@ import static org.hamcrest.Matchers.containsStringIgnoringCase;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.stringContainsInOrder; import static org.hamcrest.Matchers.stringContainsInOrder;
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.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
@ -116,21 +121,16 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
private void loadAndPersistValueSet() throws IOException { private void loadAndPersistValueSet() throws IOException {
ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml"); ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
persistTwoVersionsOfValueSet(valueSet, HttpVerb.POST); valueSet.setVersion("1");
} valueSet.setId("ValueSet/vs1");
valueSet.getCompose().getInclude().get(0).setVersion("1");
@SuppressWarnings("EnumSwitchStatementWhichMissesCases") myExtensionalVsId_v1 = persistSingleValueSet(valueSet, HttpVerb.POST);
private void persistTwoVersionsOfValueSet(ValueSet theValueSet, HttpVerb theVerb) {
theValueSet.setVersion("1");
theValueSet.setId("ValueSet/vs1");
theValueSet.getCompose().getInclude().get(0).setVersion("1");
myExtensionalVsId_v1 = persistSingleValueSet(theValueSet, theVerb);
myExtensionalVsIdOnResourceTable_v1 = myValueSetDao.readEntity(myExtensionalVsId_v1, null).getId(); myExtensionalVsIdOnResourceTable_v1 = myValueSetDao.readEntity(myExtensionalVsId_v1, null).getId();
theValueSet.setVersion("2"); valueSet.setVersion("2");
theValueSet.setId("ValueSet/vs2"); valueSet.setId("ValueSet/vs2");
theValueSet.getCompose().getInclude().get(0).setVersion("2"); valueSet.getCompose().getInclude().get(0).setVersion("2");
myExtensionalVsId_v2 = persistSingleValueSet(theValueSet, theVerb); myExtensionalVsId_v2 = persistSingleValueSet(valueSet, HttpVerb.POST);
myExtensionalVsIdOnResourceTable_v2 = myValueSetDao.readEntity(myExtensionalVsId_v2, null).getId(); myExtensionalVsIdOnResourceTable_v2 = myValueSetDao.readEntity(myExtensionalVsId_v2, null).getId();
} }
@ -138,6 +138,8 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
private IIdType persistSingleValueSet(ValueSet theValueSet, HttpVerb theVerb) { private IIdType persistSingleValueSet(ValueSet theValueSet, HttpVerb theVerb) {
final IIdType[] vsId = new IIdType[1]; final IIdType[] vsId = new IIdType[1];
switch (theVerb) { switch (theVerb) {
case GET:
break;
case POST: case POST:
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override @Override
@ -154,6 +156,8 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
} }
}); });
break; break;
case DELETE:
case NULL:
default: default:
throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb); throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb);
} }
@ -1053,7 +1057,7 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
TermValueSetConcept concept = termValueSet.getConcepts().get(0); TermValueSetConcept concept = termValueSet.getConcepts().get(0);
ourLog.info("Concept:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org|1", concept.getSystem());
assertEquals("8450-9", concept.getCode()); assertEquals("8450-9", concept.getCode());
assertEquals("Systolic blood pressure--expiration", concept.getDisplay()); assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
assertEquals(2, concept.getDesignations().size()); assertEquals(2, concept.getDesignations().size());
@ -1075,7 +1079,7 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
concept = termValueSet.getConcepts().get(1); concept = termValueSet.getConcepts().get(1);
ourLog.info("Concept:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org|1", concept.getSystem());
assertEquals("11378-7", concept.getCode()); assertEquals("11378-7", concept.getCode());
assertEquals("Systolic blood pressure at First encounter", concept.getDisplay()); assertEquals("Systolic blood pressure at First encounter", concept.getDisplay());
assertEquals(0, concept.getDesignations().size()); assertEquals(0, concept.getDesignations().size());
@ -1085,7 +1089,7 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
concept = termValueSet.getConcepts().get(22); concept = termValueSet.getConcepts().get(22);
ourLog.info("Concept:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org|1", concept.getSystem());
assertEquals("8491-3", concept.getCode()); assertEquals("8491-3", concept.getCode());
assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay()); assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay());
assertEquals(1, concept.getDesignations().size()); assertEquals(1, concept.getDesignations().size());
@ -1100,7 +1104,7 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
concept = termValueSet.getConcepts().get(23); concept = termValueSet.getConcepts().get(23);
ourLog.info("Concept:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org|1", concept.getSystem());
assertEquals("8492-1", concept.getCode()); assertEquals("8492-1", concept.getCode());
assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay()); assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay());
assertEquals(0, concept.getDesignations().size()); assertEquals(0, concept.getDesignations().size());
@ -1126,7 +1130,7 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
TermValueSetConcept concept = termValueSet.getConcepts().get(0); TermValueSetConcept concept = termValueSet.getConcepts().get(0);
ourLog.info("Concept:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org|2", concept.getSystem());
assertEquals("8450-9", concept.getCode()); assertEquals("8450-9", concept.getCode());
assertEquals("Systolic blood pressure--expiration v2", concept.getDisplay()); assertEquals("Systolic blood pressure--expiration v2", concept.getDisplay());
assertEquals(2, concept.getDesignations().size()); assertEquals(2, concept.getDesignations().size());
@ -1148,7 +1152,7 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
concept = termValueSet.getConcepts().get(1); concept = termValueSet.getConcepts().get(1);
ourLog.info("Concept:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org|2", concept.getSystem());
assertEquals("11378-7", concept.getCode()); assertEquals("11378-7", concept.getCode());
assertEquals("Systolic blood pressure at First encounter v2", concept.getDisplay()); assertEquals("Systolic blood pressure at First encounter v2", concept.getDisplay());
assertEquals(0, concept.getDesignations().size()); assertEquals(0, concept.getDesignations().size());
@ -1158,7 +1162,7 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
concept = termValueSet.getConcepts().get(22); concept = termValueSet.getConcepts().get(22);
ourLog.info("Concept:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org|2", concept.getSystem());
assertEquals("8491-3", concept.getCode()); assertEquals("8491-3", concept.getCode());
assertEquals("Systolic blood pressure 1 hour minimum v2", concept.getDisplay()); assertEquals("Systolic blood pressure 1 hour minimum v2", concept.getDisplay());
assertEquals(1, concept.getDesignations().size()); assertEquals(1, concept.getDesignations().size());
@ -1173,161 +1177,16 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
concept = termValueSet.getConcepts().get(23); concept = termValueSet.getConcepts().get(23);
ourLog.info("Concept:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org|2", concept.getSystem());
assertEquals("8492-1", concept.getCode()); assertEquals("8492-1", concept.getCode());
assertEquals("Systolic blood pressure 8 hour minimum v2", concept.getDisplay()); assertEquals("Systolic blood pressure 8 hour minimum v2", concept.getDisplay());
assertEquals(0, concept.getDesignations().size()); assertEquals(0, concept.getDesignations().size());
assertEquals(23, concept.getOrder()); assertEquals(23, concept.getOrder());
}); });
} }
/*
@Test
public void testValidateCodeOperationByCodeAndSystemInstance() throws Exception {
loadAndPersistCodeSystemAndValueSet();
Parameters respParam = ourClient
.operation()
.onInstance(myExtensionalVsId_v1)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertEquals(true, ((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test @Test
public void testValidateCodeOperationByCodeAndSystemInstanceOnType() throws IOException { public void testCreateDuplicateValueSetVersion() {
createLocalCs();
createLocalVsWithIncludeConcept();
String url = ourServerBase +
"/ValueSet/" + myLocalValueSetId_v1.getIdPart() + "/$validate-code?system=" +
UrlUtil.escapeUrlParam(URL_MY_CODE_SYSTEM) +
"&code=AA";
HttpGet request = new HttpGet(url);
request.addHeader("Accept", "application/fhir+json");
try (CloseableHttpResponse response = ourHttpClient.execute(request)) {
String respString = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
ourLog.info(respString);
Parameters respParam = myFhirCtx.newJsonParser().parseResource(Parameters.class, respString);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
}
@Test
public void testValidateCodeOperationByCodeAndSystemInstanceOnInstance() throws IOException {
createLocalCs();
createLocalVsWithIncludeConcept();
String url = ourServerBase +
"/ValueSet/" + myLocalValueSetId_v1.getIdPart() + "/$validate-code?system=" +
UrlUtil.escapeUrlParam(URL_MY_CODE_SYSTEM) +
"&code=AA";
ourLog.info("* Requesting: {}", url);
HttpGet request = new HttpGet(url);
request.addHeader("Accept", "application/fhir+json");
try (CloseableHttpResponse response = ourHttpClient.execute(request)) {
String respString = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
ourLog.info(respString);
Parameters respParam = myFhirCtx.newJsonParser().parseResource(Parameters.class, respString);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
}
@Test
public void testValidateCodeOperationByCodeAndSystemType() throws Exception {
loadAndPersistCodeSystemAndValueSet();
Parameters respParam = ourClient
.operation()
.onInstance(myExtensionalVsId_v1)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8450-9"))
.andParameter("system", new UriType("http://acme.org"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertEquals(true, ((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationNoValueSetProvided() throws Exception {
loadAndPersistCodeSystemAndValueSet();
try {
ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8450-9"))
.andParameter("system", new UriType("http://acme.org"))
.execute();
fail();
} catch (InvalidRequestException e) {
assertEquals("HTTP 400 Bad Request: Either ValueSet ID or ValueSet identifier or system and code must be provided. Unable to validate.", e.getMessage());
}
}
@Test
public void testValidateCodeOperationOnInstanceWithIsAExpansion() throws IOException {
CodeSystem cs = new CodeSystem();
cs.setUrl("http://mycs");
cs.setContent(CodeSystemContentMode.COMPLETE);
cs.setHierarchyMeaning(CodeSystem.CodeSystemHierarchyMeaning.ISA);
cs.setStatus(Enumerations.PublicationStatus.ACTIVE);
ConceptDefinitionComponent parentA = cs.addConcept().setCode("ParentA").setDisplay("Parent A");
parentA.addConcept().setCode("ChildAA").setDisplay("Child AA");
myCodeSystemDao.create(cs);
ValueSet vs = new ValueSet();
vs.setUrl("http://myvs");
vs.getCompose()
.addInclude()
.setSystem("http://mycs")
.addFilter()
.setOp(FilterOperator.ISA)
.setProperty("concept")
.setValue("ParentA");
IIdType vsId = myValueSetDao.create(vs).getId().toUnqualifiedVersionless();
HttpGet expandGet = new HttpGet(ourServerBase + "/ValueSet/" + vsId.getIdPart() + "/$expand?_pretty=true");
try (CloseableHttpResponse status = ourHttpClient.execute(expandGet)) {
String response = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
ourLog.info("Response: {}", response);
}
HttpGet validateCodeGet = new HttpGet(ourServerBase + "/ValueSet/" + vsId.getIdPart() + "/$validate-code?system=http://mycs&code=ChildAA&_pretty=true");
try (CloseableHttpResponse status = ourHttpClient.execute(validateCodeGet)) {
String response = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
ourLog.info("Response: {}", response);
Parameters output = myFhirCtx.newXmlParser().parseResource(Parameters.class, response);
assertEquals(true, output.getParameterBool("result"));
}
HttpGet validateCodeGet2 = new HttpGet(ourServerBase + "/ValueSet/" + vsId.getIdPart() + "/$validate-code?system=http://mycs&code=FOO&_pretty=true");
try (CloseableHttpResponse status = ourHttpClient.execute(validateCodeGet2)) {
String response = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
ourLog.info("Response: {}", response);
Parameters output = myFhirCtx.newXmlParser().parseResource(Parameters.class, response);
assertEquals(false, output.getParameterBool("result"));
}
}
*/
@Test
public void testCreateDuplicatValueSetVersion() {
createExternalCsAndLocalVs(); createExternalCsAndLocalVs();
try { try {
persistLocalVs(createLocalVs(URL_MY_CODE_SYSTEM, "1")); persistLocalVs(createLocalVs(URL_MY_CODE_SYSTEM, "1"));
@ -1338,6 +1197,284 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
} }
@Test
public void testValidateCodeOperationByCodeAndSystem() throws Exception {
loadAndPersistCodeSystemAndValueSet();
// With correct system version specified. Should pass.
Parameters respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
// With incorrect version specified. Should fail.
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationOnInstanceByCodeAndSystem() throws Exception {
loadAndPersistCodeSystemAndValueSet();
// With correct system version specified. Should pass.
Parameters respParam = ourClient
.operation()
.onInstance(myExtensionalVsId_v1)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onInstance(myExtensionalVsId_v2)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
// With incorrect version specified. Should fail.
respParam = ourClient
.operation()
.onInstance(myExtensionalVsId_v1)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onInstance(myExtensionalVsId_v2)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationByCoding() throws Exception {
loadAndPersistCodeSystemAndValueSet();
Coding codingToValidate_v1 = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum");
codingToValidate_v1.setVersion("1");
Coding codingToValidate_v2 = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum v2");
codingToValidate_v2.setVersion("2");
// With correct system version specified. Should pass.
Parameters respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
// With incorrect version specified. Should fail.
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationByCodeableConcept() throws Exception {
loadAndPersistCodeSystemAndValueSet();
Coding codingToValidate = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum");
codingToValidate.setVersion("1");
CodeableConcept codeableConceptToValidate_v1 = new CodeableConcept(codingToValidate);
codingToValidate = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum v2");
codingToValidate.setVersion("2");
CodeableConcept codeableConceptToValidate_v2 = new CodeableConcept(codingToValidate);
// With correct system version specified. Should pass.
Parameters respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
// With incorrect version specified. Should fail.
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@AfterEach @AfterEach
public void afterResetPreExpansionDefault() { public void afterResetPreExpansionDefault() {
myDaoConfig.setPreExpandValueSets(new DaoConfig().isPreExpandValueSets()); myDaoConfig.setPreExpandValueSets(new DaoConfig().isPreExpandValueSets());

View File

@ -13,12 +13,11 @@ import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc; import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId; import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
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.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil;
import org.apache.commons.io.Charsets; import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
@ -29,6 +28,8 @@ import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode; import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent; import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r4.model.CodeType;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.Enumerations; import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r4.model.Parameters;
@ -59,6 +60,7 @@ import static org.hamcrest.Matchers.containsStringIgnoringCase;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.stringContainsInOrder; import static org.hamcrest.Matchers.stringContainsInOrder;
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.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
@ -126,21 +128,16 @@ public class ResourceProviderR4ValueSetVersionedTest extends BaseResourceProvide
private void loadAndPersistValueSet() throws IOException { private void loadAndPersistValueSet() throws IOException {
ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml"); ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
persistTwoVersionsOfValueSet(valueSet, HttpVerb.POST); valueSet.setVersion("1");
} valueSet.setId("ValueSet/vs1");
valueSet.getCompose().getInclude().get(0).setVersion("1");
@SuppressWarnings("EnumSwitchStatementWhichMissesCases") myExtensionalVsId_v1 = persistSingleValueSet(valueSet, HttpVerb.POST);
private void persistTwoVersionsOfValueSet(ValueSet theValueSet, HttpVerb theVerb) {
theValueSet.setVersion("1");
theValueSet.setId("ValueSet/vs1");
theValueSet.getCompose().getInclude().get(0).setVersion("1");
myExtensionalVsId_v1 = persistSingleValueSet(theValueSet, theVerb);
myExtensionalVsIdOnResourceTable_v1 = myValueSetDao.readEntity(myExtensionalVsId_v1, null).getId(); myExtensionalVsIdOnResourceTable_v1 = myValueSetDao.readEntity(myExtensionalVsId_v1, null).getId();
theValueSet.setVersion("2"); valueSet.setVersion("2");
theValueSet.setId("ValueSet/vs2"); valueSet.setId("ValueSet/vs2");
theValueSet.getCompose().getInclude().get(0).setVersion("2"); valueSet.getCompose().getInclude().get(0).setVersion("2");
myExtensionalVsId_v2 = persistSingleValueSet(theValueSet, theVerb); myExtensionalVsId_v2 = persistSingleValueSet(valueSet, HttpVerb.POST);
myExtensionalVsIdOnResourceTable_v2 = myValueSetDao.readEntity(myExtensionalVsId_v2, null).getId(); myExtensionalVsIdOnResourceTable_v2 = myValueSetDao.readEntity(myExtensionalVsId_v2, null).getId();
} }
@ -148,6 +145,9 @@ public class ResourceProviderR4ValueSetVersionedTest extends BaseResourceProvide
private IIdType persistSingleValueSet(ValueSet theValueSet, HttpVerb theVerb) { private IIdType persistSingleValueSet(ValueSet theValueSet, HttpVerb theVerb) {
final IIdType[] vsId = new IIdType[1]; final IIdType[] vsId = new IIdType[1];
switch (theVerb) { switch (theVerb) {
case GET:
case HEAD:
break;
case POST: case POST:
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override @Override
@ -164,6 +164,9 @@ public class ResourceProviderR4ValueSetVersionedTest extends BaseResourceProvide
} }
}); });
break; break;
case DELETE:
case PATCH:
case NULL:
default: default:
throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb); throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb);
} }
@ -188,12 +191,6 @@ public class ResourceProviderR4ValueSetVersionedTest extends BaseResourceProvide
} }
// private void createExternalCsAndLocalVsWithUnknownCode() {
// String codeSystemUrl = createExternalCs();
// createLocalVsWithUnknownCode(codeSystemUrl);
// }
private void createLocalCs() { private void createLocalCs() {
CodeSystem codeSystem = new CodeSystem(); CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM); codeSystem.setUrl(URL_MY_CODE_SYSTEM);
@ -250,27 +247,6 @@ public class ResourceProviderR4ValueSetVersionedTest extends BaseResourceProvide
return myValueSetDao.create(theValueSet, mySrd).getId().toUnqualifiedVersionless(); return myValueSetDao.create(theValueSet, mySrd).getId().toUnqualifiedVersionless();
} }
private void createLocalVsWithUnknownCode(String codeSystemUrl) {
myLocalVs_v1 = new ValueSet();
myLocalVs_v1.setUrl(URL_MY_VALUE_SET);
myLocalVs_v1.setVersion("1");
ConceptSetComponent include = myLocalVs_v1.getCompose().addInclude();
include.setSystem(codeSystemUrl);
include.setSystem("1");
include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("childFOOOOOOO");
myLocalValueSetId_v1 = myValueSetDao.create(myLocalVs_v1, mySrd).getId().toUnqualifiedVersionless();
myLocalVs_v2 = new ValueSet();
myLocalVs_v2.setUrl(URL_MY_VALUE_SET);
myLocalVs_v2.setVersion("2");
include = myLocalVs_v2.getCompose().addInclude();
include.setSystem(codeSystemUrl);
include.setSystem("2");
include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("childFOOOOOOO");
myLocalValueSetId_v2 = myValueSetDao.create(myLocalVs_v2, mySrd).getId().toUnqualifiedVersionless();
}
@Test @Test
public void testExpandById() throws Exception { public void testExpandById() throws Exception {
loadAndPersistCodeSystemAndValueSet(); loadAndPersistCodeSystemAndValueSet();
@ -1201,151 +1177,284 @@ public class ResourceProviderR4ValueSetVersionedTest extends BaseResourceProvide
assertEquals(23, concept.getOrder()); assertEquals(23, concept.getOrder());
}); });
} }
/*
@Test @Test
public void testValidateCodeOperationByCodeAndSystemInstance() throws Exception { public void testValidateCodeOperationByCodeAndSystem() throws Exception {
loadAndPersistCodeSystemAndValueSet(); loadAndPersistCodeSystemAndValueSet();
// With correct system version specified. Should pass.
Parameters respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
// With incorrect version specified. Should fail.
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationOnInstanceByCodeAndSystem() throws Exception {
loadAndPersistCodeSystemAndValueSet();
// With correct system version specified. Should pass.
Parameters respParam = myClient Parameters respParam = myClient
.operation() .operation()
.onInstance(myExtensionalVsId_v1) .onInstance(myExtensionalVsId_v1)
.named("validate-code") .named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4")) .withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org")) .andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.execute(); .execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp); ourLog.info(resp);
assertEquals(true, ((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue()); assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test respParam = myClient
public void testValidateCodeOperationByCodeAndSystemInstanceOnType() throws IOException { .operation()
createLocalCs(); .onInstance(myExtensionalVsId_v2)
createLocalVsWithIncludeConcept(); .named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.execute();
String url = ourServerBase + resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
"/ValueSet/" + myLocalValueSetId_v1.getIdPart() + "/$validate-code?system=" + ourLog.info(resp);
UrlUtil.escapeUrlParam(URL_MY_CODE_SYSTEM) +
"&code=AA";
HttpGet request = new HttpGet(url); assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
request.addHeader("Accept", "application/fhir+json");
try (CloseableHttpResponse response = ourHttpClient.execute(request)) {
String respString = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
ourLog.info(respString);
Parameters respParam = myFhirCtx.newJsonParser().parseResource(Parameters.class, respString); // With incorrect version specified. Should fail.
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue()); respParam = myClient
}
}
@Test
public void testValidateCodeOperationByCodeAndSystemInstanceOnInstance() throws IOException {
createLocalCs();
createLocalVsWithIncludeConcept();
String url = ourServerBase +
"/ValueSet/" + myLocalValueSetId_v1.getIdPart() + "/$validate-code?system=" +
UrlUtil.escapeUrlParam(URL_MY_CODE_SYSTEM) +
"&code=AA";
ourLog.info("* Requesting: {}", url);
HttpGet request = new HttpGet(url);
request.addHeader("Accept", "application/fhir+json");
try (CloseableHttpResponse response = ourHttpClient.execute(request)) {
String respString = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
ourLog.info(respString);
Parameters respParam = myFhirCtx.newJsonParser().parseResource(Parameters.class, respString);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
}
@Test
public void testValidateCodeOperationByCodeAndSystemType() throws Exception {
loadAndPersistCodeSystemAndValueSet();
Parameters respParam = myClient
.operation() .operation()
.onInstance(myExtensionalVsId_v1) .onInstance(myExtensionalVsId_v1)
.named("validate-code") .named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8450-9")) .withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org")) .andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = myClient
.operation()
.onInstance(myExtensionalVsId_v2)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationByCoding() throws Exception {
loadAndPersistCodeSystemAndValueSet();
Coding codingToValidate_v1 = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum");
codingToValidate_v1.setVersion("1");
Coding codingToValidate_v2 = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum v2");
codingToValidate_v2.setVersion("2");
// With correct system version specified. Should pass.
Parameters respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute(); .execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp); ourLog.info(resp);
assertEquals(true, ((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue()); assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
// With incorrect version specified. Should fail.
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
} }
@Test @Test
public void testValidateCodeOperationNoValueSetProvided() throws Exception { public void testValidateCodeOperationByCodeableConcept() throws Exception {
loadAndPersistCodeSystemAndValueSet(); loadAndPersistCodeSystemAndValueSet();
try { Coding codingToValidate = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum");
myClient codingToValidate.setVersion("1");
.operation() CodeableConcept codeableConceptToValidate_v1 = new CodeableConcept(codingToValidate);
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8450-9"))
.andParameter("system", new UriType("http://acme.org"))
.execute();
fail();
} catch (InvalidRequestException e) {
assertEquals("HTTP 400 Bad Request: Either ValueSet ID or ValueSet identifier or system and code must be provided. Unable to validate.", e.getMessage());
}
}
@Test codingToValidate = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum v2");
public void testValidateCodeOperationOnInstanceWithIsAExpansion() throws IOException { codingToValidate.setVersion("2");
CodeSystem cs = new CodeSystem(); CodeableConcept codeableConceptToValidate_v2 = new CodeableConcept(codingToValidate);
cs.setUrl("http://mycs");
cs.setContent(CodeSystemContentMode.COMPLETE);
cs.setHierarchyMeaning(CodeSystem.CodeSystemHierarchyMeaning.ISA);
cs.setStatus(Enumerations.PublicationStatus.ACTIVE);
ConceptDefinitionComponent parentA = cs.addConcept().setCode("ParentA").setDisplay("Parent A");
parentA.addConcept().setCode("ChildAA").setDisplay("Child AA");
myCodeSystemDao.create(cs);
ValueSet vs = new ValueSet(); // With correct system version specified. Should pass.
vs.setUrl("http://myvs"); Parameters respParam = myClient
vs.getCompose() .operation()
.addInclude() .onType(ValueSet.class)
.setSystem("http://mycs") .named("validate-code")
.addFilter() .withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v1)
.setOp(FilterOperator.ISA) .andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.setProperty("concept") .andParameter("valueSetVersion", new StringType("1"))
.setValue("ParentA"); .execute();
IIdType vsId = myValueSetDao.create(vs).getId().toUnqualifiedVersionless();
HttpGet expandGet = new HttpGet(ourServerBase + "/ValueSet/" + vsId.getIdPart() + "/$expand?_pretty=true"); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
try (CloseableHttpResponse status = ourHttpClient.execute(expandGet)) { ourLog.info(resp);
String response = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
ourLog.info("Response: {}", response);
}
HttpGet validateCodeGet = new HttpGet(ourServerBase + "/ValueSet/" + vsId.getIdPart() + "/$validate-code?system=http://mycs&code=ChildAA&_pretty=true"); assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
try (CloseableHttpResponse status = ourHttpClient.execute(validateCodeGet)) {
String response = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
ourLog.info("Response: {}", response);
Parameters output = myFhirCtx.newXmlParser().parseResource(Parameters.class, response);
assertEquals(true, output.getParameterBool("result"));
}
HttpGet validateCodeGet2 = new HttpGet(ourServerBase + "/ValueSet/" + vsId.getIdPart() + "/$validate-code?system=http://mycs&code=FOO&_pretty=true"); respParam = myClient
try (CloseableHttpResponse status = ourHttpClient.execute(validateCodeGet2)) { .operation()
String response = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); .onType(ValueSet.class)
ourLog.info("Response: {}", response); .named("validate-code")
Parameters output = myFhirCtx.newXmlParser().parseResource(Parameters.class, response); .withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v2)
assertEquals(false, output.getParameterBool("result")); .andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
} .andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
// With incorrect version specified. Should fail.
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
} }
*/
private boolean clearDeferredStorageQueue() { private boolean clearDeferredStorageQueue() {

View File

@ -326,6 +326,30 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
return url; return url;
} }
public static String getValueSetVersion(@Nonnull IBaseResource theValueSet) {
String version;
switch (theValueSet.getStructureFhirVersionEnum()) {
case DSTU3: {
version = ((org.hl7.fhir.dstu3.model.ValueSet) theValueSet).getVersion();
break;
}
case R4: {
version = ((org.hl7.fhir.r4.model.ValueSet) theValueSet).getVersion();
break;
}
case R5: {
version = ((org.hl7.fhir.r5.model.ValueSet) theValueSet).getVersion();
break;
}
case DSTU2:
case DSTU2_HL7ORG:
case DSTU2_1:
default:
throw new IllegalArgumentException("Can not handle version: " + theValueSet.getStructureFhirVersionEnum());
}
return version;
}
private static HashMap<String, String> buildUspsCodes() { private static HashMap<String, String> buildUspsCodes() {
HashMap<String, String> uspsCodes = new HashMap<>(); HashMap<String, String> uspsCodes = new HashMap<>();
uspsCodes.put("AK", "Alaska"); uspsCodes.put("AK", "Alaska");

View File

@ -91,23 +91,23 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
return new ValueSetExpansionOutcome(expansion, null); return new ValueSetExpansionOutcome(expansion, null);
} }
private org.hl7.fhir.r5.model.ValueSet expandValueSetToCanonical(ValidationSupportContext theValidationSupportContext, IBaseResource theValueSetToExpand, @Nullable String theWantSystem, @Nullable String theWantCode) { private org.hl7.fhir.r5.model.ValueSet expandValueSetToCanonical(ValidationSupportContext theValidationSupportContext, IBaseResource theValueSetToExpand, @Nullable String theWantSystemIdentifier, @Nullable String theWantCode) {
org.hl7.fhir.r5.model.ValueSet expansionR5; org.hl7.fhir.r5.model.ValueSet expansionR5;
switch (theValueSetToExpand.getStructureFhirVersionEnum()) { switch (theValueSetToExpand.getStructureFhirVersionEnum()) {
case DSTU2: { case DSTU2: {
expansionR5 = expandValueSetDstu2(theValidationSupportContext, (ca.uhn.fhir.model.dstu2.resource.ValueSet) theValueSetToExpand, theWantSystem, theWantCode); expansionR5 = expandValueSetDstu2(theValidationSupportContext, (ca.uhn.fhir.model.dstu2.resource.ValueSet) theValueSetToExpand, theWantSystemIdentifier, theWantCode);
break; break;
} }
case DSTU2_HL7ORG: { case DSTU2_HL7ORG: {
expansionR5 = expandValueSetDstu2Hl7Org(theValidationSupportContext, (ValueSet) theValueSetToExpand, theWantSystem, theWantCode); expansionR5 = expandValueSetDstu2Hl7Org(theValidationSupportContext, (ValueSet) theValueSetToExpand, theWantSystemIdentifier, theWantCode);
break; break;
} }
case DSTU3: { case DSTU3: {
expansionR5 = expandValueSetDstu3(theValidationSupportContext, (org.hl7.fhir.dstu3.model.ValueSet) theValueSetToExpand, theWantSystem, theWantCode); expansionR5 = expandValueSetDstu3(theValidationSupportContext, (org.hl7.fhir.dstu3.model.ValueSet) theValueSetToExpand, theWantSystemIdentifier, theWantCode);
break; break;
} }
case R4: { case R4: {
expansionR5 = expandValueSetR4(theValidationSupportContext, (org.hl7.fhir.r4.model.ValueSet) theValueSetToExpand, theWantSystem, theWantCode); expansionR5 = expandValueSetR4(theValidationSupportContext, (org.hl7.fhir.r4.model.ValueSet) theValueSetToExpand, theWantSystemIdentifier, theWantCode);
break; break;
} }
case R5: { case R5: {
@ -119,20 +119,17 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
throw new IllegalArgumentException("Can not handle version: " + myCtx.getVersion().getVersion()); throw new IllegalArgumentException("Can not handle version: " + myCtx.getVersion().getVersion());
} }
if (expansionR5 == null) {
return null;
}
return expansionR5; return expansionR5;
} }
@Override @Override
public CodeValidationResult public CodeValidationResult
validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) { validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystemIdentifier, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) {
org.hl7.fhir.r5.model.ValueSet expansion = expandValueSetToCanonical(theValidationSupportContext, theValueSet, theCodeSystem, theCode); org.hl7.fhir.r5.model.ValueSet expansion = expandValueSetToCanonical(theValidationSupportContext, theValueSet, theCodeSystemIdentifier, theCode);
if (expansion == null) { if (expansion == null) {
return null; return null;
} }
return validateCodeInExpandedValueSet(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, expansion); return validateCodeInExpandedValueSet(theValidationSupportContext, theOptions, theCodeSystemIdentifier, theCode, theDisplay, expansion);
} }
@ -145,26 +142,59 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
return null; return null;
} }
} else { } else {
String codeSystemUrl;
String codeSystemVersion = null;
int codeSystemVersionIndex = theCodeSystem.indexOf("|");
if (codeSystemVersionIndex > -1) {
codeSystemUrl = theCodeSystem.substring(0, codeSystemVersionIndex);
codeSystemVersion = theCodeSystem.substring(codeSystemVersionIndex + 1);
} else {
codeSystemUrl = theCodeSystem;
}
switch (myCtx.getVersion().getVersion()) { switch (myCtx.getVersion().getVersion()) {
case DSTU2_HL7ORG: case DSTU2_HL7ORG:
vs = new org.hl7.fhir.dstu2.model.ValueSet() if (codeSystemVersion != null) {
.setCompose(new org.hl7.fhir.dstu2.model.ValueSet.ValueSetComposeComponent() vs = new org.hl7.fhir.dstu2.model.ValueSet()
.addInclude(new org.hl7.fhir.dstu2.model.ValueSet.ConceptSetComponent().setSystem(theCodeSystem))); .setCompose(new org.hl7.fhir.dstu2.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.dstu2.model.ValueSet.ConceptSetComponent().setSystem(codeSystemUrl).setVersion(codeSystemVersion)));
} else {
vs = new org.hl7.fhir.dstu2.model.ValueSet()
.setCompose(new org.hl7.fhir.dstu2.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.dstu2.model.ValueSet.ConceptSetComponent().setSystem(theCodeSystem)));
}
break; break;
case DSTU3: case DSTU3:
vs = new org.hl7.fhir.dstu3.model.ValueSet() if (codeSystemVersion != null) {
.setCompose(new org.hl7.fhir.dstu3.model.ValueSet.ValueSetComposeComponent() vs = new org.hl7.fhir.dstu3.model.ValueSet()
.addInclude(new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(theCodeSystem))); .setCompose(new org.hl7.fhir.dstu3.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(codeSystemUrl).setVersion(codeSystemVersion)));
} else {
vs = new org.hl7.fhir.dstu3.model.ValueSet()
.setCompose(new org.hl7.fhir.dstu3.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(theCodeSystem)));
}
break; break;
case R4: case R4:
vs = new org.hl7.fhir.r4.model.ValueSet() if (codeSystemVersion != null) {
.setCompose(new org.hl7.fhir.r4.model.ValueSet.ValueSetComposeComponent() vs = new org.hl7.fhir.r4.model.ValueSet()
.addInclude(new org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent().setSystem(theCodeSystem))); .setCompose(new org.hl7.fhir.r4.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent().setSystem(codeSystemUrl).setVersion(codeSystemVersion)));
} else {
vs = new org.hl7.fhir.r4.model.ValueSet()
.setCompose(new org.hl7.fhir.r4.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent().setSystem(theCodeSystem)));
}
break; break;
case R5: case R5:
vs = new org.hl7.fhir.r5.model.ValueSet() if (codeSystemVersion != null) {
.setCompose(new org.hl7.fhir.r5.model.ValueSet.ValueSetComposeComponent() vs = new org.hl7.fhir.r5.model.ValueSet()
.addInclude(new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(theCodeSystem))); .setCompose(new org.hl7.fhir.r5.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(codeSystemUrl).setVersion(codeSystemVersion)));
} else {
vs = new org.hl7.fhir.r5.model.ValueSet()
.setCompose(new org.hl7.fhir.r5.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(theCodeSystem)));
}
break; break;
case DSTU2: case DSTU2:
case DSTU2_1: case DSTU2_1:
@ -184,39 +214,39 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
} }
private CodeValidationResult validateCodeInExpandedValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, IBaseResource theExpansion) { private CodeValidationResult validateCodeInExpandedValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystemIdentifierToValidate, String theCodeToValidate, String theDisplayToValidate, IBaseResource theExpansion) {
assert theExpansion != null; assert theExpansion != null;
boolean caseSensitive = true; boolean caseSensitive = true;
IBaseResource system = null; IBaseResource codeSystemToValidateResource = null;
if (!theOptions.isInferSystem() && isNotBlank(theCodeSystem)) { if (!theOptions.isInferSystem() && isNotBlank(theCodeSystemIdentifierToValidate)) {
system = theValidationSupportContext.getRootValidationSupport().fetchCodeSystem(theCodeSystem); codeSystemToValidateResource = theValidationSupportContext.getRootValidationSupport().fetchCodeSystem(theCodeSystemIdentifierToValidate);
} }
List<VersionIndependentConcept> codes = new ArrayList<>(); List<VersionIndependentConcept> codesInValueSetExpansion = new ArrayList<>();
switch (theExpansion.getStructureFhirVersionEnum()) { switch (theExpansion.getStructureFhirVersionEnum()) {
case DSTU2_HL7ORG: { case DSTU2_HL7ORG: {
ValueSet expansionVs = (ValueSet) theExpansion; ValueSet expansionVs = (ValueSet) theExpansion;
List<ValueSet.ValueSetExpansionContainsComponent> contains = expansionVs.getExpansion().getContains(); List<ValueSet.ValueSetExpansionContainsComponent> contains = expansionVs.getExpansion().getContains();
flattenAndConvertCodesDstu2(contains, codes); flattenAndConvertCodesDstu2(contains, codesInValueSetExpansion);
break; break;
} }
case DSTU3: { case DSTU3: {
org.hl7.fhir.dstu3.model.ValueSet expansionVs = (org.hl7.fhir.dstu3.model.ValueSet) theExpansion; org.hl7.fhir.dstu3.model.ValueSet expansionVs = (org.hl7.fhir.dstu3.model.ValueSet) theExpansion;
List<org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent> contains = expansionVs.getExpansion().getContains(); List<org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent> contains = expansionVs.getExpansion().getContains();
flattenAndConvertCodesDstu3(contains, codes); flattenAndConvertCodesDstu3(contains, codesInValueSetExpansion);
break; break;
} }
case R4: { case R4: {
org.hl7.fhir.r4.model.ValueSet expansionVs = (org.hl7.fhir.r4.model.ValueSet) theExpansion; org.hl7.fhir.r4.model.ValueSet expansionVs = (org.hl7.fhir.r4.model.ValueSet) theExpansion;
List<org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent> contains = expansionVs.getExpansion().getContains(); List<org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent> contains = expansionVs.getExpansion().getContains();
flattenAndConvertCodesR4(contains, codes); flattenAndConvertCodesR4(contains, codesInValueSetExpansion);
break; break;
} }
case R5: { case R5: {
org.hl7.fhir.r5.model.ValueSet expansionVs = (org.hl7.fhir.r5.model.ValueSet) theExpansion; org.hl7.fhir.r5.model.ValueSet expansionVs = (org.hl7.fhir.r5.model.ValueSet) theExpansion;
List<org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent> contains = expansionVs.getExpansion().getContains(); List<org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent> contains = expansionVs.getExpansion().getContains();
flattenAndConvertCodesR5(contains, codes); flattenAndConvertCodesR5(contains, codesInValueSetExpansion);
break; break;
} }
case DSTU2: case DSTU2:
@ -225,37 +255,37 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
throw new IllegalArgumentException("Can not handle version: " + myCtx.getVersion().getVersion()); throw new IllegalArgumentException("Can not handle version: " + myCtx.getVersion().getVersion());
} }
String codeSystemName = null; String codeSystemResourceName = null;
String codeSystemVersion = null; String codeSystemResourceVersion = null;
String codeSystemContentMode = null; String codeSystemResourceContentMode = null;
if (system != null) { if (codeSystemToValidateResource != null) {
switch (system.getStructureFhirVersionEnum()) { switch (codeSystemToValidateResource.getStructureFhirVersionEnum()) {
case DSTU2_HL7ORG: { case DSTU2_HL7ORG: {
caseSensitive = true; caseSensitive = true;
break; break;
} }
case DSTU3: { case DSTU3: {
org.hl7.fhir.dstu3.model.CodeSystem systemDstu3 = (org.hl7.fhir.dstu3.model.CodeSystem) system; org.hl7.fhir.dstu3.model.CodeSystem systemDstu3 = (org.hl7.fhir.dstu3.model.CodeSystem) codeSystemToValidateResource;
caseSensitive = systemDstu3.getCaseSensitive(); caseSensitive = systemDstu3.getCaseSensitive();
codeSystemName = systemDstu3.getName(); codeSystemResourceName = systemDstu3.getName();
codeSystemVersion = systemDstu3.getVersion(); codeSystemResourceVersion = systemDstu3.getVersion();
codeSystemContentMode = systemDstu3.getContentElement().getValueAsString(); codeSystemResourceContentMode = systemDstu3.getContentElement().getValueAsString();
break; break;
} }
case R4: { case R4: {
org.hl7.fhir.r4.model.CodeSystem systemR4 = (org.hl7.fhir.r4.model.CodeSystem) system; org.hl7.fhir.r4.model.CodeSystem systemR4 = (org.hl7.fhir.r4.model.CodeSystem) codeSystemToValidateResource;
caseSensitive = systemR4.getCaseSensitive(); caseSensitive = systemR4.getCaseSensitive();
codeSystemName = systemR4.getName(); codeSystemResourceName = systemR4.getName();
codeSystemVersion = systemR4.getVersion(); codeSystemResourceVersion = systemR4.getVersion();
codeSystemContentMode = systemR4.getContentElement().getValueAsString(); codeSystemResourceContentMode = systemR4.getContentElement().getValueAsString();
break; break;
} }
case R5: { case R5: {
CodeSystem systemR5 = (CodeSystem) system; CodeSystem systemR5 = (CodeSystem) codeSystemToValidateResource;
caseSensitive = systemR5.getCaseSensitive(); caseSensitive = systemR5.getCaseSensitive();
codeSystemName = systemR5.getName(); codeSystemResourceName = systemR5.getName();
codeSystemVersion = systemR5.getVersion(); codeSystemResourceVersion = systemR5.getVersion();
codeSystemContentMode = systemR5.getContentElement().getValueAsString(); codeSystemResourceContentMode = systemR5.getContentElement().getValueAsString();
break; break;
} }
case DSTU2: case DSTU2:
@ -265,29 +295,40 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
} }
} }
for (VersionIndependentConcept nextExpansionCode : codes) { String codeSystemUrlToValidate=null;
String codeSystemVersionToValidate=null;
if (theCodeSystemIdentifierToValidate != null) {
int versionIndex = theCodeSystemIdentifierToValidate.indexOf("|");
if (versionIndex > -1) {
codeSystemUrlToValidate = theCodeSystemIdentifierToValidate.substring(0, versionIndex);
codeSystemVersionToValidate = theCodeSystemIdentifierToValidate.substring(versionIndex+1);
} else {
codeSystemUrlToValidate = theCodeSystemIdentifierToValidate;
}
}
for (VersionIndependentConcept nextExpansionCode : codesInValueSetExpansion) {
boolean codeMatches; boolean codeMatches;
if (caseSensitive) { if (caseSensitive) {
codeMatches = defaultString(theCode).equals(nextExpansionCode.getCode()); codeMatches = defaultString(theCodeToValidate).equals(nextExpansionCode.getCode());
} else { } else {
codeMatches = defaultString(theCode).equalsIgnoreCase(nextExpansionCode.getCode()); codeMatches = defaultString(theCodeToValidate).equalsIgnoreCase(nextExpansionCode.getCode());
} }
if (codeMatches) { if (codeMatches) {
if (theOptions.isInferSystem() || nextExpansionCode.getSystem().equals(theCodeSystem)) { if (theOptions.isInferSystem() || (nextExpansionCode.getSystem().equals(codeSystemUrlToValidate) && (codeSystemVersionToValidate == null || codeSystemVersionToValidate.equals(nextExpansionCode.getSystemVersion())))) {
if (!theOptions.isValidateDisplay() || (isBlank(nextExpansionCode.getDisplay()) || isBlank(theDisplay) || nextExpansionCode.getDisplay().equals(theDisplay))) { if (!theOptions.isValidateDisplay() || (isBlank(nextExpansionCode.getDisplay()) || isBlank(theDisplayToValidate) || nextExpansionCode.getDisplay().equals(theDisplayToValidate))) {
return new CodeValidationResult() return new CodeValidationResult()
.setCode(theCode) .setCode(theCodeToValidate)
.setDisplay(nextExpansionCode.getDisplay()) .setDisplay(nextExpansionCode.getDisplay())
.setCodeSystemName(codeSystemName) .setCodeSystemName(codeSystemResourceName)
.setCodeSystemVersion(codeSystemVersion); .setCodeSystemVersion(codeSystemResourceVersion);
} else { } else {
return new CodeValidationResult() return new CodeValidationResult()
.setSeverity(IssueSeverity.ERROR) .setSeverity(IssueSeverity.ERROR)
.setDisplay(nextExpansionCode.getDisplay()) .setDisplay(nextExpansionCode.getDisplay())
.setMessage("Concept Display \"" + theDisplay + "\" does not match expected \"" + nextExpansionCode.getDisplay() + "\"") .setMessage("Concept Display \"" + theDisplayToValidate + "\" does not match expected \"" + nextExpansionCode.getDisplay() + "\"")
.setCodeSystemName(codeSystemName) .setCodeSystemName(codeSystemResourceName)
.setCodeSystemVersion(codeSystemVersion); .setCodeSystemVersion(codeSystemResourceVersion);
} }
} }
} }
@ -295,12 +336,12 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
ValidationMessage.IssueSeverity severity; ValidationMessage.IssueSeverity severity;
String message; String message;
if ("fragment".equals(codeSystemContentMode)) { if ("fragment".equals(codeSystemResourceContentMode)) {
severity = ValidationMessage.IssueSeverity.WARNING; severity = ValidationMessage.IssueSeverity.WARNING;
message = "Unknown code in fragment CodeSystem '" + (isNotBlank(theCodeSystem) ? theCodeSystem + "#" : "") + theCode + "'"; message = "Unknown code in fragment CodeSystem '" + (isNotBlank(theCodeSystemIdentifierToValidate) ? theCodeSystemIdentifierToValidate + "#" : "") + theCodeToValidate + "'";
} else { } else {
severity = ValidationMessage.IssueSeverity.ERROR; severity = ValidationMessage.IssueSeverity.ERROR;
message = "Unknown code '" + (isNotBlank(theCodeSystem) ? theCodeSystem + "#" : "") + theCode + "'"; message = "Unknown code '" + (isNotBlank(theCodeSystemIdentifierToValidate) ? theCodeSystemIdentifierToValidate + "#" : "") + theCodeToValidate + "'";
} }
return new CodeValidationResult() return new CodeValidationResult()
@ -314,7 +355,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
} }
@Nullable @Nullable
private org.hl7.fhir.r5.model.ValueSet expandValueSetDstu2Hl7Org(ValidationSupportContext theValidationSupportContext, ValueSet theInput, @Nullable String theWantSystem, @Nullable String theWantCode) { private org.hl7.fhir.r5.model.ValueSet expandValueSetDstu2Hl7Org(ValidationSupportContext theValidationSupportContext, ValueSet theInput, @Nullable String theWantSystemIdentifier, @Nullable String theWantCode) {
Function<String, CodeSystem> codeSystemLoader = t -> { Function<String, CodeSystem> codeSystemLoader = t -> {
org.hl7.fhir.dstu2.model.ValueSet codeSystem = (org.hl7.fhir.dstu2.model.ValueSet) theValidationSupportContext.getRootValidationSupport().fetchCodeSystem(t); org.hl7.fhir.dstu2.model.ValueSet codeSystem = (org.hl7.fhir.dstu2.model.ValueSet) theValidationSupportContext.getRootValidationSupport().fetchCodeSystem(t);
CodeSystem retVal = new CodeSystem(); CodeSystem retVal = new CodeSystem();
@ -327,12 +368,12 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
}; };
org.hl7.fhir.r5.model.ValueSet input = ValueSet10_50.convertValueSet(theInput); org.hl7.fhir.r5.model.ValueSet input = ValueSet10_50.convertValueSet(theInput);
org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystem, theWantCode); org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystemIdentifier, theWantCode);
return (output); return (output);
} }
@Nullable @Nullable
private org.hl7.fhir.r5.model.ValueSet expandValueSetDstu2(ValidationSupportContext theValidationSupportContext, ca.uhn.fhir.model.dstu2.resource.ValueSet theInput, @Nullable String theWantSystem, @Nullable String theWantCode) { private org.hl7.fhir.r5.model.ValueSet expandValueSetDstu2(ValidationSupportContext theValidationSupportContext, ca.uhn.fhir.model.dstu2.resource.ValueSet theInput, @Nullable String theWantSystemIdentifier, @Nullable String theWantCode) {
IParser parserRi = FhirContext.forCached(FhirVersionEnum.DSTU2_HL7ORG).newJsonParser(); IParser parserRi = FhirContext.forCached(FhirVersionEnum.DSTU2_HL7ORG).newJsonParser();
IParser parserHapi = FhirContext.forCached(FhirVersionEnum.DSTU2).newJsonParser(); IParser parserHapi = FhirContext.forCached(FhirVersionEnum.DSTU2).newJsonParser();
@ -355,7 +396,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
org.hl7.fhir.dstu2.model.ValueSet valueSetRi = parserRi.parseResource(org.hl7.fhir.dstu2.model.ValueSet.class, parserHapi.encodeResourceToString(theInput)); org.hl7.fhir.dstu2.model.ValueSet valueSetRi = parserRi.parseResource(org.hl7.fhir.dstu2.model.ValueSet.class, parserHapi.encodeResourceToString(theInput));
org.hl7.fhir.r5.model.ValueSet input = ValueSet10_50.convertValueSet(valueSetRi); org.hl7.fhir.r5.model.ValueSet input = ValueSet10_50.convertValueSet(valueSetRi);
org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystem, theWantCode); org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystemIdentifier, theWantCode);
return (output); return (output);
} }
@ -404,7 +445,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
} }
@Nullable @Nullable
private org.hl7.fhir.r5.model.ValueSet expandValueSetDstu3(ValidationSupportContext theValidationSupportContext, org.hl7.fhir.dstu3.model.ValueSet theInput, @Nullable String theWantSystem, @Nullable String theWantCode) { private org.hl7.fhir.r5.model.ValueSet expandValueSetDstu3(ValidationSupportContext theValidationSupportContext, org.hl7.fhir.dstu3.model.ValueSet theInput, @Nullable String theWantSystemIdentifier, @Nullable String theWantCode) {
Function<String, org.hl7.fhir.r5.model.CodeSystem> codeSystemLoader = t -> { Function<String, org.hl7.fhir.r5.model.CodeSystem> codeSystemLoader = t -> {
org.hl7.fhir.dstu3.model.CodeSystem codeSystem = (org.hl7.fhir.dstu3.model.CodeSystem) theValidationSupportContext.getRootValidationSupport().fetchCodeSystem(t); org.hl7.fhir.dstu3.model.CodeSystem codeSystem = (org.hl7.fhir.dstu3.model.CodeSystem) theValidationSupportContext.getRootValidationSupport().fetchCodeSystem(t);
return CodeSystem30_50.convertCodeSystem(codeSystem); return CodeSystem30_50.convertCodeSystem(codeSystem);
@ -415,12 +456,12 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
}; };
org.hl7.fhir.r5.model.ValueSet input = ValueSet30_50.convertValueSet(theInput); org.hl7.fhir.r5.model.ValueSet input = ValueSet30_50.convertValueSet(theInput);
org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystem, theWantCode); org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystemIdentifier, theWantCode);
return (output); return (output);
} }
@Nullable @Nullable
private org.hl7.fhir.r5.model.ValueSet expandValueSetR4(ValidationSupportContext theValidationSupportContext, org.hl7.fhir.r4.model.ValueSet theInput, @Nullable String theWantSystem, @Nullable String theWantCode) { private org.hl7.fhir.r5.model.ValueSet expandValueSetR4(ValidationSupportContext theValidationSupportContext, org.hl7.fhir.r4.model.ValueSet theInput, @Nullable String theWantSystemIdentifier, @Nullable String theWantCode) {
Function<String, org.hl7.fhir.r5.model.CodeSystem> codeSystemLoader = t -> { Function<String, org.hl7.fhir.r5.model.CodeSystem> codeSystemLoader = t -> {
org.hl7.fhir.r4.model.CodeSystem codeSystem = (org.hl7.fhir.r4.model.CodeSystem) theValidationSupportContext.getRootValidationSupport().fetchCodeSystem(t); org.hl7.fhir.r4.model.CodeSystem codeSystem = (org.hl7.fhir.r4.model.CodeSystem) theValidationSupportContext.getRootValidationSupport().fetchCodeSystem(t);
return CodeSystem40_50.convertCodeSystem(codeSystem); return CodeSystem40_50.convertCodeSystem(codeSystem);
@ -431,7 +472,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
}; };
org.hl7.fhir.r5.model.ValueSet input = ValueSet40_50.convertValueSet(theInput); org.hl7.fhir.r5.model.ValueSet input = ValueSet40_50.convertValueSet(theInput);
org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystem, theWantCode); org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystemIdentifier, theWantCode);
return (output); return (output);
} }
@ -444,12 +485,12 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
} }
@Nullable @Nullable
private org.hl7.fhir.r5.model.ValueSet expandValueSetR5(ValidationSupportContext theValidationSupportContext, org.hl7.fhir.r5.model.ValueSet theInput, Function<String, CodeSystem> theCodeSystemLoader, Function<String, org.hl7.fhir.r5.model.ValueSet> theValueSetLoader, @Nullable String theWantSystem, @Nullable String theWantCode) { private org.hl7.fhir.r5.model.ValueSet expandValueSetR5(ValidationSupportContext theValidationSupportContext, org.hl7.fhir.r5.model.ValueSet theInput, Function<String, CodeSystem> theCodeSystemLoader, Function<String, org.hl7.fhir.r5.model.ValueSet> theValueSetLoader, @Nullable String theWantSystemIdentifier, @Nullable String theWantCode) {
Set<VersionIndependentConcept> concepts = new HashSet<>(); Set<VersionIndependentConcept> concepts = new HashSet<>();
try { try {
expandValueSetR5IncludeOrExclude(theValidationSupportContext, concepts, theCodeSystemLoader, theValueSetLoader, theInput.getCompose().getInclude(), true, theWantSystem, theWantCode); expandValueSetR5IncludeOrExclude(theValidationSupportContext, concepts, theCodeSystemLoader, theValueSetLoader, theInput.getCompose().getInclude(), true, theWantSystemIdentifier, theWantCode);
expandValueSetR5IncludeOrExclude(theValidationSupportContext, concepts, theCodeSystemLoader, theValueSetLoader, theInput.getCompose().getExclude(), false, theWantSystem, theWantCode); expandValueSetR5IncludeOrExclude(theValidationSupportContext, concepts, theCodeSystemLoader, theValueSetLoader, theInput.getCompose().getExclude(), false, theWantSystemIdentifier, theWantCode);
} catch (ExpansionCouldNotBeCompletedInternallyException e) { } catch (ExpansionCouldNotBeCompletedInternallyException e) {
return null; return null;
} }
@ -460,23 +501,46 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
contains.setSystem(next.getSystem()); contains.setSystem(next.getSystem());
contains.setCode(next.getCode()); contains.setCode(next.getCode());
contains.setDisplay(next.getDisplay()); contains.setDisplay(next.getDisplay());
contains.setVersion(next.getSystemVersion());
} }
return retVal; return retVal;
} }
private void expandValueSetR5IncludeOrExclude(ValidationSupportContext theValidationSupportContext, Set<VersionIndependentConcept> theConcepts, Function<String, CodeSystem> theCodeSystemLoader, Function<String, org.hl7.fhir.r5.model.ValueSet> theValueSetLoader, List<org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent> theComposeList, boolean theComposeListIsInclude, @Nullable String theWantSystem, @Nullable String theWantCode) throws ExpansionCouldNotBeCompletedInternallyException { private void expandValueSetR5IncludeOrExclude(ValidationSupportContext theValidationSupportContext, Set<VersionIndependentConcept> theConcepts, Function<String, CodeSystem> theCodeSystemLoader, Function<String, org.hl7.fhir.r5.model.ValueSet> theValueSetLoader, List<org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent> theComposeList, boolean theComposeListIsInclude, @Nullable String theWantSystemIdentifier, @Nullable String theWantCode) throws ExpansionCouldNotBeCompletedInternallyException {
String wantSystemUrl = null;
String wantSystemVersion = null;
if (theWantSystemIdentifier != null) {
int versionIndex = theWantSystemIdentifier.indexOf("|");
if (versionIndex > -1) {
wantSystemUrl = theWantSystemIdentifier.substring(0,versionIndex);
wantSystemVersion = theWantSystemIdentifier.substring(versionIndex+1);
} else {
wantSystemUrl = theWantSystemIdentifier;
}
}
for (org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent nextInclude : theComposeList) { for (org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent nextInclude : theComposeList) {
List<VersionIndependentConcept> nextCodeList = new ArrayList<>(); List<VersionIndependentConcept> nextCodeList = new ArrayList<>();
String system = nextInclude.getSystem(); String includeOrExcludeConceptSystemUrl = nextInclude.getSystem();
if (isNotBlank(system)) { String includeOrExcludeConceptSystemVersion = nextInclude.getVersion();
if (isNotBlank(includeOrExcludeConceptSystemUrl)) {
if (theWantSystem != null && !theWantSystem.equals(system)) { if (wantSystemUrl != null && !wantSystemUrl.equals(includeOrExcludeConceptSystemUrl)) {
continue; continue;
} }
CodeSystem codeSystem = theCodeSystemLoader.apply(system); if (wantSystemVersion != null && !wantSystemVersion.equals(includeOrExcludeConceptSystemVersion)) {
continue;
}
CodeSystem includeOrExcludeSystemResource;
if (includeOrExcludeConceptSystemVersion != null) {
includeOrExcludeSystemResource = theCodeSystemLoader.apply(includeOrExcludeConceptSystemUrl + "|" + includeOrExcludeConceptSystemVersion);
} else {
includeOrExcludeSystemResource = theCodeSystemLoader.apply(includeOrExcludeConceptSystemUrl);
}
Set<String> wantCodes; Set<String> wantCodes;
if (nextInclude.getConcept().isEmpty()) { if (nextInclude.getConcept().isEmpty()) {
@ -488,18 +552,18 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
} }
boolean ableToHandleCode = false; boolean ableToHandleCode = false;
if (codeSystem == null || codeSystem.getContent() == CodeSystem.CodeSystemContentMode.NOTPRESENT) { if (includeOrExcludeSystemResource == null || includeOrExcludeSystemResource.getContent() == CodeSystem.CodeSystemContentMode.NOTPRESENT) {
if (theWantCode != null) { if (theWantCode != null) {
if (theValidationSupportContext.getRootValidationSupport().isCodeSystemSupported(theValidationSupportContext, system)) { if (theValidationSupportContext.getRootValidationSupport().isCodeSystemSupported(theValidationSupportContext, includeOrExcludeConceptSystemUrl)) {
LookupCodeResult lookup = theValidationSupportContext.getRootValidationSupport().lookupCode(theValidationSupportContext, system, theWantCode); LookupCodeResult lookup = theValidationSupportContext.getRootValidationSupport().lookupCode(theValidationSupportContext, includeOrExcludeConceptSystemUrl, theWantCode);
if (lookup != null && lookup.isFound()) { if (lookup != null && lookup.isFound()) {
CodeSystem.ConceptDefinitionComponent conceptDefinition = new CodeSystem.ConceptDefinitionComponent() CodeSystem.ConceptDefinitionComponent conceptDefinition = new CodeSystem.ConceptDefinitionComponent()
.addConcept() .addConcept()
.setCode(theWantCode) .setCode(theWantCode)
.setDisplay(lookup.getCodeDisplay()); .setDisplay(lookup.getCodeDisplay());
List<CodeSystem.ConceptDefinitionComponent> codesList = Collections.singletonList(conceptDefinition); List<CodeSystem.ConceptDefinitionComponent> codesList = Collections.singletonList(conceptDefinition);
addCodes(system, codesList, nextCodeList, wantCodes); addCodes(includeOrExcludeConceptSystemUrl, includeOrExcludeConceptSystemVersion, codesList, nextCodeList, wantCodes);
ableToHandleCode = true; ableToHandleCode = true;
} }
} else if (theComposeListIsInclude) { } else if (theComposeListIsInclude) {
@ -514,7 +578,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
* enumerate a set of good codes for them is a nice compromise there. * enumerate a set of good codes for them is a nice compromise there.
*/ */
for (org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent next : theComposeList) { for (org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent next : theComposeList) {
if (Objects.equals(next.getSystem(), theWantSystem)) { if (Objects.equals(next.getSystem(), theWantSystemIdentifier)) {
Optional<org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent> matchingEnumeratedConcept = next.getConcept().stream().filter(t -> Objects.equals(t.getCode(), theWantCode)).findFirst(); Optional<org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent> matchingEnumeratedConcept = next.getConcept().stream().filter(t -> Objects.equals(t.getCode(), theWantCode)).findFirst();
if (matchingEnumeratedConcept.isPresent()) { if (matchingEnumeratedConcept.isPresent()) {
CodeSystem.ConceptDefinitionComponent conceptDefinition = new CodeSystem.ConceptDefinitionComponent() CodeSystem.ConceptDefinitionComponent conceptDefinition = new CodeSystem.ConceptDefinitionComponent()
@ -522,7 +586,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
.setCode(theWantCode) .setCode(theWantCode)
.setDisplay(matchingEnumeratedConcept.get().getDisplay()); .setDisplay(matchingEnumeratedConcept.get().getDisplay());
List<CodeSystem.ConceptDefinitionComponent> codesList = Collections.singletonList(conceptDefinition); List<CodeSystem.ConceptDefinitionComponent> codesList = Collections.singletonList(conceptDefinition);
addCodes(system, codesList, nextCodeList, wantCodes); addCodes(includeOrExcludeConceptSystemUrl, includeOrExcludeConceptSystemVersion, codesList, nextCodeList, wantCodes);
ableToHandleCode = true; ableToHandleCode = true;
break; break;
} }
@ -540,8 +604,8 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
throw new ExpansionCouldNotBeCompletedInternallyException(); throw new ExpansionCouldNotBeCompletedInternallyException();
} }
if (codeSystem != null && codeSystem.getContent() != CodeSystem.CodeSystemContentMode.NOTPRESENT) { if (includeOrExcludeSystemResource != null && includeOrExcludeSystemResource.getContent() != CodeSystem.CodeSystemContentMode.NOTPRESENT) {
addCodes(system, codeSystem.getConcept(), nextCodeList, wantCodes); addCodes(includeOrExcludeConceptSystemUrl, includeOrExcludeConceptSystemVersion, includeOrExcludeSystemResource.getConcept(), nextCodeList, wantCodes);
} }
} }
@ -549,12 +613,12 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
for (CanonicalType nextValueSetInclude : nextInclude.getValueSet()) { for (CanonicalType nextValueSetInclude : nextInclude.getValueSet()) {
org.hl7.fhir.r5.model.ValueSet vs = theValueSetLoader.apply(nextValueSetInclude.getValueAsString()); org.hl7.fhir.r5.model.ValueSet vs = theValueSetLoader.apply(nextValueSetInclude.getValueAsString());
if (vs != null) { if (vs != null) {
org.hl7.fhir.r5.model.ValueSet subExpansion = expandValueSetR5(theValidationSupportContext, vs, theCodeSystemLoader, theValueSetLoader, theWantSystem, theWantCode); org.hl7.fhir.r5.model.ValueSet subExpansion = expandValueSetR5(theValidationSupportContext, vs, theCodeSystemLoader, theValueSetLoader, theWantSystemIdentifier, theWantCode);
if (subExpansion == null) { if (subExpansion == null) {
throw new ExpansionCouldNotBeCompletedInternallyException(); throw new ExpansionCouldNotBeCompletedInternallyException();
} }
for (org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent next : subExpansion.getExpansion().getContains()) { for (org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent next : subExpansion.getExpansion().getContains()) {
nextCodeList.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay())); nextCodeList.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay(), next.getVersion()));
} }
} }
} }
@ -569,14 +633,14 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
} }
private void addCodes(String theSystem, List<CodeSystem.ConceptDefinitionComponent> theSource, List<VersionIndependentConcept> theTarget, Set<String> theCodeFilter) { private void addCodes(String theCodeSystemUrl, String theCodeSystemVersion, List<CodeSystem.ConceptDefinitionComponent> theSource, List<VersionIndependentConcept> theTarget, Set<String> theCodeFilter) {
for (CodeSystem.ConceptDefinitionComponent next : theSource) { for (CodeSystem.ConceptDefinitionComponent next : theSource) {
if (isNotBlank(next.getCode())) { if (isNotBlank(next.getCode())) {
if (theCodeFilter == null || theCodeFilter.contains(next.getCode())) { if (theCodeFilter == null || theCodeFilter.contains(next.getCode())) {
theTarget.add(new VersionIndependentConcept(theSystem, next.getCode(), next.getDisplay())); theTarget.add(new VersionIndependentConcept(theCodeSystemUrl, next.getCode(), next.getDisplay(), theCodeSystemVersion));
} }
} }
addCodes(theSystem, next.getConcept(), theTarget, theCodeFilter); addCodes(theCodeSystemUrl, theCodeSystemVersion, next.getConcept(), theTarget, theCodeFilter);
} }
} }
@ -593,21 +657,21 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
private static void flattenAndConvertCodesDstu3(List<org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent> theInput, List<VersionIndependentConcept> theVersionIndependentConcepts) { private static void flattenAndConvertCodesDstu3(List<org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent> theInput, List<VersionIndependentConcept> theVersionIndependentConcepts) {
for (org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent next : theInput) { for (org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent next : theInput) {
theVersionIndependentConcepts.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay())); theVersionIndependentConcepts.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay(), next.getVersion()));
flattenAndConvertCodesDstu3(next.getContains(), theVersionIndependentConcepts); flattenAndConvertCodesDstu3(next.getContains(), theVersionIndependentConcepts);
} }
} }
private static void flattenAndConvertCodesR4(List<org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent> theInput, List<VersionIndependentConcept> theVersionIndependentConcepts) { private static void flattenAndConvertCodesR4(List<org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent> theInput, List<VersionIndependentConcept> theVersionIndependentConcepts) {
for (org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent next : theInput) { for (org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent next : theInput) {
theVersionIndependentConcepts.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay())); theVersionIndependentConcepts.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay(), next.getVersion()));
flattenAndConvertCodesR4(next.getContains(), theVersionIndependentConcepts); flattenAndConvertCodesR4(next.getContains(), theVersionIndependentConcepts);
} }
} }
private static void flattenAndConvertCodesR5(List<org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent> theInput, List<VersionIndependentConcept> theVersionIndependentConcepts) { private static void flattenAndConvertCodesR5(List<org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent> theInput, List<VersionIndependentConcept> theVersionIndependentConcepts) {
for (org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent next : theInput) { for (org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent next : theInput) {
theVersionIndependentConcepts.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay())); theVersionIndependentConcepts.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay(), next.getVersion()));
flattenAndConvertCodesR5(next.getContains(), theVersionIndependentConcepts); flattenAndConvertCodesR5(next.getContains(), theVersionIndependentConcepts);
} }
} }