More terminology service work
This commit is contained in:
parent
c318d1a040
commit
32cebb2a9f
|
@ -0,0 +1,168 @@
|
||||||
|
package example;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.validation.DefaultProfileValidationSupport;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.validation.ValidationSupportChain;
|
||||||
|
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||||
|
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||||
|
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||||
|
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||||
|
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
import ca.uhn.fhir.validation.FhirValidator;
|
||||||
|
import ca.uhn.fhir.validation.ValidationResult;
|
||||||
|
|
||||||
|
public class ValidateDirectory {
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidateDirectory.class);
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
// Load all profiles in this directory
|
||||||
|
File profileDirectory = new File("/tmp/directory/with/profiles");
|
||||||
|
|
||||||
|
// Validate resources in this directory
|
||||||
|
File resourceDirectory = new File("/tmp/directory/with/resources/to/validate");
|
||||||
|
|
||||||
|
FhirContext ctx = FhirContext.forDstu3();
|
||||||
|
IParser xmlParser = ctx.newXmlParser();
|
||||||
|
IParser jsonParser = ctx.newJsonParser();
|
||||||
|
|
||||||
|
Map<String, StructureDefinition> structureDefinitions = new HashMap<String, StructureDefinition>();
|
||||||
|
Map<String, CodeSystem> codeSystems = new HashMap<String, CodeSystem>();
|
||||||
|
Map<String, ValueSet> valueSets = new HashMap<String, ValueSet>();
|
||||||
|
|
||||||
|
// Load all profile files
|
||||||
|
for (File nextFile : profileDirectory.listFiles()) {
|
||||||
|
|
||||||
|
IBaseResource parsedRes = null;
|
||||||
|
if (nextFile.getAbsolutePath().toLowerCase().endsWith(".xml")) {
|
||||||
|
parsedRes = xmlParser.parseResource(new FileReader(nextFile));
|
||||||
|
} else if (nextFile.getAbsolutePath().toLowerCase().endsWith(".json")) {
|
||||||
|
parsedRes = jsonParser.parseResource(new FileReader(nextFile));
|
||||||
|
} else {
|
||||||
|
ourLog.info("Ignoring file: {}", nextFile.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedRes instanceof StructureDefinition) {
|
||||||
|
StructureDefinition res = (StructureDefinition) parsedRes;
|
||||||
|
if (isNotBlank(res.getUrl())) {
|
||||||
|
structureDefinitions.put(res.getUrl(), res);
|
||||||
|
}
|
||||||
|
} else if (parsedRes instanceof ValueSet) {
|
||||||
|
ValueSet res = (ValueSet) parsedRes;
|
||||||
|
if (isNotBlank(res.getUrl())) {
|
||||||
|
valueSets.put(res.getUrl(), res);
|
||||||
|
}
|
||||||
|
} else if (parsedRes instanceof CodeSystem) {
|
||||||
|
CodeSystem res = (CodeSystem) parsedRes;
|
||||||
|
if (isNotBlank(res.getUrl())) {
|
||||||
|
codeSystems.put(res.getUrl(), res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FhirInstanceValidator instanceValidator = new FhirInstanceValidator();
|
||||||
|
|
||||||
|
ValidationSupportChain validationSupportChain = new ValidationSupportChain();
|
||||||
|
validationSupportChain.addValidationSupport(new DefaultProfileValidationSupport());
|
||||||
|
validationSupportChain.addValidationSupport(new PrePopulatedValidationSupport(structureDefinitions, valueSets, codeSystems));
|
||||||
|
|
||||||
|
instanceValidator.setValidationSupport(validationSupportChain);
|
||||||
|
|
||||||
|
FhirValidator val = ctx.newValidator();
|
||||||
|
val.registerValidatorModule(instanceValidator);
|
||||||
|
|
||||||
|
// Loop through the files in the validation directory and validate each one
|
||||||
|
for (File nextFile : resourceDirectory.listFiles()) {
|
||||||
|
|
||||||
|
if (nextFile.getAbsolutePath().toLowerCase().endsWith(".xml")) {
|
||||||
|
ourLog.info("Going to validate: {}", nextFile.getName());
|
||||||
|
} else if (nextFile.getAbsolutePath().toLowerCase().endsWith(".json")) {
|
||||||
|
ourLog.info("Going to validate: {}", nextFile.getName());
|
||||||
|
} else {
|
||||||
|
ourLog.info("Ignoring file: {}", nextFile.getName());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String input = IOUtils.toString(new FileReader(nextFile));
|
||||||
|
ValidationResult result = val.validateWithResult(input);
|
||||||
|
IBaseOperationOutcome oo = result.toOperationOutcome();
|
||||||
|
ourLog.info("Result:\n{}", xmlParser.setPrettyPrint(true).encodeResourceToString(oo));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PrePopulatedValidationSupport implements IValidationSupport {
|
||||||
|
|
||||||
|
private Map<String, StructureDefinition> myStructureDefinitions;
|
||||||
|
private Map<String, ValueSet> myValueSets;
|
||||||
|
private Map<String, CodeSystem> myCodeSystems;
|
||||||
|
|
||||||
|
public PrePopulatedValidationSupport(Map<String, StructureDefinition> theStructureDefinitions, Map<String, ValueSet> theValueSets, Map<String, CodeSystem> theCodeSystems) {
|
||||||
|
myStructureDefinitions = theStructureDefinitions;
|
||||||
|
myValueSets = theValueSets;
|
||||||
|
myCodeSystems = theCodeSystems;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||||
|
return new ArrayList<StructureDefinition>(myStructureDefinitions.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||||
|
return myCodeSystems.get(theSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||||
|
if (theClass.equals(StructureDefinition.class)) {
|
||||||
|
return (T) myStructureDefinitions.get(theUri);
|
||||||
|
}
|
||||||
|
if (theClass.equals(ValueSet.class)) {
|
||||||
|
return (T) myValueSets.get(theUri);
|
||||||
|
}
|
||||||
|
if (theClass.equals(CodeSystem.class)) {
|
||||||
|
return (T) myCodeSystems.get(theUri);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||||
|
return myStructureDefinitions.get(theUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -30,6 +30,7 @@ import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.StringUtils;
|
import org.apache.commons.codec.binary.StringUtils;
|
||||||
|
import org.hl7.fhir.dstu3.exceptions.TerminologyServiceException;
|
||||||
import org.hl7.fhir.dstu3.hapi.validation.HapiWorkerContext;
|
import org.hl7.fhir.dstu3.hapi.validation.HapiWorkerContext;
|
||||||
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
|
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
|
||||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||||
|
@ -75,7 +76,7 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
|
||||||
String filterLc = theFilter != null ? theFilter.toLowerCase() : null;
|
String filterLc = theFilter != null ? theFilter.toLowerCase() : null;
|
||||||
|
|
||||||
ValueSetExpansionOutcome outcome = workerContext.expand(source);
|
ValueSetExpansionOutcome outcome = workerContext.expand(source);
|
||||||
ValueSetExpansionComponent expansion = outcome.getValueset().getExpansion();
|
ValueSetExpansionComponent expansion = outcome.getValueset().getExpansion();
|
||||||
if (isNotBlank(theFilter)) {
|
if (isNotBlank(theFilter)) {
|
||||||
for (Iterator<ValueSetExpansionContainsComponent> containsIter = expansion.getContains().iterator(); containsIter.hasNext();) {
|
for (Iterator<ValueSetExpansionContainsComponent> containsIter = expansion.getContains().iterator(); containsIter.hasNext();) {
|
||||||
ValueSetExpansionContainsComponent nextContains = containsIter.next();
|
ValueSetExpansionContainsComponent nextContains = containsIter.next();
|
||||||
|
|
|
@ -207,11 +207,12 @@ public class TermConcept implements Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDisplay(String theDisplay) {
|
public TermConcept setDisplay(String theDisplay) {
|
||||||
myDisplay = theDisplay;
|
myDisplay = theDisplay;
|
||||||
if (isNotBlank(theDisplay) && theDisplay.length() > MAX_DESC_LENGTH) {
|
if (isNotBlank(theDisplay) && theDisplay.length() > MAX_DESC_LENGTH) {
|
||||||
myDisplay = myDisplay.substring(0, MAX_DESC_LENGTH);
|
myDisplay = myDisplay.substring(0, MAX_DESC_LENGTH);
|
||||||
}
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setParentPids(Set<Long> theParentPids) {
|
public void setParentPids(Set<Long> theParentPids) {
|
||||||
|
|
|
@ -66,27 +66,18 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||||
@Autowired
|
@Autowired
|
||||||
protected ITermConceptDao myConceptDao;
|
protected ITermConceptDao myConceptDao;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private DaoConfig myDaoConfig;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ITermConceptParentChildLinkDao myConceptParentChildLinkDao;
|
private ITermConceptParentChildLinkDao myConceptParentChildLinkDao;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected FhirContext myContext;
|
protected FhirContext myContext;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DaoConfig myDaoConfig;
|
||||||
|
|
||||||
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
||||||
protected EntityManager myEntityManager;
|
protected EntityManager myEntityManager;
|
||||||
|
|
||||||
private void fetchChildren(TermConcept theConcept, Set<TermConcept> theSetToPopulate) {
|
|
||||||
for (TermConceptParentChildLink nextChildLink : theConcept.getChildren()) {
|
|
||||||
TermConcept nextChild = nextChildLink.getChild();
|
|
||||||
if (addToSet(theSetToPopulate, nextChild)) {
|
|
||||||
fetchChildren(nextChild, theSetToPopulate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean addToSet(Set<TermConcept> theSetToPopulate, TermConcept theConcept) {
|
private boolean addToSet(Set<TermConcept> theSetToPopulate, TermConcept theConcept) {
|
||||||
boolean retVal = theSetToPopulate.add(theConcept);
|
boolean retVal = theSetToPopulate.add(theConcept);
|
||||||
if (retVal) {
|
if (retVal) {
|
||||||
|
@ -98,6 +89,15 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fetchChildren(TermConcept theConcept, Set<TermConcept> theSetToPopulate) {
|
||||||
|
for (TermConceptParentChildLink nextChildLink : theConcept.getChildren()) {
|
||||||
|
TermConcept nextChild = nextChildLink.getChild();
|
||||||
|
if (addToSet(theSetToPopulate, nextChild)) {
|
||||||
|
fetchChildren(nextChild, theSetToPopulate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private TermConcept fetchLoadedCode(Long theCodeSystemResourcePid, Long theCodeSystemVersionPid, String theCode) {
|
private TermConcept fetchLoadedCode(Long theCodeSystemResourcePid, Long theCodeSystemVersionPid, String theCode) {
|
||||||
TermCodeSystemVersion codeSystem = myCodeSystemVersionDao.findByCodeSystemResourceAndVersion(theCodeSystemResourcePid, theCodeSystemVersionPid);
|
TermCodeSystemVersion codeSystem = myCodeSystemVersionDao.findByCodeSystemResourceAndVersion(theCodeSystemResourcePid, theCodeSystemVersionPid);
|
||||||
TermConcept concept = myConceptDao.findByCodeSystemAndCode(codeSystem, theCode);
|
TermConcept concept = myConceptDao.findByCodeSystemAndCode(codeSystem, theCode);
|
||||||
|
@ -113,6 +113,17 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TermConcept findCode(String theCodeSystem, String theCode) {
|
||||||
|
TermCodeSystemVersion csv = findCurrentCodeSystemVersionForSystem(theCodeSystem);
|
||||||
|
|
||||||
|
return myConceptDao.findByCodeSystemAndCode(csv, theCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TermConcept> findCodes(String theSystem) {
|
||||||
|
return myConceptDao.findByCodeSystemVersion(findCurrentCodeSystemVersionForSystem(theSystem));
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
@Transactional(propagation = Propagation.REQUIRED)
|
||||||
@Override
|
@Override
|
||||||
public Set<TermConcept> findCodesAbove(Long theCodeSystemResourcePid, Long theCodeSystemVersionPid, String theCode) {
|
public Set<TermConcept> findCodesAbove(Long theCodeSystemResourcePid, Long theCodeSystemVersionPid, String theCode) {
|
||||||
|
@ -177,6 +188,20 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TermCodeSystemVersion findCurrentCodeSystemVersionForSystem(String theCodeSystem) {
|
||||||
|
TermCodeSystem cs = getCodeSystem(theCodeSystem);
|
||||||
|
if (cs == null || cs.getCurrentVersion() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TermCodeSystemVersion csv = cs.getCurrentVersion();
|
||||||
|
return csv;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TermCodeSystem getCodeSystem(String theSystem) {
|
||||||
|
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(theSystem);
|
||||||
|
return cs;
|
||||||
|
}
|
||||||
|
|
||||||
private void persistChildren(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap<TermConcept, Object> theConceptsStack, HashSet<Long> thePidsInHierarchy) {
|
private void persistChildren(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap<TermConcept, Object> theConceptsStack, HashSet<Long> thePidsInHierarchy) {
|
||||||
if (theConceptsStack.put(theConcept, PLACEHOLDER_OBJECT) != null) {
|
if (theConceptsStack.put(theConcept, PLACEHOLDER_OBJECT) != null) {
|
||||||
return;
|
return;
|
||||||
|
@ -277,11 +302,6 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||||
return cs != null;
|
return cs != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TermCodeSystem getCodeSystem(String theSystem) {
|
|
||||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(theSystem);
|
|
||||||
return cs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ArrayList<VersionIndependentConcept> toVersionIndependentConcepts(String theSystem, Set<TermConcept> codes) {
|
private ArrayList<VersionIndependentConcept> toVersionIndependentConcepts(String theSystem, Set<TermConcept> codes) {
|
||||||
ArrayList<VersionIndependentConcept> retVal = new ArrayList<VersionIndependentConcept>(codes.size());
|
ArrayList<VersionIndependentConcept> retVal = new ArrayList<VersionIndependentConcept>(codes.size());
|
||||||
for (TermConcept next : codes) {
|
for (TermConcept next : codes) {
|
||||||
|
@ -309,14 +329,4 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TermConcept findCode(String theCodeSystem, String theCode) {
|
|
||||||
TermCodeSystem cs = getCodeSystem(theCodeSystem);
|
|
||||||
if (cs == null || cs.getCurrentVersion() == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
TermCodeSystemVersion csv = cs.getCurrentVersion();
|
|
||||||
|
|
||||||
return myConceptDao.findByCodeSystemAndCode(csv, theCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,60 +121,82 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc implements I
|
||||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system);
|
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system);
|
||||||
TermCodeSystemVersion csv = cs.getCurrentVersion();
|
TermCodeSystemVersion csv = cs.getCurrentVersion();
|
||||||
|
|
||||||
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
|
ValueSetExpansionComponent retVal = new ValueSetExpansionComponent();
|
||||||
QueryBuilder qb = em.getSearchFactory().buildQueryBuilder().forEntity(TermConcept.class).get();
|
Set<String> addedCodes = new HashSet<String>();
|
||||||
BooleanJunction<?> bool = qb.bool();
|
boolean haveIncludeCriteria = false;
|
||||||
|
|
||||||
bool.must(qb.keyword().onField("myCodeSystemVersionPid").matching(csv.getPid()).createQuery());
|
/*
|
||||||
|
* Include Concepts
|
||||||
Set<String> wantCodes = new HashSet<String>();
|
*/
|
||||||
for (ConceptReferenceComponent next : theInclude.getConcept()) {
|
for (ConceptReferenceComponent next : theInclude.getConcept()) {
|
||||||
String nextCode = next.getCode();
|
String nextCode = next.getCode();
|
||||||
if (isNotBlank(nextCode)) {
|
if (isNotBlank(nextCode) && !addedCodes.contains(nextCode)) {
|
||||||
wantCodes.add(nextCode);
|
haveIncludeCriteria = true;
|
||||||
bool.should(qb.keyword().onField("myCode").matching(nextCode).createQuery());
|
TermConcept code = super.findCode(system, nextCode);
|
||||||
|
if (code != null) {
|
||||||
|
addedCodes.add(nextCode);
|
||||||
|
ValueSetExpansionContainsComponent contains = retVal.addContains();
|
||||||
|
contains.setCode(nextCode);
|
||||||
|
contains.setSystem(system);
|
||||||
|
contains.setDisplay(code.getDisplay());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ConceptSetFilterComponent nextFilter : theInclude.getFilter()) {
|
/*
|
||||||
if (nextFilter.getProperty().equals("display") && nextFilter.getOp() == FilterOperator.EQUAL) {
|
* Filters
|
||||||
if (isNotBlank(nextFilter.getValue())) {
|
*/
|
||||||
bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery());
|
|
||||||
|
if (theInclude.getFilter().size() > 0) {
|
||||||
|
haveIncludeCriteria = true;
|
||||||
|
|
||||||
|
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
|
||||||
|
QueryBuilder qb = em.getSearchFactory().buildQueryBuilder().forEntity(TermConcept.class).get();
|
||||||
|
BooleanJunction<?> bool = qb.bool();
|
||||||
|
|
||||||
|
bool.must(qb.keyword().onField("myCodeSystemVersionPid").matching(csv.getPid()).createQuery());
|
||||||
|
|
||||||
|
for (ConceptSetFilterComponent nextFilter : theInclude.getFilter()) {
|
||||||
|
if (nextFilter.getProperty().equals("display") && nextFilter.getOp() == FilterOperator.EQUAL) {
|
||||||
|
if (isNotBlank(nextFilter.getValue())) {
|
||||||
|
bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery());
|
||||||
|
}
|
||||||
|
} else if (nextFilter.getOp() == FilterOperator.ISA) {
|
||||||
|
if (isNotBlank(nextFilter.getValue())) {
|
||||||
|
TermConcept code = super.findCode(system, nextFilter.getValue());
|
||||||
|
bool.must(qb.keyword().onField("myParentPids").matching(code.getId()).createQuery());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new InvalidRequestException("Unknown filter property[" + nextFilter + "] + op[" + nextFilter.getOpElement().getValueAsString() + "]");
|
||||||
}
|
}
|
||||||
} else if (nextFilter.getOp() == FilterOperator.ISA) {
|
}
|
||||||
if (isNotBlank(nextFilter.getValue())) {
|
|
||||||
TermConcept code = super.findCode(system, nextFilter.getValue());
|
Query luceneQuery = bool.createQuery();
|
||||||
bool.must(qb.keyword().onField("myParentPids").matching(code.getId()).createQuery());
|
FullTextQuery jpaQuery = em.createFullTextQuery(luceneQuery, TermConcept.class);
|
||||||
}
|
@SuppressWarnings("unchecked")
|
||||||
} else {
|
List<TermConcept> result = jpaQuery.getResultList();
|
||||||
throw new InvalidRequestException("Unknown filter property[" + nextFilter + "] + op[" + nextFilter.getOpElement().getValueAsString() + "]");
|
for (TermConcept nextConcept : result) {
|
||||||
|
addCodeIfNotAlreadyAdded(system, retVal, addedCodes, nextConcept);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueSetExpansionComponent retVal = new ValueSetExpansionComponent();
|
if (!haveIncludeCriteria) {
|
||||||
|
List<TermConcept> allCodes = super.findCodes(system);
|
||||||
Query luceneQuery = bool.createQuery();
|
for (TermConcept nextConcept : allCodes) {
|
||||||
FullTextQuery jpaQuery = em.createFullTextQuery(luceneQuery, TermConcept.class);
|
addCodeIfNotAlreadyAdded(system, retVal, addedCodes, nextConcept);
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
List<TermConcept> result = jpaQuery.getResultList();
|
|
||||||
for (TermConcept nextConcept : result) {
|
|
||||||
if (!wantCodes.isEmpty() && !wantCodes.contains(nextConcept.getCode())) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
ValueSetExpansionContainsComponent contains = retVal.addContains();
|
|
||||||
contains.setCode(nextConcept.getCode());
|
|
||||||
contains.setSystem(system);
|
|
||||||
contains.setDisplay(nextConcept.getDisplay());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCodeIfFilterMatches(ValueSetExpansionComponent retVal, TermConcept termCode, List<ConceptSetFilterComponent> theFilters, String theSystem) {
|
private void addCodeIfNotAlreadyAdded(String system, ValueSetExpansionComponent retVal, Set<String> addedCodes, TermConcept nextConcept) {
|
||||||
ValueSetExpansionContainsComponent contains = retVal.addContains();
|
if (addedCodes.add(nextConcept.getCode())) {
|
||||||
contains.setSystem(theSystem);
|
ValueSetExpansionContainsComponent contains = retVal.addContains();
|
||||||
contains.setCode(termCode.getCode());
|
contains.setCode(nextConcept.getCode());
|
||||||
contains.setDisplay(termCode.getDisplay());
|
contains.setSystem(system);
|
||||||
|
contains.setDisplay(nextConcept.getDisplay());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -185,7 +207,7 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc implements I
|
||||||
@CoverageIgnore
|
@CoverageIgnore
|
||||||
@Override
|
@Override
|
||||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||||
throw new UnsupportedOperationException();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -46,4 +46,6 @@ public interface IHapiTerminologySvc {
|
||||||
|
|
||||||
void storeNewCodeSystemVersion(String theSystem, TermCodeSystemVersion theCodeSystemVersion, RequestDetails theRequestDetails);
|
void storeNewCodeSystemVersion(String theSystem, TermCodeSystemVersion theCodeSystemVersion, RequestDetails theRequestDetails);
|
||||||
|
|
||||||
|
List<TermConcept> findCodes(String theSystem);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,38 +132,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchCodeInExternalCodesystem() {
|
public void testSearchCodeInExternalCodesystem() {
|
||||||
CodeSystem codeSystem = new CodeSystem();
|
createExternalCsAndLocalVs();
|
||||||
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
|
|
||||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
|
||||||
IIdType id = myCodeSystemDao.create(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
|
|
||||||
|
|
||||||
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
|
|
||||||
|
|
||||||
TermCodeSystemVersion cs = new TermCodeSystemVersion();
|
|
||||||
cs.setResource(table);
|
|
||||||
cs.setResourceVersionId(table.getVersion());
|
|
||||||
|
|
||||||
TermConcept parentA = new TermConcept(cs, "ParentA");
|
|
||||||
cs.getConcepts().add(parentA);
|
|
||||||
|
|
||||||
TermConcept childAA = new TermConcept(cs, "childAA");
|
|
||||||
parentA.addChild(childAA, RelationshipTypeEnum.ISA);
|
|
||||||
|
|
||||||
TermConcept childAAA = new TermConcept(cs, "childAAA");
|
|
||||||
childAA.addChild(childAAA, RelationshipTypeEnum.ISA);
|
|
||||||
|
|
||||||
TermConcept childAAB = new TermConcept(cs, "childAAB");
|
|
||||||
childAA.addChild(childAAB, RelationshipTypeEnum.ISA);
|
|
||||||
|
|
||||||
TermConcept childAB = new TermConcept(cs, "childAB");
|
|
||||||
parentA.addChild(childAB, RelationshipTypeEnum.ISA);
|
|
||||||
|
|
||||||
TermConcept parentB = new TermConcept(cs, "ParentB");
|
|
||||||
cs.getConcepts().add(parentB);
|
|
||||||
|
|
||||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
|
|
||||||
|
|
||||||
createLocalVs(codeSystem);
|
|
||||||
|
|
||||||
Observation obsPA = new Observation();
|
Observation obsPA = new Observation();
|
||||||
obsPA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("ParentA");
|
obsPA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("ParentA");
|
||||||
|
@ -195,6 +164,48 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void createExternalCsAndLocalVs() {
|
||||||
|
CodeSystem codeSystem = createExternalCs();
|
||||||
|
|
||||||
|
createLocalVs(codeSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private CodeSystem createExternalCs() {
|
||||||
|
CodeSystem codeSystem = new CodeSystem();
|
||||||
|
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
|
||||||
|
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||||
|
IIdType id = myCodeSystemDao.create(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
|
||||||
|
|
||||||
|
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
|
||||||
|
|
||||||
|
TermCodeSystemVersion cs = new TermCodeSystemVersion();
|
||||||
|
cs.setResource(table);
|
||||||
|
cs.setResourceVersionId(table.getVersion());
|
||||||
|
|
||||||
|
TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A");
|
||||||
|
cs.getConcepts().add(parentA);
|
||||||
|
|
||||||
|
TermConcept childAA = new TermConcept(cs, "childAA").setDisplay("Child AA");
|
||||||
|
parentA.addChild(childAA, RelationshipTypeEnum.ISA);
|
||||||
|
|
||||||
|
TermConcept childAAA = new TermConcept(cs, "childAAA").setDisplay("Child AAA");
|
||||||
|
childAA.addChild(childAAA, RelationshipTypeEnum.ISA);
|
||||||
|
|
||||||
|
TermConcept childAAB = new TermConcept(cs, "childAAB").setDisplay("Child AAB");
|
||||||
|
childAA.addChild(childAAB, RelationshipTypeEnum.ISA);
|
||||||
|
|
||||||
|
TermConcept childAB = new TermConcept(cs, "childAB").setDisplay("Child AB");
|
||||||
|
parentA.addChild(childAB, RelationshipTypeEnum.ISA);
|
||||||
|
|
||||||
|
TermConcept parentB = new TermConcept(cs, "ParentB").setDisplay("Parent B");
|
||||||
|
cs.getConcepts().add(parentB);
|
||||||
|
|
||||||
|
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
|
||||||
|
return codeSystem;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchCodeBelowAndAboveUnknownCodeSystem() {
|
public void testSearchCodeBelowAndAboveUnknownCodeSystem() {
|
||||||
|
|
||||||
|
@ -299,19 +310,48 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandWithSystemAndCodesAndFilterInLocalValueSet() {
|
public void testExpandWithSystemAndCodesAndFilterInExternalValueSet() {
|
||||||
|
createExternalCsAndLocalVs();
|
||||||
|
|
||||||
|
ValueSet vs = new ValueSet();
|
||||||
|
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||||
|
include.addConcept().setCode("ParentA");
|
||||||
|
include.addConcept().setCode("childAA");
|
||||||
|
include.addConcept().setCode("childAAA");
|
||||||
|
|
||||||
|
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue("Parent B");
|
||||||
|
|
||||||
|
ValueSet result = myValueSetDao.expand(vs, null);
|
||||||
|
|
||||||
|
String encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
|
||||||
|
ourLog.info(encoded);
|
||||||
|
|
||||||
|
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAA", "ParentB"));
|
||||||
|
|
||||||
|
int idx = codes.indexOf("childAA");
|
||||||
|
assertEquals("childAA", result.getExpansion().getContains().get(idx).getCode());
|
||||||
|
assertEquals("Child AA", result.getExpansion().getContains().get(idx).getDisplay());
|
||||||
|
assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(idx).getSystem());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandWithSystemAndCodesAndFilterKeywordInLocalValueSet() {
|
||||||
createLocalCsAndVs();
|
createLocalCsAndVs();
|
||||||
|
|
||||||
ValueSet vs = new ValueSet();
|
ValueSet vs = new ValueSet();
|
||||||
ConceptSetComponent include = vs.getCompose().addInclude();
|
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||||
include.setSystem(URL_MY_CODE_SYSTEM);
|
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||||
include.addConcept().setCode("A");
|
// include.addConcept().setCode("A");
|
||||||
include.addConcept().setCode("AA");
|
// include.addConcept().setCode("AA");
|
||||||
include.addConcept().setCode("AAA");
|
// include.addConcept().setCode("AAA");
|
||||||
include.addConcept().setCode("AB");
|
// include.addConcept().setCode("AB");
|
||||||
|
|
||||||
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue("Code AAA");
|
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue("AAA");
|
||||||
|
|
||||||
ValueSet result = myValueSetDao.expand(vs, null);
|
ValueSet result = myValueSetDao.expand(vs, null);
|
||||||
|
|
||||||
|
@ -324,11 +364,44 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
||||||
assertEquals("AAA", result.getExpansion().getContains().get(0).getCode());
|
assertEquals("AAA", result.getExpansion().getContains().get(0).getCode());
|
||||||
assertEquals("Code AAA", result.getExpansion().getContains().get(0).getDisplay());
|
assertEquals("Code AAA", result.getExpansion().getContains().get(0).getDisplay());
|
||||||
assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(0).getSystem());
|
assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(0).getSystem());
|
||||||
// ValueSet expansion = myValueSetDao.expandByIdentifier(URL_MY_VALUE_SET, "cervical");
|
|
||||||
// ValueSet expansion = myValueSetDao.expandByIdentifier(URL_MY_VALUE_SET, "cervical");
|
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandWithNoResultsInLocalValueSet1() {
|
||||||
|
createLocalCsAndVs();
|
||||||
|
|
||||||
|
ValueSet vs = new ValueSet();
|
||||||
|
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||||
|
include.addConcept().setCode("ZZZZ");
|
||||||
|
|
||||||
|
try {
|
||||||
|
myValueSetDao.expand(vs, null);
|
||||||
|
fail();
|
||||||
|
} catch (InvalidRequestException e) {
|
||||||
|
assertEquals("Unable to find code 'ZZZZ' in code system http://example.com/my_code_system", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandWithNoResultsInLocalValueSet2() {
|
||||||
|
createLocalCsAndVs();
|
||||||
|
|
||||||
|
ValueSet vs = new ValueSet();
|
||||||
|
ConceptSetComponent include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(URL_MY_CODE_SYSTEM + "AA");
|
||||||
|
include.addConcept().setCode("A");
|
||||||
|
|
||||||
|
try {
|
||||||
|
myValueSetDao.expand(vs, null);
|
||||||
|
fail();
|
||||||
|
} catch (InvalidRequestException e) {
|
||||||
|
assertEquals("unable to find code system http://example.com/my_code_systemAA", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private ArrayList<String> toCodesContains(List<ValueSetExpansionContainsComponent> theContains) {
|
private ArrayList<String> toCodesContains(List<ValueSetExpansionContainsComponent> theContains) {
|
||||||
ArrayList<String> retVal = new ArrayList<String>();
|
ArrayList<String> retVal = new ArrayList<String>();
|
||||||
for (ValueSetExpansionContainsComponent next : theContains) {
|
for (ValueSetExpansionContainsComponent next : theContains) {
|
||||||
|
|
|
@ -158,23 +158,19 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
|
||||||
ValueSet expanded = myValueSetDao.expand(myExtensionalVsId, null);
|
ValueSet expanded = myValueSetDao.expand(myExtensionalVsId, null);
|
||||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
// @formatter:off
|
assertThat(resp, containsString("<ValueSet xmlns=\"http://hl7.org/fhir\">"));
|
||||||
assertThat(resp,
|
assertThat(resp, containsString("<expansion>"));
|
||||||
stringContainsInOrder("<ValueSet xmlns=\"http://hl7.org/fhir\">",
|
assertThat(resp, containsString("<contains>"));
|
||||||
"<expansion>",
|
assertThat(resp, containsString("<system value=\"http://acme.org\"/>"));
|
||||||
"<contains>",
|
assertThat(resp, containsString("<code value=\"8450-9\"/>"));
|
||||||
"<system value=\"http://acme.org\"/>",
|
assertThat(resp, containsString("<display value=\"Systolic blood pressure--expiration\"/>"));
|
||||||
"<code value=\"8450-9\"/>",
|
assertThat(resp, containsString("</contains>"));
|
||||||
"<display value=\"Systolic blood pressure--expiration\"/>",
|
assertThat(resp, containsString("<contains>"));
|
||||||
"</contains>",
|
assertThat(resp, containsString("<system value=\"http://acme.org\"/>"));
|
||||||
"<contains>",
|
assertThat(resp, containsString("<code value=\"11378-7\"/>"));
|
||||||
"<system value=\"http://acme.org\"/>",
|
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||||
"<code value=\"11378-7\"/>",
|
assertThat(resp, containsString("</contains>"));
|
||||||
"<display value=\"Systolic blood pressure at First encounter\"/>",
|
assertThat(resp, containsString("</expansion>"));
|
||||||
"</contains>",
|
|
||||||
"</expansion>"
|
|
||||||
));
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Filter with display name
|
* Filter with display name
|
||||||
|
|
|
@ -2830,23 +2830,19 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
String resp = IOUtils.toString(response.getEntity().getContent());
|
String resp = IOUtils.toString(response.getEntity().getContent());
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||||
// @formatter:off
|
assertThat(resp, containsString("<ValueSet xmlns=\"http://hl7.org/fhir\">"));
|
||||||
assertThat(resp,
|
assertThat(resp, containsString("<expansion>"));
|
||||||
stringContainsInOrder("<ValueSet xmlns=\"http://hl7.org/fhir\">",
|
assertThat(resp, containsString("<contains>"));
|
||||||
"<expansion>",
|
assertThat(resp, containsString("<system value=\"http://acme.org\"/>"));
|
||||||
"<contains>",
|
assertThat(resp, containsString("<code value=\"8450-9\"/>"));
|
||||||
"<system value=\"http://acme.org\"/>",
|
assertThat(resp, containsString("<display value=\"Systolic blood pressure--expiration\"/>"));
|
||||||
"<code value=\"8450-9\"/>",
|
assertThat(resp, containsString("</contains>"));
|
||||||
"<display value=\"Systolic blood pressure--expiration\"/>",
|
assertThat(resp, containsString("<contains>"));
|
||||||
"</contains>",
|
assertThat(resp, containsString("<system value=\"http://acme.org\"/>"));
|
||||||
"<contains>",
|
assertThat(resp, containsString("<code value=\"11378-7\"/>"));
|
||||||
"<system value=\"http://acme.org\"/>",
|
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||||
"<code value=\"11378-7\"/>",
|
assertThat(resp, containsString("</contains>"));
|
||||||
"<display value=\"Systolic blood pressure at First encounter\"/>",
|
assertThat(resp, containsString("</expansion>"));
|
||||||
"</contains>",
|
|
||||||
"</expansion>"
|
|
||||||
));
|
|
||||||
//@formatter:on
|
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
IOUtils.closeQuietly(response.getEntity().getContent());
|
||||||
response.close();
|
response.close();
|
||||||
|
|
|
@ -62,23 +62,19 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
// @formatter:off
|
assertThat(resp, containsString("<ValueSet xmlns=\"http://hl7.org/fhir\">"));
|
||||||
assertThat(resp,
|
assertThat(resp, containsString("<expansion>"));
|
||||||
stringContainsInOrder("<ValueSet xmlns=\"http://hl7.org/fhir\">",
|
assertThat(resp, containsString("<contains>"));
|
||||||
"<expansion>",
|
assertThat(resp, containsString("<system value=\"http://acme.org\"/>"));
|
||||||
"<contains>",
|
assertThat(resp, containsString("<code value=\"8450-9\"/>"));
|
||||||
"<system value=\"http://acme.org\"/>",
|
assertThat(resp, containsString("<display value=\"Systolic blood pressure--expiration\"/>"));
|
||||||
"<code value=\"8450-9\"/>",
|
assertThat(resp, containsString("</contains>"));
|
||||||
"<display value=\"Systolic blood pressure--expiration\"/>",
|
assertThat(resp, containsString("<contains>"));
|
||||||
"</contains>",
|
assertThat(resp, containsString("<system value=\"http://acme.org\"/>"));
|
||||||
"<contains>",
|
assertThat(resp, containsString("<code value=\"11378-7\"/>"));
|
||||||
"<system value=\"http://acme.org\"/>",
|
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||||
"<code value=\"11378-7\"/>",
|
assertThat(resp, containsString("</contains>"));
|
||||||
"<display value=\"Systolic blood pressure at First encounter\"/>",
|
assertThat(resp, containsString("</expansion>"));
|
||||||
"</contains>",
|
|
||||||
"</expansion>"
|
|
||||||
));
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Filter with display name
|
* Filter with display name
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
"LOINC_NUM","COMPONENT","PROPERTY","TIME_ASPCT","SYSTEM","SCALE_TYP","METHOD_TYP","CLASS","SOURCE","VersionLastChanged","CHNG_TYPE","DefinitionDescription","STATUS","CONSUMER_NAME","CLASSTYPE","FORMULA","SPECIES","EXMPL_ANSWERS","SURVEY_QUEST_TEXT","SURVEY_QUEST_SRC","UNITSREQUIRED","SUBMITTED_UNITS","RELATEDNAMES2","SHORTNAME","ORDER_OBS","CDISC_COMMON_TESTS","HL7_FIELD_SUBFIELD_ID","EXTERNAL_COPYRIGHT_NOTICE","EXAMPLE_UNITS","LONG_COMMON_NAME","UnitsAndRange","DOCUMENT_SECTION","EXAMPLE_UCUM_UNITS","EXAMPLE_SI_UCUM_UNITS","STATUS_REASON","STATUS_TEXT","CHANGE_REASON_PUBLIC","COMMON_TEST_RANK","COMMON_ORDER_RANK","COMMON_SI_TEST_RANK","HL7_ATTACHMENT_STRUCTURE","EXTERNAL_COPYRIGHT_LINK","PanelType","AskAtOrderEntry","AssociatedObservations"
|
||||||
|
"10013-1","R' wave amplitude.lead I","Elpot","Pt","Heart","Qn","EKG","EKG.MEAS","CH","2.48","MIN",,"ACTIVE",,2,,,,,,"Y",,"Cardiac; ECG; EKG.MEASUREMENTS; Electrical potential; Electrocardiogram; Electrocardiograph; Hrt; Painter's colic; PB; Plumbism; Point in time; QNT; Quan; Quant; Quantitative; R prime; R' wave Amp L-I; R wave Amp L-I; Random; Right; Voltage","R' wave Amp L-I","Observation",,,,"mV","R' wave amplitude in lead I",,,"mV",,,,,0,0,0,,,,,
|
||||||
|
"10014-9","R' wave amplitude.lead II","Elpot","Pt","Heart","Qn","EKG","EKG.MEAS","CH","2.48","MIN",,"ACTIVE",,2,,,,,,"Y",,"2; Cardiac; ECG; EKG.MEASUREMENTS; Electrical potential; Electrocardiogram; Electrocardiograph; Hrt; Painter's colic; PB; Plumbism; Point in time; QNT; Quan; Quant; Quantitative; R prime; R' wave Amp L-II; R wave Amp L-II; Random; Right; Voltage","R' wave Amp L-II","Observation",,,,"mV","R' wave amplitude in lead II",,,"mV",,,,,0,0,0,,,,,
|
||||||
|
"10015-6","R' wave amplitude.lead III","Elpot","Pt","Heart","Qn","EKG","EKG.MEAS","CH","2.48","MIN",,"ACTIVE",,2,,,,,,"Y",,"3; Cardiac; ECG; EKG.MEASUREMENTS; Electrical potential; Electrocardiogram; Electrocardiograph; Hrt; Painter's colic; PB; Plumbism; Point in time; QNT; Quan; Quant; Quantitative; R prime; R' wave Amp L-III; R wave Amp L-III; Random; Right; Voltage","R' wave Amp L-III","Observation",,,,"mV","R' wave amplitude in lead III",,,"mV",,,,,0,0,0,,,,,
|
||||||
|
"10016-4","R' wave amplitude.lead V1","Elpot","Pt","Heart","Qn","EKG","EKG.MEAS","CH","2.48","MIN",,"ACTIVE",,2,,,,,,"Y",,"Cardiac; ECG; EKG.MEASUREMENTS; Electrical potential; Electrocardiogram; Electrocardiograph; Hrt; Painter's colic; PB; Plumbism; Point in time; QNT; Quan; Quant; Quantitative; R prime; R' wave Amp L-V1; R wave Amp L-V1; Random; Right; Voltage","R' wave Amp L-V1","Observation",,,,"mV","R' wave amplitude in lead V1",,,"mV",,,,,0,0,0,,,,,
|
||||||
|
"1001-7","DBG Ab","Pr","Pt","Ser/Plas^donor","Ord",,"BLDBK","FS","2.44","MIN",,"ACTIVE",,1,,,,,,,,"ABS; Aby; Antby; Anti; Antibodies; Antibody; Autoantibodies; Autoantibody; BLOOD BANK; Donna Bennett-Goodspeed; Donr; Ordinal; Pl; Plasma; Plsm; Point in time; QL; Qual; Qualitative; Random; Screen; SerP; SerPl; SerPl^donor; SerPlas; Serum; Serum or plasma; SR","DBG Ab SerPl Donr Ql","Observation",,,,,"DBG Ab [Presence] in Serum or Plasma from donor",,,,,,,"The Property has been changed from ACnc to Pr (Presence) to reflect the new model for ordinal terms where results are based on presence or absence.",0,0,0,,,,,
|
||||||
|
"10017-2","R' wave amplitude.lead V2","Elpot","Pt","Heart","Qn","EKG","EKG.MEAS","CH","2.48","MIN",,"ACTIVE",,2,,,,,,"Y",,"Cardiac; ECG; EKG.MEASUREMENTS; Electrical potential; Electrocardiogram; Electrocardiograph; Hrt; Painter's colic; PB; Plumbism; Point in time; QNT; Quan; Quant; Quantitative; R prime; R' wave Amp L-V2; R wave Amp L-V2; Random; Right; Voltage","R' wave Amp L-V2","Observation",,,,"mV","R' wave amplitude in lead V2",,,"mV",,,,,0,0,0,,,,,
|
||||||
|
"10018-0","R' wave amplitude.lead V3","Elpot","Pt","Heart","Qn","EKG","EKG.MEAS","CH","2.48","MIN",,"ACTIVE",,2,,,,,,"Y",,"Cardiac; ECG; EKG.MEASUREMENTS; Electrical potential; Electrocardiogram; Electrocardiograph; Hrt; Painter's colic; PB; Plumbism; Point in time; QNT; Quan; Quant; Quantitative; R prime; R' wave Amp L-V3; R wave Amp L-V3; Random; Right; Voltage","R' wave Amp L-V3","Observation",,,,"mV","R' wave amplitude in lead V3",,,"mV",,,,,0,0,0,,,,,
|
||||||
|
"10019-8","R' wave amplitude.lead V4","Elpot","Pt","Heart","Qn","EKG","EKG.MEAS","CH","2.48","MIN",,"ACTIVE",,2,,,,,,"Y",,"Cardiac; ECG; EKG.MEASUREMENTS; Electrical potential; Electrocardiogram; Electrocardiograph; Hrt; Painter's colic; PB; Plumbism; Point in time; QNT; Quan; Quant; Quantitative; R prime; R' wave Amp L-V4; R wave Amp L-V4; Random; Right; Voltage","R' wave Amp L-V4","Observation",,,,"mV","R' wave amplitude in lead V4",,,"mV",,,,,0,0,0,,,,,
|
||||||
|
"10020-6","R' wave amplitude.lead V5","Elpot","Pt","Heart","Qn","EKG","EKG.MEAS","CH","2.48","MIN",,"ACTIVE",,2,,,,,,"Y",,"Cardiac; ECG; EKG.MEASUREMENTS; Electrical potential; Electrocardiogram; Electrocardiograph; Hrt; Painter's colic; PB; Plumbism; Point in time; QNT; Quan; Quant; Quantitative; R prime; R' wave Amp L-V5; R wave Amp L-V5; Random; Right; Voltage","R' wave Amp L-V5","Observation",,,,"mV","R' wave amplitude in lead V5",,,"mV",,,,,0,0,0,,,,,
|
|
|
@ -11,6 +11,7 @@ import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.hl7.fhir.dstu3.exceptions.TerminologyServiceException;
|
||||||
import org.hl7.fhir.dstu3.formats.IParser;
|
import org.hl7.fhir.dstu3.formats.IParser;
|
||||||
import org.hl7.fhir.dstu3.formats.ParserType;
|
import org.hl7.fhir.dstu3.formats.ParserType;
|
||||||
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport.CodeValidationResult;
|
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport.CodeValidationResult;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.hl7.fhir.dstu3.terminologies;
|
package org.hl7.fhir.dstu3.terminologies;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -46,6 +48,7 @@ import org.hl7.fhir.dstu3.model.Type;
|
||||||
import org.hl7.fhir.dstu3.model.UriType;
|
import org.hl7.fhir.dstu3.model.UriType;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||||
|
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
|
||||||
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
|
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent;
|
import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||||
|
@ -144,20 +147,16 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void includeCodes(ConceptSetComponent inc, List<ValueSetExpansionParameterComponent> params) throws TerminologyServiceException, ETooCostly {
|
private void includeCodes(ConceptSetComponent inc, List<ValueSetExpansionParameterComponent> params) throws TerminologyServiceException, ETooCostly {
|
||||||
if (context.supportsSystem(inc.getSystem())) {
|
CodeSystem cs = context.fetchCodeSystem(inc.getSystem());
|
||||||
try {
|
if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(inc.getSystem())) {
|
||||||
int i = codes.size();
|
|
||||||
addCodes(context.expandVS(inc), params);
|
addCodes(context.expandVS(inc), params);
|
||||||
if (codes.size() > i)
|
return;
|
||||||
return;
|
|
||||||
} catch (Exception e) {
|
|
||||||
// ok, we'll try locally
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeSystem cs = context.fetchCodeSystem(inc.getSystem());
|
if (cs == null)
|
||||||
if (cs == null)
|
throw new TerminologyServiceException("unable to find code system "+inc.getSystem().toString());
|
||||||
throw new TerminologyServiceException("unable to find code system "+inc.getSystem().toString());
|
if (cs.getContent() != CodeSystemContentMode.COMPLETE)
|
||||||
|
throw new TerminologyServiceException("Code system "+inc.getSystem().toString()+" is incomplete");
|
||||||
if (cs.hasVersion())
|
if (cs.hasVersion())
|
||||||
if (!existsInParams(params, "version", new UriType(cs.getUrl()+"?version="+cs.getVersion())))
|
if (!existsInParams(params, "version", new UriType(cs.getUrl()+"?version="+cs.getVersion())))
|
||||||
params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(cs.getUrl()+"?version="+cs.getVersion())));
|
params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(cs.getUrl()+"?version="+cs.getVersion())));
|
||||||
|
@ -181,8 +180,17 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
|
||||||
if (def == null)
|
if (def == null)
|
||||||
throw new TerminologyServiceException("Code '"+fc.getValue()+"' not found in system '"+inc.getSystem()+"'");
|
throw new TerminologyServiceException("Code '"+fc.getValue()+"' not found in system '"+inc.getSystem()+"'");
|
||||||
addCodeAndDescendents(cs, inc.getSystem(), def);
|
addCodeAndDescendents(cs, inc.getSystem(), def);
|
||||||
|
} else if ("display".equals(fc.getProperty()) && fc.getOp() == FilterOperator.EQUAL) {
|
||||||
|
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||||
|
if (def != null) {
|
||||||
|
if (isNotBlank(def.getDisplay()) && isNotBlank(fc.getValue())) {
|
||||||
|
if (def.getDisplay().contains(fc.getValue())) {
|
||||||
|
addCode(inc.getSystem(), def.getCode(), def.getDisplay());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
throw new NotImplementedException("not done yet");
|
throw new NotImplementedException("Search by property[" + fc.getProperty() + "] and op[" + fc.getOp() + "] is not supported yet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue