Incremental work on large ValueSet expansion support; still need to fix asynchronous tests and actually use the terminology tables when expanding.
This commit is contained in:
parent
d1cba9f928
commit
0e2dcce841
|
@ -26,10 +26,15 @@ import org.springframework.data.jpa.repository.Modifying;
|
|||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ITermValueSetConceptDao extends JpaRepository<TermValueSetConcept, Long> {
|
||||
|
||||
@Query("DELETE FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myId = :pid")
|
||||
@Modifying
|
||||
void deleteTermValueSetConceptsByValueSetId(@Param("pid") Long theValueSetId);
|
||||
void deleteByTermValueSetId(@Param("pid") Long theValueSetId);
|
||||
|
||||
@Query("SELECT vsc FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myId = :pid AND vsc.mySystem = :system_url AND vsc.myCode = :codeval")
|
||||
Optional<TermValueSetConcept> findByValueSetIdSystemAndCode(@Param("pid") Long theValueSetId, @Param("system_url") String theSystem, @Param("codeval") String theCode);
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,6 @@ public interface ITermValueSetConceptDesignationDao extends JpaRepository<TermVa
|
|||
|
||||
@Query("DELETE FROM TermValueSetConceptDesignation vscd WHERE vscd.myConcept.myValueSet.myId = :pid")
|
||||
@Modifying
|
||||
void deleteTermValueSetConceptDesignationsByValueSetId(@Param("pid") Long theValueSetId);
|
||||
void deleteByTermValueSetId(@Param("pid") Long theValueSetId);
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,9 @@ package ca.uhn.fhir.jpa.dao.data;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.entity.TermValueSet;
|
||||
import ca.uhn.fhir.jpa.entity.TermValueSetExpansionStatusEnum;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
@ -32,7 +35,7 @@ public interface ITermValueSetDao extends JpaRepository<TermValueSet, Long> {
|
|||
|
||||
@Query("DELETE FROM TermValueSet vs WHERE vs.myId = :pid")
|
||||
@Modifying
|
||||
void deleteTermValueSetById(@Param("pid") Long theId);
|
||||
void deleteByTermValueSetId(@Param("pid") Long theId);
|
||||
|
||||
@Query("SELECT vs FROM TermValueSet vs WHERE vs.myResourcePid = :resource_pid")
|
||||
Optional<TermValueSet> findByResourcePid(@Param("resource_pid") Long theResourcePid);
|
||||
|
@ -40,4 +43,7 @@ public interface ITermValueSetDao extends JpaRepository<TermValueSet, Long> {
|
|||
@Query("SELECT vs FROM TermValueSet vs WHERE vs.myUrl = :url")
|
||||
Optional<TermValueSet> findByUrl(@Param("url") String theUrl);
|
||||
|
||||
@Query("SELECT vs FROM TermValueSet vs WHERE vs.myExpansionStatus = :expansion_status")
|
||||
Page<TermValueSet> findByExpansionStatus(Pageable pageable, @Param("expansion_status") TermValueSetExpansionStatusEnum theExpansionStatus);
|
||||
|
||||
}
|
||||
|
|
|
@ -315,7 +315,7 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
|
|||
try {
|
||||
ValueSet valueSet = (ValueSet) theResource;
|
||||
org.hl7.fhir.r4.model.ValueSet converted = VersionConvertor_30_40.convertValueSet(valueSet);
|
||||
myHapiTerminologySvc.storeTermValueSetAndChildren(retVal, converted);
|
||||
myHapiTerminologySvc.storeTermValueSet(retVal, converted);
|
||||
} catch (FHIRException fe) {
|
||||
throw new InternalErrorException(fe);
|
||||
}
|
||||
|
|
|
@ -313,7 +313,7 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4<ValueSet> imple
|
|||
if (myDaoConfig.isPreExpandValueSetsExperimental()) {
|
||||
if (retVal.getDeleted() == null) {
|
||||
ValueSet valueSet = (ValueSet) theResource;
|
||||
myHapiTerminologySvc.storeTermValueSetAndChildren(retVal, valueSet);
|
||||
myHapiTerminologySvc.storeTermValueSet(retVal, valueSet);
|
||||
} else {
|
||||
myHapiTerminologySvc.deleteValueSetAndChildren(retVal);
|
||||
}
|
||||
|
|
|
@ -101,6 +101,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
private static boolean ourLastResultsFromTranslationCache; // For testing.
|
||||
private static boolean ourLastResultsFromTranslationWithReverseCache; // For testing.
|
||||
@Autowired
|
||||
protected DaoRegistry myDaoRegistry;
|
||||
@Autowired
|
||||
protected ITermCodeSystemDao myCodeSystemDao;
|
||||
@Autowired
|
||||
protected ITermConceptDao myConceptDao;
|
||||
|
@ -151,8 +153,10 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
private PlatformTransactionManager myTransactionManager;
|
||||
@Autowired(required = false)
|
||||
private IFulltextSearchSvc myFulltextSearchSvc;
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTxManager;
|
||||
|
||||
private void addCodeIfNotAlreadyAdded(IValueSetCodeAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, TermConcept theConcept, boolean theAdd, AtomicInteger theCodeCounter) {
|
||||
private void addCodeIfNotAlreadyAdded(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, TermConcept theConcept, boolean theAdd, AtomicInteger theCodeCounter) {
|
||||
String codeSystem = theConcept.getCodeSystemVersion().getCodeSystem().getCodeSystemUri();
|
||||
String code = theConcept.getCode();
|
||||
String display = theConcept.getDisplay();
|
||||
|
@ -160,28 +164,28 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, designations, theAdd, theCodeCounter, codeSystem, code, display);
|
||||
}
|
||||
|
||||
private void addCodeIfNotAlreadyAdded(IValueSetCodeAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, Collection<TermConceptDesignation> theDesignations, boolean theAdd, AtomicInteger theCodeCounter, String theCodeSystem, String theCode, String theDisplay) {
|
||||
private void addCodeIfNotAlreadyAdded(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, Collection<TermConceptDesignation> theDesignations, boolean theAdd, AtomicInteger theCodeCounter, String theCodeSystem, String theCode, String theDisplay) {
|
||||
if (isNoneBlank(theCodeSystem, theCode)) {
|
||||
if (theAdd && theAddedCodes.add(theCodeSystem + "|" + theCode)) {
|
||||
theValueSetCodeAccumulator.includeCodeWithDesignations(theCodeSystem, theCode, theDisplay, theDesignations);
|
||||
theValueSetCodeAccumulator.includeConceptWithDesignations(theCodeSystem, theCode, theDisplay, theDesignations);
|
||||
theCodeCounter.incrementAndGet();
|
||||
}
|
||||
|
||||
if (!theAdd && theAddedCodes.remove(theCodeSystem + "|" + theCode)) {
|
||||
theValueSetCodeAccumulator.excludeCode(theCodeSystem, theCode);
|
||||
theValueSetCodeAccumulator.excludeConcept(theCodeSystem, theCode);
|
||||
theCodeCounter.decrementAndGet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addConceptsToList(IValueSetCodeAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, String theSystem, List<CodeSystem.ConceptDefinitionComponent> theConcept, boolean theAdd) {
|
||||
private void addConceptsToList(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, String theSystem, List<CodeSystem.ConceptDefinitionComponent> theConcept, boolean theAdd) {
|
||||
for (CodeSystem.ConceptDefinitionComponent next : theConcept) {
|
||||
if (isNoneBlank(theSystem, next.getCode())) {
|
||||
if (theAdd && theAddedCodes.add(theSystem + "|" + next.getCode())) {
|
||||
theValueSetCodeAccumulator.includeCode(theSystem, next.getCode(), next.getDisplay());
|
||||
theValueSetCodeAccumulator.includeConcept(theSystem, next.getCode(), next.getDisplay());
|
||||
}
|
||||
if (!theAdd && theAddedCodes.remove(theSystem + "|" + next.getCode())) {
|
||||
theValueSetCodeAccumulator.excludeCode(theSystem, next.getCode());
|
||||
theValueSetCodeAccumulator.excludeConcept(theSystem, next.getCode());
|
||||
}
|
||||
}
|
||||
addConceptsToList(theValueSetCodeAccumulator, theAddedCodes, theSystem, next.getConcept(), theAdd);
|
||||
|
@ -389,9 +393,9 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
TermValueSet existingTermValueSet = optionalExistingTermValueSetById.get();
|
||||
|
||||
ourLog.info("Deleting existing TermValueSet {} and its children...", existingTermValueSet.getId());
|
||||
myValueSetConceptDesignationDao.deleteTermValueSetConceptDesignationsByValueSetId(existingTermValueSet.getId());
|
||||
myValueSetConceptDao.deleteTermValueSetConceptsByValueSetId(existingTermValueSet.getId());
|
||||
myValueSetDao.deleteTermValueSetById(existingTermValueSet.getId());
|
||||
myValueSetConceptDesignationDao.deleteByTermValueSetId(existingTermValueSet.getId());
|
||||
myValueSetConceptDao.deleteByTermValueSetId(existingTermValueSet.getId());
|
||||
myValueSetDao.deleteByTermValueSetId(existingTermValueSet.getId());
|
||||
ourLog.info("Done deleting existing TermValueSet {} and its children.", existingTermValueSet.getId());
|
||||
|
||||
ourLog.info("Flushing...");
|
||||
|
@ -457,7 +461,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public ValueSet expandValueSet(ValueSet theValueSetToExpand) {
|
||||
|
||||
ValueSetExpansionComponentWithCodeAccumulator expansionComponent = new ValueSetExpansionComponentWithCodeAccumulator();
|
||||
ValueSetExpansionComponentWithConceptAccumulator expansionComponent = new ValueSetExpansionComponentWithConceptAccumulator();
|
||||
expansionComponent.setIdentifier(UUID.randomUUID().toString());
|
||||
expansionComponent.setTimestamp(new Date());
|
||||
|
||||
|
@ -476,11 +480,11 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public void expandValueSet(ValueSet theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator) {
|
||||
public void expandValueSet(ValueSet theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator) {
|
||||
expandValueSet(theValueSetToExpand, theValueSetCodeAccumulator, new AtomicInteger(0));
|
||||
}
|
||||
|
||||
private void expandValueSet(ValueSet theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator, AtomicInteger theCodeCounter) {
|
||||
private void expandValueSet(ValueSet theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator, AtomicInteger theCodeCounter) {
|
||||
Set<String> addedCodes = new HashSet<>();
|
||||
|
||||
// Handle includes
|
||||
|
@ -509,7 +513,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
return retVal;
|
||||
}
|
||||
|
||||
private void expandValueSetHandleIncludeOrExclude(IValueSetCodeAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theInclude, boolean theAdd, AtomicInteger theCodeCounter) {
|
||||
private void expandValueSetHandleIncludeOrExclude(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theInclude, boolean theAdd, AtomicInteger theCodeCounter) {
|
||||
String system = theInclude.getSystem();
|
||||
boolean hasSystem = isNotBlank(system);
|
||||
boolean hasValueSet = theInclude.getValueSet().size() > 0;
|
||||
|
@ -676,10 +680,10 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode);
|
||||
if (code != null) {
|
||||
if (theAdd && theAddedCodes.add(system + "|" + nextCode)) {
|
||||
theValueSetCodeAccumulator.includeCode(system, nextCode, code.getDisplay());
|
||||
theValueSetCodeAccumulator.includeConcept(system, nextCode, code.getDisplay());
|
||||
}
|
||||
if (!theAdd && theAddedCodes.remove(system + "|" + nextCode)) {
|
||||
theValueSetCodeAccumulator.excludeCode(system, nextCode);
|
||||
theValueSetCodeAccumulator.excludeConcept(system, nextCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -706,7 +710,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
|
||||
}
|
||||
if (isNoneBlank(nextConcept.getSystem(), nextConcept.getCode()) && !theAdd && theAddedCodes.remove(nextConcept.getSystem() + "|" + nextConcept.getCode())) {
|
||||
theValueSetCodeAccumulator.excludeCode(nextConcept.getSystem(), nextConcept.getCode());
|
||||
theValueSetCodeAccumulator.excludeConcept(nextConcept.getSystem(), nextConcept.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -716,10 +720,10 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
}
|
||||
}
|
||||
|
||||
private void expandWithoutHibernateSearch(IValueSetCodeAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theInclude, String theSystem, boolean theAdd, AtomicInteger theCodeCounter) {
|
||||
private void expandWithoutHibernateSearch(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theInclude, String theSystem, boolean theAdd, AtomicInteger theCodeCounter) {
|
||||
ourLog.trace("Hibernate search is not enabled");
|
||||
if (theValueSetCodeAccumulator instanceof ValueSetExpansionComponentWithCodeAccumulator) {
|
||||
Validate.isTrue(((ValueSetExpansionComponentWithCodeAccumulator) theValueSetCodeAccumulator).getParameter().isEmpty(), "Can not expand ValueSet with parameters - Hibernate Search is not enabled on this server.");
|
||||
if (theValueSetCodeAccumulator instanceof ValueSetExpansionComponentWithConceptAccumulator) {
|
||||
Validate.isTrue(((ValueSetExpansionComponentWithConceptAccumulator) theValueSetCodeAccumulator).getParameter().isEmpty(), "Can not expand ValueSet with parameters - Hibernate Search is not enabled on this server.");
|
||||
}
|
||||
Validate.isTrue(theInclude.getFilter().isEmpty(), "Can not expand ValueSet with filters - Hibernate Search is not enabled on this server.");
|
||||
Validate.isTrue(isNotBlank(theSystem), "Can not expand ValueSet without explicit system - Hibernate Search is not enabled on this server.");
|
||||
|
@ -1491,9 +1495,46 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
ourLog.info("Done storing TermConceptMap.");
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = 1000)
|
||||
@Transactional
|
||||
@Override
|
||||
public synchronized void preExpandValueSetToTerminologyTables() {
|
||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
||||
Optional<TermValueSet> optionalTermValueSet = getNextTermValueSetNotExpanded();
|
||||
if (optionalTermValueSet.isPresent()) {
|
||||
TermValueSet termValueSet = optionalTermValueSet.get();
|
||||
termValueSet.setExpansionStatus(TermValueSetExpansionStatusEnum.EXPANSION_IN_PROGRESS);
|
||||
myValueSetDao.saveAndFlush(termValueSet);
|
||||
|
||||
ValueSet valueSet = getValueSetFromResourceTable(termValueSet.getResource());
|
||||
|
||||
expandValueSet(valueSet, new ValueSetConceptAccumulator(termValueSet, myValueSetConceptDao, myValueSetConceptDesignationDao));
|
||||
|
||||
termValueSet.setExpansionStatus(TermValueSetExpansionStatusEnum.EXPANDED);
|
||||
myValueSetDao.saveAndFlush(termValueSet);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract ValueSet getValueSetFromResourceTable(ResourceTable theResourceTable);
|
||||
|
||||
private Optional<TermValueSet> getNextTermValueSetNotExpanded() {
|
||||
Optional<TermValueSet> retVal = Optional.empty();
|
||||
Page<TermValueSet> page = myValueSetDao.findByExpansionStatus(PageRequest.of(0, 1), TermValueSetExpansionStatusEnum.NOT_EXPANDED);
|
||||
|
||||
if (!page.getContent().isEmpty()) {
|
||||
retVal = Optional.of(page.getContent().get(0));
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void storeTermValueSetAndChildren(ResourceTable theResourceTable, ValueSet theValueSet) {
|
||||
public void storeTermValueSet(ResourceTable theResourceTable, ValueSet theValueSet) {
|
||||
ourLog.info("Storing TermValueSet {}", theValueSet.getIdElement().getValue());
|
||||
|
||||
ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied");
|
||||
|
@ -1513,58 +1554,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
String url = termValueSet.getUrl();
|
||||
Optional<TermValueSet> optionalExistingTermValueSetByUrl = myValueSetDao.findByUrl(url);
|
||||
if (!optionalExistingTermValueSetByUrl.isPresent()) {
|
||||
|
||||
myValueSetDao.save(termValueSet);
|
||||
int conceptsSaved = 0;
|
||||
int designationsSaved = 0;
|
||||
|
||||
// FIXME: DM 2019-07-15 - Here we should call expandValueSet(ValueSet theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator).
|
||||
// FIXME: DM 2019-07-15 - We need an implementation IValueSetCodeAccumulator that saves ValueSetConcept records and their children.
|
||||
ValueSet expandedValueSet = expandValueSet(theValueSet);
|
||||
if (expandedValueSet.hasExpansion()) {
|
||||
if (expandedValueSet.getExpansion().hasTotal() && expandedValueSet.getExpansion().getTotal() > 0) {
|
||||
TermValueSetConcept concept;
|
||||
for (ValueSet.ValueSetExpansionContainsComponent contains : expandedValueSet.getExpansion().getContains()) {
|
||||
ValidateUtil.isNotBlankOrThrowInvalidRequest(contains.getSystem(), "ValueSet contains a concept with no system value");
|
||||
ValidateUtil.isNotBlankOrThrowInvalidRequest(contains.getCode(), "ValueSet contains a concept with no code value");
|
||||
|
||||
concept = new TermValueSetConcept();
|
||||
concept.setValueSet(termValueSet);
|
||||
concept.setSystem(contains.getSystem());
|
||||
concept.setCode(contains.getCode());
|
||||
concept.setDisplay(contains.hasDisplay() ? contains.getDisplay() : null);
|
||||
myValueSetConceptDao.save(concept);
|
||||
|
||||
TermValueSetConceptDesignation designation;
|
||||
for (ValueSet.ConceptReferenceDesignationComponent containedDesignation : contains.getDesignation()) {
|
||||
ValidateUtil.isNotBlankOrThrowInvalidRequest(containedDesignation.getValue(), "ValueSet contains a concept designation with no value");
|
||||
|
||||
designation = new TermValueSetConceptDesignation();
|
||||
designation.setConcept(concept);
|
||||
designation.setLanguage(containedDesignation.hasLanguage() ? containedDesignation.getLanguage() : null);
|
||||
if (containedDesignation.hasUse()) {
|
||||
designation.setUseSystem(containedDesignation.getUse().hasSystem() ? containedDesignation.getUse().getSystem() : null);
|
||||
designation.setUseCode(containedDesignation.getUse().hasCode() ? containedDesignation.getUse().getCode() : null);
|
||||
designation.setUseDisplay(containedDesignation.getUse().hasDisplay() ? containedDesignation.getUse().getDisplay() : null);
|
||||
}
|
||||
designation.setValue(containedDesignation.getValue());
|
||||
myValueSetConceptDesignationDao.save(designation);
|
||||
|
||||
if (designationsSaved++ % 250 == 0) {
|
||||
ourLog.info("Have pre-expanded {} designations in ValueSet", designationsSaved);
|
||||
myValueSetConceptDesignationDao.flush();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: DM 2019-07-16 - We need TermValueSetConceptProperty, similar to TermConceptProperty.
|
||||
// TODO: DM 2019-07-16 - We should also populate TermValueSetConceptProperty entities here.
|
||||
|
||||
if (conceptsSaved++ % 250 == 0) {
|
||||
ourLog.info("Have pre-expanded {} concepts in ValueSet", conceptsSaved);
|
||||
myValueSetConceptDao.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
TermValueSet existingTermValueSet = optionalExistingTermValueSetByUrl.get();
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.term;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.hapi.validation.IValidationSupport;
|
||||
|
@ -81,13 +82,18 @@ public class HapiTerminologySvcDstu2 extends BaseHapiTerminologySvcImpl {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ValueSet getValueSetFromResourceTable(ResourceTable theResourceTable) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseResource expandValueSet(IBaseResource theValueSetToExpand) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator) {
|
||||
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
@ -177,7 +178,7 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen
|
|||
}
|
||||
|
||||
@Override
|
||||
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator) {
|
||||
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator) {
|
||||
ValueSet valueSetToExpand = (ValueSet) theValueSetToExpand;
|
||||
|
||||
try {
|
||||
|
@ -292,6 +293,20 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected org.hl7.fhir.r4.model.ValueSet getValueSetFromResourceTable(ResourceTable theResourceTable) {
|
||||
ValueSet valueSet = myValueSetResourceDao.toResource(ValueSet.class, theResourceTable, null, false);
|
||||
|
||||
org.hl7.fhir.r4.model.ValueSet valueSetR4;
|
||||
try {
|
||||
valueSetR4 = VersionConvertor_30_40.convertValueSet(valueSet);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
|
||||
return valueSetR4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||
return myTerminologySvc.supportsSystem(theSystem);
|
||||
|
|
|
@ -3,9 +3,9 @@ package ca.uhn.fhir.jpa.term;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import ca.uhn.fhir.util.ValidateUtil;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
|
@ -138,7 +138,7 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator) {
|
||||
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator) {
|
||||
ValueSet valueSetToExpand = (ValueSet) theValueSetToExpand;
|
||||
super.expandValueSet(valueSetToExpand, theValueSetCodeAccumulator);
|
||||
}
|
||||
|
@ -231,6 +231,11 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
|||
return myValidationSupport.fetchCodeSystem(myContext, theSystem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ValueSet getValueSetFromResourceTable(ResourceTable theResourceTable) {
|
||||
return myValueSetResourceDao.toResource(ValueSet.class, theResourceTable, null, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||
return supportsSystem(theSystem);
|
||||
|
|
|
@ -44,14 +44,14 @@ public interface IHapiTerminologySvc {
|
|||
|
||||
ValueSet expandValueSet(ValueSet theValueSetToExpand);
|
||||
|
||||
void expandValueSet(ValueSet theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator);
|
||||
void expandValueSet(ValueSet theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator);
|
||||
|
||||
/**
|
||||
* Version independent
|
||||
*/
|
||||
IBaseResource expandValueSet(IBaseResource theValueSetToExpand);
|
||||
|
||||
void expandValueSet(IBaseResource theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator);
|
||||
void expandValueSet(IBaseResource theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator);
|
||||
|
||||
List<VersionIndependentConcept> expandValueSet(String theValueSet);
|
||||
|
||||
|
@ -94,7 +94,7 @@ public interface IHapiTerminologySvc {
|
|||
|
||||
void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap);
|
||||
|
||||
void storeTermValueSetAndChildren(ResourceTable theResourceTable, ValueSet theValueSet);
|
||||
void storeTermValueSet(ResourceTable theResourceTable, ValueSet theValueSet);
|
||||
|
||||
boolean supportsSystem(String theCodeSystem);
|
||||
|
||||
|
@ -107,4 +107,6 @@ public interface IHapiTerminologySvc {
|
|||
AtomicInteger applyDeltaCodesystemsAdd(String theSystem, @Nullable String theParent, CodeSystem theValue);
|
||||
|
||||
AtomicInteger applyDeltaCodesystemsRemove(String theSystem, CodeSystem theDelta);
|
||||
|
||||
void preExpandValueSetToTerminologyTables();
|
||||
}
|
||||
|
|
|
@ -24,12 +24,12 @@ import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
|
|||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface IValueSetCodeAccumulator {
|
||||
public interface IValueSetConceptAccumulator {
|
||||
|
||||
void includeCode(String theSystem, String theCode, String theDisplay);
|
||||
void includeConcept(String theSystem, String theCode, String theDisplay);
|
||||
|
||||
void includeCodeWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations);
|
||||
void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations);
|
||||
|
||||
void excludeCode(String theSystem, String theCode);
|
||||
void excludeConcept(String theSystem, String theCode);
|
||||
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
package ca.uhn.fhir.jpa.term;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptDesignationDao;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
|
||||
import ca.uhn.fhir.jpa.entity.TermValueSet;
|
||||
import ca.uhn.fhir.jpa.entity.TermValueSetConcept;
|
||||
import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation;
|
||||
import ca.uhn.fhir.util.ValidateUtil;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValueSetConceptAccumulator.class);
|
||||
|
||||
private TermValueSet myTermValueSet;
|
||||
private ITermValueSetConceptDao myValueSetConceptDao;
|
||||
private ITermValueSetConceptDesignationDao myValueSetConceptDesignationDao;
|
||||
private int myConceptsSaved;
|
||||
private int myDesignationsSaved;
|
||||
|
||||
public ValueSetConceptAccumulator(@Nonnull TermValueSet theTermValueSet, @Nonnull ITermValueSetConceptDao theValueSetConceptDao, @Nonnull ITermValueSetConceptDesignationDao theValueSetConceptDesignationDao) {
|
||||
myTermValueSet = theTermValueSet;
|
||||
myValueSetConceptDao = theValueSetConceptDao;
|
||||
myValueSetConceptDesignationDao = theValueSetConceptDesignationDao;
|
||||
myConceptsSaved = 0;
|
||||
myDesignationsSaved = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void includeConcept(String theSystem, String theCode, String theDisplay) {
|
||||
saveConcept(theSystem, theCode, theDisplay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations) {
|
||||
TermValueSetConcept concept = saveConcept(theSystem, theCode, theDisplay);
|
||||
for (TermConceptDesignation designation : theDesignations) {
|
||||
saveConceptDesignation(concept, designation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void excludeConcept(String theSystem, String theCode) {
|
||||
if (isAnyBlank(theSystem, theCode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get existing entity so it can be deleted.
|
||||
Optional<TermValueSetConcept> optionalConcept = myValueSetConceptDao.findByValueSetIdSystemAndCode(myTermValueSet.getId(), theSystem, theCode);
|
||||
|
||||
if (optionalConcept.isPresent()) {
|
||||
TermValueSetConcept concept = optionalConcept.get();
|
||||
|
||||
ourLog.info("Excluding [{}|{}] from ValueSet[{}]", concept.getSystem(), concept.getCode(), myTermValueSet.getUrl());
|
||||
for (TermValueSetConceptDesignation designation : concept.getDesignations()) {
|
||||
myValueSetConceptDesignationDao.deleteById(designation.getId());
|
||||
}
|
||||
myValueSetConceptDao.deleteById(concept.getId());
|
||||
ourLog.info("Done excluding [{}|{}] from ValueSet[{}]", concept.getSystem(), concept.getCode(), myTermValueSet.getUrl());
|
||||
|
||||
ourLog.info("Flushing...");
|
||||
myValueSetConceptDesignationDao.flush();
|
||||
myValueSetConceptDao.flush();
|
||||
ourLog.info("Done flushing.");
|
||||
}
|
||||
}
|
||||
|
||||
private TermValueSetConcept saveConcept(String theSystem, String theCode, String theDisplay) {
|
||||
ValidateUtil.isNotBlankOrThrowInvalidRequest(theSystem, "ValueSet contains a concept with no system value");
|
||||
ValidateUtil.isNotBlankOrThrowInvalidRequest(theCode, "ValueSet contains a concept with no code value");
|
||||
|
||||
TermValueSetConcept concept = new TermValueSetConcept();
|
||||
concept.setValueSet(myTermValueSet);
|
||||
concept.setSystem(theSystem);
|
||||
concept.setCode(theCode);
|
||||
if (isNotBlank(theDisplay)) {
|
||||
concept.setDisplay(theDisplay);
|
||||
}
|
||||
myValueSetConceptDao.save(concept);
|
||||
|
||||
if (myConceptsSaved++ % 250 == 0) {
|
||||
ourLog.info("Have pre-expanded {} concepts in ValueSet[{}]", myConceptsSaved, myTermValueSet.getUrl());
|
||||
myValueSetConceptDao.flush();
|
||||
}
|
||||
|
||||
return concept;
|
||||
}
|
||||
|
||||
private TermValueSetConceptDesignation saveConceptDesignation(TermValueSetConcept theConcept, TermConceptDesignation theDesignation) {
|
||||
ValidateUtil.isNotBlankOrThrowInvalidRequest(theDesignation.getValue(), "ValueSet contains a concept designation with no value");
|
||||
|
||||
TermValueSetConceptDesignation designation = new TermValueSetConceptDesignation();
|
||||
designation.setConcept(theConcept);
|
||||
designation.setLanguage(theDesignation.getLanguage());
|
||||
if (isNoneBlank(theDesignation.getUseSystem(), theDesignation.getUseCode())) {
|
||||
designation.setUseSystem(theDesignation.getUseSystem());
|
||||
designation.setUseCode(theDesignation.getUseCode());
|
||||
if (isNotBlank(theDesignation.getUseDisplay())) {
|
||||
designation.setUseDisplay(theDesignation.getUseDisplay());
|
||||
}
|
||||
}
|
||||
designation.setValue(theDesignation.getValue());
|
||||
myValueSetConceptDesignationDao.save(designation);
|
||||
|
||||
if (myDesignationsSaved++ % 250 == 0) {
|
||||
ourLog.info("Have pre-expanded {} designations in ValueSet[{}]", myDesignationsSaved, myTermValueSet.getUrl());
|
||||
myValueSetConceptDesignationDao.flush();
|
||||
}
|
||||
|
||||
return designation;
|
||||
}
|
||||
|
||||
// TODO: DM 2019-07-16 - We need TermValueSetConceptProperty, similar to TermConceptProperty.
|
||||
// TODO: DM 2019-07-16 - We should also populate TermValueSetConceptProperty entities here.
|
||||
// TODO: DM 2019-07-30 - Expansions don't include the properties themselves; they are needed to facilitate filters and parameterized expansions.
|
||||
}
|
|
@ -27,10 +27,10 @@ import org.hl7.fhir.r4.model.ValueSet;
|
|||
import java.util.Collection;
|
||||
|
||||
@Block()
|
||||
public class ValueSetExpansionComponentWithCodeAccumulator extends ValueSet.ValueSetExpansionComponent implements IValueSetCodeAccumulator {
|
||||
public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.ValueSetExpansionComponent implements IValueSetConceptAccumulator {
|
||||
|
||||
@Override
|
||||
public void includeCode(String theSystem, String theCode, String theDisplay) {
|
||||
public void includeConcept(String theSystem, String theCode, String theDisplay) {
|
||||
ValueSet.ValueSetExpansionContainsComponent contains = this.addContains();
|
||||
contains.setSystem(theSystem);
|
||||
contains.setCode(theCode);
|
||||
|
@ -38,7 +38,7 @@ public class ValueSetExpansionComponentWithCodeAccumulator extends ValueSet.Valu
|
|||
}
|
||||
|
||||
@Override
|
||||
public void includeCodeWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations) {
|
||||
public void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations) {
|
||||
ValueSet.ValueSetExpansionContainsComponent contains = this.addContains();
|
||||
contains.setSystem(theSystem);
|
||||
contains.setCode(theCode);
|
||||
|
@ -58,7 +58,7 @@ public class ValueSetExpansionComponentWithCodeAccumulator extends ValueSet.Valu
|
|||
}
|
||||
|
||||
@Override
|
||||
public void excludeCode(String theSystem, String theCode) {
|
||||
public void excludeConcept(String theSystem, String theCode) {
|
||||
this
|
||||
.getContains()
|
||||
.removeIf(t ->
|
|
@ -11,6 +11,7 @@ import ca.uhn.fhir.rest.param.UriParam;
|
|||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
|
@ -42,7 +43,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
@Rule
|
||||
public final ExpectedException expectedException = ExpectedException.none();
|
||||
@Mock
|
||||
IValueSetCodeAccumulator myValueSetCodeAccumulator;
|
||||
IValueSetConceptAccumulator myValueSetCodeAccumulator;
|
||||
private IIdType myConceptMapId;
|
||||
private IIdType myExtensionalCsId;
|
||||
private IIdType myExtensionalVsId;
|
||||
|
@ -135,6 +136,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
loadAndPersistValueSet();
|
||||
}
|
||||
|
||||
private void loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude() throws IOException {
|
||||
loadAndPersistCodeSystemWithDesignations();
|
||||
loadAndPersistValueSetWithExclude();
|
||||
}
|
||||
|
||||
private void loadAndPersistCodeSystem() throws IOException {
|
||||
CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
|
||||
persistCodeSystem(codeSystem);
|
||||
|
@ -159,6 +165,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
persistValueSet(valueSet);
|
||||
}
|
||||
|
||||
private void loadAndPersistValueSetWithExclude() throws IOException {
|
||||
ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs-with-exclude.xml");
|
||||
persistValueSet(valueSet);
|
||||
}
|
||||
|
||||
private void persistValueSet(ValueSet theValueSet) {
|
||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
|
@ -589,7 +600,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
include.setSystem(CS_URL);
|
||||
|
||||
myTermSvc.expandValueSet(vs, myValueSetCodeAccumulator);
|
||||
verify(myValueSetCodeAccumulator, times(9)).includeCodeWithDesignations(anyString(), anyString(), nullable(String.class), anyCollection());
|
||||
verify(myValueSetCodeAccumulator, times(9)).includeConceptWithDesignations(anyString(), anyString(), nullable(String.class), anyCollection());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -625,15 +636,24 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
TermConcept concept = concepts.get(0);
|
||||
assertEquals("8450-9", concept.getCode());
|
||||
assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
|
||||
assertEquals(1, concept.getDesignations().size());
|
||||
assertEquals(2, concept.getDesignations().size());
|
||||
|
||||
TermConceptDesignation designation = concept.getDesignations().iterator().next();
|
||||
List<TermConceptDesignation> designations = Lists.newArrayList(concept.getDesignations().iterator());
|
||||
|
||||
TermConceptDesignation designation = designations.get(0);
|
||||
assertEquals("nl", designation.getLanguage());
|
||||
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||
assertEquals("900000000000013009", designation.getUseCode());
|
||||
assertEquals("Synonym", designation.getUseDisplay());
|
||||
assertEquals("Systolische bloeddruk - expiratie", designation.getValue());
|
||||
|
||||
designation = designations.get(1);
|
||||
assertEquals("sv", designation.getLanguage());
|
||||
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||
assertEquals("900000000000013009", designation.getUseCode());
|
||||
assertEquals("Synonym", designation.getUseDisplay());
|
||||
assertEquals("Systoliskt blodtryck - utgång", designation.getValue());
|
||||
|
||||
concept = concepts.get(1);
|
||||
assertEquals("11378-7", concept.getCode());
|
||||
assertEquals("Systolic blood pressure at First encounter", concept.getDisplay());
|
||||
|
@ -948,67 +968,197 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
ValueSet valueSet = myValueSetDao.read(myExtensionalVsId);
|
||||
ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet));
|
||||
|
||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
||||
Optional<TermValueSet> optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong());
|
||||
assertTrue(optionalValueSetByResourcePid.isPresent());
|
||||
runInTransaction(()->{
|
||||
Optional<TermValueSet> optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong());
|
||||
assertTrue(optionalValueSetByResourcePid.isPresent());
|
||||
|
||||
Optional<TermValueSet> optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||
assertTrue(optionalValueSetByUrl.isPresent());
|
||||
Optional<TermValueSet> optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||
assertTrue(optionalValueSetByUrl.isPresent());
|
||||
|
||||
TermValueSet valueSet = optionalValueSetByUrl.get();
|
||||
assertSame(optionalValueSetByResourcePid.get(), valueSet);
|
||||
ourLog.info("ValueSet:\n" + valueSet.toString());
|
||||
assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", valueSet.getUrl());
|
||||
assertEquals("Terminology Services Connectation #1 Extensional case #2", valueSet.getName());
|
||||
assertEquals(codeSystem.getConcept().size(), valueSet.getConcepts().size());
|
||||
assertEquals(TermValueSetExpansionStatusEnum.NOT_EXPANDED, valueSet.getExpansionStatus());
|
||||
TermValueSet termValueSet = optionalValueSetByUrl.get();
|
||||
assertSame(optionalValueSetByResourcePid.get(), termValueSet);
|
||||
ourLog.info("ValueSet:\n" + termValueSet.toString());
|
||||
assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", termValueSet.getUrl());
|
||||
assertEquals("Terminology Services Connectation #1 Extensional case #2", termValueSet.getName());
|
||||
assertEquals(0, termValueSet.getConcepts().size()); // DM 2019-07-30: Concepts are persisted in the background.
|
||||
assertEquals(TermValueSetExpansionStatusEnum.NOT_EXPANDED, termValueSet.getExpansionStatus());
|
||||
});
|
||||
|
||||
TermValueSetConcept concept = valueSet.getConcepts().get(0);
|
||||
ourLog.info("Code:\n" + concept.toString());
|
||||
assertEquals("http://acme.org", concept.getSystem());
|
||||
assertEquals("8450-9", concept.getCode());
|
||||
assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
|
||||
assertEquals(1, concept.getDesignations().size());
|
||||
// FIXME: DM 2019-07-31 - Wait for ValueSet expansion status to be EXPANDED.
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException theE) {
|
||||
theE.printStackTrace();
|
||||
}
|
||||
|
||||
TermValueSetConceptDesignation designation = concept.getDesignations().get(0);
|
||||
assertEquals("nl", designation.getLanguage());
|
||||
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||
assertEquals("900000000000013009", designation.getUseCode());
|
||||
assertEquals("Synonym", designation.getUseDisplay());
|
||||
assertEquals("Systolische bloeddruk - expiratie", designation.getValue());
|
||||
runInTransaction(()->{
|
||||
Optional<TermValueSet> optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong());
|
||||
assertTrue(optionalValueSetByResourcePid.isPresent());
|
||||
|
||||
concept = valueSet.getConcepts().get(1);
|
||||
ourLog.info("Code:\n" + concept.toString());
|
||||
assertEquals("http://acme.org", concept.getSystem());
|
||||
assertEquals("11378-7", concept.getCode());
|
||||
assertEquals("Systolic blood pressure at First encounter", concept.getDisplay());
|
||||
assertEquals(0, concept.getDesignations().size());
|
||||
Optional<TermValueSet> optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||
assertTrue(optionalValueSetByUrl.isPresent());
|
||||
|
||||
// ...
|
||||
TermValueSet termValueSet = optionalValueSetByUrl.get();
|
||||
assertSame(optionalValueSetByResourcePid.get(), termValueSet);
|
||||
ourLog.info("ValueSet:\n" + termValueSet.toString());
|
||||
assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", termValueSet.getUrl());
|
||||
assertEquals("Terminology Services Connectation #1 Extensional case #2", termValueSet.getName());
|
||||
assertEquals(codeSystem.getConcept().size(), termValueSet.getConcepts().size());
|
||||
assertEquals(TermValueSetExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus());
|
||||
|
||||
concept = valueSet.getConcepts().get(22);
|
||||
ourLog.info("Code:\n" + concept.toString());
|
||||
assertEquals("http://acme.org", concept.getSystem());
|
||||
assertEquals("8491-3", concept.getCode());
|
||||
assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay());
|
||||
assertEquals(1, concept.getDesignations().size());
|
||||
TermValueSetConcept concept = termValueSet.getConcepts().get(0);
|
||||
ourLog.info("Code:\n" + concept.toString());
|
||||
assertEquals("http://acme.org", concept.getSystem());
|
||||
assertEquals("8450-9", concept.getCode());
|
||||
assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
|
||||
assertEquals(2, concept.getDesignations().size());
|
||||
|
||||
designation = concept.getDesignations().get(0);
|
||||
assertEquals("nl", designation.getLanguage());
|
||||
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||
assertEquals("900000000000013009", designation.getUseCode());
|
||||
assertEquals("Synonym", designation.getUseDisplay());
|
||||
assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue());
|
||||
TermValueSetConceptDesignation designation = concept.getDesignations().get(0);
|
||||
assertEquals("nl", designation.getLanguage());
|
||||
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||
assertEquals("900000000000013009", designation.getUseCode());
|
||||
assertEquals("Synonym", designation.getUseDisplay());
|
||||
assertEquals("Systolische bloeddruk - expiratie", designation.getValue());
|
||||
|
||||
concept = valueSet.getConcepts().get(23);
|
||||
ourLog.info("Code:\n" + concept.toString());
|
||||
assertEquals("http://acme.org", concept.getSystem());
|
||||
assertEquals("8492-1", concept.getCode());
|
||||
assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay());
|
||||
assertEquals(0, concept.getDesignations().size());
|
||||
}
|
||||
designation = concept.getDesignations().get(1);
|
||||
assertEquals("sv", designation.getLanguage());
|
||||
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||
assertEquals("900000000000013009", designation.getUseCode());
|
||||
assertEquals("Synonym", designation.getUseDisplay());
|
||||
assertEquals("Systoliskt blodtryck - utgång", designation.getValue());
|
||||
|
||||
concept = termValueSet.getConcepts().get(1);
|
||||
ourLog.info("Code:\n" + concept.toString());
|
||||
assertEquals("http://acme.org", concept.getSystem());
|
||||
assertEquals("11378-7", concept.getCode());
|
||||
assertEquals("Systolic blood pressure at First encounter", concept.getDisplay());
|
||||
assertEquals(0, concept.getDesignations().size());
|
||||
|
||||
// ...
|
||||
|
||||
concept = termValueSet.getConcepts().get(22);
|
||||
ourLog.info("Code:\n" + concept.toString());
|
||||
assertEquals("http://acme.org", concept.getSystem());
|
||||
assertEquals("8491-3", concept.getCode());
|
||||
assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay());
|
||||
assertEquals(1, concept.getDesignations().size());
|
||||
|
||||
designation = concept.getDesignations().get(0);
|
||||
assertEquals("nl", designation.getLanguage());
|
||||
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||
assertEquals("900000000000013009", designation.getUseCode());
|
||||
assertEquals("Synonym", designation.getUseDisplay());
|
||||
assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue());
|
||||
|
||||
concept = termValueSet.getConcepts().get(23);
|
||||
ourLog.info("Code:\n" + concept.toString());
|
||||
assertEquals("http://acme.org", concept.getSystem());
|
||||
assertEquals("8492-1", concept.getCode());
|
||||
assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay());
|
||||
assertEquals(0, concept.getDesignations().size());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoreTermValueSetAndChildrenWithExclude() throws Exception {
|
||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
||||
|
||||
loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude();
|
||||
|
||||
CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId);
|
||||
ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem));
|
||||
|
||||
ValueSet valueSet = myValueSetDao.read(myExtensionalVsId);
|
||||
ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet));
|
||||
|
||||
runInTransaction(()->{
|
||||
Optional<TermValueSet> optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong());
|
||||
assertTrue(optionalValueSetByResourcePid.isPresent());
|
||||
|
||||
Optional<TermValueSet> optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||
assertTrue(optionalValueSetByUrl.isPresent());
|
||||
|
||||
TermValueSet termValueSet = optionalValueSetByUrl.get();
|
||||
assertSame(optionalValueSetByResourcePid.get(), termValueSet);
|
||||
ourLog.info("ValueSet:\n" + termValueSet.toString());
|
||||
assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", termValueSet.getUrl());
|
||||
assertEquals("Terminology Services Connectation #1 Extensional case #2", termValueSet.getName());
|
||||
assertEquals(0, termValueSet.getConcepts().size()); // DM 2019-07-30: Concepts are persisted in the background.
|
||||
assertEquals(TermValueSetExpansionStatusEnum.NOT_EXPANDED, termValueSet.getExpansionStatus());
|
||||
});
|
||||
|
||||
// FIXME: DM 2019-07-31 - Wait for ValueSet expansion status to be EXPANDED.
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException theE) {
|
||||
theE.printStackTrace();
|
||||
}
|
||||
|
||||
runInTransaction(()->{
|
||||
Optional<TermValueSet> optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong());
|
||||
assertTrue(optionalValueSetByResourcePid.isPresent());
|
||||
|
||||
Optional<TermValueSet> optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||
assertTrue(optionalValueSetByUrl.isPresent());
|
||||
|
||||
TermValueSet termValueSet = optionalValueSetByUrl.get();
|
||||
assertSame(optionalValueSetByResourcePid.get(), termValueSet);
|
||||
ourLog.info("ValueSet:\n" + termValueSet.toString());
|
||||
assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", termValueSet.getUrl());
|
||||
assertEquals("Terminology Services Connectation #1 Extensional case #2", termValueSet.getName());
|
||||
assertEquals(codeSystem.getConcept().size() - 2, termValueSet.getConcepts().size());
|
||||
assertEquals(TermValueSetExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus());
|
||||
|
||||
TermValueSetConcept concept = termValueSet.getConcepts().get(0);
|
||||
ourLog.info("Code:\n" + concept.toString());
|
||||
assertEquals("http://acme.org", concept.getSystem());
|
||||
assertEquals("8450-9", concept.getCode());
|
||||
assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
|
||||
assertEquals(2, concept.getDesignations().size());
|
||||
|
||||
TermValueSetConceptDesignation designation = concept.getDesignations().get(0);
|
||||
assertEquals("nl", designation.getLanguage());
|
||||
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||
assertEquals("900000000000013009", designation.getUseCode());
|
||||
assertEquals("Synonym", designation.getUseDisplay());
|
||||
assertEquals("Systolische bloeddruk - expiratie", designation.getValue());
|
||||
|
||||
designation = concept.getDesignations().get(1);
|
||||
assertEquals("sv", designation.getLanguage());
|
||||
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||
assertEquals("900000000000013009", designation.getUseCode());
|
||||
assertEquals("Synonym", designation.getUseDisplay());
|
||||
assertEquals("Systoliskt blodtryck - utgång", designation.getValue());
|
||||
|
||||
concept = termValueSet.getConcepts().get(1);
|
||||
ourLog.info("Code:\n" + concept.toString());
|
||||
assertEquals("http://acme.org", concept.getSystem());
|
||||
assertEquals("11378-7", concept.getCode());
|
||||
assertEquals("Systolic blood pressure at First encounter", concept.getDisplay());
|
||||
assertEquals(0, concept.getDesignations().size());
|
||||
|
||||
// ...
|
||||
|
||||
concept = termValueSet.getConcepts().get(22 - 2);
|
||||
ourLog.info("Code:\n" + concept.toString());
|
||||
assertEquals("http://acme.org", concept.getSystem());
|
||||
assertEquals("8491-3", concept.getCode());
|
||||
assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay());
|
||||
assertEquals(1, concept.getDesignations().size());
|
||||
|
||||
designation = concept.getDesignations().get(0);
|
||||
assertEquals("nl", designation.getLanguage());
|
||||
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||
assertEquals("900000000000013009", designation.getUseCode());
|
||||
assertEquals("Synonym", designation.getUseDisplay());
|
||||
assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue());
|
||||
|
||||
concept = termValueSet.getConcepts().get(23 - 2);
|
||||
ourLog.info("Code:\n" + concept.toString());
|
||||
assertEquals("http://acme.org", concept.getSystem());
|
||||
assertEquals("8492-1", concept.getCode());
|
||||
assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay());
|
||||
assertEquals(0, concept.getDesignations().size());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,15 @@
|
|||
</use>
|
||||
<value value="Systolische bloeddruk - expiratie"/>
|
||||
</designation>
|
||||
<designation>
|
||||
<language value="sv"/>
|
||||
<use>
|
||||
<system value="http://snomed.info/sct"/>
|
||||
<code value="900000000000013009"/>
|
||||
<display value="Synonym"/>
|
||||
</use>
|
||||
<value value="Systoliskt blodtryck - utgång"/>
|
||||
</designation>
|
||||
</concept>
|
||||
<concept>
|
||||
<code value="11378-7" />
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<ValueSet xmlns="http://hl7.org/fhir">
|
||||
<url value="http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2" />
|
||||
<identifier>
|
||||
<value value="http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2" />
|
||||
</identifier>
|
||||
<name value="Terminology Services Connectation #1 Extensional case #2" />
|
||||
<publisher value="Grahame Grieve" />
|
||||
<contact>
|
||||
<telecom>
|
||||
<system value="email" />
|
||||
<value value="grahame@healthintersections.com.au" />
|
||||
</telecom>
|
||||
</contact>
|
||||
<description value="an enumeration of codes defined by LOINC" />
|
||||
<status value="draft" />
|
||||
<experimental value="true" />
|
||||
<compose>
|
||||
<include>
|
||||
<system value="http://acme.org"/>
|
||||
</include>
|
||||
<exclude>
|
||||
<system value="http://acme.org"/>
|
||||
<concept>
|
||||
<code value="8489-7" />
|
||||
</concept>
|
||||
<concept>
|
||||
<code value="8490-5" />
|
||||
</concept>
|
||||
</exclude>
|
||||
</compose>
|
||||
</ValueSet>
|
Loading…
Reference in New Issue