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.jpa.repository.Query;
|
||||||
import org.springframework.data.repository.query.Param;
|
import org.springframework.data.repository.query.Param;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public interface ITermValueSetConceptDao extends JpaRepository<TermValueSetConcept, Long> {
|
public interface ITermValueSetConceptDao extends JpaRepository<TermValueSetConcept, Long> {
|
||||||
|
|
||||||
@Query("DELETE FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myId = :pid")
|
@Query("DELETE FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myId = :pid")
|
||||||
@Modifying
|
@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")
|
@Query("DELETE FROM TermValueSetConceptDesignation vscd WHERE vscd.myConcept.myValueSet.myId = :pid")
|
||||||
@Modifying
|
@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.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.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.Modifying;
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
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")
|
@Query("DELETE FROM TermValueSet vs WHERE vs.myId = :pid")
|
||||||
@Modifying
|
@Modifying
|
||||||
void deleteTermValueSetById(@Param("pid") Long theId);
|
void deleteByTermValueSetId(@Param("pid") Long theId);
|
||||||
|
|
||||||
@Query("SELECT vs FROM TermValueSet vs WHERE vs.myResourcePid = :resource_pid")
|
@Query("SELECT vs FROM TermValueSet vs WHERE vs.myResourcePid = :resource_pid")
|
||||||
Optional<TermValueSet> findByResourcePid(@Param("resource_pid") Long theResourcePid);
|
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")
|
@Query("SELECT vs FROM TermValueSet vs WHERE vs.myUrl = :url")
|
||||||
Optional<TermValueSet> findByUrl(@Param("url") String theUrl);
|
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 {
|
try {
|
||||||
ValueSet valueSet = (ValueSet) theResource;
|
ValueSet valueSet = (ValueSet) theResource;
|
||||||
org.hl7.fhir.r4.model.ValueSet converted = VersionConvertor_30_40.convertValueSet(valueSet);
|
org.hl7.fhir.r4.model.ValueSet converted = VersionConvertor_30_40.convertValueSet(valueSet);
|
||||||
myHapiTerminologySvc.storeTermValueSetAndChildren(retVal, converted);
|
myHapiTerminologySvc.storeTermValueSet(retVal, converted);
|
||||||
} catch (FHIRException fe) {
|
} catch (FHIRException fe) {
|
||||||
throw new InternalErrorException(fe);
|
throw new InternalErrorException(fe);
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,7 +313,7 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4<ValueSet> imple
|
||||||
if (myDaoConfig.isPreExpandValueSetsExperimental()) {
|
if (myDaoConfig.isPreExpandValueSetsExperimental()) {
|
||||||
if (retVal.getDeleted() == null) {
|
if (retVal.getDeleted() == null) {
|
||||||
ValueSet valueSet = (ValueSet) theResource;
|
ValueSet valueSet = (ValueSet) theResource;
|
||||||
myHapiTerminologySvc.storeTermValueSetAndChildren(retVal, valueSet);
|
myHapiTerminologySvc.storeTermValueSet(retVal, valueSet);
|
||||||
} else {
|
} else {
|
||||||
myHapiTerminologySvc.deleteValueSetAndChildren(retVal);
|
myHapiTerminologySvc.deleteValueSetAndChildren(retVal);
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
private static boolean ourLastResultsFromTranslationCache; // For testing.
|
private static boolean ourLastResultsFromTranslationCache; // For testing.
|
||||||
private static boolean ourLastResultsFromTranslationWithReverseCache; // For testing.
|
private static boolean ourLastResultsFromTranslationWithReverseCache; // For testing.
|
||||||
@Autowired
|
@Autowired
|
||||||
|
protected DaoRegistry myDaoRegistry;
|
||||||
|
@Autowired
|
||||||
protected ITermCodeSystemDao myCodeSystemDao;
|
protected ITermCodeSystemDao myCodeSystemDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected ITermConceptDao myConceptDao;
|
protected ITermConceptDao myConceptDao;
|
||||||
|
@ -151,8 +153,10 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
private PlatformTransactionManager myTransactionManager;
|
private PlatformTransactionManager myTransactionManager;
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
private IFulltextSearchSvc myFulltextSearchSvc;
|
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 codeSystem = theConcept.getCodeSystemVersion().getCodeSystem().getCodeSystemUri();
|
||||||
String code = theConcept.getCode();
|
String code = theConcept.getCode();
|
||||||
String display = theConcept.getDisplay();
|
String display = theConcept.getDisplay();
|
||||||
|
@ -160,28 +164,28 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, designations, theAdd, theCodeCounter, codeSystem, code, display);
|
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 (isNoneBlank(theCodeSystem, theCode)) {
|
||||||
if (theAdd && theAddedCodes.add(theCodeSystem + "|" + theCode)) {
|
if (theAdd && theAddedCodes.add(theCodeSystem + "|" + theCode)) {
|
||||||
theValueSetCodeAccumulator.includeCodeWithDesignations(theCodeSystem, theCode, theDisplay, theDesignations);
|
theValueSetCodeAccumulator.includeConceptWithDesignations(theCodeSystem, theCode, theDisplay, theDesignations);
|
||||||
theCodeCounter.incrementAndGet();
|
theCodeCounter.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!theAdd && theAddedCodes.remove(theCodeSystem + "|" + theCode)) {
|
if (!theAdd && theAddedCodes.remove(theCodeSystem + "|" + theCode)) {
|
||||||
theValueSetCodeAccumulator.excludeCode(theCodeSystem, theCode);
|
theValueSetCodeAccumulator.excludeConcept(theCodeSystem, theCode);
|
||||||
theCodeCounter.decrementAndGet();
|
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) {
|
for (CodeSystem.ConceptDefinitionComponent next : theConcept) {
|
||||||
if (isNoneBlank(theSystem, next.getCode())) {
|
if (isNoneBlank(theSystem, next.getCode())) {
|
||||||
if (theAdd && theAddedCodes.add(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())) {
|
if (!theAdd && theAddedCodes.remove(theSystem + "|" + next.getCode())) {
|
||||||
theValueSetCodeAccumulator.excludeCode(theSystem, next.getCode());
|
theValueSetCodeAccumulator.excludeConcept(theSystem, next.getCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addConceptsToList(theValueSetCodeAccumulator, theAddedCodes, theSystem, next.getConcept(), theAdd);
|
addConceptsToList(theValueSetCodeAccumulator, theAddedCodes, theSystem, next.getConcept(), theAdd);
|
||||||
|
@ -389,9 +393,9 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
TermValueSet existingTermValueSet = optionalExistingTermValueSetById.get();
|
TermValueSet existingTermValueSet = optionalExistingTermValueSetById.get();
|
||||||
|
|
||||||
ourLog.info("Deleting existing TermValueSet {} and its children...", existingTermValueSet.getId());
|
ourLog.info("Deleting existing TermValueSet {} and its children...", existingTermValueSet.getId());
|
||||||
myValueSetConceptDesignationDao.deleteTermValueSetConceptDesignationsByValueSetId(existingTermValueSet.getId());
|
myValueSetConceptDesignationDao.deleteByTermValueSetId(existingTermValueSet.getId());
|
||||||
myValueSetConceptDao.deleteTermValueSetConceptsByValueSetId(existingTermValueSet.getId());
|
myValueSetConceptDao.deleteByTermValueSetId(existingTermValueSet.getId());
|
||||||
myValueSetDao.deleteTermValueSetById(existingTermValueSet.getId());
|
myValueSetDao.deleteByTermValueSetId(existingTermValueSet.getId());
|
||||||
ourLog.info("Done deleting existing TermValueSet {} and its children.", existingTermValueSet.getId());
|
ourLog.info("Done deleting existing TermValueSet {} and its children.", existingTermValueSet.getId());
|
||||||
|
|
||||||
ourLog.info("Flushing...");
|
ourLog.info("Flushing...");
|
||||||
|
@ -457,7 +461,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
@Transactional(propagation = Propagation.REQUIRED)
|
||||||
public ValueSet expandValueSet(ValueSet theValueSetToExpand) {
|
public ValueSet expandValueSet(ValueSet theValueSetToExpand) {
|
||||||
|
|
||||||
ValueSetExpansionComponentWithCodeAccumulator expansionComponent = new ValueSetExpansionComponentWithCodeAccumulator();
|
ValueSetExpansionComponentWithConceptAccumulator expansionComponent = new ValueSetExpansionComponentWithConceptAccumulator();
|
||||||
expansionComponent.setIdentifier(UUID.randomUUID().toString());
|
expansionComponent.setIdentifier(UUID.randomUUID().toString());
|
||||||
expansionComponent.setTimestamp(new Date());
|
expansionComponent.setTimestamp(new Date());
|
||||||
|
|
||||||
|
@ -476,11 +480,11 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
@Transactional(propagation = Propagation.REQUIRED)
|
||||||
public void expandValueSet(ValueSet theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator) {
|
public void expandValueSet(ValueSet theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator) {
|
||||||
expandValueSet(theValueSetToExpand, theValueSetCodeAccumulator, new AtomicInteger(0));
|
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<>();
|
Set<String> addedCodes = new HashSet<>();
|
||||||
|
|
||||||
// Handle includes
|
// Handle includes
|
||||||
|
@ -509,7 +513,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
return retVal;
|
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();
|
String system = theInclude.getSystem();
|
||||||
boolean hasSystem = isNotBlank(system);
|
boolean hasSystem = isNotBlank(system);
|
||||||
boolean hasValueSet = theInclude.getValueSet().size() > 0;
|
boolean hasValueSet = theInclude.getValueSet().size() > 0;
|
||||||
|
@ -676,10 +680,10 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode);
|
CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode);
|
||||||
if (code != null) {
|
if (code != null) {
|
||||||
if (theAdd && theAddedCodes.add(system + "|" + nextCode)) {
|
if (theAdd && theAddedCodes.add(system + "|" + nextCode)) {
|
||||||
theValueSetCodeAccumulator.includeCode(system, nextCode, code.getDisplay());
|
theValueSetCodeAccumulator.includeConcept(system, nextCode, code.getDisplay());
|
||||||
}
|
}
|
||||||
if (!theAdd && theAddedCodes.remove(system + "|" + nextCode)) {
|
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())) {
|
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");
|
ourLog.trace("Hibernate search is not enabled");
|
||||||
if (theValueSetCodeAccumulator instanceof ValueSetExpansionComponentWithCodeAccumulator) {
|
if (theValueSetCodeAccumulator instanceof ValueSetExpansionComponentWithConceptAccumulator) {
|
||||||
Validate.isTrue(((ValueSetExpansionComponentWithCodeAccumulator) theValueSetCodeAccumulator).getParameter().isEmpty(), "Can not expand ValueSet with parameters - Hibernate Search is not enabled on this server.");
|
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(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.");
|
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.");
|
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
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void storeTermValueSetAndChildren(ResourceTable theResourceTable, ValueSet theValueSet) {
|
public void storeTermValueSet(ResourceTable theResourceTable, ValueSet theValueSet) {
|
||||||
ourLog.info("Storing TermValueSet {}", theValueSet.getIdElement().getValue());
|
ourLog.info("Storing TermValueSet {}", theValueSet.getIdElement().getValue());
|
||||||
|
|
||||||
ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied");
|
ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied");
|
||||||
|
@ -1513,58 +1554,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
String url = termValueSet.getUrl();
|
String url = termValueSet.getUrl();
|
||||||
Optional<TermValueSet> optionalExistingTermValueSetByUrl = myValueSetDao.findByUrl(url);
|
Optional<TermValueSet> optionalExistingTermValueSetByUrl = myValueSetDao.findByUrl(url);
|
||||||
if (!optionalExistingTermValueSetByUrl.isPresent()) {
|
if (!optionalExistingTermValueSetByUrl.isPresent()) {
|
||||||
|
|
||||||
myValueSetDao.save(termValueSet);
|
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 {
|
} else {
|
||||||
TermValueSet existingTermValueSet = optionalExistingTermValueSetByUrl.get();
|
TermValueSet existingTermValueSet = optionalExistingTermValueSetByUrl.get();
|
||||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.term;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.instance.hapi.validation.IValidationSupport;
|
import org.hl7.fhir.instance.hapi.validation.IValidationSupport;
|
||||||
|
@ -81,13 +82,18 @@ public class HapiTerminologySvcDstu2 extends BaseHapiTerminologySvcImpl {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ValueSet getValueSetFromResourceTable(ResourceTable theResourceTable) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBaseResource expandValueSet(IBaseResource theValueSetToExpand) {
|
public IBaseResource expandValueSet(IBaseResource theValueSetToExpand) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator) {
|
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator) {
|
||||||
throw new UnsupportedOperationException();
|
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.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
|
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
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.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.util.CoverageIgnore;
|
import ca.uhn.fhir.util.CoverageIgnore;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
|
@ -177,7 +178,7 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator) {
|
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator) {
|
||||||
ValueSet valueSetToExpand = (ValueSet) theValueSetToExpand;
|
ValueSet valueSetToExpand = (ValueSet) theValueSetToExpand;
|
||||||
|
|
||||||
try {
|
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
|
@Override
|
||||||
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||||
return myTerminologySvc.supportsSystem(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.context.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
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.CoverageIgnore;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
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.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||||
|
@ -138,7 +138,7 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator) {
|
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator) {
|
||||||
ValueSet valueSetToExpand = (ValueSet) theValueSetToExpand;
|
ValueSet valueSetToExpand = (ValueSet) theValueSetToExpand;
|
||||||
super.expandValueSet(valueSetToExpand, theValueSetCodeAccumulator);
|
super.expandValueSet(valueSetToExpand, theValueSetCodeAccumulator);
|
||||||
}
|
}
|
||||||
|
@ -231,6 +231,11 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
||||||
return myValidationSupport.fetchCodeSystem(myContext, theSystem);
|
return myValidationSupport.fetchCodeSystem(myContext, theSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ValueSet getValueSetFromResourceTable(ResourceTable theResourceTable) {
|
||||||
|
return myValueSetResourceDao.toResource(ValueSet.class, theResourceTable, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||||
return supportsSystem(theSystem);
|
return supportsSystem(theSystem);
|
||||||
|
|
|
@ -44,14 +44,14 @@ public interface IHapiTerminologySvc {
|
||||||
|
|
||||||
ValueSet expandValueSet(ValueSet theValueSetToExpand);
|
ValueSet expandValueSet(ValueSet theValueSetToExpand);
|
||||||
|
|
||||||
void expandValueSet(ValueSet theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator);
|
void expandValueSet(ValueSet theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Version independent
|
* Version independent
|
||||||
*/
|
*/
|
||||||
IBaseResource expandValueSet(IBaseResource theValueSetToExpand);
|
IBaseResource expandValueSet(IBaseResource theValueSetToExpand);
|
||||||
|
|
||||||
void expandValueSet(IBaseResource theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator);
|
void expandValueSet(IBaseResource theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator);
|
||||||
|
|
||||||
List<VersionIndependentConcept> expandValueSet(String theValueSet);
|
List<VersionIndependentConcept> expandValueSet(String theValueSet);
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ public interface IHapiTerminologySvc {
|
||||||
|
|
||||||
void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap);
|
void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap);
|
||||||
|
|
||||||
void storeTermValueSetAndChildren(ResourceTable theResourceTable, ValueSet theValueSet);
|
void storeTermValueSet(ResourceTable theResourceTable, ValueSet theValueSet);
|
||||||
|
|
||||||
boolean supportsSystem(String theCodeSystem);
|
boolean supportsSystem(String theCodeSystem);
|
||||||
|
|
||||||
|
@ -107,4 +107,6 @@ public interface IHapiTerminologySvc {
|
||||||
AtomicInteger applyDeltaCodesystemsAdd(String theSystem, @Nullable String theParent, CodeSystem theValue);
|
AtomicInteger applyDeltaCodesystemsAdd(String theSystem, @Nullable String theParent, CodeSystem theValue);
|
||||||
|
|
||||||
AtomicInteger applyDeltaCodesystemsRemove(String theSystem, CodeSystem theDelta);
|
AtomicInteger applyDeltaCodesystemsRemove(String theSystem, CodeSystem theDelta);
|
||||||
|
|
||||||
|
void preExpandValueSetToTerminologyTables();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,12 @@ import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
|
||||||
|
|
||||||
import java.util.Collection;
|
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;
|
import java.util.Collection;
|
||||||
|
|
||||||
@Block()
|
@Block()
|
||||||
public class ValueSetExpansionComponentWithCodeAccumulator extends ValueSet.ValueSetExpansionComponent implements IValueSetCodeAccumulator {
|
public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.ValueSetExpansionComponent implements IValueSetConceptAccumulator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void includeCode(String theSystem, String theCode, String theDisplay) {
|
public void includeConcept(String theSystem, String theCode, String theDisplay) {
|
||||||
ValueSet.ValueSetExpansionContainsComponent contains = this.addContains();
|
ValueSet.ValueSetExpansionContainsComponent contains = this.addContains();
|
||||||
contains.setSystem(theSystem);
|
contains.setSystem(theSystem);
|
||||||
contains.setCode(theCode);
|
contains.setCode(theCode);
|
||||||
|
@ -38,7 +38,7 @@ public class ValueSetExpansionComponentWithCodeAccumulator extends ValueSet.Valu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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();
|
ValueSet.ValueSetExpansionContainsComponent contains = this.addContains();
|
||||||
contains.setSystem(theSystem);
|
contains.setSystem(theSystem);
|
||||||
contains.setCode(theCode);
|
contains.setCode(theCode);
|
||||||
|
@ -58,7 +58,7 @@ public class ValueSetExpansionComponentWithCodeAccumulator extends ValueSet.Valu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void excludeCode(String theSystem, String theCode) {
|
public void excludeConcept(String theSystem, String theCode) {
|
||||||
this
|
this
|
||||||
.getContains()
|
.getContains()
|
||||||
.removeIf(t ->
|
.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.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
|
@ -42,7 +43,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
@Rule
|
@Rule
|
||||||
public final ExpectedException expectedException = ExpectedException.none();
|
public final ExpectedException expectedException = ExpectedException.none();
|
||||||
@Mock
|
@Mock
|
||||||
IValueSetCodeAccumulator myValueSetCodeAccumulator;
|
IValueSetConceptAccumulator myValueSetCodeAccumulator;
|
||||||
private IIdType myConceptMapId;
|
private IIdType myConceptMapId;
|
||||||
private IIdType myExtensionalCsId;
|
private IIdType myExtensionalCsId;
|
||||||
private IIdType myExtensionalVsId;
|
private IIdType myExtensionalVsId;
|
||||||
|
@ -135,6 +136,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
loadAndPersistValueSet();
|
loadAndPersistValueSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude() throws IOException {
|
||||||
|
loadAndPersistCodeSystemWithDesignations();
|
||||||
|
loadAndPersistValueSetWithExclude();
|
||||||
|
}
|
||||||
|
|
||||||
private void loadAndPersistCodeSystem() throws IOException {
|
private void loadAndPersistCodeSystem() throws IOException {
|
||||||
CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
|
CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
|
||||||
persistCodeSystem(codeSystem);
|
persistCodeSystem(codeSystem);
|
||||||
|
@ -159,6 +165,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
persistValueSet(valueSet);
|
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) {
|
private void persistValueSet(ValueSet theValueSet) {
|
||||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -589,7 +600,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
include.setSystem(CS_URL);
|
include.setSystem(CS_URL);
|
||||||
|
|
||||||
myTermSvc.expandValueSet(vs, myValueSetCodeAccumulator);
|
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
|
@Test
|
||||||
|
@ -625,15 +636,24 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
TermConcept concept = concepts.get(0);
|
TermConcept concept = concepts.get(0);
|
||||||
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(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("nl", designation.getLanguage());
|
||||||
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||||
assertEquals("900000000000013009", designation.getUseCode());
|
assertEquals("900000000000013009", designation.getUseCode());
|
||||||
assertEquals("Synonym", designation.getUseDisplay());
|
assertEquals("Synonym", designation.getUseDisplay());
|
||||||
assertEquals("Systolische bloeddruk - expiratie", designation.getValue());
|
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);
|
concept = concepts.get(1);
|
||||||
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());
|
||||||
|
@ -948,67 +968,197 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
ValueSet valueSet = myValueSetDao.read(myExtensionalVsId);
|
ValueSet valueSet = myValueSetDao.read(myExtensionalVsId);
|
||||||
ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet));
|
ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet));
|
||||||
|
|
||||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
runInTransaction(()->{
|
||||||
@Override
|
Optional<TermValueSet> optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong());
|
||||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
assertTrue(optionalValueSetByResourcePid.isPresent());
|
||||||
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");
|
Optional<TermValueSet> optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||||
assertTrue(optionalValueSetByUrl.isPresent());
|
assertTrue(optionalValueSetByUrl.isPresent());
|
||||||
|
|
||||||
TermValueSet valueSet = optionalValueSetByUrl.get();
|
TermValueSet termValueSet = optionalValueSetByUrl.get();
|
||||||
assertSame(optionalValueSetByResourcePid.get(), valueSet);
|
assertSame(optionalValueSetByResourcePid.get(), termValueSet);
|
||||||
ourLog.info("ValueSet:\n" + valueSet.toString());
|
ourLog.info("ValueSet:\n" + termValueSet.toString());
|
||||||
assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", valueSet.getUrl());
|
assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", termValueSet.getUrl());
|
||||||
assertEquals("Terminology Services Connectation #1 Extensional case #2", valueSet.getName());
|
assertEquals("Terminology Services Connectation #1 Extensional case #2", termValueSet.getName());
|
||||||
assertEquals(codeSystem.getConcept().size(), valueSet.getConcepts().size());
|
assertEquals(0, termValueSet.getConcepts().size()); // DM 2019-07-30: Concepts are persisted in the background.
|
||||||
assertEquals(TermValueSetExpansionStatusEnum.NOT_EXPANDED, valueSet.getExpansionStatus());
|
assertEquals(TermValueSetExpansionStatusEnum.NOT_EXPANDED, termValueSet.getExpansionStatus());
|
||||||
|
});
|
||||||
|
|
||||||
TermValueSetConcept concept = valueSet.getConcepts().get(0);
|
// FIXME: DM 2019-07-31 - Wait for ValueSet expansion status to be EXPANDED.
|
||||||
ourLog.info("Code:\n" + concept.toString());
|
try {
|
||||||
assertEquals("http://acme.org", concept.getSystem());
|
Thread.sleep(10000);
|
||||||
assertEquals("8450-9", concept.getCode());
|
} catch (InterruptedException theE) {
|
||||||
assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
|
theE.printStackTrace();
|
||||||
assertEquals(1, concept.getDesignations().size());
|
}
|
||||||
|
|
||||||
TermValueSetConceptDesignation designation = concept.getDesignations().get(0);
|
runInTransaction(()->{
|
||||||
assertEquals("nl", designation.getLanguage());
|
Optional<TermValueSet> optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong());
|
||||||
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
assertTrue(optionalValueSetByResourcePid.isPresent());
|
||||||
assertEquals("900000000000013009", designation.getUseCode());
|
|
||||||
assertEquals("Synonym", designation.getUseDisplay());
|
|
||||||
assertEquals("Systolische bloeddruk - expiratie", designation.getValue());
|
|
||||||
|
|
||||||
concept = valueSet.getConcepts().get(1);
|
Optional<TermValueSet> optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||||
ourLog.info("Code:\n" + concept.toString());
|
assertTrue(optionalValueSetByUrl.isPresent());
|
||||||
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());
|
|
||||||
|
|
||||||
// ...
|
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);
|
TermValueSetConcept concept = termValueSet.getConcepts().get(0);
|
||||||
ourLog.info("Code:\n" + concept.toString());
|
ourLog.info("Code:\n" + concept.toString());
|
||||||
assertEquals("http://acme.org", concept.getSystem());
|
assertEquals("http://acme.org", concept.getSystem());
|
||||||
assertEquals("8491-3", concept.getCode());
|
assertEquals("8450-9", concept.getCode());
|
||||||
assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay());
|
assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
|
||||||
assertEquals(1, concept.getDesignations().size());
|
assertEquals(2, concept.getDesignations().size());
|
||||||
|
|
||||||
designation = concept.getDesignations().get(0);
|
TermValueSetConceptDesignation designation = concept.getDesignations().get(0);
|
||||||
assertEquals("nl", designation.getLanguage());
|
assertEquals("nl", designation.getLanguage());
|
||||||
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||||
assertEquals("900000000000013009", designation.getUseCode());
|
assertEquals("900000000000013009", designation.getUseCode());
|
||||||
assertEquals("Synonym", designation.getUseDisplay());
|
assertEquals("Synonym", designation.getUseDisplay());
|
||||||
assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue());
|
assertEquals("Systolische bloeddruk - expiratie", designation.getValue());
|
||||||
|
|
||||||
concept = valueSet.getConcepts().get(23);
|
designation = concept.getDesignations().get(1);
|
||||||
ourLog.info("Code:\n" + concept.toString());
|
assertEquals("sv", designation.getLanguage());
|
||||||
assertEquals("http://acme.org", concept.getSystem());
|
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||||
assertEquals("8492-1", concept.getCode());
|
assertEquals("900000000000013009", designation.getUseCode());
|
||||||
assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay());
|
assertEquals("Synonym", designation.getUseDisplay());
|
||||||
assertEquals(0, concept.getDesignations().size());
|
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>
|
</use>
|
||||||
<value value="Systolische bloeddruk - expiratie"/>
|
<value value="Systolische bloeddruk - expiratie"/>
|
||||||
</designation>
|
</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>
|
||||||
<concept>
|
<concept>
|
||||||
<code value="11378-7" />
|
<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