Expanding ValueSet using hierarchical CodeSystem fails with constraint violation exception (#5461)

* Expanding a ValueSet using hierarchical CodeSystem would fail in different scenarios with a constraint violation exception when codes (term concepts) were being persisted

* Expanding a ValueSet using hierarchical CodeSystem would fail in different scenarios with a constraint violation exception when codes (term concepts) were being persisted

* Small changes after code review. Doing some variable/method renaming and correcting changelog Jira issue number.
This commit is contained in:
Martha Mitran 2023-11-20 10:23:37 -08:00 committed by GitHub
parent 2e4f8fe4b6
commit 6f84d17b13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 167 additions and 50 deletions

View File

@ -1,5 +1,5 @@
--- ---
type: fix type: fix
issue: 5431 issue: 5431
jira: SMILE-5306 jira: SMILE-7589
title: "Previously, using VersionCanonicalizer to convert a CapabilityStatement from R5 to DSTU2 would fail. This is now fixed." title: "Previously, using VersionCanonicalizer to convert a CapabilityStatement from R5 to DSTU2 would fail. This is now fixed."

View File

@ -0,0 +1,6 @@
---
type: fix
issue: 5460
jira: SMILE-7594
title: "Previously, expanding a ValueSet using hierarchical CodeSystem would fail in different scenarios
with a constraint violation exception when codes (term concepts) were being persisted. This is now fixed."

View File

@ -196,14 +196,9 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
public static final int DEFAULT_MASS_INDEXER_OBJECT_LOADING_THREADS = 2; public static final int DEFAULT_MASS_INDEXER_OBJECT_LOADING_THREADS = 2;
// doesn't seem to be much gain by using more threads than this value // doesn't seem to be much gain by using more threads than this value
public static final int MAX_MASS_INDEXER_OBJECT_LOADING_THREADS = 6; public static final int MAX_MASS_INDEXER_OBJECT_LOADING_THREADS = 6;
private static final int SINGLE_FETCH_SIZE = 1;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TermReadSvcImpl.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TermReadSvcImpl.class);
private static final ValueSetExpansionOptions DEFAULT_EXPANSION_OPTIONS = new ValueSetExpansionOptions(); private static final ValueSetExpansionOptions DEFAULT_EXPANSION_OPTIONS = new ValueSetExpansionOptions();
private static final TermCodeSystemVersionDetails NO_CURRENT_VERSION = new TermCodeSystemVersionDetails(-1L, null); private static final TermCodeSystemVersionDetails NO_CURRENT_VERSION = new TermCodeSystemVersionDetails(-1L, null);
private static final String IDX_PROPERTIES = "myProperties";
private static final String IDX_PROP_KEY = IDX_PROPERTIES + ".myKey";
private static final String IDX_PROP_VALUE_STRING = IDX_PROPERTIES + ".myValueString";
private static final String IDX_PROP_DISPLAY_STRING = IDX_PROPERTIES + ".myDisplayString";
private static final String OUR_PIPE_CHARACTER = "|"; private static final String OUR_PIPE_CHARACTER = "|";
private static final int SECONDS_IN_MINUTE = 60; private static final int SECONDS_IN_MINUTE = 60;
private static final int INDEXED_ROOTS_LOGGING_COUNT = 50_000; private static final int INDEXED_ROOTS_LOGGING_COUNT = 50_000;
@ -540,6 +535,7 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
@Nullable ValueSetExpansionOptions theExpansionOptions, @Nullable ValueSetExpansionOptions theExpansionOptions,
ValueSet theValueSetToExpand, ValueSet theValueSetToExpand,
ExpansionFilter theFilter) { ExpansionFilter theFilter) {
Set<String> addedCodes = new HashSet<>();
ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSetToExpand, "ValueSet to expand can not be null"); ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSetToExpand, "ValueSet to expand can not be null");
ValueSetExpansionOptions expansionOptions = provideExpansionOptions(theExpansionOptions); ValueSetExpansionOptions expansionOptions = provideExpansionOptions(theExpansionOptions);
@ -560,9 +556,8 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
accumulator.addParameter().setName("count").setValue(new IntegerType(count)); accumulator.addParameter().setName("count").setValue(new IntegerType(count));
} }
myTxTemplate.executeWithoutResult(tx -> { myTxTemplate.executeWithoutResult(tx -> expandValueSetIntoAccumulator(
expandValueSetIntoAccumulator(theValueSetToExpand, theExpansionOptions, accumulator, theFilter, true); theValueSetToExpand, theExpansionOptions, accumulator, theFilter, true, addedCodes));
});
if (accumulator.getTotalConcepts() != null) { if (accumulator.getTotalConcepts() != null) {
accumulator.setTotal(accumulator.getTotalConcepts()); accumulator.setTotal(accumulator.getTotalConcepts());
@ -594,7 +589,8 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
ValueSetExpansionOptions theExpansionOptions, ValueSetExpansionOptions theExpansionOptions,
IValueSetConceptAccumulator theAccumulator, IValueSetConceptAccumulator theAccumulator,
ExpansionFilter theFilter, ExpansionFilter theFilter,
boolean theAdd) { boolean theAdd,
Set<String> theAddedCodes) {
Optional<TermValueSet> optionalTermValueSet; Optional<TermValueSet> optionalTermValueSet;
if (theValueSetToExpand.hasUrl()) { if (theValueSetToExpand.hasUrl()) {
if (theValueSetToExpand.hasVersion()) { if (theValueSetToExpand.hasVersion()) {
@ -621,7 +617,7 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
"valueSetExpandedUsingInMemoryExpansion", "valueSetExpandedUsingInMemoryExpansion",
getValueSetInfo(theValueSetToExpand)); getValueSetInfo(theValueSetToExpand));
theAccumulator.addMessage(msg); theAccumulator.addMessage(msg);
doExpandValueSet(theExpansionOptions, theValueSetToExpand, theAccumulator, theFilter); doExpandValueSet(theExpansionOptions, theValueSetToExpand, theAccumulator, theFilter, theAddedCodes);
return; return;
} }
@ -639,7 +635,7 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
termValueSet.getExpansionStatus().name(), termValueSet.getExpansionStatus().name(),
termValueSet.getExpansionStatus().getDescription()); termValueSet.getExpansionStatus().getDescription());
theAccumulator.addMessage(msg); theAccumulator.addMessage(msg);
doExpandValueSet(theExpansionOptions, theValueSetToExpand, theAccumulator, theFilter); doExpandValueSet(theExpansionOptions, theValueSetToExpand, theAccumulator, theFilter, theAddedCodes);
return; return;
} }
@ -651,7 +647,8 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
.getLocalizer() .getLocalizer()
.getMessage(TermReadSvcImpl.class, "valueSetExpandedUsingPreExpansion", expansionTimestamp); .getMessage(TermReadSvcImpl.class, "valueSetExpandedUsingPreExpansion", expansionTimestamp);
theAccumulator.addMessage(msg); theAccumulator.addMessage(msg);
expandConcepts(theExpansionOptions, theAccumulator, termValueSet, theFilter, theAdd, isOracleDialect()); expandConcepts(
theExpansionOptions, theAccumulator, termValueSet, theFilter, theAdd, theAddedCodes, isOracleDialect());
} }
@Nonnull @Nonnull
@ -676,6 +673,7 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
TermValueSet theTermValueSet, TermValueSet theTermValueSet,
ExpansionFilter theFilter, ExpansionFilter theFilter,
boolean theAdd, boolean theAdd,
Set<String> theAddedCodes,
boolean theOracle) { boolean theOracle) {
// NOTE: if you modifiy the logic here, look to `expandConceptsOracle` and see if your new code applies to its // NOTE: if you modifiy the logic here, look to `expandConceptsOracle` and see if your new code applies to its
// copy pasted sibling // copy pasted sibling
@ -708,10 +706,6 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
} }
wasFilteredResult = true; wasFilteredResult = true;
} else { } else {
// TODO JA HS: I'm pretty sure we are overfetching here. test says offset 3, count 4, but we are fetching
// index 3 -> 10 here, grabbing 7 concepts.
// Specifically this test
// testExpandInline_IncludePreExpandedValueSetByUri_FilterOnDisplay_LeftMatch_SelectRange
if (theOracle) { if (theOracle) {
conceptViews = myTermValueSetConceptViewOracleDao.findByTermValueSetId( conceptViews = myTermValueSetConceptViewOracleDao.findByTermValueSetId(
offset, toIndex, theTermValueSet.getId()); offset, toIndex, theTermValueSet.getId());
@ -802,26 +796,27 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
Long sourceConceptPid = pidToSourcePid.get(nextPid); Long sourceConceptPid = pidToSourcePid.get(nextPid);
String sourceConceptDirectParentPids = pidToSourceDirectParentPids.get(nextPid); String sourceConceptDirectParentPids = pidToSourceDirectParentPids.get(nextPid);
theAccumulator.includeConceptWithDesignations( if (theAddedCodes.add(system + OUR_PIPE_CHARACTER + code)) {
system, theAccumulator.includeConceptWithDesignations(
code, system,
display, code,
designations, display,
sourceConceptPid, designations,
sourceConceptDirectParentPids, sourceConceptPid,
systemVersion); sourceConceptDirectParentPids,
systemVersion);
if (wasFilteredResult) {
theAccumulator.incrementOrDecrementTotalConcepts(true, 1);
}
}
} else { } else {
boolean removed = theAccumulator.excludeConcept(system, code); if (theAddedCodes.remove(system + OUR_PIPE_CHARACTER + code)) {
if (removed) { theAccumulator.excludeConcept(system, code);
theAccumulator.incrementOrDecrementTotalConcepts(false, 1); theAccumulator.incrementOrDecrementTotalConcepts(false, 1);
} }
} }
} }
if (wasFilteredResult && theAdd) {
theAccumulator.incrementOrDecrementTotalConcepts(true, pidToConcept.size());
}
logDesignationsExpanded("Finished expanding designations. ", theTermValueSet, designationsExpanded); logDesignationsExpanded("Finished expanding designations. ", theTermValueSet, designationsExpanded);
logConceptsExpanded("Finished expanding concepts. ", theTermValueSet, conceptsExpanded); logConceptsExpanded("Finished expanding concepts. ", theTermValueSet, conceptsExpanded);
} }
@ -886,8 +881,13 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
ValueSetExpansionOptions theExpansionOptions, ValueSetExpansionOptions theExpansionOptions,
ValueSet theValueSetToExpand, ValueSet theValueSetToExpand,
IValueSetConceptAccumulator theValueSetCodeAccumulator) { IValueSetConceptAccumulator theValueSetCodeAccumulator) {
Set<String> addedCodes = new HashSet<>();
doExpandValueSet( doExpandValueSet(
theExpansionOptions, theValueSetToExpand, theValueSetCodeAccumulator, ExpansionFilter.NO_FILTER); theExpansionOptions,
theValueSetToExpand,
theValueSetCodeAccumulator,
ExpansionFilter.NO_FILTER,
addedCodes);
} }
/** /**
@ -898,8 +898,8 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
ValueSetExpansionOptions theExpansionOptions, ValueSetExpansionOptions theExpansionOptions,
ValueSet theValueSetToExpand, ValueSet theValueSetToExpand,
IValueSetConceptAccumulator theValueSetCodeAccumulator, IValueSetConceptAccumulator theValueSetCodeAccumulator,
@Nonnull ExpansionFilter theExpansionFilter) { @Nonnull ExpansionFilter theExpansionFilter,
Set<String> addedCodes = new HashSet<>(); Set<String> theAddedCodes) {
StopWatch sw = new StopWatch(); StopWatch sw = new StopWatch();
String valueSetInfo = getValueSetInfo(theValueSetToExpand); String valueSetInfo = getValueSetInfo(theValueSetToExpand);
@ -908,7 +908,7 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
// Offset can't be combined with excludes // Offset can't be combined with excludes
Integer skipCountRemaining = theValueSetCodeAccumulator.getSkipCountRemaining(); Integer skipCountRemaining = theValueSetCodeAccumulator.getSkipCountRemaining();
if (skipCountRemaining != null && skipCountRemaining > 0) { if (skipCountRemaining != null && skipCountRemaining > 0) {
if (theValueSetToExpand.getCompose().getExclude().size() > 0) { if (!theValueSetToExpand.getCompose().getExclude().isEmpty()) {
String msg = myContext String msg = myContext
.getLocalizer() .getLocalizer()
.getMessage(TermReadSvcImpl.class, "valueSetNotYetExpanded_OffsetNotAllowed", valueSetInfo); .getMessage(TermReadSvcImpl.class, "valueSetNotYetExpanded_OffsetNotAllowed", valueSetInfo);
@ -921,7 +921,7 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
for (ValueSet.ConceptSetComponent include : for (ValueSet.ConceptSetComponent include :
theValueSetToExpand.getCompose().getInclude()) { theValueSetToExpand.getCompose().getInclude()) {
myTxTemplate.executeWithoutResult(tx -> expandValueSetHandleIncludeOrExclude( myTxTemplate.executeWithoutResult(tx -> expandValueSetHandleIncludeOrExclude(
theExpansionOptions, theValueSetCodeAccumulator, addedCodes, include, true, theExpansionFilter)); theExpansionOptions, theValueSetCodeAccumulator, theAddedCodes, include, true, theExpansionFilter));
} }
// Handle excludes // Handle excludes
@ -931,7 +931,7 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
myTxTemplate.executeWithoutResult(tx -> expandValueSetHandleIncludeOrExclude( myTxTemplate.executeWithoutResult(tx -> expandValueSetHandleIncludeOrExclude(
theExpansionOptions, theExpansionOptions,
theValueSetCodeAccumulator, theValueSetCodeAccumulator,
addedCodes, theAddedCodes,
exclude, exclude,
false, false,
ExpansionFilter.NO_FILTER)); ExpansionFilter.NO_FILTER));
@ -976,7 +976,7 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
String system = theIncludeOrExclude.getSystem(); String system = theIncludeOrExclude.getSystem();
boolean hasSystem = isNotBlank(system); boolean hasSystem = isNotBlank(system);
boolean hasValueSet = theIncludeOrExclude.getValueSet().size() > 0; boolean hasValueSet = !theIncludeOrExclude.getValueSet().isEmpty();
if (hasSystem) { if (hasSystem) {
@ -1004,7 +1004,7 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
} else { } else {
if (theIncludeOrExclude.getConcept().size() > 0 && theExpansionFilter.hasCode()) { if (!theIncludeOrExclude.getConcept().isEmpty() && theExpansionFilter.hasCode()) {
if (defaultString(theIncludeOrExclude.getSystem()).equals(theExpansionFilter.getSystem())) { if (defaultString(theIncludeOrExclude.getSystem()).equals(theExpansionFilter.getSystem())) {
if (theIncludeOrExclude.getConcept().stream() if (theIncludeOrExclude.getConcept().stream()
.noneMatch(t -> t.getCode().equals(theExpansionFilter.getCode()))) { .noneMatch(t -> t.getCode().equals(theExpansionFilter.getCode()))) {
@ -1065,7 +1065,12 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
} }
expandValueSetIntoAccumulator( expandValueSetIntoAccumulator(
valueSet, theExpansionOptions, theValueSetCodeAccumulator, subExpansionFilter, theAdd); valueSet,
theExpansionOptions,
theValueSetCodeAccumulator,
subExpansionFilter,
theAdd,
theAddedCodes);
} }
} else { } else {
@ -1855,12 +1860,11 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
if (!handled) { if (!handled) {
throwInvalidFilter( throwInvalidFilter(
nextFilter, nextFilter,
" - Note that Hibernate Search is disabled on this server so not all ValueSet expansion funtionality is available."); " - Note that Hibernate Search is disabled on this server so not all ValueSet expansion functionality is available.");
} }
} }
if (theInclude.getConcept().isEmpty()) { if (theInclude.getFilter().isEmpty() && theInclude.getConcept().isEmpty()) {
Collection<TermConcept> concepts = Collection<TermConcept> concepts =
myConceptDao.fetchConceptsAndDesignationsByVersionPid(theVersion.getPid()); myConceptDao.fetchConceptsAndDesignationsByVersionPid(theVersion.getPid());
for (TermConcept next : concepts) { for (TermConcept next : concepts) {
@ -2392,7 +2396,8 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
sw); sw);
} catch (Exception e) { } catch (Exception e) {
ourLog.error("Failed to pre-expand ValueSet: " + e.getMessage(), e); ourLog.error(
"Failed to pre-expand ValueSet with URL[{}]: {}", valueSetToExpand.getUrl(), e.getMessage(), e);
txTemplate.executeWithoutResult(t -> { txTemplate.executeWithoutResult(t -> {
valueSetToExpand.setExpansionStatus(TermValueSetPreExpansionStatusEnum.FAILED_TO_EXPAND); valueSetToExpand.setExpansionStatus(TermValueSetPreExpansionStatusEnum.FAILED_TO_EXPAND);
myTermValueSetDao.saveAndFlush(valueSetToExpand); myTermValueSetDao.saveAndFlush(valueSetToExpand);

View File

@ -36,7 +36,6 @@ import org.hl7.fhir.r4.model.codesystems.HttpVerb;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
@ -73,9 +72,6 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
private final ValueSetTestUtil myValueSetTestUtil = new ValueSetTestUtil(FhirVersionEnum.R4); private final ValueSetTestUtil myValueSetTestUtil = new ValueSetTestUtil(FhirVersionEnum.R4);
@Mock
private IValueSetConceptAccumulator myValueSetCodeAccumulator;
@AfterEach @AfterEach
public void afterEach() { public void afterEach() {
SearchBuilder.setMaxPageSize50ForTest(false); SearchBuilder.setMaxPageSize50ForTest(false);
@ -280,8 +276,9 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
//Ensure that the subsequent expansion with offset returns the same slice we are anticipating. //Ensure that the subsequent expansion with offset returns the same slice we are anticipating.
assertThat(myValueSetTestUtil.toCodes(expandedValueSet).toString(), myValueSetTestUtil.toCodes(expandedValueSet), is(equalTo(expandedConceptCodes.subList(offset, offset + count)))); assertThat(myValueSetTestUtil.toCodes(expandedValueSet).toString(), myValueSetTestUtil.toCodes(expandedValueSet), is(equalTo(expandedConceptCodes.subList(offset, offset + count))));
Assertions.assertEquals(4, expandedValueSet.getExpansion().getContains().size(), myValueSetTestUtil.toCodes(expandedValueSet).toString()); Assertions.assertEquals(count, expandedValueSet.getExpansion().getContains().size(), myValueSetTestUtil.toCodes(expandedValueSet).toString());
assertEquals(11, expandedValueSet.getExpansion().getTotal()); assertEquals(offset + count, expandedValueSet.getExpansion().getTotal());
assertEquals(count, expandedValueSet.getExpansion().getContains().size());
// Make sure we used the pre-expanded version // Make sure we used the pre-expanded version
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries(); List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();

View File

@ -0,0 +1,109 @@
package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.ValueSet;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.Optional;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.params.provider.Arguments.arguments;
public class ValueSetExpansionWithHierarchyR4Test extends BaseTermR4Test {
private static final String ourCodeSystemId = "CodeSystem-WithHierarchy", ourCodeSystemUrl = "http://example/" + ourCodeSystemId;
private static final String ourCodeA = "CodeA", ourCodeB = "CodeB", ourCodeC = "CodeC", ourCodeD = "CodeD";
private static final String ourValueSetAUrl = "http://example/ValueSetA", ourValueSetBUrl = "http://example/ValueSetB", ourValueSetUrl = "http://example/ValueSet";
private static final int ourChildConceptCount = 10;
@BeforeAll
public static void setup() {
TermReadSvcImpl.setForceDisableHibernateSearchForUnitTest(true);
}
@AfterAll
public static void tearDown() {
TermReadSvcImpl.setForceDisableHibernateSearchForUnitTest(false);
}
@BeforeEach
public void setupHierarchicalCodeSystemWithValueSets() {
myStorageSettings.setPreExpandValueSets(true);
CodeSystem codeSystem = new CodeSystem();
codeSystem.setId(ourCodeSystemId);
codeSystem.setUrl(ourCodeSystemUrl);
CodeSystem.ConceptDefinitionComponent concept1 = codeSystem.addConcept().setCode(ourCodeA);
CodeSystem.ConceptDefinitionComponent concept2 = codeSystem.addConcept().setCode(ourCodeB);
for (int i = 0; i < ourChildConceptCount; i++) {
concept1.addConcept().setCode(concept1.getCode() + i);
concept2.addConcept().setCode(concept2.getCode() + i);
}
codeSystem.addConcept().setCode(ourCodeC);
codeSystem.addConcept().setCode(ourCodeD);
myCodeSystemDao.create(codeSystem, mySrd);
ValueSet valueSetA = new ValueSet();
valueSetA.setUrl(ourValueSetAUrl);
valueSetA.getCompose().addInclude().setSystem(ourCodeSystemUrl)
.addFilter().setProperty("concept").setOp(ValueSet.FilterOperator.ISA).setValue(ourCodeA);
myValueSetDao.create(valueSetA, mySrd);
ValueSet valueSetB = new ValueSet();
valueSetB.setUrl(ourValueSetBUrl);
valueSetA.getCompose().addInclude().setSystem(ourCodeSystemUrl)
.addFilter().setProperty("concept").setOp(ValueSet.FilterOperator.ISA).setValue(ourCodeB);
myValueSetDao.create(valueSetB, mySrd);
}
static Stream<Arguments> parametersValueSets() {
ValueSet valueSet0 = new ValueSet();
valueSet0.setUrl(ourValueSetUrl + "-WithIncludeChildValueSet");
valueSet0.getCompose().addInclude().addValueSet(ourValueSetAUrl);
ValueSet valueSet1 = new ValueSet();
valueSet1.setUrl(ourValueSetUrl + "-WithIncludeChildValueSetAndCodeSystem");
valueSet1.getCompose().addInclude().addValueSet(ourValueSetAUrl);
valueSet1.getCompose().addInclude().addValueSet(ourValueSetBUrl);
valueSet1.getCompose().addInclude().setSystem(ourCodeSystemUrl);
ValueSet valueSet2 = new ValueSet();
valueSet2.setUrl(ourValueSetUrl + "-WithIncludeChildValueSetAndCodeSystemConceptSet-NoIntersectionCodes");
valueSet2.getCompose().addInclude().addValueSet(ourValueSetAUrl);
ValueSet.ConceptSetComponent conceptSetWithCodeSystem = valueSet2.getCompose().addInclude().setSystem(ourCodeSystemUrl);
conceptSetWithCodeSystem.addConcept().setCode(ourCodeC);
conceptSetWithCodeSystem.addConcept().setCode(ourCodeD);
ValueSet valueSet3 = new ValueSet();
valueSet3.setUrl(ourValueSetUrl + "-WithIncludeChildValueSetAndCodeSystemConceptSet-WithIntersectionCodes");
valueSet3.getCompose().addInclude().addValueSet(ourValueSetAUrl);
conceptSetWithCodeSystem = valueSet3.getCompose().addInclude().setSystem(ourCodeSystemUrl);
conceptSetWithCodeSystem.addConcept().setCode(ourCodeA + "1");
conceptSetWithCodeSystem.addConcept().setCode(ourCodeA + "2");
return Stream.of(
arguments(valueSet0, ourChildConceptCount),
arguments(valueSet1, 4 + ourChildConceptCount * 2),
arguments(valueSet2, 2 + ourChildConceptCount),
arguments(valueSet3, ourChildConceptCount)
);
}
@ParameterizedTest
@MethodSource(value = "parametersValueSets")
public void testExpandValueSet_whenUsingHierarchicalCodeSystem_willExpandSuccessfully(ValueSet theValueSet, int theExpectedConceptExpensionCount) {
myValueSetDao.create(theValueSet, mySrd);
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
Optional<TermValueSet> optionalTermValueSet = runInTransaction(() -> myTermValueSetDao.findTermValueSetByUrlAndNullVersion(theValueSet.getUrl()));
assertTrue(optionalTermValueSet.isPresent());
TermValueSet expandedTermValueSet = optionalTermValueSet.get();
assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, expandedTermValueSet.getExpansionStatus());
assertEquals(theExpectedConceptExpensionCount, expandedTermValueSet.getTotalConcepts());
}
}