Merge branch 'master' of github.com:jamesagnew/hapi-fhir

This commit is contained in:
jamesagnew 2019-09-11 08:29:13 -04:00
commit cfdb3b222e
24 changed files with 876 additions and 236 deletions

View File

@ -146,12 +146,12 @@ public class DaoConfig {
private boolean myEnableInMemorySubscriptionMatching = true; private boolean myEnableInMemorySubscriptionMatching = true;
private boolean myEnforceReferenceTargetTypes = true; private boolean myEnforceReferenceTargetTypes = true;
private ClientIdStrategyEnum myResourceClientIdStrategy = ClientIdStrategyEnum.ALPHANUMERIC; private ClientIdStrategyEnum myResourceClientIdStrategy = ClientIdStrategyEnum.ALPHANUMERIC;
private boolean myFilterParameterEnabled = false;
private StoreMetaSourceInformationEnum myStoreMetaSourceInformation = StoreMetaSourceInformationEnum.SOURCE_URI_AND_REQUEST_ID;
/** /**
* EXPERIMENTAL - Do not use in production! Do not change default of {@code false}! * EXPERIMENTAL - Do not use in production! Do not change default of {@code false}!
*/ */
private boolean myPreExpandValueSetsExperimental = false; private boolean myPreExpandValueSetsExperimental = false;
private boolean myFilterParameterEnabled = false;
private StoreMetaSourceInformationEnum myStoreMetaSourceInformation = StoreMetaSourceInformationEnum.SOURCE_URI_AND_REQUEST_ID;
/** /**
* EXPERIMENTAL - Do not use in production! Do not change default of {@code 0}! * EXPERIMENTAL - Do not use in production! Do not change default of {@code 0}!
*/ */

View File

@ -21,8 +21,6 @@ package ca.uhn.fhir.jpa.dao.data;
*/ */
import ca.uhn.fhir.jpa.entity.TermValueSetConcept; import ca.uhn.fhir.jpa.entity.TermValueSetConcept;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
@ -33,17 +31,14 @@ import java.util.Optional;
public interface ITermValueSetConceptDao extends JpaRepository<TermValueSetConcept, Long> { public interface ITermValueSetConceptDao extends JpaRepository<TermValueSetConcept, Long> {
@Query("SELECT COUNT(*) FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myId = :pid") @Query("SELECT COUNT(*) FROM TermValueSetConcept vsc WHERE vsc.myValueSetPid = :pid")
Integer countByTermValueSetId(@Param("pid") Long theValueSetId); Integer countByTermValueSetId(@Param("pid") Long theValueSetId);
@Query("DELETE FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myId = :pid") @Query("DELETE FROM TermValueSetConcept vsc WHERE vsc.myValueSetPid = :pid")
@Modifying @Modifying
void deleteByTermValueSetId(@Param("pid") Long theValueSetId); void deleteByTermValueSetId(@Param("pid") Long theValueSetId);
@Query("SELECT vsc from TermValueSetConcept vsc LEFT OUTER JOIN FETCH vsc.myDesignations WHERE vsc.myValueSet.myId = :pid") @Query("SELECT vsc FROM TermValueSetConcept vsc WHERE vsc.myValueSetPid = :pid AND vsc.mySystem = :system_url AND vsc.myCode = :codeval")
Slice<TermValueSetConcept> findByTermValueSetIdAndPreFetchDesignations(Pageable thePage, @Param("pid") Long theValueSetId);
@Query("SELECT vsc FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myId = :pid AND vsc.mySystem = :system_url AND vsc.myCode = :codeval")
Optional<TermValueSetConcept> findByTermValueSetIdSystemAndCode(@Param("pid") Long theValueSetId, @Param("system_url") String theSystem, @Param("codeval") String theCode); Optional<TermValueSetConcept> findByTermValueSetIdSystemAndCode(@Param("pid") Long theValueSetId, @Param("system_url") String theSystem, @Param("codeval") String theCode);
@Query("SELECT vsc FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myResourcePid = :resource_pid AND vsc.myCode = :codeval") @Query("SELECT vsc FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myResourcePid = :resource_pid AND vsc.myCode = :codeval")
@ -51,4 +46,11 @@ public interface ITermValueSetConceptDao extends JpaRepository<TermValueSetConce
@Query("SELECT vsc FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myResourcePid = :resource_pid AND vsc.mySystem = :system_url AND vsc.myCode = :codeval") @Query("SELECT vsc FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myResourcePid = :resource_pid AND vsc.mySystem = :system_url AND vsc.myCode = :codeval")
Optional<TermValueSetConcept> findByValueSetResourcePidSystemAndCode(@Param("resource_pid") Long theValueSetId, @Param("system_url") String theSystem, @Param("codeval") String theCode); Optional<TermValueSetConcept> findByValueSetResourcePidSystemAndCode(@Param("resource_pid") Long theValueSetId, @Param("system_url") String theSystem, @Param("codeval") String theCode);
@Query("SELECT vsc.myId FROM TermValueSetConcept vsc WHERE vsc.myValueSetPid = :pid ORDER BY vsc.myId")
List<Long> findIdsByTermValueSetId(@Param("pid") Long theValueSetId);
@Query("UPDATE TermValueSetConcept vsc SET vsc.myOrder = :order WHERE vsc.myId = :pid")
@Modifying
void updateOrderById(@Param("pid") Long theId, @Param("order") int theOrder);
} }

View File

@ -30,10 +30,10 @@ import org.springframework.data.repository.query.Param;
public interface ITermValueSetConceptDesignationDao extends JpaRepository<TermValueSetConceptDesignation, Long> { public interface ITermValueSetConceptDesignationDao extends JpaRepository<TermValueSetConceptDesignation, Long> {
@Query("SELECT COUNT(vscd) FROM TermValueSetConceptDesignation vscd WHERE vscd.myValueSet.myId = :pid") @Query("SELECT COUNT(vscd) FROM TermValueSetConceptDesignation vscd WHERE vscd.myValueSetPid = :pid")
Integer countByTermValueSetId(@Param("pid") Long theValueSetId); Integer countByTermValueSetId(@Param("pid") Long theValueSetId);
@Query("DELETE FROM TermValueSetConceptDesignation vscd WHERE vscd.myValueSet.myId = :pid") @Query("DELETE FROM TermValueSetConceptDesignation vscd WHERE vscd.myValueSetPid = :pid")
@Modifying @Modifying
void deleteByTermValueSetId(@Param("pid") Long theValueSetId); void deleteByTermValueSetId(@Param("pid") Long theValueSetId);

View File

@ -0,0 +1,35 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermValueSetConceptView;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface ITermValueSetConceptViewDao extends JpaRepository<TermValueSetConceptView, Long> {
@Query("SELECT v FROM TermValueSetConceptView v WHERE v.myConceptValueSetPid = :pid AND v.myConceptOrder >= :from AND v.myConceptOrder < :to ORDER BY v.myConceptOrder")
List<TermValueSetConceptView> findByTermValueSetId(@Param("from") int theFrom, @Param("to") int theTo, @Param("pid") Long theValueSetId);
}

View File

@ -25,7 +25,6 @@ import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
@ -33,10 +32,6 @@ import java.util.Optional;
public interface ITermValueSetDao extends JpaRepository<TermValueSet, Long> { public interface ITermValueSetDao extends JpaRepository<TermValueSet, Long> {
@Query("DELETE FROM TermValueSet vs WHERE vs.myId = :pid")
@Modifying
void deleteByTermValueSetId(@Param("pid") Long theId);
@Query("SELECT vs FROM TermValueSet vs WHERE vs.myResourcePid = :resource_pid") @Query("SELECT vs FROM TermValueSet vs WHERE vs.myResourcePid = :resource_pid")
Optional<TermValueSet> findByResourcePid(@Param("resource_pid") Long theResourcePid); Optional<TermValueSet> findByResourcePid(@Param("resource_pid") Long theResourcePid);

View File

@ -93,12 +93,12 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
boolean allSystemsAreSuppportedByTerminologyService = true; boolean allSystemsAreSuppportedByTerminologyService = true;
for (ConceptSetComponent next : theSource.getCompose().getInclude()) { for (ConceptSetComponent next : theSource.getCompose().getInclude()) {
if (!myTerminologySvc.supportsSystem(next.getSystem())) { if (!isBlank(next.getSystem()) && !myTerminologySvc.supportsSystem(next.getSystem())) {
allSystemsAreSuppportedByTerminologyService = false; allSystemsAreSuppportedByTerminologyService = false;
} }
} }
for (ConceptSetComponent next : theSource.getCompose().getExclude()) { for (ConceptSetComponent next : theSource.getCompose().getExclude()) {
if (!myTerminologySvc.supportsSystem(next.getSystem())) { if (!isBlank(next.getSystem()) && !myTerminologySvc.supportsSystem(next.getSystem())) {
allSystemsAreSuppportedByTerminologyService = false; allSystemsAreSuppportedByTerminologyService = false;
} }
} }
@ -125,12 +125,12 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
boolean allSystemsAreSuppportedByTerminologyService = true; boolean allSystemsAreSuppportedByTerminologyService = true;
for (ConceptSetComponent next : theSource.getCompose().getInclude()) { for (ConceptSetComponent next : theSource.getCompose().getInclude()) {
if (!myTerminologySvc.supportsSystem(next.getSystem())) { if (!isBlank(next.getSystem()) && !myTerminologySvc.supportsSystem(next.getSystem())) {
allSystemsAreSuppportedByTerminologyService = false; allSystemsAreSuppportedByTerminologyService = false;
} }
} }
for (ConceptSetComponent next : theSource.getCompose().getExclude()) { for (ConceptSetComponent next : theSource.getCompose().getExclude()) {
if (!myTerminologySvc.supportsSystem(next.getSystem())) { if (!isBlank(next.getSystem()) && !myTerminologySvc.supportsSystem(next.getSystem())) {
allSystemsAreSuppportedByTerminologyService = false; allSystemsAreSuppportedByTerminologyService = false;
} }
} }
@ -160,6 +160,7 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
} }
ValueSet source = new ValueSet(); ValueSet source = new ValueSet();
source.setUrl(theUri);
source.getCompose().addInclude().addValueSet(theUri); source.getCompose().addInclude().addValueSet(theUri);

View File

@ -156,6 +156,7 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4<ValueSet> imple
} }
ValueSet source = new ValueSet(); ValueSet source = new ValueSet();
source.setUrl(theUri);
source.getCompose().addInclude().addValueSet(theUri); source.getCompose().addInclude().addValueSet(theUri);

View File

@ -162,6 +162,7 @@ public class FhirResourceDaoValueSetR5 extends FhirResourceDaoR5<ValueSet> imple
} }
ValueSet source = new ValueSet(); ValueSet source = new ValueSet();
source.setUrl(theUri);
source.getCompose().addInclude().addValueSet(theUri); source.getCompose().addInclude().addValueSet(theUri);

View File

@ -23,7 +23,6 @@ package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.util.ValidateUtil; import ca.uhn.fhir.util.ValidateUtil;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.ColumnDefault;
@ -67,7 +66,7 @@ public class TermValueSet implements Serializable {
@Column(name = "VSNAME", nullable = true, length = MAX_NAME_LENGTH) @Column(name = "VSNAME", nullable = true, length = MAX_NAME_LENGTH)
private String myName; private String myName;
@OneToMany(mappedBy = "myValueSet") @OneToMany(mappedBy = "myValueSet", fetch = FetchType.LAZY)
private List<TermValueSetConcept> myConcepts; private List<TermValueSetConcept> myConcepts;
@Column(name = "TOTAL_CONCEPTS", nullable = false) @Column(name = "TOTAL_CONCEPTS", nullable = false)
@ -82,6 +81,9 @@ public class TermValueSet implements Serializable {
@Column(name = "EXPANSION_STATUS", nullable = false, length = MAX_EXPANSION_STATUS_LENGTH) @Column(name = "EXPANSION_STATUS", nullable = false, length = MAX_EXPANSION_STATUS_LENGTH)
private TermValueSetPreExpansionStatusEnum myExpansionStatus; private TermValueSetPreExpansionStatusEnum myExpansionStatus;
@Transient
private transient Integer myHashCode;
public TermValueSet() { public TermValueSet() {
super(); super();
myExpansionStatus = TermValueSetPreExpansionStatusEnum.NOT_EXPANDED; myExpansionStatus = TermValueSetPreExpansionStatusEnum.NOT_EXPANDED;
@ -196,9 +198,10 @@ public class TermValueSet implements Serializable {
@Override @Override
public int hashCode() { public int hashCode() {
return new HashCodeBuilder(17, 37) if (myHashCode == null) {
.append(getUrl()) myHashCode = getUrl().hashCode();
.toHashCode(); }
return myHashCode;
} }
@Override @Override

View File

@ -40,7 +40,8 @@ import static org.apache.commons.lang3.StringUtils.length;
* bork up migration tasks. * bork up migration tasks.
*/ */
@Table(name = "TRM_VALUESET_CONCEPT", uniqueConstraints = { @Table(name = "TRM_VALUESET_CONCEPT", uniqueConstraints = {
@UniqueConstraint(name = "IDX_VS_CONCEPT_CS_CD", columnNames = {"VALUESET_PID", "SYSTEM_URL", "CODEVAL"}) @UniqueConstraint(name = "IDX_VS_CONCEPT_CS_CD", columnNames = {"VALUESET_PID", "SYSTEM_URL", "CODEVAL"}),
@UniqueConstraint(name = "IDX_VS_CONCEPT_ORDER", columnNames = {"VALUESET_PID", "VALUESET_ORDER"})
}) })
@Entity() @Entity()
public class TermValueSetConcept implements Serializable { public class TermValueSetConcept implements Serializable {
@ -52,10 +53,16 @@ public class TermValueSetConcept implements Serializable {
@Column(name = "PID") @Column(name = "PID")
private Long myId; private Long myId;
@ManyToOne() @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "VALUESET_PID", referencedColumnName = "PID", nullable = false, foreignKey = @ForeignKey(name = "FK_TRM_VALUESET_PID")) @JoinColumn(name = "VALUESET_PID", referencedColumnName = "PID", nullable = false, foreignKey = @ForeignKey(name = "FK_TRM_VALUESET_PID"))
private TermValueSet myValueSet; private TermValueSet myValueSet;
@Column(name = "VALUESET_PID", insertable = false, updatable = false, nullable = false)
private Long myValueSetPid;
@Column(name = "VALUESET_ORDER", nullable = false)
private int myOrder;
@Transient @Transient
private String myValueSetUrl; private String myValueSetUrl;
@ -71,9 +78,12 @@ public class TermValueSetConcept implements Serializable {
@Column(name = "DISPLAY", nullable = true, length = TermConcept.MAX_DESC_LENGTH) @Column(name = "DISPLAY", nullable = true, length = TermConcept.MAX_DESC_LENGTH)
private String myDisplay; private String myDisplay;
@OneToMany(mappedBy = "myConcept") @OneToMany(mappedBy = "myConcept", fetch = FetchType.LAZY)
private List<TermValueSetConceptDesignation> myDesignations; private List<TermValueSetConceptDesignation> myDesignations;
@Transient
private transient Integer myHashCode;
public Long getId() { public Long getId() {
return myId; return myId;
} }
@ -87,6 +97,15 @@ public class TermValueSetConcept implements Serializable {
return this; return this;
} }
public int getOrder() {
return myOrder;
}
public TermValueSetConcept setOrder(int theOrder) {
myOrder = theOrder;
return this;
}
public String getValueSetUrl() { public String getValueSetUrl() {
if (myValueSetUrl == null) { if (myValueSetUrl == null) {
myValueSetUrl = getValueSet().getUrl(); myValueSetUrl = getValueSet().getUrl();
@ -153,7 +172,7 @@ public class TermValueSetConcept implements Serializable {
TermValueSetConcept that = (TermValueSetConcept) theO; TermValueSetConcept that = (TermValueSetConcept) theO;
return new EqualsBuilder() return new EqualsBuilder()
.append(getValueSetUrl(), that.getValueSetUrl()) .append(myValueSetPid, that.myValueSetPid)
.append(getSystem(), that.getSystem()) .append(getSystem(), that.getSystem())
.append(getCode(), that.getCode()) .append(getCode(), that.getCode())
.isEquals(); .isEquals();
@ -161,18 +180,23 @@ public class TermValueSetConcept implements Serializable {
@Override @Override
public int hashCode() { public int hashCode() {
return new HashCodeBuilder(17, 37) if (myHashCode == null) {
.append(getValueSetUrl()) myHashCode = new HashCodeBuilder(17, 37)
.append(myValueSetPid)
.append(getSystem()) .append(getSystem())
.append(getCode()) .append(getCode())
.toHashCode(); .toHashCode();
} }
return myHashCode;
}
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("myId", myId) .append("myId", myId)
.append(myValueSet != null ? ("myValueSet - id=" + myValueSet.getId()) : ("myValueSet=(null)")) .append(myValueSet != null ? ("myValueSet - id=" + myValueSet.getId()) : ("myValueSet=(null)"))
.append("myValueSetPid", myValueSetPid)
.append("myOrder", myOrder)
.append("myValueSetUrl", this.getValueSetUrl()) .append("myValueSetUrl", this.getValueSetUrl())
.append("myValueSetName", this.getValueSetName()) .append("myValueSetName", this.getValueSetName())
.append("mySystem", mySystem) .append("mySystem", mySystem)

View File

@ -48,14 +48,20 @@ public class TermValueSetConceptDesignation implements Serializable {
@Column(name = "PID") @Column(name = "PID")
private Long myId; private Long myId;
@ManyToOne() @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "VALUESET_CONCEPT_PID", referencedColumnName = "PID", nullable = false, foreignKey = @ForeignKey(name = "FK_TRM_VALUESET_CONCEPT_PID")) @JoinColumn(name = "VALUESET_CONCEPT_PID", referencedColumnName = "PID", nullable = false, foreignKey = @ForeignKey(name = "FK_TRM_VALUESET_CONCEPT_PID"))
private TermValueSetConcept myConcept; private TermValueSetConcept myConcept;
@Column(name = "VALUESET_CONCEPT_PID", insertable = false, updatable = false, nullable = false)
private Long myConceptPid;
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "VALUESET_PID", referencedColumnName = "PID", nullable = false, foreignKey = @ForeignKey(name = "FK_TRM_VSCD_VS_PID")) @JoinColumn(name = "VALUESET_PID", referencedColumnName = "PID", nullable = false, foreignKey = @ForeignKey(name = "FK_TRM_VSCD_VS_PID"))
private TermValueSet myValueSet; private TermValueSet myValueSet;
@Column(name = "VALUESET_PID", insertable = false, updatable = false, nullable = false)
private Long myValueSetPid;
@Transient @Transient
private String myValueSetUrl; private String myValueSetUrl;
@ -77,6 +83,9 @@ public class TermValueSetConceptDesignation implements Serializable {
@Column(name = "VAL", nullable = false, length = MAX_LENGTH) @Column(name = "VAL", nullable = false, length = MAX_LENGTH)
private String myValue; private String myValue;
@Transient
private transient Integer myHashCode;
public Long getId() { public Long getId() {
return myId; return myId;
} }
@ -188,7 +197,8 @@ public class TermValueSetConceptDesignation implements Serializable {
@Override @Override
public int hashCode() { public int hashCode() {
return new HashCodeBuilder(17, 37) if (myHashCode == null) {
myHashCode = new HashCodeBuilder(17, 37)
.append(getLanguage()) .append(getLanguage())
.append(getUseSystem()) .append(getUseSystem())
.append(getUseCode()) .append(getUseCode())
@ -196,13 +206,17 @@ public class TermValueSetConceptDesignation implements Serializable {
.append(getValue()) .append(getValue())
.toHashCode(); .toHashCode();
} }
return myHashCode;
}
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("myId", myId) .append("myId", myId)
.append(myConcept != null ? ("myConcept - id=" + myConcept.getId()) : ("myConcept=(null)")) .append(myConcept != null ? ("myConcept - id=" + myConcept.getId()) : ("myConcept=(null)"))
.append("myConceptPid", myConceptPid)
.append(myValueSet != null ? ("myValueSet - id=" + myValueSet.getId()) : ("myValueSet=(null)")) .append(myValueSet != null ? ("myValueSet - id=" + myValueSet.getId()) : ("myValueSet=(null)"))
.append("myValueSetPid", myValueSetPid)
.append("myValueSetUrl", this.getValueSetUrl()) .append("myValueSetUrl", this.getValueSetUrl())
.append("myValueSetName", this.getValueSetName()) .append("myValueSetName", this.getValueSetName())
.append("myLanguage", myLanguage) .append("myLanguage", myLanguage)

View File

@ -0,0 +1,135 @@
package ca.uhn.fhir.jpa.entity;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hibernate.annotations.Immutable;
import org.hibernate.annotations.Subselect;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.io.Serializable;
@Entity
@Immutable
@Subselect(
"SELECT CONCAT(vsc.PID, ' ', vscd.PID) AS PID, " +
" vsc.PID AS CONCEPT_PID, " +
" vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " +
" vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " +
" vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " +
" vsc.CODEVAL AS CONCEPT_CODEVAL, " +
" vsc.DISPLAY AS CONCEPT_DISPLAY, " +
" vscd.PID AS DESIGNATION_PID, " +
" vscd.LANG AS DESIGNATION_LANG, " +
" vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " +
" vscd.USE_CODE AS DESIGNATION_USE_CODE, " +
" vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " +
" vscd.VAL AS DESIGNATION_VAL " +
"FROM TRM_VALUESET_CONCEPT vsc " +
" LEFT OUTER JOIN TRM_VALUESET_C_DESIGNATION vscd ON vsc.PID = vscd.VALUESET_CONCEPT_PID"
)
public class TermValueSetConceptView implements Serializable {
private static final long serialVersionUID = 1L;
private static final int MAX_LENGTH = 500;
@Id
@Column(name="PID", length = MAX_LENGTH)
private String myPid;
@Column(name = "CONCEPT_PID")
private Long myConceptPid;
@Column(name = "CONCEPT_VALUESET_PID")
private Long myConceptValueSetPid;
@Column(name = "CONCEPT_VALUESET_ORDER")
private int myConceptOrder;
@Column(name = "CONCEPT_SYSTEM_URL", length = TermCodeSystem.MAX_URL_LENGTH)
private String myConceptSystemUrl;
@Column(name = "CONCEPT_CODEVAL", length = TermConcept.MAX_CODE_LENGTH)
private String myConceptCode;
@Column(name = "CONCEPT_DISPLAY", length = TermConcept.MAX_DESC_LENGTH)
private String myConceptDisplay;
@Column(name = "DESIGNATION_PID")
private Long myDesignationPid;
@Column(name = "DESIGNATION_LANG", length = TermValueSetConceptDesignation.MAX_LENGTH)
private String myDesignationLang;
@Column(name = "DESIGNATION_USE_SYSTEM", length = TermValueSetConceptDesignation.MAX_LENGTH)
private String myDesignationUseSystem;
@Column(name = "DESIGNATION_USE_CODE", length = TermValueSetConceptDesignation.MAX_LENGTH)
private String myDesignationUseCode;
@Column(name = "DESIGNATION_USE_DISPLAY", length = TermValueSetConceptDesignation.MAX_LENGTH)
private String myDesignationUseDisplay;
@Column(name = "DESIGNATION_VAL", length = TermValueSetConceptDesignation.MAX_LENGTH)
private String myDesignationVal;
public Long getConceptPid() {
return myConceptPid;
}
public String getConceptSystemUrl() {
return myConceptSystemUrl;
}
public String getConceptCode() {
return myConceptCode;
}
public String getConceptDisplay() {
return myConceptDisplay;
}
public Long getDesignationPid() {
return myDesignationPid;
}
public String getDesignationLang() {
return myDesignationLang;
}
public String getDesignationUseSystem() {
return myDesignationUseSystem;
}
public String getDesignationUseCode() {
return myDesignationUseCode;
}
public String getDesignationUseDisplay() {
return myDesignationUseDisplay;
}
public String getDesignationVal() {
return myDesignationVal;
}
}

View File

@ -28,14 +28,15 @@ import ca.uhn.fhir.jpa.dao.data.*;
import ca.uhn.fhir.jpa.entity.*; import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum; import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
import ca.uhn.fhir.jpa.util.ScrollableResultsIterator; import ca.uhn.fhir.jpa.util.ScrollableResultsIterator;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.ObjectUtil; import ca.uhn.fhir.util.ObjectUtil;
import ca.uhn.fhir.util.StopWatch; import ca.uhn.fhir.util.StopWatch;
import ca.uhn.fhir.util.UrlUtil;
import ca.uhn.fhir.util.ValidateUtil; import ca.uhn.fhir.util.ValidateUtil;
import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
@ -159,6 +160,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
private IFulltextSearchSvc myFulltextSearchSvc; private IFulltextSearchSvc myFulltextSearchSvc;
@Autowired @Autowired
private PlatformTransactionManager myTxManager; private PlatformTransactionManager myTxManager;
@Autowired
private ITermValueSetConceptViewDao myTermValueSetConceptViewDao;
private void addCodeIfNotAlreadyAdded(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, TermConcept theConcept, boolean theAdd, AtomicInteger theCodeCounter) { private void addCodeIfNotAlreadyAdded(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, TermConcept theConcept, boolean theAdd, AtomicInteger theCodeCounter) {
String codeSystem = theConcept.getCodeSystemVersion().getCodeSystem().getCodeSystemUri(); String codeSystem = theConcept.getCodeSystemVersion().getCodeSystem().getCodeSystemUri();
@ -392,7 +395,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
ourLog.info("Deleting existing TermValueSet[{}] and its children...", existingTermValueSet.getId()); ourLog.info("Deleting existing TermValueSet[{}] and its children...", existingTermValueSet.getId());
myValueSetConceptDesignationDao.deleteByTermValueSetId(existingTermValueSet.getId()); myValueSetConceptDesignationDao.deleteByTermValueSetId(existingTermValueSet.getId());
myValueSetConceptDao.deleteByTermValueSetId(existingTermValueSet.getId()); myValueSetConceptDao.deleteByTermValueSetId(existingTermValueSet.getId());
myValueSetDao.deleteByTermValueSetId(existingTermValueSet.getId()); myValueSetDao.deleteById(existingTermValueSet.getId());
ourLog.info("Done deleting existing TermValueSet[{}] and its children.", existingTermValueSet.getId()); ourLog.info("Done deleting existing TermValueSet[{}] and its children.", existingTermValueSet.getId());
} }
} }
@ -485,8 +488,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
} }
if (!optionalTermValueSet.isPresent()) { if (!optionalTermValueSet.isPresent()) {
ourLog.warn("ValueSet is not present in terminology tables. Will perform in-memory expansion without parameters. Will schedule this ValueSet for pre-expansion. {}", getValueSetInfo(theValueSetToExpand)); ourLog.warn("ValueSet is not present in terminology tables. Will perform in-memory expansion without parameters. {}", getValueSetInfo(theValueSetToExpand));
myDeferredValueSets.add(theValueSetToExpand);
return expandValueSet(theValueSetToExpand); // In-memory expansion. return expandValueSet(theValueSetToExpand); // In-memory expansion.
} }
@ -518,7 +520,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
theExpansionComponent.addParameter().setName("offset").setValue(new IntegerType(theOffset)); theExpansionComponent.addParameter().setName("offset").setValue(new IntegerType(theOffset));
theExpansionComponent.addParameter().setName("count").setValue(new IntegerType(theCount)); theExpansionComponent.addParameter().setName("count").setValue(new IntegerType(theCount));
if (theCount == 0 || total == 0) { if (theCount == 0) {
return; return;
} }
@ -527,58 +529,64 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
private void expandConcepts(ValueSet.ValueSetExpansionComponent theExpansionComponent, TermValueSet theTermValueSet, int theOffset, int theCount) { private void expandConcepts(ValueSet.ValueSetExpansionComponent theExpansionComponent, TermValueSet theTermValueSet, int theOffset, int theCount) {
int conceptsExpanded = 0; int conceptsExpanded = 0;
int designationsExpanded = 0;
int toIndex = theOffset + theCount; int toIndex = theOffset + theCount;
Slice<TermValueSetConcept> slice = myValueSetConceptDao.findByTermValueSetIdAndPreFetchDesignations(SearchCoordinatorSvcImpl.toPage(theOffset, toIndex), theTermValueSet.getId()); Collection<TermValueSetConceptView> conceptViews = myTermValueSetConceptViewDao.findByTermValueSetId(theOffset, toIndex, theTermValueSet.getId());
if (!slice.hasContent()) {
logConceptsExpanded(theTermValueSet, conceptsExpanded); if (conceptViews.isEmpty()) {
logConceptsExpanded("No concepts to expand. ", theTermValueSet, conceptsExpanded);
return; return;
} }
for (TermValueSetConcept concept : slice.getContent()) { Map<Long, ValueSet.ValueSetExpansionContainsComponent> pidToConcept = new HashMap<>();
ValueSet.ValueSetExpansionContainsComponent containsComponent = theExpansionComponent.addContains(); for (TermValueSetConceptView conceptView : conceptViews) {
containsComponent.setSystem(concept.getSystem());
containsComponent.setCode(concept.getCode());
containsComponent.setDisplay(concept.getDisplay());
// TODO: DM 2019-08-17 - Implement includeDesignations parameter for $expand operation to make this optional. Long conceptPid = conceptView.getConceptPid();
expandDesignations(theTermValueSet, concept, containsComponent); ValueSet.ValueSetExpansionContainsComponent containsComponent;
if (++conceptsExpanded % 250 == 0) { if (!pidToConcept.containsKey(conceptPid)) {
logConceptsExpanded(theTermValueSet, conceptsExpanded); containsComponent = theExpansionComponent.addContains();
} containsComponent.setSystem(conceptView.getConceptSystemUrl());
containsComponent.setCode(conceptView.getConceptCode());
containsComponent.setDisplay(conceptView.getConceptDisplay());
pidToConcept.put(conceptPid, containsComponent);
} else {
containsComponent = pidToConcept.get(conceptPid);
} }
logConceptsExpanded(theTermValueSet, conceptsExpanded); // TODO: DM 2019-08-17 - Implement includeDesignations parameter for $expand operation to designations optional.
} if (conceptView.getDesignationPid() != null) {
ValueSet.ConceptReferenceDesignationComponent designationComponent = containsComponent.addDesignation();
private void logConceptsExpanded(TermValueSet theTermValueSet, int theConceptsExpanded) { designationComponent.setLanguage(conceptView.getDesignationLang());
if (theConceptsExpanded > 0) {
ourLog.info("Have expanded {} concepts in ValueSet[{}]", theConceptsExpanded, theTermValueSet.getUrl());
}
}
private void expandDesignations(TermValueSet theValueSet, TermValueSetConcept theConcept, ValueSet.ValueSetExpansionContainsComponent theContainsComponent) {
int designationsExpanded = 0;
for (TermValueSetConceptDesignation designation : theConcept.getDesignations()) {
ValueSet.ConceptReferenceDesignationComponent designationComponent = theContainsComponent.addDesignation();
designationComponent.setLanguage(designation.getLanguage());
designationComponent.setUse(new Coding( designationComponent.setUse(new Coding(
designation.getUseSystem(), conceptView.getDesignationUseSystem(),
designation.getUseCode(), conceptView.getDesignationUseCode(),
designation.getUseDisplay())); conceptView.getDesignationUseDisplay()));
designationComponent.setValue(designation.getValue()); designationComponent.setValue(conceptView.getDesignationVal());
if (++designationsExpanded % 250 == 0) { if (++designationsExpanded % 250 == 0) {
logDesignationsExpanded(theValueSet, theConcept, designationsExpanded); logDesignationsExpanded("Expansion of designations in progress. ", theTermValueSet, designationsExpanded);
} }
} }
logDesignationsExpanded(theValueSet, theConcept, designationsExpanded); if (++conceptsExpanded % 250 == 0) {
logConceptsExpanded("Expansion of concepts in progress. ", theTermValueSet, conceptsExpanded);
}
} }
private void logDesignationsExpanded(TermValueSet theValueSet, TermValueSetConcept theConcept, int theDesignationsExpanded) { logDesignationsExpanded("Finished expanding designations. ", theTermValueSet, designationsExpanded);
logConceptsExpanded("Finished expanding concepts. ", theTermValueSet, conceptsExpanded);
}
private void logConceptsExpanded(String theLogDescriptionPrefix, TermValueSet theTermValueSet, int theConceptsExpanded) {
if (theConceptsExpanded > 0) {
ourLog.info("{}Have expanded {} concepts in ValueSet[{}]", theLogDescriptionPrefix, theConceptsExpanded, theTermValueSet.getUrl());
}
}
private void logDesignationsExpanded(String theLogDescriptionPrefix, TermValueSet theTermValueSet, int theDesignationsExpanded) {
if (theDesignationsExpanded > 0) { if (theDesignationsExpanded > 0) {
ourLog.info("Have expanded {} designations for Concept[{}|{}] in ValueSet[{}]", theDesignationsExpanded, theConcept.getSystem(), theConcept.getCode(), theValueSet.getUrl()); ourLog.info("{}Have expanded {} designations in ValueSet[{}]", theLogDescriptionPrefix, theDesignationsExpanded, theTermValueSet.getUrl());
} }
} }
@ -600,10 +608,10 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
ourLog.debug("Handling includes"); ourLog.debug("Handling includes");
for (ValueSet.ConceptSetComponent include : theValueSetToExpand.getCompose().getInclude()) { for (ValueSet.ConceptSetComponent include : theValueSetToExpand.getCompose().getInclude()) {
for (int i = 0; ; i++) { for (int i = 0; ; i++) {
int finalI = i; int queryIndex = i;
Boolean shouldContinue = myTxTemplate.execute(t -> { Boolean shouldContinue = myTxTemplate.execute(t -> {
boolean add = true; boolean add = true;
return expandValueSetHandleIncludeOrExclude(theValueSetCodeAccumulator, addedCodes, include, add, theCodeCounter, finalI); return expandValueSetHandleIncludeOrExclude(theValueSetCodeAccumulator, addedCodes, include, add, theCodeCounter, queryIndex);
}); });
if (!shouldContinue) { if (!shouldContinue) {
break; break;
@ -615,10 +623,10 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
ourLog.debug("Handling excludes"); ourLog.debug("Handling excludes");
for (ValueSet.ConceptSetComponent exclude : theValueSetToExpand.getCompose().getExclude()) { for (ValueSet.ConceptSetComponent exclude : theValueSetToExpand.getCompose().getExclude()) {
for (int i = 0; ; i++) { for (int i = 0; ; i++) {
int finalI = i; int queryIndex = i;
Boolean shouldContinue = myTxTemplate.execute(t -> { Boolean shouldContinue = myTxTemplate.execute(t -> {
boolean add = false; boolean add = false;
return expandValueSetHandleIncludeOrExclude(theValueSetCodeAccumulator, addedCodes, exclude, add, theCodeCounter, finalI); return expandValueSetHandleIncludeOrExclude(theValueSetCodeAccumulator, addedCodes, exclude, add, theCodeCounter, queryIndex);
}); });
if (!shouldContinue) { if (!shouldContinue) {
break; break;
@ -626,6 +634,10 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
} }
} }
if (theValueSetCodeAccumulator instanceof ValueSetConceptAccumulator) {
myTxTemplate.execute(t -> ((ValueSetConceptAccumulator) theValueSetCodeAccumulator).removeGapsFromConceptOrder());
}
ourLog.info("Done working with {} in {}ms", valueSetInfo, sw.getMillis()); ourLog.info("Done working with {} in {}ms", valueSetInfo, sw.getMillis());
} }
@ -935,8 +947,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
Optional<TermValueSet> optionalTermValueSet = myValueSetDao.findByResourcePid(valueSetResourcePid); Optional<TermValueSet> optionalTermValueSet = myValueSetDao.findByResourcePid(valueSetResourcePid);
if (!optionalTermValueSet.isPresent()) { if (!optionalTermValueSet.isPresent()) {
ourLog.warn("ValueSet is not present in terminology tables. Will perform in-memory code validation. Will schedule this ValueSet for pre-expansion. {}", getValueSetInfo(theValueSet)); ourLog.warn("ValueSet is not present in terminology tables. Will perform in-memory code validation. {}", getValueSetInfo(theValueSet));
myDeferredValueSets.add(theValueSet);
return false; return false;
} }
@ -1750,7 +1761,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
} catch (FHIRException fe) { } catch (FHIRException fe) {
throw new InternalErrorException(fe); throw new InternalErrorException(fe);
} }
myConceptMapDao.save(termConceptMap); termConceptMap = myConceptMapDao.save(termConceptMap);
int codesSaved = 0; int codesSaved = 0;
if (theConceptMap.hasGroup()) { if (theConceptMap.hasGroup()) {
@ -1793,7 +1804,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
termConceptMapGroupElementTarget.setEquivalence(elementTarget.getEquivalence()); termConceptMapGroupElementTarget.setEquivalence(elementTarget.getEquivalence());
myConceptMapGroupElementTargetDao.save(termConceptMapGroupElementTarget); myConceptMapGroupElementTargetDao.save(termConceptMapGroupElementTarget);
if (codesSaved++ % 250 == 0) { if (++codesSaved % 250 == 0) {
ourLog.info("Have saved {} codes in ConceptMap", codesSaved); ourLog.info("Have saved {} codes in ConceptMap", codesSaved);
myConceptMapGroupElementTargetDao.flush(); myConceptMapGroupElementTargetDao.flush();
} }
@ -1815,7 +1826,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
throw new UnprocessableEntityException(msg); throw new UnprocessableEntityException(msg);
} }
ourLog.info("Done storing TermConceptMap."); ourLog.info("Done storing TermConceptMap[{}]", termConceptMap.getId());
} }
@Scheduled(fixedDelay = 600000) // 10 minutes. @Scheduled(fixedDelay = 600000) // 10 minutes.
@ -1932,7 +1943,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
Optional<TermValueSet> optionalExistingTermValueSetByUrl = myValueSetDao.findByUrl(url); Optional<TermValueSet> optionalExistingTermValueSetByUrl = myValueSetDao.findByUrl(url);
if (!optionalExistingTermValueSetByUrl.isPresent()) { if (!optionalExistingTermValueSetByUrl.isPresent()) {
myValueSetDao.save(termValueSet); termValueSet = myValueSetDao.save(termValueSet);
} else { } else {
TermValueSet existingTermValueSet = optionalExistingTermValueSetByUrl.get(); TermValueSet existingTermValueSet = optionalExistingTermValueSetByUrl.get();
@ -1946,7 +1957,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
throw new UnprocessableEntityException(msg); throw new UnprocessableEntityException(msg);
} }
ourLog.info("Done storing TermValueSet."); ourLog.info("Done storing TermValueSet[{}]", termValueSet.getId());
} }
@Override @Override
@ -2354,6 +2365,10 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
return retVal; return retVal;
} }
protected void throwInvalidValueSet(String theValueSet) {
throw new ResourceNotFoundException("Unknown ValueSet: " + UrlUtil.escapeUrlParam(theValueSet));
}
private static void extractLinksFromConceptAndChildren(TermConcept theConcept, List<TermConceptParentChildLink> theLinks) { private static void extractLinksFromConceptAndChildren(TermConcept theConcept, List<TermConceptParentChildLink> theLinks) {
theLinks.addAll(theConcept.getParents()); theLinks.addAll(theConcept.getParents());
for (TermConceptParentChildLink child : theConcept.getChildren()) { for (TermConceptParentChildLink child : theConcept.getChildren()) {

View File

@ -210,9 +210,10 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen
@Override @Override
public List<VersionIndependentConcept> expandValueSet(String theValueSet) { public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
// TODO: DM 2019-09-10 - This is problematic because an incorrect URL that matches ValueSet.id will not be found in the terminology tables but will yield a ValueSet here. Depending on the ValueSet, the expansion may time-out.
ValueSet vs = myValidationSupport.fetchResource(myContext, ValueSet.class, theValueSet); ValueSet vs = myValidationSupport.fetchResource(myContext, ValueSet.class, theValueSet);
if (vs == null) { if (vs == null) {
return Collections.emptyList(); super.throwInvalidValueSet(theValueSet);
} }
org.hl7.fhir.r4.model.ValueSet valueSetToExpandR4; org.hl7.fhir.r4.model.ValueSet valueSetToExpandR4;

View File

@ -122,9 +122,10 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
@Override @Override
public List<VersionIndependentConcept> expandValueSet(String theValueSet) { public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
// TODO: DM 2019-09-10 - This is problematic because an incorrect URL that matches ValueSet.id will not be found in the terminology tables but will yield a ValueSet here. Depending on the ValueSet, the expansion may time-out.
ValueSet vs = myValidationSupport.fetchResource(myContext, ValueSet.class, theValueSet); ValueSet vs = myValidationSupport.fetchResource(myContext, ValueSet.class, theValueSet);
if (vs == null) { if (vs == null) {
return Collections.emptyList(); super.throwInvalidValueSet(theValueSet);
} }
return expandValueSetAndReturnVersionIndependentConcepts(vs); return expandValueSetAndReturnVersionIndependentConcepts(vs);

View File

@ -131,9 +131,10 @@ public class HapiTerminologySvcR5 extends BaseHapiTerminologySvcImpl implements
@Override @Override
public List<VersionIndependentConcept> expandValueSet(String theValueSet) { public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
// TODO: DM 2019-09-10 - This is problematic because an incorrect URL that matches ValueSet.id will not be found in the terminology tables but will yield a ValueSet here. Depending on the ValueSet, the expansion may time-out.
ValueSet valueSetR5 = myValidationSupport.fetchResource(myContext, ValueSet.class, theValueSet); ValueSet valueSetR5 = myValidationSupport.fetchResource(myContext, ValueSet.class, theValueSet);
if (valueSetR5 == null) { if (valueSetR5 == null) {
return Collections.emptyList(); super.throwInvalidValueSet(theValueSet);
} }
return expandValueSetAndReturnVersionIndependentConcepts(org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(valueSetR5)); return expandValueSetAndReturnVersionIndependentConcepts(org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(valueSetR5));

View File

@ -31,6 +31,7 @@ import ca.uhn.fhir.util.ValidateUtil;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import static org.apache.commons.lang3.StringUtils.*; import static org.apache.commons.lang3.StringUtils.*;
@ -44,6 +45,7 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
private ITermValueSetConceptDesignationDao myValueSetConceptDesignationDao; private ITermValueSetConceptDesignationDao myValueSetConceptDesignationDao;
private int myConceptsSaved; private int myConceptsSaved;
private int myDesignationsSaved; private int myDesignationsSaved;
private int myConceptsExcluded;
public ValueSetConceptAccumulator(@Nonnull TermValueSet theTermValueSet, @Nonnull ITermValueSetDao theValueSetDao, @Nonnull ITermValueSetConceptDao theValueSetConceptDao, @Nonnull ITermValueSetConceptDesignationDao theValueSetConceptDesignationDao) { public ValueSetConceptAccumulator(@Nonnull TermValueSet theTermValueSet, @Nonnull ITermValueSetDao theValueSetDao, @Nonnull ITermValueSetConceptDao theValueSetConceptDao, @Nonnull ITermValueSetConceptDesignationDao theValueSetConceptDesignationDao) {
myTermValueSet = theTermValueSet; myTermValueSet = theTermValueSet;
@ -52,6 +54,7 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
myValueSetConceptDesignationDao = theValueSetConceptDesignationDao; myValueSetConceptDesignationDao = theValueSetConceptDesignationDao;
myConceptsSaved = 0; myConceptsSaved = 0;
myDesignationsSaved = 0; myDesignationsSaved = 0;
myConceptsExcluded = 0;
} }
@Override @Override
@ -88,6 +91,10 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
myTermValueSet.decrementTotalConcepts(); myTermValueSet.decrementTotalConcepts();
myValueSetDao.save(myTermValueSet); myValueSetDao.save(myTermValueSet);
ourLog.info("Done excluding [{}|{}] from ValueSet[{}]", concept.getSystem(), concept.getCode(), myTermValueSet.getUrl()); ourLog.info("Done excluding [{}|{}] from ValueSet[{}]", concept.getSystem(), concept.getCode(), myTermValueSet.getUrl());
if (++myConceptsExcluded % 250 == 0) {
ourLog.info("Have excluded {} concepts from ValueSet[{}]", myConceptsExcluded, myTermValueSet.getUrl());
}
} }
} }
@ -97,6 +104,7 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
TermValueSetConcept concept = new TermValueSetConcept(); TermValueSetConcept concept = new TermValueSetConcept();
concept.setValueSet(myTermValueSet); concept.setValueSet(myTermValueSet);
concept.setOrder(myConceptsSaved);
concept.setSystem(theSystem); concept.setSystem(theSystem);
concept.setCode(theCode); concept.setCode(theCode);
if (isNotBlank(theDisplay)) { if (isNotBlank(theDisplay)) {
@ -105,7 +113,7 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
myValueSetConceptDao.save(concept); myValueSetConceptDao.save(concept);
myValueSetDao.save(myTermValueSet.incrementTotalConcepts()); myValueSetDao.save(myTermValueSet.incrementTotalConcepts());
if (myConceptsSaved++ % 250 == 0) { // TODO: DM 2019-08-23 - This message never appears in the log. Fix it! if (++myConceptsSaved % 250 == 0) {
ourLog.info("Have pre-expanded {} concepts in ValueSet[{}]", myConceptsSaved, myTermValueSet.getUrl()); ourLog.info("Have pre-expanded {} concepts in ValueSet[{}]", myConceptsSaved, myTermValueSet.getUrl());
} }
@ -130,14 +138,30 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
myValueSetConceptDesignationDao.save(designation); myValueSetConceptDesignationDao.save(designation);
myValueSetDao.save(myTermValueSet.incrementTotalConceptDesignations()); myValueSetDao.save(myTermValueSet.incrementTotalConceptDesignations());
if (myDesignationsSaved++ % 250 == 0) { // TODO: DM 2019-08-23 - This message never appears in the log. Fix it! if (++myDesignationsSaved % 250 == 0) {
ourLog.info("Have pre-expanded {} designations for Concept[{}|{}] in ValueSet[{}]", myDesignationsSaved, theConcept.getSystem(), theConcept.getCode(), myTermValueSet.getUrl()); ourLog.debug("Have pre-expanded {} designations for Concept[{}|{}] in ValueSet[{}]", myDesignationsSaved, theConcept.getSystem(), theConcept.getCode(), myTermValueSet.getUrl());
} }
return designation; return designation;
} }
// TODO: DM 2019-07-16 - We need TermValueSetConceptProperty, similar to TermConceptProperty. public Boolean removeGapsFromConceptOrder() {
// TODO: DM 2019-07-16 - We should also populate TermValueSetConceptProperty entities here. if (myConceptsExcluded <= 0) {
// TODO: DM 2019-07-30 - Expansions don't include the properties themselves; they are needed to facilitate filters and parameterized expansions. return false;
}
ourLog.info("Removing gaps from concept order for ValueSet[{}]", myTermValueSet.getUrl());
int order = 0;
List<Long> conceptIds = myValueSetConceptDao.findIdsByTermValueSetId(myTermValueSet.getId());
for (Long conceptId : conceptIds) {
myValueSetConceptDao.updateOrderById(conceptId, order++);
}
ourLog.info("Have removed gaps from concept order for {} concepts in ValueSet[{}]", conceptIds.size(), myTermValueSet.getUrl());
return true;
}
// TODO: DM 2019-07-16 - We may need TermValueSetConceptProperty, similar to TermConceptProperty.
// TODO: DM 2019-07-16 - If so, we should also populate TermValueSetConceptProperty entities here.
// TODO: DM 2019-07-30 - Expansions don't include the properties themselves; they may be needed to facilitate filters and parameterized expansions.
} }

View File

@ -13,6 +13,7 @@ import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.TokenParamModifier; import ca.uhn.fhir.rest.param.TokenParamModifier;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
@ -801,8 +802,8 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
try { try {
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN)); params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty()); assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
} catch (InvalidRequestException e) { } catch (ResourceNotFoundException e) {
assertEquals("Unable to find imported value set http://example.com/my_value_set", e.getMessage()); assertEquals("Unknown ValueSet: http%3A%2F%2Fexample.com%2Fmy_value_set", e.getMessage());
} }
} }
@ -1117,10 +1118,13 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
valueSet.setUrl(URL_MY_VALUE_SET); valueSet.setUrl(URL_MY_VALUE_SET);
myValueSetDao.update(valueSet, mySrd).getId().toUnqualifiedVersionless(); myValueSetDao.update(valueSet, mySrd).getId().toUnqualifiedVersionless();
try {
params = new SearchParameterMap(); params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN)); params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
params.add(Observation.SP_STATUS, new TokenParam(null, "final")); params.add(Observation.SP_STATUS, new TokenParam(null, "final"));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty()); } catch (ResourceNotFoundException e) {
assertEquals("Unknown ValueSet: http%3A%2F%2Fexample.com%2Fmy_value_set", e.getMessage());
}
} }

View File

@ -13,6 +13,7 @@ import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.TokenParamModifier; import ca.uhn.fhir.rest.param.TokenParamModifier;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
@ -1168,9 +1169,12 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
params.add(AuditEvent.SP_TYPE, new TokenParam(null, "http://hl7.org/fhir/ValueSet/audit-event-type").setModifier(TokenParamModifier.IN)); params.add(AuditEvent.SP_TYPE, new TokenParam(null, "http://hl7.org/fhir/ValueSet/audit-event-type").setModifier(TokenParamModifier.IN));
assertThat(toUnqualifiedVersionlessIdValues(myAuditEventDao.search(params)), containsInAnyOrder(idIn1.getValue(), idIn2.getValue())); assertThat(toUnqualifiedVersionlessIdValues(myAuditEventDao.search(params)), containsInAnyOrder(idIn1.getValue(), idIn2.getValue()));
try {
params = new SearchParameterMap(); params = new SearchParameterMap();
params.add(AuditEvent.SP_TYPE, new TokenParam(null, "http://hl7.org/fhir/ValueSet/v3-PurposeOfUse").setModifier(TokenParamModifier.IN)); params.add(AuditEvent.SP_TYPE, new TokenParam(null, "http://hl7.org/fhir/ValueSet/v3-PurposeOfUse").setModifier(TokenParamModifier.IN));
assertThat(toUnqualifiedVersionlessIdValues(myAuditEventDao.search(params)), empty()); } catch (ResourceNotFoundException e) {
assertEquals("Unknown ValueSet: http%3A%2F%2Fhl7.org%2Ffhir%2FValueSet%2Fv3-PurposeOfUse", e.getMessage());
}
} }
@Test @Test
@ -1203,8 +1207,8 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
try { try {
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN)); params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty()); assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
} catch (InvalidRequestException e) { } catch (ResourceNotFoundException e) {
assertEquals("Unable to find imported value set http://example.com/my_value_set", e.getMessage()); assertEquals("Unknown ValueSet: http%3A%2F%2Fexample.com%2Fmy_value_set", e.getMessage());
} }
} }
@ -1234,10 +1238,13 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
valueSet.setUrl(URL_MY_VALUE_SET); valueSet.setUrl(URL_MY_VALUE_SET);
myValueSetDao.update(valueSet, mySrd).getId().toUnqualifiedVersionless(); myValueSetDao.update(valueSet, mySrd).getId().toUnqualifiedVersionless();
try {
params = new SearchParameterMap(); params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN)); params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
params.add(Observation.SP_STATUS, new TokenParam(null, "final")); params.add(Observation.SP_STATUS, new TokenParam(null, "final"));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty()); } catch (ResourceNotFoundException e) {
assertEquals("Unknown ValueSet: http%3A%2F%2Fnon_existant_VS", e.getMessage());
}
} }

View File

@ -1,14 +1,16 @@
package ca.uhn.fhir.jpa.provider.dstu3; package ca.uhn.fhir.jpa.provider.dstu3;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao; import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
import ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest; import ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept; import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum; import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc; import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil;
@ -25,11 +27,14 @@ 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.ConceptSetComponent; import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator; import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
import org.hl7.fhir.dstu3.model.codesystems.HttpVerb;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -43,18 +48,76 @@ import static org.junit.Assert.*;
public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3Test { public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderDstu3ValueSetTest.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderDstu3ValueSetTest.class);
private IIdType myExtensionalCsId;
private IIdType myExtensionalVsId; private IIdType myExtensionalVsId;
private IIdType myLocalValueSetId; private IIdType myLocalValueSetId;
private Long myExtensionalCsIdOnResourceTable;
private Long myExtensionalVsIdOnResourceTable;
private ValueSet myLocalVs; private ValueSet myLocalVs;
@Before private void loadAndPersistCodeSystemAndValueSet(HttpVerb theVerb) throws IOException {
@Transactional loadAndPersistCodeSystem(theVerb);
public void before02() throws IOException { loadAndPersistValueSet(theVerb);
CodeSystem cs = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml"); }
myCodeSystemDao.create(cs, mySrd);
ValueSet upload = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml"); private void loadAndPersistCodeSystem(HttpVerb theVerb) throws IOException {
myExtensionalVsId = myValueSetDao.create(upload, mySrd).getId().toUnqualifiedVersionless(); CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
codeSystem.setId("CodeSystem/cs");
persistCodeSystem(codeSystem, theVerb);
}
private void persistCodeSystem(CodeSystem theCodeSystem, HttpVerb theVerb) {
switch (theVerb) {
case POST:
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
myExtensionalCsId = myCodeSystemDao.create(theCodeSystem, mySrd).getId().toUnqualifiedVersionless();
}
});
break;
case PUT:
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
myExtensionalCsId = myCodeSystemDao.update(theCodeSystem, mySrd).getId().toUnqualifiedVersionless();
}
});
break;
default:
throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb);
}
myExtensionalCsIdOnResourceTable = myCodeSystemDao.readEntity(myExtensionalCsId, null).getId();
}
private void loadAndPersistValueSet(HttpVerb theVerb) throws IOException {
ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
valueSet.setId("ValueSet/vs");
persistValueSet(valueSet, theVerb);
}
private void persistValueSet(ValueSet theValueSet, HttpVerb theVerb) {
switch (theVerb) {
case POST:
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
myExtensionalVsId = myValueSetDao.create(theValueSet, mySrd).getId().toUnqualifiedVersionless();
}
});
break;
case PUT:
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
myExtensionalVsId = myValueSetDao.update(theValueSet, mySrd).getId().toUnqualifiedVersionless();
}
});
break;
default:
throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb);
}
myExtensionalVsIdOnResourceTable = myValueSetDao.readEntity(myExtensionalVsId, null).getId();
} }
private CodeSystem createExternalCs() { private CodeSystem createExternalCs() {
@ -78,7 +141,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
} }
private void createLocalCsAndVs() { private void createLocalCsAndVs() {
//@formatter:off
CodeSystem codeSystem = new CodeSystem(); CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM); codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setContent(CodeSystemContentMode.COMPLETE); codeSystem.setContent(CodeSystemContentMode.COMPLETE);
@ -92,7 +154,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
.addConcept().setCode("B").setDisplay("Code B") .addConcept().setCode("B").setDisplay("Code B")
.addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code BA")) .addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code BA"))
.addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code BB")); .addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code BB"));
//@formatter:on
myCodeSystemDao.create(codeSystem, mySrd); myCodeSystemDao.create(codeSystem, mySrd);
createLocalVs(codeSystem); createLocalVs(codeSystem);
@ -169,7 +230,9 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
@Test @Test
public void testExpandValueSetPropertySearchWithRegexExcludeUsingOr() { public void testExpandValueSetPropertySearchWithRegexExcludeUsingOr() throws Exception {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
createLoincSystemWithSomeCodes(); createLoincSystemWithSomeCodes();
List<String> codes; List<String> codes;
@ -207,7 +270,9 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
@Test @Test
public void testExpandValueSetPropertySearchWithRegexExcludeNoFilter() { public void testExpandValueSetPropertySearchWithRegexExcludeNoFilter() throws Exception {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
createLoincSystemWithSomeCodes(); createLoincSystemWithSomeCodes();
List<String> codes; List<String> codes;
@ -233,8 +298,9 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
@Test @Test
public void testExpandById() { public void testExpandById() throws Exception {
//@formatter:off loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onInstance(myExtensionalVsId) .onInstance(myExtensionalVsId)
@ -242,7 +308,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
.withNoParameters(Parameters.class) .withNoParameters(Parameters.class)
.execute(); .execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource(); ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
@ -263,9 +328,42 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
} }
@Test @Test
public void testExpandByIdWithFilter() { public void testExpandByIdWithPreExpansion() throws Exception {
myDaoConfig.setPreExpandValueSetsExperimental(true);
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
Parameters respParam = ourClient
.operation()
.onInstance(myExtensionalVsId)
.named("expand")
.withNoParameters(Parameters.class)
.execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, Matchers.containsString("<ValueSet xmlns=\"http://hl7.org/fhir\">"));
assertThat(resp, Matchers.containsString("<expansion>"));
assertThat(resp, Matchers.containsString("<contains>"));
assertThat(resp, Matchers.containsString("<system value=\"http://acme.org\"/>"));
assertThat(resp, Matchers.containsString("<code value=\"8450-9\"/>"));
assertThat(resp, Matchers.containsString("<display value=\"Systolic blood pressure--expiration\"/>"));
assertThat(resp, Matchers.containsString("</contains>"));
assertThat(resp, Matchers.containsString("<contains>"));
assertThat(resp, Matchers.containsString("<system value=\"http://acme.org\"/>"));
assertThat(resp, Matchers.containsString("<code value=\"11378-7\"/>"));
assertThat(resp, Matchers.containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
assertThat(resp, Matchers.containsString("</contains>"));
assertThat(resp, Matchers.containsString("</expansion>"));
}
@Test
public void testExpandByIdWithFilter() throws Exception {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
//@formatter:off
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onInstance(myExtensionalVsId) .onInstance(myExtensionalVsId)
@ -273,7 +371,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
.withParameter(Parameters.class, "filter", new StringType("first")) .withParameter(Parameters.class, "filter", new StringType("first"))
.execute(); .execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource(); ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
@ -290,7 +387,9 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
* https://groups.google.com/d/msgid/hapi-fhir/CAN2Cfy8kW%2BAOkgC6VjPsU3gRCpExCNZBmJdi-k5R_TWeyWH4tA%40mail.gmail.com?utm_medium=email&utm_source=footer * https://groups.google.com/d/msgid/hapi-fhir/CAN2Cfy8kW%2BAOkgC6VjPsU3gRCpExCNZBmJdi-k5R_TWeyWH4tA%40mail.gmail.com?utm_medium=email&utm_source=footer
*/ */
@Test @Test
public void testExpandByIdentifier() { public void testExpandByIdentifier() throws Exception {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onType(ValueSet.class) .onType(ValueSet.class)
@ -308,7 +407,9 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
} }
@Test @Test
public void testExpandByUrl() { public void testExpandByUrl() throws Exception {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onType(ValueSet.class) .onType(ValueSet.class)
@ -325,11 +426,72 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
} }
@Test
public void testExpandByUrlWithBogusUrl() throws Exception {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
try {
ourClient
.operation()
.onType(ValueSet.class)
.named("expand")
.withParameter(Parameters.class, "url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/bogus"))
.execute();
} catch (ResourceNotFoundException e) {
assertEquals(404, e.getStatusCode());
assertEquals("HTTP 404 Not Found: Unknown ValueSet: http%3A%2F%2Fwww.healthintersections.com.au%2Ffhir%2FValueSet%2Fbogus", e.getMessage());
}
}
@Test
public void testExpandByUrlWithPreExpansion() throws Exception {
myDaoConfig.setPreExpandValueSetsExperimental(true);
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
Parameters respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("expand")
.withParameter(Parameters.class, "url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, Matchers.stringContainsInOrder(
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
}
@Test
public void testExpandByUrlWithPreExpansionAndBogusUrl() throws Exception {
myDaoConfig.setPreExpandValueSetsExperimental(true);
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
try {
Parameters respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("expand")
.withParameter(Parameters.class, "url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/bogus"))
.execute();
} catch (ResourceNotFoundException e) {
assertEquals(404, e.getStatusCode());
assertEquals("HTTP 404 Not Found: Unknown ValueSet: http%3A%2F%2Fwww.healthintersections.com.au%2Ffhir%2FValueSet%2Fbogus", e.getMessage());
}
}
@Test @Test
public void testExpandByValueSet() throws IOException { public void testExpandByValueSet() throws IOException {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml"); ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
//@formatter:off
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onType(ValueSet.class) .onType(ValueSet.class)
@ -337,15 +499,12 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
.withParameter(Parameters.class, "valueSet", toExpand) .withParameter(Parameters.class, "valueSet", toExpand)
.execute(); .execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource(); ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
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, Matchers.stringContainsInOrder( assertThat(resp, Matchers.stringContainsInOrder(
"<code value=\"11378-7\"/>", "<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>")); "<display value=\"Systolic blood pressure at First encounter\"/>"));
//@formatter:on
} }
@ -354,7 +513,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
createLocalVsPointingAtBuiltInCodeSystem(); createLocalVsPointingAtBuiltInCodeSystem();
assertNotNull(myLocalValueSetId); assertNotNull(myLocalValueSetId);
//@formatter:off
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onType(ValueSet.class) .onType(ValueSet.class)
@ -362,7 +520,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
.withParameter(Parameters.class, "valueSet", myLocalVs) .withParameter(Parameters.class, "valueSet", myLocalVs)
.execute(); .execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource(); ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
@ -376,7 +533,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
assertNotNull(myLocalVs); assertNotNull(myLocalVs);
myLocalVs.setId(""); myLocalVs.setId("");
//@formatter:off
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onType(ValueSet.class) .onType(ValueSet.class)
@ -384,7 +540,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
.withParameter(Parameters.class, "valueSet", myLocalVs) .withParameter(Parameters.class, "valueSet", myLocalVs)
.execute(); .execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource(); ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
@ -397,6 +552,8 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
@Test @Test
public void testExpandInvalidParams() throws IOException { public void testExpandInvalidParams() throws IOException {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
try { try {
ourClient ourClient
.operation() .operation()
@ -467,7 +624,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
createLocalVsPointingAtBuiltInCodeSystem(); createLocalVsPointingAtBuiltInCodeSystem();
assertNotNull(myLocalValueSetId); assertNotNull(myLocalValueSetId);
//@formatter:off
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onInstance(myLocalValueSetId) .onInstance(myLocalValueSetId)
@ -475,7 +631,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
.withNoParameters(Parameters.class) .withNoParameters(Parameters.class)
.execute(); .execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource(); ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
@ -488,7 +643,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
createExternalCsAndLocalVs(); createExternalCsAndLocalVs();
assertNotNull(myLocalValueSetId); assertNotNull(myLocalValueSetId);
//@formatter:off
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onInstance(myLocalValueSetId) .onInstance(myLocalValueSetId)
@ -496,7 +650,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
.withNoParameters(Parameters.class) .withNoParameters(Parameters.class)
.execute(); .execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource(); ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
@ -512,7 +665,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
createExternalCsAndLocalVs(); createExternalCsAndLocalVs();
assertNotNull(myLocalValueSetId); assertNotNull(myLocalValueSetId);
//@formatter:off
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onType(ValueSet.class) .onType(ValueSet.class)
@ -520,7 +672,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
.withParameter(Parameters.class, "identifier", new UriType(URL_MY_VALUE_SET)) .withParameter(Parameters.class, "identifier", new UriType(URL_MY_VALUE_SET))
.execute(); .execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource(); ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
@ -536,7 +687,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
createExternalCsAndLocalVsWithUnknownCode(); createExternalCsAndLocalVsWithUnknownCode();
assertNotNull(myLocalValueSetId); assertNotNull(myLocalValueSetId);
//@formatter:off
try { try {
ourClient ourClient
.operation() .operation()
@ -547,7 +697,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
} catch (InvalidRequestException e) { } catch (InvalidRequestException e) {
assertEquals("HTTP 400 Bad Request: Invalid filter criteria - code does not exist: {http://example.com/my_code_system}childFOOOOOOO", e.getMessage()); assertEquals("HTTP 400 Bad Request: Invalid filter criteria - code does not exist: {http://example.com/my_code_system}childFOOOOOOO", e.getMessage());
} }
//@formatter:on
} }
/** /**
@ -576,8 +725,9 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
} }
@Test @Test
public void testValidateCodeOperationByCodeAndSystemInstance() { public void testValidateCodeOperationByCodeAndSystemInstance() throws Exception {
//@formatter:off loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onInstance(myExtensionalVsId) .onInstance(myExtensionalVsId)
@ -585,7 +735,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
.withParameter(Parameters.class, "code", new CodeType("8495-4")) .withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org")) .andParameter("system", new UriType("http://acme.org"))
.execute(); .execute();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp); ourLog.info(resp);
@ -595,6 +744,8 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
@Test @Test
public void testValidateCodeOperationByCodeAndSystemInstanceOnInstance() throws IOException { public void testValidateCodeOperationByCodeAndSystemInstanceOnInstance() throws IOException {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
createLocalCsAndVs(); createLocalCsAndVs();
createLocalVsWithIncludeConcept(); createLocalVsWithIncludeConcept();
@ -617,8 +768,9 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
} }
@Test @Test
public void testValidateCodeOperationByCodeAndSystemType() { public void testValidateCodeOperationByCodeAndSystemType() throws Exception {
//@formatter:off loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onType(ValueSet.class) .onType(ValueSet.class)
@ -626,7 +778,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
.withParameter(Parameters.class, "code", new CodeType("8450-9")) .withParameter(Parameters.class, "code", new CodeType("8450-9"))
.andParameter("system", new UriType("http://acme.org")) .andParameter("system", new UriType("http://acme.org"))
.execute(); .execute();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp); ourLog.info(resp);
@ -638,7 +789,9 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
* Technically this is the wrong param name * Technically this is the wrong param name
*/ */
@Test @Test
public void testValiedateCodeAgainstBuiltInSystem() { public void testValiedateCodeAgainstBuiltInSystem() throws Exception {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onType(ValueSet.class) .onType(ValueSet.class)
@ -666,7 +819,9 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
* Technically this is the right param name * Technically this is the right param name
*/ */
@Test @Test
public void testValiedateCodeAgainstBuiltInSystemByUrl() { public void testValiedateCodeAgainstBuiltInSystemByUrl() throws Exception {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onType(ValueSet.class) .onType(ValueSet.class)
@ -690,6 +845,11 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
assertEquals("Burn", ((StringType) respParam.getParameter().get(2).getValue()).getValue()); assertEquals("Burn", ((StringType) respParam.getParameter().get(2).getValue()).getValue());
} }
@After
public void afterResetPreExpansionDefault() {
myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental());
}
@AfterClass @AfterClass
public static void afterClassClearContext() { public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest(); TestUtil.clearAllStaticFieldsForUnitTest();

View File

@ -347,22 +347,16 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
public void testExpungeEverythingWhereResourceInSearchResults() { public void testExpungeEverythingWhereResourceInSearchResults() {
createStandardPatients(); createStandardPatients();
runInTransaction(() -> { await().until(()-> runInTransaction(() -> mySearchEntityDao.count() == 0));
await().until(()->mySearchEntityDao.count() == 0); await().until(()-> runInTransaction(() -> mySearchResultDao.count() == 0));
await().until(()->mySearchResultDao.count() == 0);
});
PersistedJpaSearchFirstPageBundleProvider search = (PersistedJpaSearchFirstPageBundleProvider) myPatientDao.search(new SearchParameterMap()); PersistedJpaSearchFirstPageBundleProvider search = (PersistedJpaSearchFirstPageBundleProvider) myPatientDao.search(new SearchParameterMap());
assertEquals(PersistedJpaSearchFirstPageBundleProvider.class, search.getClass()); assertEquals(PersistedJpaSearchFirstPageBundleProvider.class, search.getClass());
assertEquals(2, search.size().intValue()); assertEquals(2, search.size().intValue());
assertEquals(2, search.getResources(0, 2).size()); assertEquals(2, search.getResources(0, 2).size());
runInTransaction(() -> { await().until(()-> runInTransaction(() -> mySearchEntityDao.count() == 1));
await().until(()->mySearchEntityDao.count() == 1); await().until(()-> runInTransaction(() -> mySearchResultDao.count() == 2));
await().until(()->mySearchResultDao.count() == 2);
ourLog.info("Search results: {}", mySearchResultDao.findAll().toString());
assertEquals(mySearchResultDao.findAll().toString(), 2, mySearchResultDao.count());
});
mySystemDao.expunge(new ExpungeOptions() mySystemDao.expunge(new ExpungeOptions()
.setExpungeEverything(true), null); .setExpungeEverything(true), null);

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.provider.r4; package ca.uhn.fhir.jpa.provider.r4;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao; import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
@ -8,6 +9,7 @@ import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc; import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil;
@ -24,10 +26,13 @@ import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent; import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r4.model.ValueSet.FilterOperator; import org.hl7.fhir.r4.model.ValueSet.FilterOperator;
import org.hl7.fhir.r4.model.codesystems.HttpVerb;
import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -40,18 +45,76 @@ import static org.junit.Assert.*;
public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test { public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4ValueSetTest.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4ValueSetTest.class);
private IIdType myExtensionalCsId;
private IIdType myExtensionalVsId; private IIdType myExtensionalVsId;
private IIdType myLocalValueSetId; private IIdType myLocalValueSetId;
private Long myExtensionalCsIdOnResourceTable;
private Long myExtensionalVsIdOnResourceTable;
private ValueSet myLocalVs; private ValueSet myLocalVs;
@Before private void loadAndPersistCodeSystemAndValueSet(HttpVerb theVerb) throws IOException {
@Transactional loadAndPersistCodeSystem(theVerb);
public void before02() throws IOException { loadAndPersistValueSet(theVerb);
CodeSystem cs = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml"); }
myCodeSystemDao.create(cs, mySrd);
ValueSet upload = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml"); private void loadAndPersistCodeSystem(HttpVerb theVerb) throws IOException {
myExtensionalVsId = myValueSetDao.create(upload, mySrd).getId().toUnqualifiedVersionless(); CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
codeSystem.setId("CodeSystem/cs");
persistCodeSystem(codeSystem, theVerb);
}
private void persistCodeSystem(CodeSystem theCodeSystem, HttpVerb theVerb) {
switch (theVerb) {
case POST:
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
myExtensionalCsId = myCodeSystemDao.create(theCodeSystem, mySrd).getId().toUnqualifiedVersionless();
}
});
break;
case PUT:
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
myExtensionalCsId = myCodeSystemDao.update(theCodeSystem, mySrd).getId().toUnqualifiedVersionless();
}
});
break;
default:
throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb);
}
myExtensionalCsIdOnResourceTable = myCodeSystemDao.readEntity(myExtensionalCsId, null).getId();
}
private void loadAndPersistValueSet(HttpVerb theVerb) throws IOException {
ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
valueSet.setId("ValueSet/vs");
persistValueSet(valueSet, theVerb);
}
private void persistValueSet(ValueSet theValueSet, HttpVerb theVerb) {
switch (theVerb) {
case POST:
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
myExtensionalVsId = myValueSetDao.create(theValueSet, mySrd).getId().toUnqualifiedVersionless();
}
});
break;
case PUT:
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
myExtensionalVsId = myValueSetDao.update(theValueSet, mySrd).getId().toUnqualifiedVersionless();
}
});
break;
default:
throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb);
}
myExtensionalVsIdOnResourceTable = myValueSetDao.readEntity(myExtensionalVsId, null).getId();
} }
private CodeSystem createExternalCs() { private CodeSystem createExternalCs() {
@ -128,8 +191,9 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
} }
@Test @Test
public void testExpandById() { public void testExpandById() throws Exception {
//@formatter:off loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onInstance(myExtensionalVsId) .onInstance(myExtensionalVsId)
@ -137,7 +201,6 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
.withNoParameters(Parameters.class) .withNoParameters(Parameters.class)
.execute(); .execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource(); ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
@ -158,9 +221,42 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
} }
@Test @Test
public void testExpandByIdWithFilter() { public void testExpandByIdWithPreExpansion() throws Exception {
myDaoConfig.setPreExpandValueSetsExperimental(true);
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
Parameters respParam = ourClient
.operation()
.onInstance(myExtensionalVsId)
.named("expand")
.withNoParameters(Parameters.class)
.execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, containsString("<ValueSet xmlns=\"http://hl7.org/fhir\">"));
assertThat(resp, containsString("<expansion>"));
assertThat(resp, containsString("<contains>"));
assertThat(resp, containsString("<system value=\"http://acme.org\"/>"));
assertThat(resp, containsString("<code value=\"8450-9\"/>"));
assertThat(resp, containsString("<display value=\"Systolic blood pressure--expiration\"/>"));
assertThat(resp, containsString("</contains>"));
assertThat(resp, containsString("<contains>"));
assertThat(resp, containsString("<system value=\"http://acme.org\"/>"));
assertThat(resp, containsString("<code value=\"11378-7\"/>"));
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
assertThat(resp, containsString("</contains>"));
assertThat(resp, containsString("</expansion>"));
}
@Test
public void testExpandByIdWithFilter() throws Exception {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
//@formatter:off
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onInstance(myExtensionalVsId) .onInstance(myExtensionalVsId)
@ -168,7 +264,6 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
.withParameter(Parameters.class, "filter", new StringType("first")) .withParameter(Parameters.class, "filter", new StringType("first"))
.execute(); .execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource(); ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
@ -178,7 +273,31 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
} }
@Test @Test
public void testExpandByUrl() { public void testExpandByIdWithFilterWithPreExpansion() throws Exception {
myDaoConfig.setPreExpandValueSetsExperimental(true);
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
Parameters respParam = ourClient
.operation()
.onInstance(myExtensionalVsId)
.named("expand")
.withParameter(Parameters.class, "filter", new StringType("first"))
.execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
}
@Test
public void testExpandByUrl() throws Exception {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onType(ValueSet.class) .onType(ValueSet.class)
@ -195,8 +314,70 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
} }
@Test
public void testExpandByUrlWithBogusUrl() throws Exception {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
try {
ourClient
.operation()
.onType(ValueSet.class)
.named("expand")
.withParameter(Parameters.class, "url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/bogus"))
.execute();
} catch (ResourceNotFoundException e) {
assertEquals(404, e.getStatusCode());
assertEquals("HTTP 404 Not Found: Unknown ValueSet: http%3A%2F%2Fwww.healthintersections.com.au%2Ffhir%2FValueSet%2Fbogus", e.getMessage());
}
}
@Test
public void testExpandByUrlWithPreExpansion() throws Exception {
myDaoConfig.setPreExpandValueSetsExperimental(true);
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
Parameters respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("expand")
.withParameter(Parameters.class, "url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, stringContainsInOrder(
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
}
@Test
public void testExpandByUrlWithPreExpansionAndBogusUrl() throws Exception {
myDaoConfig.setPreExpandValueSetsExperimental(true);
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
try {
Parameters respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("expand")
.withParameter(Parameters.class, "url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/bogus"))
.execute();
} catch (ResourceNotFoundException e) {
assertEquals(404, e.getStatusCode());
assertEquals("HTTP 404 Not Found: Unknown ValueSet: http%3A%2F%2Fwww.healthintersections.com.au%2Ffhir%2FValueSet%2Fbogus", e.getMessage());
}
}
@Test @Test
public void testExpandByValueSet() throws IOException { public void testExpandByValueSet() throws IOException {
loadAndPersistCodeSystem(HttpVerb.POST);
ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml"); ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
Parameters respParam = ourClient Parameters respParam = ourClient
@ -215,13 +396,36 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
} }
@Test
public void testExpandByValueSetWithPreExpansion() throws IOException {
myDaoConfig.setPreExpandValueSetsExperimental(true);
loadAndPersistCodeSystem(HttpVerb.POST);
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
Parameters respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("expand")
.withParameter(Parameters.class, "valueSet", toExpand)
.execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, stringContainsInOrder(
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
}
@Test @Test
public void testExpandInlineVsAgainstBuiltInCs() { public void testExpandInlineVsAgainstBuiltInCs() {
createLocalVsPointingAtBuiltInCodeSystem(); createLocalVsPointingAtBuiltInCodeSystem();
assertNotNull(myLocalValueSetId); assertNotNull(myLocalValueSetId);
//@formatter:off
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onType(ValueSet.class) .onType(ValueSet.class)
@ -229,7 +433,6 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
.withParameter(Parameters.class, "valueSet", myLocalVs) .withParameter(Parameters.class, "valueSet", myLocalVs)
.execute(); .execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource(); ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
@ -243,7 +446,6 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
assertNotNull(myLocalVs); assertNotNull(myLocalVs);
myLocalVs.setId(""); myLocalVs.setId("");
//@formatter:off
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onType(ValueSet.class) .onType(ValueSet.class)
@ -251,7 +453,6 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
.withParameter(Parameters.class, "valueSet", myLocalVs) .withParameter(Parameters.class, "valueSet", myLocalVs)
.execute(); .execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource(); ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
@ -263,7 +464,9 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
} }
@Test @Test
public void testExpandInvalidParams() throws IOException { public void testExpandInvalidParams() throws Exception {
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
try { try {
ourClient ourClient
.operation() .operation()
@ -334,7 +537,6 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
createLocalVsPointingAtBuiltInCodeSystem(); createLocalVsPointingAtBuiltInCodeSystem();
assertNotNull(myLocalValueSetId); assertNotNull(myLocalValueSetId);
//@formatter:off
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onInstance(myLocalValueSetId) .onInstance(myLocalValueSetId)
@ -342,7 +544,6 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
.withNoParameters(Parameters.class) .withNoParameters(Parameters.class)
.execute(); .execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource(); ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
@ -355,7 +556,6 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
createExternalCsAndLocalVs(); createExternalCsAndLocalVs();
assertNotNull(myLocalValueSetId); assertNotNull(myLocalValueSetId);
//@formatter:off
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onInstance(myLocalValueSetId) .onInstance(myLocalValueSetId)
@ -363,7 +563,6 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
.withNoParameters(Parameters.class) .withNoParameters(Parameters.class)
.execute(); .execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource(); ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
@ -401,7 +600,6 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
createExternalCsAndLocalVsWithUnknownCode(); createExternalCsAndLocalVsWithUnknownCode();
assertNotNull(myLocalValueSetId); assertNotNull(myLocalValueSetId);
//@formatter:off
try { try {
ourClient ourClient
.operation() .operation()
@ -412,7 +610,6 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
} catch (InvalidRequestException e) { } catch (InvalidRequestException e) {
assertEquals("HTTP 400 Bad Request: Invalid filter criteria - code does not exist: {http://example.com/my_code_system}childFOOOOOOO", e.getMessage()); assertEquals("HTTP 400 Bad Request: Invalid filter criteria - code does not exist: {http://example.com/my_code_system}childFOOOOOOO", e.getMessage());
} }
//@formatter:on
} }
/** /**
@ -438,8 +635,9 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
} }
@Test @Test
public void testValidateCodeOperationByCodeAndSystemInstance() { public void testValidateCodeOperationByCodeAndSystemInstance() throws Exception {
//@formatter:off loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onInstance(myExtensionalVsId) .onInstance(myExtensionalVsId)
@ -498,8 +696,9 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
} }
@Test @Test
public void testValidateCodeOperationByCodeAndSystemType() { public void testValidateCodeOperationByCodeAndSystemType() throws Exception {
//@formatter:off loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
Parameters respParam = ourClient Parameters respParam = ourClient
.operation() .operation()
.onType(ValueSet.class) .onType(ValueSet.class)
@ -585,6 +784,11 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
} }
@After
public void afterResetPreExpansionDefault() {
myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental());
}
@AfterClass @AfterClass
public static void afterClassClearContext() { public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest(); TestUtil.clearAllStaticFieldsForUnitTest();

View File

@ -658,7 +658,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals(0, myTermValueSetConceptDesignationDao.countByTermValueSetId(termValueSetId).intValue()); assertEquals(0, myTermValueSetConceptDesignationDao.countByTermValueSetId(termValueSetId).intValue());
myTermValueSetConceptDao.deleteByTermValueSetId(termValueSetId); myTermValueSetConceptDao.deleteByTermValueSetId(termValueSetId);
assertEquals(0, myTermValueSetConceptDao.countByTermValueSetId(termValueSetId).intValue()); assertEquals(0, myTermValueSetConceptDao.countByTermValueSetId(termValueSetId).intValue());
myTermValueSetDao.deleteByTermValueSetId(termValueSetId); myTermValueSetDao.deleteById(termValueSetId);
assertFalse(myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).isPresent()); assertFalse(myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).isPresent());
} }
}); });
@ -695,7 +695,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals(0, myTermValueSetConceptDesignationDao.countByTermValueSetId(termValueSetId).intValue()); assertEquals(0, myTermValueSetConceptDesignationDao.countByTermValueSetId(termValueSetId).intValue());
myTermValueSetConceptDao.deleteByTermValueSetId(termValueSetId); myTermValueSetConceptDao.deleteByTermValueSetId(termValueSetId);
assertEquals(0, myTermValueSetConceptDao.countByTermValueSetId(termValueSetId).intValue()); assertEquals(0, myTermValueSetConceptDao.countByTermValueSetId(termValueSetId).intValue());
myTermValueSetDao.deleteByTermValueSetId(termValueSetId); myTermValueSetDao.deleteById(termValueSetId);
assertFalse(myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).isPresent()); assertFalse(myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).isPresent());
} }
}); });
@ -885,19 +885,12 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals("Systolic blood pressure 8 hour minimum", containsComponent.getDisplay()); assertEquals("Systolic blood pressure 8 hour minimum", containsComponent.getDisplay());
assertFalse(containsComponent.hasDesignation()); assertFalse(containsComponent.hasDesignation());
myTermSvc.saveDeferred();
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental());
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal()); assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset()); assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset());
assertEquals(2, expandedValueSet.getExpansion().getParameter().size()); assertEquals(0, expandedValueSet.getExpansion().getParameter().size());
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
assertEquals("count", expandedValueSet.getExpansion().getParameter().get(1).getName());
assertEquals(1000, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue());
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getContains().size()); assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getContains().size());
@ -2097,11 +2090,12 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus()); assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus());
TermValueSetConcept concept = termValueSet.getConcepts().get(0); TermValueSetConcept concept = termValueSet.getConcepts().get(0);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("8450-9", concept.getCode()); assertEquals("8450-9", concept.getCode());
assertEquals("Systolic blood pressure--expiration", concept.getDisplay()); assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
assertEquals(2, concept.getDesignations().size()); assertEquals(2, concept.getDesignations().size());
assertEquals(0, concept.getOrder());
TermValueSetConceptDesignation designation = concept.getDesignations().get(0); TermValueSetConceptDesignation designation = concept.getDesignations().get(0);
assertEquals("nl", designation.getLanguage()); assertEquals("nl", designation.getLanguage());
@ -2118,20 +2112,22 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals("Systoliskt blodtryck - utgång", designation.getValue()); assertEquals("Systoliskt blodtryck - utgång", designation.getValue());
concept = termValueSet.getConcepts().get(1); concept = termValueSet.getConcepts().get(1);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("11378-7", concept.getCode()); assertEquals("11378-7", concept.getCode());
assertEquals("Systolic blood pressure at First encounter", concept.getDisplay()); assertEquals("Systolic blood pressure at First encounter", concept.getDisplay());
assertEquals(0, concept.getDesignations().size()); assertEquals(0, concept.getDesignations().size());
assertEquals(1, concept.getOrder());
// ... // ...
concept = termValueSet.getConcepts().get(22); concept = termValueSet.getConcepts().get(22);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("8491-3", concept.getCode()); assertEquals("8491-3", concept.getCode());
assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay()); assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay());
assertEquals(1, concept.getDesignations().size()); assertEquals(1, concept.getDesignations().size());
assertEquals(22, concept.getOrder());
designation = concept.getDesignations().get(0); designation = concept.getDesignations().get(0);
assertEquals("nl", designation.getLanguage()); assertEquals("nl", designation.getLanguage());
@ -2141,11 +2137,12 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue()); assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue());
concept = termValueSet.getConcepts().get(23); concept = termValueSet.getConcepts().get(23);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("8492-1", concept.getCode()); assertEquals("8492-1", concept.getCode());
assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay()); assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay());
assertEquals(0, concept.getDesignations().size()); assertEquals(0, concept.getDesignations().size());
assertEquals(23, concept.getOrder());
}); });
} }
@ -2195,11 +2192,12 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus()); assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus());
TermValueSetConcept concept = termValueSet.getConcepts().get(0); TermValueSetConcept concept = termValueSet.getConcepts().get(0);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("8450-9", concept.getCode()); assertEquals("8450-9", concept.getCode());
assertEquals("Systolic blood pressure--expiration", concept.getDisplay()); assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
assertEquals(2, concept.getDesignations().size()); assertEquals(2, concept.getDesignations().size());
assertEquals(0, concept.getOrder());
TermValueSetConceptDesignation designation = concept.getDesignations().get(0); TermValueSetConceptDesignation designation = concept.getDesignations().get(0);
assertEquals("nl", designation.getLanguage()); assertEquals("nl", designation.getLanguage());
@ -2216,20 +2214,22 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals("Systoliskt blodtryck - utgång", designation.getValue()); assertEquals("Systoliskt blodtryck - utgång", designation.getValue());
concept = termValueSet.getConcepts().get(1); concept = termValueSet.getConcepts().get(1);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("11378-7", concept.getCode()); assertEquals("11378-7", concept.getCode());
assertEquals("Systolic blood pressure at First encounter", concept.getDisplay()); assertEquals("Systolic blood pressure at First encounter", concept.getDisplay());
assertEquals(0, concept.getDesignations().size()); assertEquals(0, concept.getDesignations().size());
assertEquals(1, concept.getOrder());
// ... // ...
concept = termValueSet.getConcepts().get(22); concept = termValueSet.getConcepts().get(22);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("8491-3", concept.getCode()); assertEquals("8491-3", concept.getCode());
assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay()); assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay());
assertEquals(1, concept.getDesignations().size()); assertEquals(1, concept.getDesignations().size());
assertEquals(22, concept.getOrder());
designation = concept.getDesignations().get(0); designation = concept.getDesignations().get(0);
assertEquals("nl", designation.getLanguage()); assertEquals("nl", designation.getLanguage());
@ -2239,11 +2239,12 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue()); assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue());
concept = termValueSet.getConcepts().get(23); concept = termValueSet.getConcepts().get(23);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("8492-1", concept.getCode()); assertEquals("8492-1", concept.getCode());
assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay()); assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay());
assertEquals(0, concept.getDesignations().size()); assertEquals(0, concept.getDesignations().size());
assertEquals(23, concept.getOrder());
}); });
} }
@ -2293,11 +2294,12 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus()); assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus());
TermValueSetConcept concept = termValueSet.getConcepts().get(0); TermValueSetConcept concept = termValueSet.getConcepts().get(0);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("8450-9", concept.getCode()); assertEquals("8450-9", concept.getCode());
assertEquals("Systolic blood pressure--expiration", concept.getDisplay()); assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
assertEquals(2, concept.getDesignations().size()); assertEquals(2, concept.getDesignations().size());
assertEquals(0, concept.getOrder());
TermValueSetConceptDesignation designation = concept.getDesignations().get(0); TermValueSetConceptDesignation designation = concept.getDesignations().get(0);
assertEquals("nl", designation.getLanguage()); assertEquals("nl", designation.getLanguage());
@ -2314,20 +2316,22 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals("Systoliskt blodtryck - utgång", designation.getValue()); assertEquals("Systoliskt blodtryck - utgång", designation.getValue());
concept = termValueSet.getConcepts().get(1); concept = termValueSet.getConcepts().get(1);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("11378-7", concept.getCode()); assertEquals("11378-7", concept.getCode());
assertEquals("Systolic blood pressure at First encounter", concept.getDisplay()); assertEquals("Systolic blood pressure at First encounter", concept.getDisplay());
assertEquals(0, concept.getDesignations().size()); assertEquals(0, concept.getDesignations().size());
assertEquals(1, concept.getOrder());
// ... // ...
concept = termValueSet.getConcepts().get(22 - 2); concept = termValueSet.getConcepts().get(20);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("8491-3", concept.getCode()); assertEquals("8491-3", concept.getCode());
assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay()); assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay());
assertEquals(1, concept.getDesignations().size()); assertEquals(1, concept.getDesignations().size());
assertEquals(20, concept.getOrder());
designation = concept.getDesignations().get(0); designation = concept.getDesignations().get(0);
assertEquals("nl", designation.getLanguage()); assertEquals("nl", designation.getLanguage());
@ -2336,12 +2340,13 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals("Synonym", designation.getUseDisplay()); assertEquals("Synonym", designation.getUseDisplay());
assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue()); assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue());
concept = termValueSet.getConcepts().get(23 - 2); concept = termValueSet.getConcepts().get(21);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("8492-1", concept.getCode()); assertEquals("8492-1", concept.getCode());
assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay()); assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay());
assertEquals(0, concept.getDesignations().size()); assertEquals(0, concept.getDesignations().size());
assertEquals(21, concept.getOrder());
}); });
} }
@ -2391,11 +2396,12 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus()); assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus());
TermValueSetConcept concept = termValueSet.getConcepts().get(0); TermValueSetConcept concept = termValueSet.getConcepts().get(0);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("8450-9", concept.getCode()); assertEquals("8450-9", concept.getCode());
assertEquals("Systolic blood pressure--expiration", concept.getDisplay()); assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
assertEquals(2, concept.getDesignations().size()); assertEquals(2, concept.getDesignations().size());
assertEquals(0, concept.getOrder());
TermValueSetConceptDesignation designation = concept.getDesignations().get(0); TermValueSetConceptDesignation designation = concept.getDesignations().get(0);
assertEquals("nl", designation.getLanguage()); assertEquals("nl", designation.getLanguage());
@ -2412,20 +2418,22 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals("Systoliskt blodtryck - utgång", designation.getValue()); assertEquals("Systoliskt blodtryck - utgång", designation.getValue());
concept = termValueSet.getConcepts().get(1); concept = termValueSet.getConcepts().get(1);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("11378-7", concept.getCode()); assertEquals("11378-7", concept.getCode());
assertEquals("Systolic blood pressure at First encounter", concept.getDisplay()); assertEquals("Systolic blood pressure at First encounter", concept.getDisplay());
assertEquals(0, concept.getDesignations().size()); assertEquals(0, concept.getDesignations().size());
assertEquals(1, concept.getOrder());
// ... // ...
concept = termValueSet.getConcepts().get(22 - 2); concept = termValueSet.getConcepts().get(20);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("8491-3", concept.getCode()); assertEquals("8491-3", concept.getCode());
assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay()); assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay());
assertEquals(1, concept.getDesignations().size()); assertEquals(1, concept.getDesignations().size());
assertEquals(20, concept.getOrder());
designation = concept.getDesignations().get(0); designation = concept.getDesignations().get(0);
assertEquals("nl", designation.getLanguage()); assertEquals("nl", designation.getLanguage());
@ -2434,12 +2442,13 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
assertEquals("Synonym", designation.getUseDisplay()); assertEquals("Synonym", designation.getUseDisplay());
assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue()); assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue());
concept = termValueSet.getConcepts().get(23 - 2); concept = termValueSet.getConcepts().get(21);
ourLog.info("Code:\n" + concept.toString()); ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("8492-1", concept.getCode()); assertEquals("8492-1", concept.getCode());
assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay()); assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay());
assertEquals(0, concept.getDesignations().size()); assertEquals(0, concept.getDesignations().size());
assertEquals(21, concept.getOrder());
}); });
} }

View File

@ -100,6 +100,15 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
.dropIndex("IDX_VALUESET_EXP_STATUS"); .dropIndex("IDX_VALUESET_EXP_STATUS");
version.dropIdGenerator("SEQ_SEARCHPARM_ID"); version.dropIdGenerator("SEQ_SEARCHPARM_ID");
// TermValueSetConcept
version.startSectionWithMessage("Processing table: TRM_VALUESET_CONCEPT");
Builder.BuilderWithTableName termValueSetConceptTable = version.onTable("TRM_VALUESET_CONCEPT");
termValueSetConceptTable.addColumn("VALUESET_ORDER").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.INT);
termValueSetConceptTable
.addIndex("IDX_VS_CONCEPT_ORDER")
.unique(true)
.withColumns("VALUESET_PID", "VALUESET_ORDER");
} }
protected void init400() { protected void init400() {