Merge branch 'master' of github.com:jamesagnew/hapi-fhir
This commit is contained in:
commit
de1796d114
|
@ -3,8 +3,6 @@ package ca.uhn.fhir.jpa.config.dstu3;
|
|||
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.HapiWorkerContext;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander;
|
||||
import org.hl7.fhir.dstu3.utils.IWorkerContext;
|
||||
import org.hl7.fhir.dstu3.validation.IResourceValidator.BestPracticeWarningLevel;
|
||||
|
||||
/*
|
||||
|
@ -41,7 +39,7 @@ import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
|||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamExtractorDstu3;
|
||||
import ca.uhn.fhir.jpa.term.HapiTerminologySvcDstu3;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcDstu3;
|
||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
|
||||
|
@ -50,7 +48,7 @@ import ca.uhn.fhir.validation.IValidatorModule;
|
|||
public class BaseDstu3Config extends BaseConfig {
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IHapiTerminologySvc terminologyService() {
|
||||
public IHapiTerminologySvcDstu3 terminologyService() {
|
||||
return new HapiTerminologySvcDstu3();
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,6 @@ import org.springframework.transaction.TransactionStatus;
|
|||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
|
@ -1384,6 +1383,7 @@ public class SearchBuilder {
|
|||
} else if (modifier == TokenParamModifier.BELOW) {
|
||||
codes = myTerminologySvc.findCodesBelow(system, code);
|
||||
}
|
||||
|
||||
if (codes != null) {
|
||||
if (codes.isEmpty()) {
|
||||
return null;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.dao.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -28,6 +30,9 @@ import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
|||
|
||||
public interface ITermCodeSystemVersionDao extends JpaRepository<TermCodeSystemVersion, Long> {
|
||||
|
||||
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myResource.myId = :resource_id")
|
||||
List<TermCodeSystemVersion> findByCodeSystemResource(@Param("resource_id") Long theCodeSystemResourcePid);
|
||||
|
||||
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myResource.myId = :resource_id AND cs.myResourceVersionId = :version_id")
|
||||
TermCodeSystemVersion findByCodeSystemResourceAndVersion(@Param("resource_id") Long theCodeSystemResourcePid, @Param("version_id") Long theCodeSystemVersionPid);
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.dao.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -21,6 +23,7 @@ package ca.uhn.fhir.jpa.dao.data;
|
|||
*/
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
|
@ -32,4 +35,11 @@ public interface ITermConceptDao extends JpaRepository<TermConcept, Long> {
|
|||
@Query("SELECT c FROM TermConcept c WHERE c.myCodeSystem = :code_system AND c.myCode = :code")
|
||||
TermConcept findByCodeSystemAndCode(@Param("code_system") TermCodeSystemVersion theCodeSystem, @Param("code") String theCode);
|
||||
|
||||
@Query("SELECT c FROM TermConcept c WHERE c.myCodeSystem = :code_system")
|
||||
List<TermConcept> findByCodeSystemVersion(@Param("code_system") TermCodeSystemVersion theCodeSystem);
|
||||
|
||||
@Query("DELETE FROM TermConcept t WHERE t.myCodeSystem.myId = :cs_pid")
|
||||
@Modifying
|
||||
void deleteByCodeSystemVersion(@Param("cs_pid") Long thePid);
|
||||
|
||||
}
|
||||
|
|
|
@ -21,9 +21,16 @@ package ca.uhn.fhir.jpa.dao.data;
|
|||
*/
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||
|
||||
public interface ITermConceptParentChildLinkDao extends JpaRepository<TermConceptParentChildLink, Long> {
|
||||
// nothing
|
||||
|
||||
@Query("DELETE FROM TermConceptParentChildLink t WHERE t.myCodeSystem.myId = :cs_pid")
|
||||
@Modifying
|
||||
void deleteByCodeSystemVersion(@Param("cs_pid") Long thePid);
|
||||
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.dstu3.hapi.validation.HapiWorkerContext;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport.CodeValidationResult;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.ValidationSupportChain;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
|
||||
|
@ -35,10 +35,7 @@ import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
|
|||
import org.hl7.fhir.dstu3.model.CodeableConcept;
|
||||
import org.hl7.fhir.dstu3.model.Coding;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander;
|
||||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
@ -53,7 +50,6 @@ import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
|||
import ca.uhn.fhir.jpa.util.LogicUtil;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSystem> implements IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> {
|
||||
|
@ -77,29 +73,29 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
|
|||
return valueSetIds;
|
||||
}
|
||||
|
||||
private LookupCodeResult lookup(List<ValueSetExpansionContainsComponent> theContains, String theSystem, String theCode) {
|
||||
for (ValueSetExpansionContainsComponent nextCode : theContains) {
|
||||
|
||||
String system = nextCode.getSystem();
|
||||
String code = nextCode.getCode();
|
||||
if (theSystem.equals(system) && theCode.equals(code)) {
|
||||
LookupCodeResult retVal = new LookupCodeResult();
|
||||
retVal.setSearchedForCode(code);
|
||||
retVal.setSearchedForSystem(system);
|
||||
retVal.setFound(true);
|
||||
if (nextCode.getAbstractElement().getValue() != null) {
|
||||
retVal.setCodeIsAbstract(nextCode.getAbstractElement().booleanValue());
|
||||
}
|
||||
retVal.setCodeDisplay(nextCode.getDisplay());
|
||||
retVal.setCodeSystemVersion(nextCode.getVersion());
|
||||
retVal.setCodeSystemDisplayName("Unknown"); // TODO: implement
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
// private LookupCodeResult lookup(List<ValueSetExpansionContainsComponent> theContains, String theSystem, String theCode) {
|
||||
// for (ValueSetExpansionContainsComponent nextCode : theContains) {
|
||||
//
|
||||
// String system = nextCode.getSystem();
|
||||
// String code = nextCode.getCode();
|
||||
// if (theSystem.equals(system) && theCode.equals(code)) {
|
||||
// LookupCodeResult retVal = new LookupCodeResult();
|
||||
// retVal.setSearchedForCode(code);
|
||||
// retVal.setSearchedForSystem(system);
|
||||
// retVal.setFound(true);
|
||||
// if (nextCode.getAbstractElement().getValue() != null) {
|
||||
// retVal.setCodeIsAbstract(nextCode.getAbstractElement().booleanValue());
|
||||
// }
|
||||
// retVal.setCodeDisplay(nextCode.getDisplay());
|
||||
// retVal.setCodeSystemVersion(nextCode.getVersion());
|
||||
// retVal.setCodeSystemDisplayName("Unknown"); // TODO: implement
|
||||
// return retVal;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, Coding theCoding, RequestDetails theRequestDetails) {
|
||||
|
@ -138,47 +134,40 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
|
|||
// return result;
|
||||
|
||||
if (myValidationSupport.isCodeSystemSupported(getContext(), system)) {
|
||||
HapiWorkerContext ctx = new HapiWorkerContext(getContext(), myValidationSupport);
|
||||
ValueSetExpander expander = ctx.getExpander();
|
||||
ValueSet source = new ValueSet();
|
||||
source.getCompose().addInclude().setSystem(system).addConcept().setCode(code);
|
||||
|
||||
ValueSetExpansionOutcome expansion;
|
||||
try {
|
||||
expansion = expander.expand(source);
|
||||
} catch (Exception e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
|
||||
if (expansion.getValueset() != null) {
|
||||
List<ValueSetExpansionContainsComponent> contains = expansion.getValueset().getExpansion().getContains();
|
||||
LookupCodeResult result = lookup(contains, system, code);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/*
|
||||
* If it's not a built-in code system, use ones from the database
|
||||
*/
|
||||
|
||||
List<IIdType> valueSetIds = findCodeSystemIdsContainingSystemAndCode(code, system);
|
||||
for (IIdType nextId : valueSetIds) {
|
||||
CodeSystem expansion = read(nextId, theRequestDetails);
|
||||
for (ConceptDefinitionComponent next : expansion.getConcept()) {
|
||||
if (code.equals(next.getCode())) {
|
||||
LookupCodeResult retVal = new LookupCodeResult();
|
||||
retVal.setSearchedForCode(code);
|
||||
retVal.setSearchedForSystem(system);
|
||||
retVal.setFound(true);
|
||||
retVal.setCodeDisplay(next.getDisplay());
|
||||
retVal.setCodeSystemDisplayName("Unknown"); // TODO: implement
|
||||
return retVal;
|
||||
}
|
||||
|
||||
CodeValidationResult result = myValidationSupport.validateCode(getContext(), system, code, null);
|
||||
if (result != null) {
|
||||
if (result.isOk()) {
|
||||
LookupCodeResult retVal = new LookupCodeResult();
|
||||
retVal.setFound(true);
|
||||
retVal.setSearchedForCode(code);
|
||||
retVal.setSearchedForSystem(system);
|
||||
retVal.setCodeDisplay(result.getDisplay());
|
||||
retVal.setCodeSystemDisplayName("Unknown");
|
||||
retVal.setCodeSystemVersion("");
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
// HapiWorkerContext ctx = new HapiWorkerContext(getContext(), myValidationSupport);
|
||||
// ValueSetExpander expander = ctx.getExpander();
|
||||
// ValueSet source = new ValueSet();
|
||||
// source.getCompose().addInclude().setSystem(system).addConcept().setCode(code);
|
||||
//
|
||||
// ValueSetExpansionOutcome expansion;
|
||||
// try {
|
||||
// expansion = expander.expand(source);
|
||||
// } catch (Exception e) {
|
||||
// throw new InternalErrorException(e);
|
||||
// }
|
||||
//
|
||||
// if (expansion.getValueset() != null) {
|
||||
// List<ValueSetExpansionContainsComponent> contains = expansion.getValueset().getExpansion().getContains();
|
||||
// LookupCodeResult result = lookup(contains, system, code);
|
||||
// if (result != null) {
|
||||
// return result;
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
@ -217,8 +206,8 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
|
|||
|
||||
if (cs != null && isNotBlank(cs.getUrl())) {
|
||||
String codeSystemUrl = cs.getUrl();
|
||||
if (cs.getContent() == CodeSystemContentMode.COMPLETE) {
|
||||
ourLog.info("CodeSystem {} has a status of {}, going to store concepts in terminology tables", retVal.getIdDt().getValue(), cs.getContent().toCode());
|
||||
if (cs.getContent() == CodeSystemContentMode.COMPLETE || cs.getContent() == null) {
|
||||
ourLog.info("CodeSystem {} has a status of {}, going to store concepts in terminology tables", retVal.getIdDt().getValue(), cs.getContentElement().getValueAsString());
|
||||
TermCodeSystemVersion persCs = new TermCodeSystemVersion();
|
||||
persCs.setResource(retVal);
|
||||
persCs.setResourceVersionId(retVal.getVersion());
|
||||
|
|
|
@ -54,7 +54,7 @@ public class TermCodeSystemVersion implements Serializable {
|
|||
@SequenceGenerator(name = "SEQ_CODESYSTEMVER_PID", sequenceName = "SEQ_CODESYSTEMVER_PID")
|
||||
@GeneratedValue(strategy=GenerationType.AUTO, generator="SEQ_CODESYSTEMVER_PID")
|
||||
@Column(name = "PID")
|
||||
private Long myPid;
|
||||
private Long myId;
|
||||
|
||||
@OneToOne()
|
||||
@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", nullable = false, updatable = false, foreignKey=@ForeignKey(name="FK_CODESYSVER_RES_ID"))
|
||||
|
@ -70,6 +70,10 @@ public class TermCodeSystemVersion implements Serializable {
|
|||
return myConcepts;
|
||||
}
|
||||
|
||||
public Long getPid() {
|
||||
return myId;
|
||||
}
|
||||
|
||||
public ResourceTable getResource() {
|
||||
return myResource;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jboss.logging.MDC;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
|
|
|
@ -79,5 +79,4 @@ public class BaseJpaResourceProviderCodeSystemDstu3 extends JpaResourceProviderD
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package ca.uhn.fhir.jpa.provider.dstu3;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.Attachment;
|
||||
import org.hl7.fhir.dstu3.model.IntegerType;
|
||||
import org.hl7.fhir.dstu3.model.Parameters;
|
||||
import org.hl7.fhir.dstu3.model.UriType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import ca.uhn.fhir.jpa.provider.BaseJpaProvider;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||
import ca.uhn.fhir.rest.annotation.Operation;
|
||||
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
public class TerminologyUploaderProviderDstu3 extends BaseJpaProvider {
|
||||
|
||||
@Autowired
|
||||
private IHapiTerminologyLoaderSvc myTerminologyLoaderSvc;
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name = "$upload-external-code-system", idempotent = false, returnParameters= {
|
||||
@OperationParam(name="conceptCount", type=IntegerType.class, min=1)
|
||||
})
|
||||
public Parameters lookup(
|
||||
HttpServletRequest theServletRequest,
|
||||
@OperationParam(name="url", min=1) UriType theUrl,
|
||||
@OperationParam(name="package", min=1) Attachment thePackage,
|
||||
RequestDetails theRequestDetails
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
startRequest(theServletRequest);
|
||||
try {
|
||||
byte[] data = thePackage.getData();
|
||||
String url = theUrl.getValueAsString();
|
||||
|
||||
if (IHapiTerminologyLoaderSvc.SCT_URL.equals(url)) {
|
||||
myTerminologyLoaderSvc.loadSnomedCt(data, theRequestDetails);
|
||||
} else {
|
||||
throw new InvalidRequestException("Unknown URL: " + url);
|
||||
}
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("conceptCount").setValue(new IntegerType(0));
|
||||
return retVal;
|
||||
} finally {
|
||||
endRequest(theServletRequest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -36,7 +36,6 @@ import com.google.common.base.Stopwatch;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
|
||||
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ITermConceptDao;
|
||||
|
@ -45,7 +44,6 @@ import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
|||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.ObjectUtil;
|
||||
|
@ -62,7 +60,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
|||
private ITermCodeSystemVersionDao myCodeSystemVersionDao;
|
||||
|
||||
@Autowired
|
||||
private ITermConceptDao myConceptDao;
|
||||
protected ITermConceptDao myConceptDao;
|
||||
|
||||
@Autowired
|
||||
private DaoConfig myDaoConfig;
|
||||
|
@ -129,7 +127,10 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
|||
|
||||
@Override
|
||||
public List<VersionIndependentConcept> findCodesAbove(String theSystem, String theCode) {
|
||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(theSystem);
|
||||
TermCodeSystem cs = getCodeSystem(theSystem);
|
||||
if (cs == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
TermCodeSystemVersion csv = cs.getCurrentVersion();
|
||||
|
||||
Set<TermConcept> codes = findCodesAbove(cs.getResource().getId(), csv.getResourceVersionId(), theCode);
|
||||
|
@ -158,7 +159,10 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
|||
|
||||
@Override
|
||||
public List<VersionIndependentConcept> findCodesBelow(String theSystem, String theCode) {
|
||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(theSystem);
|
||||
TermCodeSystem cs = getCodeSystem(theSystem);
|
||||
if (cs == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
TermCodeSystemVersion csv = cs.getCurrentVersion();
|
||||
|
||||
Set<TermConcept> codes = findCodesBelow(cs.getResource().getId(), csv.getResourceVersionId(), theCode);
|
||||
|
@ -194,7 +198,10 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
|||
ValidateUtil.isNotNullOrThrowInvalidRequest(theCodeSystem.getResource() != null, "No resource supplied");
|
||||
ValidateUtil.isNotBlankOrThrowInvalidRequest(theSystemUri, "No system URI supplied");
|
||||
|
||||
TermCodeSystem codeSystem = myCodeSystemDao.findByCodeSystemUri(theSystemUri);
|
||||
// Grab the existing versions so we can delete them later
|
||||
List<TermCodeSystemVersion> existing = myCodeSystemVersionDao.findByCodeSystemResource(theCodeSystemResourcePid);
|
||||
|
||||
TermCodeSystem codeSystem = getCodeSystem(theSystemUri);
|
||||
if (codeSystem == null) {
|
||||
codeSystem = myCodeSystemDao.findByResourcePid(theCodeSystemResourcePid);
|
||||
if (codeSystem == null) {
|
||||
|
@ -233,14 +240,33 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
|||
for (TermConcept next : theCodeSystem.getConcepts()) {
|
||||
persistChildren(next, theCodeSystem, conceptsStack);
|
||||
}
|
||||
|
||||
/*
|
||||
* For now we always delete old versions.. At some point it would be
|
||||
* nice to allow configuration to keep old versions
|
||||
*/
|
||||
|
||||
ourLog.info("Deleting old sode system versions");
|
||||
for (TermCodeSystemVersion next : existing) {
|
||||
ourLog.info(" * Deleting code system version {}", next.getPid());
|
||||
myConceptParentChildLinkDao.deleteByCodeSystemVersion(next.getPid());
|
||||
myConceptDao.deleteByCodeSystemVersion(next.getPid());
|
||||
}
|
||||
|
||||
ourLog.info("Done saving code system");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSystem(String theSystem) {
|
||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(theSystem);
|
||||
TermCodeSystem cs = getCodeSystem(theSystem);
|
||||
return cs != null;
|
||||
}
|
||||
|
||||
private TermCodeSystem getCodeSystem(String theSystem) {
|
||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(theSystem);
|
||||
return cs;
|
||||
}
|
||||
|
||||
private ArrayList<VersionIndependentConcept> toVersionIndependentConcepts(String theSystem, Set<TermConcept> codes) {
|
||||
ArrayList<VersionIndependentConcept> retVal = new ArrayList<VersionIndependentConcept>(codes.size());
|
||||
for (TermConcept next : codes) {
|
||||
|
@ -265,5 +291,15 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
|||
theConceptsStack.remove(theConcept);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.term;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -21,37 +23,46 @@ package ca.uhn.fhir.jpa.term;
|
|||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
|
||||
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.CodeableConcept;
|
||||
import org.hl7.fhir.dstu3.model.Coding;
|
||||
import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetFilterComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander;
|
||||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.dstu3.utils.IWorkerContext;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
|
||||
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc {
|
||||
public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc implements IValidationSupport, IHapiTerminologySvcDstu3 {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(HapiTerminologySvcDstu3.class);
|
||||
|
||||
@Autowired
|
||||
private IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> myCodeSystemResourceDao;
|
||||
|
||||
@Autowired
|
||||
private IWorkerContext myWorkerContext;
|
||||
|
||||
@Autowired
|
||||
private ValueSetExpander myValueSetExpander;
|
||||
|
||||
|
@ -92,4 +103,81 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||
String system = theInclude.getSystem();
|
||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system);
|
||||
TermCodeSystemVersion csv = cs.getCurrentVersion();
|
||||
|
||||
ValueSetExpansionComponent retVal = new ValueSetExpansionComponent();
|
||||
|
||||
boolean haveSpecificWantedCode = false;
|
||||
for (ConceptReferenceComponent next : theInclude.getConcept()) {
|
||||
String nextCode = next.getCode();
|
||||
if (isNotBlank(nextCode)) {
|
||||
haveSpecificWantedCode = true;
|
||||
TermConcept termCode = myConceptDao.findByCodeSystemAndCode(csv, nextCode);
|
||||
if (termCode != null) {
|
||||
addCodeIfFilterMatches(retVal, termCode, theInclude.getFilter(), nextCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!haveSpecificWantedCode) {
|
||||
for(TermConcept next : myConceptDao.findByCodeSystemVersion(csv)) {
|
||||
addCodeIfFilterMatches(retVal, next, theInclude.getFilter(), system);
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void addCodeIfFilterMatches(ValueSetExpansionComponent retVal, TermConcept termCode, List<ConceptSetFilterComponent> theFilters, String theSystem) {
|
||||
ValueSetExpansionContainsComponent contains = retVal.addContains();
|
||||
contains.setSystem(theSystem);
|
||||
contains.setCode(termCode.getCode());
|
||||
contains.setDisplay(termCode.getDisplay());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||
return super.supportsSystem(theSystem);
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||
TermConcept code = super.findCode(theCodeSystem, theCode);
|
||||
if (code != null) {
|
||||
ConceptDefinitionComponent def = new ConceptDefinitionComponent();
|
||||
def.setCode(code.getCode());
|
||||
def.setDisplay(code.getDisplay());
|
||||
return new CodeValidationResult(def);
|
||||
}
|
||||
|
||||
return new CodeValidationResult(IssueSeverity.ERROR, "Unkonwn code {" + theCodeSystem +"}" + theCode);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package ca.uhn.fhir.jpa.term;
|
||||
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
|
||||
public interface IHapiTerminologyLoaderSvc {
|
||||
|
||||
String SCT_URL = "http://snomed.info/sct";
|
||||
|
||||
void loadSnomedCt(byte[] theZipBytes, RequestDetails theRequestDetails);
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.term;
|
||||
|
||||
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
|
||||
|
||||
public interface IHapiTerminologySvcDstu3 extends IHapiTerminologySvc, IValidationSupport {
|
||||
// nothing
|
||||
}
|
|
@ -21,20 +21,16 @@ package ca.uhn.fhir.jpa.term;
|
|||
*/
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
@ -50,7 +46,6 @@ import org.apache.commons.csv.CSVParser;
|
|||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
@ -62,101 +57,20 @@ import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
|
|||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
|
||||
public class TerminologyLoaderSvc {
|
||||
static final String SCT_FILE_RELATIONSHIP = "Terminology/sct2_Relationship_Full";
|
||||
static final String SCT_FILE_DESCRIPTION = "Terminology/sct2_Description_Full";
|
||||
static final String SCT_FILE_CONCEPT = "Terminology/sct2_Concept_Full";
|
||||
|
||||
public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyLoaderSvc.class);
|
||||
static final String SCT_FILE_CONCEPT = "Terminology/sct2_Concept_Full";
|
||||
static final String SCT_FILE_DESCRIPTION = "Terminology/sct2_Description_Full";
|
||||
|
||||
static final String SCT_FILE_RELATIONSHIP = "Terminology/sct2_Relationship_Full";
|
||||
|
||||
|
||||
@Autowired
|
||||
private IHapiTerminologySvc myTermSvc;
|
||||
|
||||
@VisibleForTesting
|
||||
void setTermSvcForUnitTests(IHapiTerminologySvc theTermSvc) {
|
||||
myTermSvc = theTermSvc;
|
||||
}
|
||||
|
||||
public void loadSnomedCt(byte[] theZipBytes, RequestDetails theRequestDetails) {
|
||||
List<String> allFilenames = Arrays.asList(SCT_FILE_DESCRIPTION, SCT_FILE_RELATIONSHIP, SCT_FILE_CONCEPT);
|
||||
|
||||
Map<String, File> filenameToFile = new HashMap<String, File>();
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(theZipBytes)));
|
||||
try {
|
||||
for (ZipEntry nextEntry; (nextEntry = zis.getNextEntry()) != null;) {
|
||||
ZippedFileInputStream inputStream = new ZippedFileInputStream(zis);
|
||||
|
||||
boolean want = false;
|
||||
for (String next : allFilenames) {
|
||||
if (nextEntry.getName().contains(next)) {
|
||||
want = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!want) {
|
||||
ourLog.info("Ignoring zip entry: {}", nextEntry.getName());
|
||||
continue;
|
||||
}
|
||||
|
||||
ourLog.debug("Streaming ZIP entry {} into temporary file", nextEntry.getName());
|
||||
|
||||
File nextOutFile = File.createTempFile("hapi_fhir", ".csv");
|
||||
nextOutFile.deleteOnExit();
|
||||
OutputStream outputStream = new SinkOutputStream(new FileOutputStream(nextOutFile, false), nextEntry.getName());
|
||||
try {
|
||||
IOUtils.copyLarge(inputStream, outputStream);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(outputStream);
|
||||
}
|
||||
|
||||
filenameToFile.put(nextEntry.getName(), nextOutFile);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new InternalErrorException(e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(zis);
|
||||
}
|
||||
|
||||
ourLog.info("Beginning SNOMED CT processing");
|
||||
|
||||
processSnomedCtFiles(filenameToFile,theRequestDetails);
|
||||
}
|
||||
|
||||
void processSnomedCtFiles(Map<String, File> filenameToFile, RequestDetails theRequestDetails) {
|
||||
final TermCodeSystemVersion codeSystemVersion = new TermCodeSystemVersion();
|
||||
final Map<String, TermConcept> id2concept = new HashMap<String, TermConcept>();
|
||||
final Map<String, TermConcept> code2concept = new HashMap<String, TermConcept>();
|
||||
final Set<String> validConceptIds = new HashSet<String>();
|
||||
final List<TermConceptParentChildLink> links = new ArrayList<TermConceptParentChildLink>();
|
||||
|
||||
IRecordHandler handler = new SctHandlerConcept(validConceptIds);
|
||||
iterateOverZipFile(filenameToFile, SCT_FILE_CONCEPT, handler);
|
||||
|
||||
ourLog.info("Have {} valid concept IDs", validConceptIds.size());
|
||||
|
||||
handler = new SctHandlerDescription(validConceptIds, code2concept, id2concept, codeSystemVersion);
|
||||
iterateOverZipFile(filenameToFile, SCT_FILE_DESCRIPTION, handler);
|
||||
|
||||
ourLog.info("Got {} concepts, cloning map", code2concept.size());
|
||||
final HashMap<String, TermConcept> rootConcepts = new HashMap<String, TermConcept>(code2concept);
|
||||
|
||||
handler = new SctHandlerRelationship(codeSystemVersion, rootConcepts, code2concept);
|
||||
iterateOverZipFile(filenameToFile, SCT_FILE_RELATIONSHIP, handler);
|
||||
|
||||
ourLog.info("Done loading SNOMED CT files - {} root codes, {} total codes", rootConcepts.size(), code2concept.size());
|
||||
|
||||
|
||||
for (TermConcept next : rootConcepts.values()){
|
||||
dropCircularRefs(next, new HashSet<String>());
|
||||
}
|
||||
|
||||
codeSystemVersion.getConcepts().addAll(rootConcepts.values());
|
||||
myTermSvc.storeNewCodeSystemVersion("http://snomed.info/sct", codeSystemVersion, theRequestDetails);
|
||||
}
|
||||
|
||||
private void dropCircularRefs(TermConcept theConcept, HashSet<String> theChain) {
|
||||
|
||||
for (Iterator<TermConceptParentChildLink> childIter = theConcept.getChildren().iterator(); childIter.hasNext(); ) {
|
||||
|
||||
for (Iterator<TermConceptParentChildLink> childIter = theConcept.getChildren().iterator(); childIter.hasNext();) {
|
||||
TermConceptParentChildLink next = childIter.next();
|
||||
TermConcept nextChild = next.getChild();
|
||||
if (theChain.contains(nextChild.getCode())) {
|
||||
|
@ -170,6 +84,16 @@ public class TerminologyLoaderSvc {
|
|||
}
|
||||
}
|
||||
|
||||
private TermConcept getOrCreateConcept(TermCodeSystemVersion codeSystemVersion, Map<String, TermConcept> id2concept, String id) {
|
||||
TermConcept concept = id2concept.get(id);
|
||||
if (concept == null) {
|
||||
concept = new TermConcept();
|
||||
id2concept.put(id, concept);
|
||||
concept.setCodeSystem(codeSystemVersion);
|
||||
}
|
||||
return concept;
|
||||
}
|
||||
|
||||
private void iterateOverZipFile(Map<String, File> theFilenameToFile, String fileNamePart, IRecordHandler handler) {
|
||||
for (Entry<String, File> nextEntry : theFilenameToFile.entrySet()) {
|
||||
|
||||
|
@ -206,79 +130,134 @@ public class TerminologyLoaderSvc {
|
|||
}
|
||||
}
|
||||
|
||||
private TermConcept getOrCreateConcept(TermCodeSystemVersion codeSystemVersion, Map<String, TermConcept> id2concept, String id) {
|
||||
TermConcept concept = id2concept.get(id);
|
||||
if (concept == null) {
|
||||
concept = new TermConcept();
|
||||
id2concept.put(id, concept);
|
||||
concept.setCodeSystem(codeSystemVersion);
|
||||
@Override
|
||||
public void loadSnomedCt(byte[] theZipBytes, RequestDetails theRequestDetails) {
|
||||
List<String> allFilenames = Arrays.asList(SCT_FILE_DESCRIPTION, SCT_FILE_RELATIONSHIP, SCT_FILE_CONCEPT);
|
||||
|
||||
Map<String, File> filenameToFile = new HashMap<String, File>();
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(theZipBytes)));
|
||||
try {
|
||||
for (ZipEntry nextEntry; (nextEntry = zis.getNextEntry()) != null;) {
|
||||
ZippedFileInputStream inputStream = new ZippedFileInputStream(zis);
|
||||
|
||||
boolean want = false;
|
||||
for (String next : allFilenames) {
|
||||
if (nextEntry.getName().contains(next)) {
|
||||
want = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!want) {
|
||||
ourLog.info("Ignoring zip entry: {}", nextEntry.getName());
|
||||
continue;
|
||||
}
|
||||
|
||||
ourLog.debug("Streaming ZIP entry {} into temporary file", nextEntry.getName());
|
||||
|
||||
File nextOutFile = File.createTempFile("hapi_fhir", ".csv");
|
||||
nextOutFile.deleteOnExit();
|
||||
OutputStream outputStream = new SinkOutputStream(new FileOutputStream(nextOutFile, false), nextEntry.getName());
|
||||
try {
|
||||
IOUtils.copyLarge(inputStream, outputStream);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(outputStream);
|
||||
}
|
||||
|
||||
filenameToFile.put(nextEntry.getName(), nextOutFile);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new InternalErrorException(e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(zis);
|
||||
}
|
||||
|
||||
ourLog.info("Beginning SNOMED CT processing");
|
||||
|
||||
try {
|
||||
processSnomedCtFiles(filenameToFile, theRequestDetails);
|
||||
} finally {
|
||||
ourLog.info("Finished SNOMED CT file import, cleaning up temporary files");
|
||||
for (File nextFile : filenameToFile.values()) {
|
||||
nextFile.delete();
|
||||
}
|
||||
}
|
||||
return concept;
|
||||
}
|
||||
|
||||
private final class SctHandlerRelationship implements IRecordHandler {
|
||||
private final TermCodeSystemVersion myCodeSystemVersion;
|
||||
private final Map<String, TermConcept> myRootConcepts;
|
||||
private final Map<String, TermConcept> myCode2concept;
|
||||
void processSnomedCtFiles(Map<String, File> filenameToFile, RequestDetails theRequestDetails) {
|
||||
final TermCodeSystemVersion codeSystemVersion = new TermCodeSystemVersion();
|
||||
final Map<String, TermConcept> id2concept = new HashMap<String, TermConcept>();
|
||||
final Map<String, TermConcept> code2concept = new HashMap<String, TermConcept>();
|
||||
final Set<String> validConceptIds = new HashSet<String>();
|
||||
|
||||
private SctHandlerRelationship(TermCodeSystemVersion theCodeSystemVersion, HashMap<String,TermConcept> theRootConcepts, Map<String, TermConcept> theCode2concept) {
|
||||
myCodeSystemVersion = theCodeSystemVersion;
|
||||
myRootConcepts = theRootConcepts;
|
||||
myCode2concept = theCode2concept;
|
||||
IRecordHandler handler = new SctHandlerConcept(validConceptIds);
|
||||
iterateOverZipFile(filenameToFile, SCT_FILE_CONCEPT, handler);
|
||||
|
||||
ourLog.info("Have {} valid concept IDs", validConceptIds.size());
|
||||
|
||||
handler = new SctHandlerDescription(validConceptIds, code2concept, id2concept, codeSystemVersion);
|
||||
iterateOverZipFile(filenameToFile, SCT_FILE_DESCRIPTION, handler);
|
||||
|
||||
ourLog.info("Got {} concepts, cloning map", code2concept.size());
|
||||
final HashMap<String, TermConcept> rootConcepts = new HashMap<String, TermConcept>(code2concept);
|
||||
|
||||
handler = new SctHandlerRelationship(codeSystemVersion, rootConcepts, code2concept);
|
||||
iterateOverZipFile(filenameToFile, SCT_FILE_RELATIONSHIP, handler);
|
||||
|
||||
ourLog.info("Done loading SNOMED CT files - {} root codes, {} total codes", rootConcepts.size(), code2concept.size());
|
||||
|
||||
for (TermConcept next : rootConcepts.values()) {
|
||||
dropCircularRefs(next, new HashSet<String>());
|
||||
}
|
||||
|
||||
codeSystemVersion.getConcepts().addAll(rootConcepts.values());
|
||||
myTermSvc.storeNewCodeSystemVersion(SCT_URL, codeSystemVersion, theRequestDetails);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setTermSvcForUnitTests(IHapiTerminologySvc theTermSvc) {
|
||||
myTermSvc = theTermSvc;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
TerminologyLoaderSvc svc = new TerminologyLoaderSvc();
|
||||
|
||||
// byte[] bytes = IOUtils.toByteArray(new FileInputStream("/Users/james/Downloads/SnomedCT_Release_INT_20160131_Full.zip"));
|
||||
// svc.loadSnomedCt(bytes);
|
||||
|
||||
Map<String, File> files = new HashMap<String, File>();
|
||||
files.put(SCT_FILE_CONCEPT, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Concept_Full_INT_20160131.txt"));
|
||||
files.put(SCT_FILE_DESCRIPTION, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Description_Full-en_INT_20160131.txt"));
|
||||
files.put(SCT_FILE_RELATIONSHIP, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Relationship_Full_INT_20160131.txt"));
|
||||
svc.processSnomedCtFiles(files, null);
|
||||
}
|
||||
|
||||
private interface IRecordHandler {
|
||||
void accept(CSVRecord theRecord);
|
||||
}
|
||||
|
||||
private final class SctHandlerConcept implements IRecordHandler {
|
||||
|
||||
private Set<String> myValidConceptIds;
|
||||
|
||||
public SctHandlerConcept(Set<String> theValidConceptIds) {
|
||||
myValidConceptIds = theValidConceptIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(CSVRecord theRecord) {
|
||||
Set<String> ignoredTypes = new HashSet<String>();
|
||||
ignoredTypes.add("Method (attribute)");
|
||||
ignoredTypes.add("Direct device (attribute)");
|
||||
ignoredTypes.add("Has focus (attribute)");
|
||||
ignoredTypes.add("Access instrument");
|
||||
ignoredTypes.add("Procedure site (attribute)");
|
||||
ignoredTypes.add("Causative agent (attribute)");
|
||||
ignoredTypes.add("Course (attribute)");
|
||||
ignoredTypes.add("Finding site (attribute)");
|
||||
ignoredTypes.add("Has definitional manifestation (attribute)");
|
||||
|
||||
String sourceId = theRecord.get("sourceId");
|
||||
String destinationId = theRecord.get("destinationId");
|
||||
String typeId = theRecord.get("typeId");
|
||||
String id = theRecord.get("id");
|
||||
boolean active = "1".equals(theRecord.get("active"));
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
TermConcept typeConcept = findConcept(myCode2concept, typeId);
|
||||
TermConcept sourceConcept = findConcept(myCode2concept, sourceId);
|
||||
TermConcept targetConcept = findConcept(myCode2concept, destinationId);
|
||||
if (typeConcept.getDisplay().equals("Is a (attribute)")) {
|
||||
TermConceptParentChildLink link = new TermConceptParentChildLink();
|
||||
link.setChild(sourceConcept);
|
||||
link.setParent(targetConcept);
|
||||
link.setRelationshipType(TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
||||
link.setCodeSystem(myCodeSystemVersion);
|
||||
myRootConcepts.remove(link.getChild().getCode());
|
||||
|
||||
targetConcept.addChild(sourceConcept, RelationshipTypeEnum.ISA);
|
||||
} else if (ignoredTypes.contains(typeConcept.getDisplay())) {
|
||||
// ignore
|
||||
} else {
|
||||
// ourLog.warn("Unknown relationship type: {}/{}", typeId, typeConcept.getDisplay());
|
||||
}
|
||||
}
|
||||
|
||||
private TermConcept findConcept(final Map<String, TermConcept> code2concept, String typeId) {
|
||||
TermConcept typeConcept = code2concept.get(typeId);
|
||||
if (typeConcept == null) {
|
||||
throw new InternalErrorException("Unknown type ID: " + typeId);
|
||||
}
|
||||
return typeConcept;
|
||||
myValidConceptIds.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
private final class SctHandlerDescription implements IRecordHandler {
|
||||
private final Map<String, TermConcept> myCode2concept;
|
||||
private final Map<String, TermConcept> myId2concept;
|
||||
private final TermCodeSystemVersion myCodeSystemVersion;
|
||||
private final Map<String, TermConcept> myId2concept;
|
||||
private Set<String> myValidConceptIds;
|
||||
|
||||
private SctHandlerDescription(Set<String> theValidConceptIds, Map<String, TermConcept> theCode2concept, Map<String, TermConcept> theId2concept, TermCodeSystemVersion theCodeSystemVersion) {
|
||||
|
@ -309,80 +288,78 @@ public class TerminologyLoaderSvc {
|
|||
}
|
||||
}
|
||||
|
||||
private final class SctHandlerConcept implements IRecordHandler {
|
||||
private final class SctHandlerRelationship implements IRecordHandler {
|
||||
private final Map<String, TermConcept> myCode2concept;
|
||||
private final TermCodeSystemVersion myCodeSystemVersion;
|
||||
private final Map<String, TermConcept> myRootConcepts;
|
||||
|
||||
private Set<String> myValidConceptIds;
|
||||
|
||||
public SctHandlerConcept(Set<String> theValidConceptIds) {
|
||||
myValidConceptIds = theValidConceptIds;
|
||||
private SctHandlerRelationship(TermCodeSystemVersion theCodeSystemVersion, HashMap<String, TermConcept> theRootConcepts, Map<String, TermConcept> theCode2concept) {
|
||||
myCodeSystemVersion = theCodeSystemVersion;
|
||||
myRootConcepts = theRootConcepts;
|
||||
myCode2concept = theCode2concept;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(CSVRecord theRecord) {
|
||||
String id = theRecord.get("id");
|
||||
Set<String> ignoredTypes = new HashSet<String>();
|
||||
ignoredTypes.add("Method (attribute)");
|
||||
ignoredTypes.add("Direct device (attribute)");
|
||||
ignoredTypes.add("Has focus (attribute)");
|
||||
ignoredTypes.add("Access instrument");
|
||||
ignoredTypes.add("Procedure site (attribute)");
|
||||
ignoredTypes.add("Causative agent (attribute)");
|
||||
ignoredTypes.add("Course (attribute)");
|
||||
ignoredTypes.add("Finding site (attribute)");
|
||||
ignoredTypes.add("Has definitional manifestation (attribute)");
|
||||
|
||||
String sourceId = theRecord.get("sourceId");
|
||||
String destinationId = theRecord.get("destinationId");
|
||||
String typeId = theRecord.get("typeId");
|
||||
boolean active = "1".equals(theRecord.get("active"));
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
myValidConceptIds.add(id);
|
||||
}
|
||||
}
|
||||
TermConcept typeConcept = findConcept(myCode2concept, typeId);
|
||||
TermConcept sourceConcept = findConcept(myCode2concept, sourceId);
|
||||
TermConcept targetConcept = findConcept(myCode2concept, destinationId);
|
||||
if (typeConcept.getDisplay().equals("Is a (attribute)")) {
|
||||
TermConceptParentChildLink link = new TermConceptParentChildLink();
|
||||
link.setChild(sourceConcept);
|
||||
link.setParent(targetConcept);
|
||||
link.setRelationshipType(TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
||||
link.setCodeSystem(myCodeSystemVersion);
|
||||
myRootConcepts.remove(link.getChild().getCode());
|
||||
|
||||
private static class ZippedFileInputStream extends InputStream {
|
||||
|
||||
private ZipInputStream is;
|
||||
|
||||
public ZippedFileInputStream(ZipInputStream is) {
|
||||
this.is = is;
|
||||
targetConcept.addChild(sourceConcept, RelationshipTypeEnum.ISA);
|
||||
} else if (ignoredTypes.contains(typeConcept.getDisplay())) {
|
||||
// ignore
|
||||
} else {
|
||||
// ourLog.warn("Unknown relationship type: {}/{}", typeId, typeConcept.getDisplay());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return is.read();
|
||||
private TermConcept findConcept(final Map<String, TermConcept> code2concept, String typeId) {
|
||||
TermConcept typeConcept = code2concept.get(typeId);
|
||||
if (typeConcept == null) {
|
||||
throw new InternalErrorException("Unknown type ID: " + typeId);
|
||||
}
|
||||
return typeConcept;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
is.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
private interface IRecordHandler {
|
||||
void accept(CSVRecord theRecord);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
TerminologyLoaderSvc svc = new TerminologyLoaderSvc();
|
||||
|
||||
// byte[] bytes = IOUtils.toByteArray(new FileInputStream("/Users/james/Downloads/SnomedCT_Release_INT_20160131_Full.zip"));
|
||||
// svc.loadSnomedCt(bytes);
|
||||
|
||||
Map<String, File> files = new HashMap<String, File>();
|
||||
files.put(SCT_FILE_CONCEPT, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Concept_Full_INT_20160131.txt"));
|
||||
files.put(SCT_FILE_DESCRIPTION, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Description_Full-en_INT_20160131.txt"));
|
||||
files.put(SCT_FILE_RELATIONSHIP, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Relationship_Full_INT_20160131.txt"));
|
||||
svc.processSnomedCtFiles(files, null);
|
||||
}
|
||||
|
||||
private static class SinkOutputStream extends OutputStream {
|
||||
|
||||
private static final long LOG_INCREMENT = 10 * FileUtils.ONE_MB;
|
||||
private FileOutputStream myWrap;
|
||||
private int myBytes;
|
||||
private long myNextLogCount = LOG_INCREMENT;
|
||||
private String myFilename;
|
||||
private long myNextLogCount = LOG_INCREMENT;
|
||||
private FileOutputStream myWrap;
|
||||
|
||||
public SinkOutputStream(FileOutputStream theWrap, String theFilename) {
|
||||
myWrap = theWrap;
|
||||
myFilename = theFilename;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int theB) throws IOException {
|
||||
myWrap.write(theB);
|
||||
addCount(1);
|
||||
}
|
||||
|
||||
private void addCount(int theCount) {
|
||||
myBytes += theCount;
|
||||
if (myBytes > myNextLogCount) {
|
||||
|
@ -391,6 +368,16 @@ public class TerminologyLoaderSvc {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
myWrap.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
myWrap.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] theB) throws IOException {
|
||||
myWrap.write(theB);
|
||||
|
@ -404,15 +391,30 @@ public class TerminologyLoaderSvc {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
myWrap.flush();
|
||||
public void write(int theB) throws IOException {
|
||||
myWrap.write(theB);
|
||||
addCount(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class ZippedFileInputStream extends InputStream {
|
||||
|
||||
private ZipInputStream is;
|
||||
|
||||
public ZippedFileInputStream(ZipInputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
myWrap.close();
|
||||
is.closeEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return is.read();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ import org.hl7.fhir.dstu3.hapi.validation.ValidationSupportChain;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcDstu3;
|
||||
|
||||
public class JpaValidationSupportChainDstu3 extends ValidationSupportChain {
|
||||
|
||||
private DefaultProfileValidationSupport myDefaultProfileValidationSupport = new DefaultProfileValidationSupport();
|
||||
|
@ -36,6 +38,9 @@ public class JpaValidationSupportChainDstu3 extends ValidationSupportChain {
|
|||
@Qualifier("myJpaValidationSupportDstu3")
|
||||
public ca.uhn.fhir.jpa.dao.dstu3.IJpaValidationSupportDstu3 myJpaValidationSupportDstu3;
|
||||
|
||||
@Autowired
|
||||
private IHapiTerminologySvcDstu3 myTerminologyService;
|
||||
|
||||
public JpaValidationSupportChainDstu3() {
|
||||
super();
|
||||
}
|
||||
|
@ -48,6 +53,7 @@ public class JpaValidationSupportChainDstu3 extends ValidationSupportChain {
|
|||
public void postConstruct() {
|
||||
addValidationSupport(myDefaultProfileValidationSupport);
|
||||
addValidationSupport(myJpaValidationSupportDstu3);
|
||||
addValidationSupport(myTerminologyService);
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
|
|
|
@ -22,7 +22,10 @@ import org.junit.Ignore;
|
|||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParamModifier;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
@ -121,6 +124,87 @@ public class FhirResourceDaoTerminologyDstu3Test extends BaseJpaDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchCodeInExternalCodesystem() {
|
||||
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");
|
||||
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();
|
||||
obsPA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("ParentA");
|
||||
IIdType idPA = myObservationDao.create(obsPA, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obsAAA = new Observation();
|
||||
obsAAA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("childAAA");
|
||||
IIdType idAAA = myObservationDao.create(obsAAA, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obsAAB = new Observation();
|
||||
obsAAB.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("childAAB");
|
||||
IIdType idAAB = myObservationDao.create(obsAAB, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obsCA = new Observation();
|
||||
obsCA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("CA");
|
||||
IIdType idCA = myObservationDao.create(obsCA, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "childAA").setModifier(TokenParamModifier.BELOW));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), containsInAnyOrder(idAAA.getValue(), idAAB.getValue()));
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "childAA").setModifier(TokenParamModifier.ABOVE));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), containsInAnyOrder(idPA.getValue()));
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), containsInAnyOrder(idPA.getValue(), idAAA.getValue(), idAAB.getValue()));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchCodeBelowAndAboveUnknownCodeSystem() {
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
|
||||
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "childAA").setModifier(TokenParamModifier.BELOW));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
|
||||
|
||||
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "childAA").setModifier(TokenParamModifier.ABOVE));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
|
||||
|
||||
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchCodeInFhirCodesystem() {
|
||||
createLocalCsAndVs();
|
||||
|
@ -255,6 +339,11 @@ public class FhirResourceDaoTerminologyDstu3Test extends BaseJpaDstu3Test {
|
|||
//@formatter:on
|
||||
myCodeSystemDao.create(codeSystem, new ServletRequestDetails());
|
||||
|
||||
createLocalVs(codeSystem);
|
||||
}
|
||||
|
||||
|
||||
private void createLocalVs(CodeSystem codeSystem) {
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.setUrl(URL_MY_VALUE_SET);
|
||||
valueSet.getCompose().addInclude().setSystem(codeSystem.getUrl());
|
||||
|
|
|
@ -35,7 +35,6 @@ public class TerminologyLoaderSvcIntegrationTest extends BaseJpaDstu3Test {
|
|||
files.put(TerminologyLoaderSvc.SCT_FILE_DESCRIPTION, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Description_Full-en_INT_20160131.txt"));
|
||||
files.put(TerminologyLoaderSvc.SCT_FILE_RELATIONSHIP, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Relationship_Full_INT_20160131.txt"));
|
||||
myLoader.processSnomedCtFiles(files, mySrd);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,9 @@ import ca.uhn.fhir.util.TestUtil;
|
|||
|
||||
public class TerminologySvcImplTest extends BaseJpaDstu3Test {
|
||||
|
||||
private static final String CS_URL = "http://example.com/my_code_system";
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
|
@ -36,7 +39,7 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
|
|||
@Test
|
||||
public void testStoreCodeSystemInvalidCyclicLoop() {
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setUrl("http://example.com/my_code_system");
|
||||
codeSystem.setUrl(CS_URL);
|
||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||
IIdType id = myCodeSystemDao.create(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
|
||||
|
||||
|
@ -66,38 +69,19 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindCodesAboveAndBelowUnknown() {
|
||||
createCodeSystem();
|
||||
|
||||
assertThat(myTermSvc.findCodesBelow("http://foo", "code"), empty());
|
||||
assertThat(myTermSvc.findCodesBelow(CS_URL, "code"), empty());
|
||||
assertThat(myTermSvc.findCodesAbove("http://foo", "code"), empty());
|
||||
assertThat(myTermSvc.findCodesAbove(CS_URL, "code"), empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindCodesBelowA() {
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setUrl("http://example.com/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(), "http://foo", cs);
|
||||
IIdType id = createCodeSystem();
|
||||
|
||||
Set<TermConcept> concepts;
|
||||
Set<String> codes;
|
||||
|
@ -116,11 +100,11 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
|
|||
assertThat(codes, empty());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindCodesAbove() {
|
||||
|
||||
|
||||
private IIdType createCodeSystem() {
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setUrl("http://example.com/my_code_system");
|
||||
codeSystem.setUrl(CS_URL);
|
||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||
IIdType id = myCodeSystemDao.create(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
|
||||
|
||||
|
@ -149,6 +133,12 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
|
|||
cs.getConcepts().add(parentB);
|
||||
|
||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://foo", cs);
|
||||
return id;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindCodesAbove() {
|
||||
IIdType id = createCodeSystem();
|
||||
|
||||
Set<TermConcept> concepts;
|
||||
Set<String> codes;
|
||||
|
@ -171,7 +161,7 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
|
|||
@Test
|
||||
public void testCreateDuplicateCodeSystemUri() {
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setUrl("http://example.com/my_code_system");
|
||||
codeSystem.setUrl(CS_URL);
|
||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||
IIdType id = myCodeSystemDao.create(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
|
||||
|
||||
|
@ -181,7 +171,7 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
|
|||
cs.setResource(table);
|
||||
cs.setResourceVersionId(table.getVersion());
|
||||
|
||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://example.com/my_code_system", cs);
|
||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, cs);
|
||||
|
||||
// Update
|
||||
cs = new TermCodeSystemVersion();
|
||||
|
@ -191,18 +181,18 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
|
|||
table = myResourceTableDao.findOne(id.getIdPartAsLong());
|
||||
cs.setResource(table);
|
||||
cs.setResourceVersionId(table.getVersion());
|
||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://example.com/my_code_system", cs);
|
||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, cs);
|
||||
|
||||
// Try to update to a different resource
|
||||
codeSystem = new CodeSystem();
|
||||
codeSystem.setUrl("http://example.com/my_code_system");
|
||||
codeSystem.setUrl(CS_URL);
|
||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||
id = myCodeSystemDao.create(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
|
||||
table = myResourceTableDao.findOne(id.getIdPartAsLong());
|
||||
cs.setResource(table);
|
||||
cs.setResourceVersionId(table.getVersion());
|
||||
try {
|
||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://example.com/my_code_system", cs);
|
||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, cs);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), containsString("Can not create multiple code systems with URI \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/"));
|
||||
|
|
|
@ -84,7 +84,7 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
|||
|
||||
private IdDt myId;
|
||||
|
||||
@Child(name = "language", order = 0, min = 0, max = Child.MAX_UNLIMITED)
|
||||
@Child(name = "language", order = 0, min = 0, max = 1)
|
||||
private CodeDt myLanguage;
|
||||
|
||||
private ResourceMetadataMap myResourceMetadata;
|
||||
|
|
Loading…
Reference in New Issue