Merge remote-tracking branch 'remotes/origin/master' into add-pid-to-created-resource

This commit is contained in:
Ken Stevens 2019-07-16 20:46:31 -04:00
commit 79ce4a30cc
23 changed files with 1081 additions and 176 deletions

View File

@ -20,16 +20,16 @@ package ca.uhn.fhir.jpa.dao.data;
* #L% * #L%
*/ */
import ca.uhn.fhir.jpa.entity.TermValueSetCode; import ca.uhn.fhir.jpa.entity.TermValueSetConcept;
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;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
public interface ITermValueSetCodeDao extends JpaRepository<TermValueSetCode, Long> { public interface ITermValueSetConceptDao extends JpaRepository<TermValueSetConcept, Long> {
@Query("DELETE FROM TermValueSetCode vsc WHERE vsc.myValueSet.myId = :pid") @Query("DELETE FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myId = :pid")
@Modifying @Modifying
void deleteTermValueSetCodesByValueSetId(@Param("pid") Long theValueSetId); void deleteTermValueSetConceptsByValueSetId(@Param("pid") Long theValueSetId);
} }

View File

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

View File

@ -26,6 +26,7 @@ import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao;
import ca.uhn.fhir.jpa.entity.TermCodeSystem; import ca.uhn.fhir.jpa.entity.TermCodeSystem;
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.TermConceptDesignation;
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.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
@ -51,8 +52,7 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSystem> implements IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> { public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSystem> implements IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> {
@ -193,6 +193,21 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
termConcept.setDisplay(next.getDisplay()); termConcept.setDisplay(next.getDisplay());
termConcept.addChildren(toPersistedConcepts(next.getConcept(), theCodeSystemVersion), RelationshipTypeEnum.ISA); termConcept.addChildren(toPersistedConcepts(next.getConcept(), theCodeSystemVersion), RelationshipTypeEnum.ISA);
retVal.add(termConcept); retVal.add(termConcept);
for (CodeSystem.ConceptDefinitionDesignationComponent designationComponent : next.getDesignation()) {
if (isNotBlank(designationComponent.getValue())) {
TermConceptDesignation designation = termConcept.addDesignation();
designation.setLanguage(designationComponent.hasLanguage() ? designationComponent.getLanguage() : null);
if (designationComponent.hasUse()) {
designation.setUseSystem(designationComponent.getUse().hasSystem() ? designationComponent.getUse().getSystem() : null);
designation.setUseCode(designationComponent.getUse().hasCode() ? designationComponent.getUse().getCode() : null);
designation.setUseDisplay(designationComponent.getUse().hasDisplay() ? designationComponent.getUse().getDisplay() : null);
}
designation.setValue(designationComponent.getValue());
}
}
// TODO: DM 2019-07-16 - We should also populate TermConceptProperty entities here.
} }
} }

View File

@ -96,7 +96,8 @@ public class ExpungeEverythingService {
counter.addAndGet(expungeEverythingByType(ResourceLink.class)); counter.addAndGet(expungeEverythingByType(ResourceLink.class));
counter.addAndGet(expungeEverythingByType(SearchResult.class)); counter.addAndGet(expungeEverythingByType(SearchResult.class));
counter.addAndGet(expungeEverythingByType(SearchInclude.class)); counter.addAndGet(expungeEverythingByType(SearchInclude.class));
counter.addAndGet(expungeEverythingByType(TermValueSetCode.class)); counter.addAndGet(expungeEverythingByType(TermValueSetConceptDesignation.class));
counter.addAndGet(expungeEverythingByType(TermValueSetConcept.class));
counter.addAndGet(expungeEverythingByType(TermValueSet.class)); counter.addAndGet(expungeEverythingByType(TermValueSet.class));
counter.addAndGet(expungeEverythingByType(TermConceptParentChildLink.class)); counter.addAndGet(expungeEverythingByType(TermConceptParentChildLink.class));
counter.addAndGet(expungeEverythingByType(TermConceptMapGroupElementTarget.class)); counter.addAndGet(expungeEverythingByType(TermConceptMapGroupElementTarget.class));

View File

@ -26,8 +26,8 @@ import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao;
import ca.uhn.fhir.jpa.entity.TermCodeSystem; import ca.uhn.fhir.jpa.entity.TermCodeSystem;
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.TermConceptDesignation;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum; import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.model.entity.BaseHasResource;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.util.LogicUtil; import ca.uhn.fhir.jpa.util.LogicUtil;
@ -52,8 +52,7 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> implements IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> { public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> implements IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> {
@ -168,6 +167,21 @@ public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> i
termConcept.setDisplay(next.getDisplay()); termConcept.setDisplay(next.getDisplay());
termConcept.addChildren(toPersistedConcepts(next.getConcept(), theCodeSystemVersion), RelationshipTypeEnum.ISA); termConcept.addChildren(toPersistedConcepts(next.getConcept(), theCodeSystemVersion), RelationshipTypeEnum.ISA);
retVal.add(termConcept); retVal.add(termConcept);
for (CodeSystem.ConceptDefinitionDesignationComponent designationComponent : next.getDesignation()) {
if (isNotBlank(designationComponent.getValue())) {
TermConceptDesignation designation = termConcept.addDesignation();
designation.setLanguage(designationComponent.hasLanguage() ? designationComponent.getLanguage() : null);
if (designationComponent.hasUse()) {
designation.setUseSystem(designationComponent.getUse().hasSystem() ? designationComponent.getUse().getSystem() : null);
designation.setUseCode(designationComponent.getUse().hasCode() ? designationComponent.getUse().getCode() : null);
designation.setUseDisplay(designationComponent.getUse().hasDisplay() ? designationComponent.getUse().getDisplay() : null);
}
designation.setValue(designationComponent.getValue());
}
}
// TODO: DM 2019-07-16 - We should also populate TermConceptProperty entities here.
} }
} }

View File

@ -103,7 +103,6 @@ public class TermConceptDesignation implements Serializable {
public TermConceptDesignation setUseSystem(String theUseSystem) { public TermConceptDesignation setUseSystem(String theUseSystem) {
ValidateUtil.isNotTooLongOrThrowIllegalArgument(theUseSystem, MAX_LENGTH, ValidateUtil.isNotTooLongOrThrowIllegalArgument(theUseSystem, MAX_LENGTH,
"Use system exceeds maximum length (" + MAX_LENGTH + "): " + length(theUseSystem)); "Use system exceeds maximum length (" + MAX_LENGTH + "): " + length(theUseSystem));
myUseSystem = theUseSystem; myUseSystem = theUseSystem;
return this; return this;
} }

View File

@ -66,7 +66,7 @@ public class TermValueSet implements Serializable {
private String myName; private String myName;
@OneToMany(mappedBy = "myValueSet") @OneToMany(mappedBy = "myValueSet")
private List<TermValueSetCode> myCodes; private List<TermValueSetConcept> myConcepts;
public Long getId() { public Long getId() {
return myId; return myId;
@ -102,12 +102,12 @@ public class TermValueSet implements Serializable {
return this; return this;
} }
public List<TermValueSetCode> getCodes() { public List<TermValueSetConcept> getConcepts() {
if (myCodes == null) { if (myConcepts == null) {
myCodes = new ArrayList<>(); myConcepts = new ArrayList<>();
} }
return myCodes; return myConcepts;
} }
@Override @Override
@ -138,7 +138,7 @@ public class TermValueSet implements Serializable {
.append(myResource != null ? ("myResource=" + myResource.toString()) : ("myResource=(null)")) .append(myResource != null ? ("myResource=" + myResource.toString()) : ("myResource=(null)"))
.append("myResourcePid", myResourcePid) .append("myResourcePid", myResourcePid)
.append("myName", myName) .append("myName", myName)
.append(myCodes != null ? ("myCodes - size=" + myCodes.size()) : ("myCodes=(null)")) .append(myConcepts != null ? ("myConcepts - size=" + myConcepts.size()) : ("myConcepts=(null)"))
.toString(); .toString();
} }
} }

View File

@ -29,20 +29,22 @@ import org.apache.commons.lang3.builder.ToStringStyle;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.persistence.*; import javax.persistence.*;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import static org.apache.commons.lang3.StringUtils.left; import static org.apache.commons.lang3.StringUtils.left;
import static org.apache.commons.lang3.StringUtils.length; import static org.apache.commons.lang3.StringUtils.length;
@Table(name = "TRM_VALUESET_CODE", indexes = { @Table(name = "TRM_VALUESET_CONCEPT", indexes = {
@Index(name = "IDX_VALUESET_CODE_CS_CD", columnList = "SYSTEM, CODE") @Index(name = "IDX_VALUESET_CONCEPT_CS_CD", columnList = "SYSTEM, CODE")
}) })
@Entity() @Entity()
public class TermValueSetCode implements Serializable { public class TermValueSetConcept implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id() @Id()
@SequenceGenerator(name = "SEQ_VALUESET_CODE_PID", sequenceName = "SEQ_VALUESET_CODE_PID") @SequenceGenerator(name = "SEQ_VALUESET_CONCEPT_PID", sequenceName = "SEQ_VALUESET_CONCEPT_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_VALUESET_CODE_PID") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_VALUESET_CONCEPT_PID")
@Column(name = "PID") @Column(name = "PID")
private Long myId; private Long myId;
@ -65,6 +67,9 @@ public class TermValueSetCode 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")
private List<TermValueSetConceptDesignation> myDesignations;
public Long getId() { public Long getId() {
return myId; return myId;
} }
@ -73,7 +78,7 @@ public class TermValueSetCode implements Serializable {
return myValueSet; return myValueSet;
} }
public TermValueSetCode setValueSet(TermValueSet theValueSet) { public TermValueSetConcept setValueSet(TermValueSet theValueSet) {
myValueSet = theValueSet; myValueSet = theValueSet;
return this; return this;
} }
@ -98,7 +103,7 @@ public class TermValueSetCode implements Serializable {
return mySystem; return mySystem;
} }
public TermValueSetCode setSystem(@Nonnull String theSystem) { public TermValueSetConcept setSystem(@Nonnull String theSystem) {
ValidateUtil.isNotBlankOrThrowIllegalArgument(theSystem, "theSystem must not be null or empty"); ValidateUtil.isNotBlankOrThrowIllegalArgument(theSystem, "theSystem must not be null or empty");
ValidateUtil.isNotTooLongOrThrowIllegalArgument(theSystem, TermCodeSystem.MAX_URL_LENGTH, ValidateUtil.isNotTooLongOrThrowIllegalArgument(theSystem, TermCodeSystem.MAX_URL_LENGTH,
"System exceeds maximum length (" + TermCodeSystem.MAX_URL_LENGTH + "): " + length(theSystem)); "System exceeds maximum length (" + TermCodeSystem.MAX_URL_LENGTH + "): " + length(theSystem));
@ -110,7 +115,7 @@ public class TermValueSetCode implements Serializable {
return myCode; return myCode;
} }
public TermValueSetCode setCode(@Nonnull String theCode) { public TermValueSetConcept setCode(@Nonnull String theCode) {
ValidateUtil.isNotBlankOrThrowIllegalArgument(theCode, "theCode must not be null or empty"); ValidateUtil.isNotBlankOrThrowIllegalArgument(theCode, "theCode must not be null or empty");
ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCode, TermConcept.MAX_CODE_LENGTH, ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCode, TermConcept.MAX_CODE_LENGTH,
"Code exceeds maximum length (" + TermConcept.MAX_CODE_LENGTH + "): " + length(theCode)); "Code exceeds maximum length (" + TermConcept.MAX_CODE_LENGTH + "): " + length(theCode));
@ -122,18 +127,26 @@ public class TermValueSetCode implements Serializable {
return myDisplay; return myDisplay;
} }
public TermValueSetCode setDisplay(String theDisplay) { public TermValueSetConcept setDisplay(String theDisplay) {
myDisplay = left(theDisplay, TermConcept.MAX_DESC_LENGTH); myDisplay = left(theDisplay, TermConcept.MAX_DESC_LENGTH);
return this; return this;
} }
public List<TermValueSetConceptDesignation> getDesignations() {
if (myDesignations == null) {
myDesignations = new ArrayList<>();
}
return myDesignations;
}
@Override @Override
public boolean equals(Object theO) { public boolean equals(Object theO) {
if (this == theO) return true; if (this == theO) return true;
if (!(theO instanceof TermValueSetCode)) return false; if (!(theO instanceof TermValueSetConcept)) return false;
TermValueSetCode that = (TermValueSetCode) theO; TermValueSetConcept that = (TermValueSetConcept) theO;
return new EqualsBuilder() return new EqualsBuilder()
.append(getValueSetUrl(), that.getValueSetUrl()) .append(getValueSetUrl(), that.getValueSetUrl())
@ -161,6 +174,7 @@ public class TermValueSetCode implements Serializable {
.append("mySystem", mySystem) .append("mySystem", mySystem)
.append("myCode", myCode) .append("myCode", myCode)
.append("myDisplay", myDisplay) .append("myDisplay", myDisplay)
.append(myDesignations != null ? ("myDesignations - size=" + myDesignations.size()) : ("myDesignations=(null)"))
.toString(); .toString();
} }
} }

View File

@ -0,0 +1,177 @@
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 ca.uhn.fhir.util.ValidateUtil;
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.ToStringStyle;
import javax.annotation.Nonnull;
import javax.persistence.*;
import java.io.Serializable;
import static org.apache.commons.lang3.StringUtils.left;
import static org.apache.commons.lang3.StringUtils.length;
@Table(name = "TRM_VALUESET_C_DESIGNATION", indexes = {
@Index(name = "IDX_VALUESET_C_DSGNTN_VAL", columnList = "VAL")
})
@Entity()
public class TermValueSetConceptDesignation implements Serializable {
private static final long serialVersionUID = 1L;
public static final int MAX_LENGTH = 500;
@Id()
@SequenceGenerator(name = "SEQ_VALUESET_C_DSGNTN_PID", sequenceName = "SEQ_VALUESET_C_DSGNTN_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_VALUESET_C_DSGNTN_PID")
@Column(name = "PID")
private Long myId;
@ManyToOne()
@JoinColumn(name = "VALUESET_CONCEPT_PID", referencedColumnName = "PID", nullable = false, foreignKey = @ForeignKey(name = "FK_TRM_VALUESET_CONCEPT_PID"))
private TermValueSetConcept myConcept;
@Column(name = "LANG", nullable = true, length = MAX_LENGTH)
private String myLanguage;
@Column(name = "USE_SYSTEM", nullable = true, length = MAX_LENGTH)
private String myUseSystem;
@Column(name = "USE_CODE", nullable = true, length = MAX_LENGTH)
private String myUseCode;
@Column(name = "USE_DISPLAY", nullable = true, length = MAX_LENGTH)
private String myUseDisplay;
@Column(name = "VAL", nullable = false, length = MAX_LENGTH)
private String myValue;
public Long getId() {
return myId;
}
public TermValueSetConcept getConcept() {
return myConcept;
}
public TermValueSetConceptDesignation setConcept(TermValueSetConcept theConcept) {
myConcept = theConcept;
return this;
}
public String getLanguage() {
return myLanguage;
}
public TermValueSetConceptDesignation setLanguage(String theLanguage) {
ValidateUtil.isNotTooLongOrThrowIllegalArgument(theLanguage, MAX_LENGTH,
"Language exceeds maximum length (" + MAX_LENGTH + "): " + length(theLanguage));
myLanguage = theLanguage;
return this;
}
public String getUseSystem() {
return myUseSystem;
}
public TermValueSetConceptDesignation setUseSystem(String theUseSystem) {
ValidateUtil.isNotTooLongOrThrowIllegalArgument(theUseSystem, MAX_LENGTH,
"Use system exceeds maximum length (" + MAX_LENGTH + "): " + length(theUseSystem));
myUseSystem = theUseSystem;
return this;
}
public String getUseCode() {
return myUseCode;
}
public TermValueSetConceptDesignation setUseCode(String theUseCode) {
ValidateUtil.isNotTooLongOrThrowIllegalArgument(theUseCode, MAX_LENGTH,
"Use code exceeds maximum length (" + MAX_LENGTH + "): " + length(theUseCode));
myUseCode = theUseCode;
return this;
}
public String getUseDisplay() {
return myUseDisplay;
}
public TermValueSetConceptDesignation setUseDisplay(String theUseDisplay) {
myUseDisplay = left(theUseDisplay, MAX_LENGTH);
return this;
}
public String getValue() {
return myValue;
}
public TermValueSetConceptDesignation setValue(@Nonnull String theValue) {
ValidateUtil.isNotBlankOrThrowIllegalArgument(theValue, "theValue must not be null or empty");
ValidateUtil.isNotTooLongOrThrowIllegalArgument(theValue, MAX_LENGTH,
"Value exceeds maximum length (" + MAX_LENGTH + "): " + length(theValue));
myValue = theValue;
return this;
}
@Override
public boolean equals(Object theO) {
if (this == theO) return true;
if (!(theO instanceof TermValueSetConceptDesignation)) return false;
TermValueSetConceptDesignation that = (TermValueSetConceptDesignation) theO;
return new EqualsBuilder()
.append(getLanguage(), that.getLanguage())
.append(getUseSystem(), that.getUseSystem())
.append(getUseCode(), that.getUseCode())
.append(getUseDisplay(), that.getUseDisplay())
.append(getValue(), that.getValue())
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(getLanguage())
.append(getUseSystem())
.append(getUseCode())
.append(getUseDisplay())
.append(getValue())
.toHashCode();
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("myId", myId)
.append(myConcept != null ? ("myConcept - id=" + myConcept.getId()) : ("myConcept=(null)"))
.append("myLanguage", myLanguage)
.append("myUseSystem", myUseSystem)
.append("myUseCode", myUseCode)
.append("myUseDisplay", myUseDisplay)
.append("myValue", myValue)
.toString();
}
}

View File

@ -91,8 +91,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, ApplicationContextAware { public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, ApplicationContextAware {
public static final int DEFAULT_FETCH_SIZE = 250; public static final int DEFAULT_FETCH_SIZE = 250;
@ -121,7 +120,9 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
@Autowired @Autowired
protected ITermValueSetDao myValueSetDao; protected ITermValueSetDao myValueSetDao;
@Autowired @Autowired
protected ITermValueSetCodeDao myValueSetCodeDao; protected ITermValueSetConceptDao myValueSetConceptDao;
@Autowired
protected ITermValueSetConceptDesignationDao myValueSetConceptDesignationDao;
@Autowired @Autowired
protected FhirContext myContext; protected FhirContext myContext;
@PersistenceContext(type = PersistenceContextType.TRANSACTION) @PersistenceContext(type = PersistenceContextType.TRANSACTION)
@ -152,54 +153,39 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
@Autowired(required = false) @Autowired(required = false)
private IFulltextSearchSvc myFulltextSearchSvc; private IFulltextSearchSvc myFulltextSearchSvc;
private void addCodeIfNotAlreadyAdded(IValueSetCodeAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, TermConcept theConcept, boolean theAdd, AtomicInteger theCodeCounter) {
private void addCodeIfNotAlreadyAdded(ValueSet.ValueSetExpansionComponent theExpansionComponent, Set<String> theAddedCodes, TermConcept theConcept, boolean theAdd, AtomicInteger theCodeCounter) {
String codeSystem = theConcept.getCodeSystemVersion().getCodeSystem().getCodeSystemUri(); String codeSystem = theConcept.getCodeSystemVersion().getCodeSystem().getCodeSystemUri();
String code = theConcept.getCode(); String code = theConcept.getCode();
String display = theConcept.getDisplay(); String display = theConcept.getDisplay();
Collection<TermConceptDesignation> designations = theConcept.getDesignations(); Collection<TermConceptDesignation> designations = theConcept.getDesignations();
addCodeIfNotAlreadyAdded(theExpansionComponent, theAddedCodes, designations, theAdd, theCodeCounter, codeSystem, code, display); addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, designations, theAdd, theCodeCounter, codeSystem, code, display);
} }
private void addCodeIfNotAlreadyAdded(ValueSet.ValueSetExpansionComponent theExpansionComponent, Set<String> theAddedCodes, Collection<TermConceptDesignation> theDesignations, boolean theAdd, AtomicInteger theCodeCounter, String theCodeSystem, String theCode, String theDisplay) { private void addCodeIfNotAlreadyAdded(IValueSetCodeAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, Collection<TermConceptDesignation> theDesignations, boolean theAdd, AtomicInteger theCodeCounter, String theCodeSystem, String theCode, String theDisplay) {
if (isNotBlank(theCode) && theAdd && theAddedCodes.add(theCode)) { if (isNoneBlank(theCodeSystem, theCode)) {
ValueSet.ValueSetExpansionContainsComponent contains = theExpansionComponent.addContains(); if (theAdd && theAddedCodes.add(theCodeSystem + "|" + theCode)) {
contains.setCode(theCode); theValueSetCodeAccumulator.includeCodeWithDesignations(theCodeSystem, theCode, theDisplay, theDesignations);
contains.setSystem(theCodeSystem); theCodeCounter.incrementAndGet();
contains.setDisplay(theDisplay); }
if (theDesignations != null) {
for (TermConceptDesignation nextDesignation : theDesignations) { if (!theAdd && theAddedCodes.remove(theCodeSystem + "|" + theCode)) {
contains theValueSetCodeAccumulator.excludeCode(theCodeSystem, theCode);
.addDesignation() theCodeCounter.decrementAndGet();
.setValue(nextDesignation.getValue()) }
.getUse() }
.setSystem(nextDesignation.getUseSystem()) }
.setCode(nextDesignation.getUseCode())
.setDisplay(nextDesignation.getUseDisplay()); private void addConceptsToList(IValueSetCodeAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, String theSystem, List<CodeSystem.ConceptDefinitionComponent> theConcept, boolean theAdd) {
for (CodeSystem.ConceptDefinitionComponent next : theConcept) {
if (isNoneBlank(theSystem, next.getCode())) {
if (theAdd && theAddedCodes.add(theSystem + "|" + next.getCode())) {
theValueSetCodeAccumulator.includeCode(theSystem, next.getCode(), next.getDisplay());
}
if (!theAdd && theAddedCodes.remove(theSystem + "|" + next.getCode())) {
theValueSetCodeAccumulator.excludeCode(theSystem, next.getCode());
} }
} }
addConceptsToList(theValueSetCodeAccumulator, theAddedCodes, theSystem, next.getConcept(), theAdd);
theCodeCounter.incrementAndGet();
}
if (!theAdd && theAddedCodes.remove(theCode)) {
removeCodeFromExpansion(theCodeSystem, theCode, theExpansionComponent);
theCodeCounter.decrementAndGet();
}
}
private void addConceptsToList(ValueSet.ValueSetExpansionComponent theExpansionComponent, Set<String> theAddedCodes, String theSystem, List<CodeSystem.ConceptDefinitionComponent> theConcept, boolean theAdd) {
for (CodeSystem.ConceptDefinitionComponent next : theConcept) {
if (theAdd && theAddedCodes.add(next.getCode())) {
ValueSet.ValueSetExpansionContainsComponent contains = theExpansionComponent.addContains();
contains.setCode(next.getCode());
contains.setSystem(theSystem);
contains.setDisplay(next.getDisplay());
}
if (!theAdd && theAddedCodes.remove(next.getCode())) {
removeCodeFromExpansion(theSystem, next.getCode(), theExpansionComponent);
}
addConceptsToList(theExpansionComponent, theAddedCodes, theSystem, next.getConcept(), theAdd);
} }
} }
@ -400,12 +386,14 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
TermValueSet existingTermValueSet = optionalExistingTermValueSetById.get(); TermValueSet existingTermValueSet = optionalExistingTermValueSetById.get();
ourLog.info("Deleting existing TermValueSet {} and its children...", existingTermValueSet.getId()); ourLog.info("Deleting existing TermValueSet {} and its children...", existingTermValueSet.getId());
myValueSetCodeDao.deleteTermValueSetCodesByValueSetId(existingTermValueSet.getId()); myValueSetConceptDesignationDao.deleteTermValueSetConceptDesignationsByValueSetId(existingTermValueSet.getId());
myValueSetConceptDao.deleteTermValueSetConceptsByValueSetId(existingTermValueSet.getId());
myValueSetDao.deleteTermValueSetById(existingTermValueSet.getId()); myValueSetDao.deleteTermValueSetById(existingTermValueSet.getId());
ourLog.info("Done deleting existing TermValueSet {} and its children.", existingTermValueSet.getId()); ourLog.info("Done deleting existing TermValueSet {} and its children.", existingTermValueSet.getId());
ourLog.info("Flushing..."); ourLog.info("Flushing...");
myValueSetCodeDao.flush(); myValueSetConceptDesignationDao.flush();
myValueSetConceptDao.flush();
myValueSetDao.flush(); myValueSetDao.flush();
ourLog.info("Done flushing."); ourLog.info("Done flushing.");
} }
@ -466,26 +454,13 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
@Transactional(propagation = Propagation.REQUIRED) @Transactional(propagation = Propagation.REQUIRED)
public ValueSet expandValueSet(ValueSet theValueSetToExpand) { public ValueSet expandValueSet(ValueSet theValueSetToExpand) {
ValueSet.ValueSetExpansionComponent expansionComponent = new ValueSet.ValueSetExpansionComponent(); ValueSetExpansionComponentWithCodeAccumulator expansionComponent = new ValueSetExpansionComponentWithCodeAccumulator();
expansionComponent.setIdentifier(UUID.randomUUID().toString()); expansionComponent.setIdentifier(UUID.randomUUID().toString());
expansionComponent.setTimestamp(new Date()); expansionComponent.setTimestamp(new Date());
Set<String> addedCodes = new HashSet<>();
AtomicInteger codeCounter = new AtomicInteger(0); AtomicInteger codeCounter = new AtomicInteger(0);
// Handle includes expandValueSet(theValueSetToExpand, expansionComponent, codeCounter);
ourLog.debug("Handling includes");
for (ValueSet.ConceptSetComponent include : theValueSetToExpand.getCompose().getInclude()) {
boolean add = true;
expandValueSetHandleIncludeOrExclude(expansionComponent, addedCodes, include, add, codeCounter);
}
// Handle excludes
ourLog.debug("Handling excludes");
for (ValueSet.ConceptSetComponent include : theValueSetToExpand.getCompose().getExclude()) {
boolean add = false;
expandValueSetHandleIncludeOrExclude(expansionComponent, addedCodes, include, add, codeCounter);
}
expansionComponent.setTotal(codeCounter.get()); expansionComponent.setTotal(codeCounter.get());
@ -496,6 +471,30 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
return valueSet; return valueSet;
} }
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void expandValueSet(ValueSet theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator) {
expandValueSet(theValueSetToExpand, theValueSetCodeAccumulator, new AtomicInteger(0));
}
private void expandValueSet(ValueSet theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator, AtomicInteger theCodeCounter) {
Set<String> addedCodes = new HashSet<>();
// Handle includes
ourLog.debug("Handling includes");
for (ValueSet.ConceptSetComponent include : theValueSetToExpand.getCompose().getInclude()) {
boolean add = true;
expandValueSetHandleIncludeOrExclude(theValueSetCodeAccumulator, addedCodes, include, add, theCodeCounter);
}
// Handle excludes
ourLog.debug("Handling excludes");
for (ValueSet.ConceptSetComponent include : theValueSetToExpand.getCompose().getExclude()) {
boolean add = false;
expandValueSetHandleIncludeOrExclude(theValueSetCodeAccumulator, addedCodes, include, add, theCodeCounter);
}
}
protected List<VersionIndependentConcept> expandValueSetAndReturnVersionIndependentConcepts(org.hl7.fhir.r4.model.ValueSet theValueSetToExpandR4) { protected List<VersionIndependentConcept> expandValueSetAndReturnVersionIndependentConcepts(org.hl7.fhir.r4.model.ValueSet theValueSetToExpandR4) {
org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent expandedR4 = expandValueSet(theValueSetToExpandR4).getExpansion(); org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent expandedR4 = expandValueSet(theValueSetToExpandR4).getExpansion();
@ -507,7 +506,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
return retVal; return retVal;
} }
public void expandValueSetHandleIncludeOrExclude(ValueSet.ValueSetExpansionComponent theExpansionComponent, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theInclude, boolean theAdd, AtomicInteger theCodeCounter) { private void expandValueSetHandleIncludeOrExclude(IValueSetCodeAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theInclude, boolean theAdd, AtomicInteger theCodeCounter) {
String system = theInclude.getSystem(); String system = theInclude.getSystem();
boolean hasSystem = isNotBlank(system); boolean hasSystem = isNotBlank(system);
boolean hasValueSet = theInclude.getValueSet().size() > 0; boolean hasValueSet = theInclude.getValueSet().size() > 0;
@ -525,7 +524,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
* since we're going to do it without the database. * since we're going to do it without the database.
*/ */
if (myFulltextSearchSvc == null) { if (myFulltextSearchSvc == null) {
expandWithoutHibernateSearch(theExpansionComponent, theAddedCodes, theInclude, system, theAdd, theCodeCounter); expandWithoutHibernateSearch(theValueSetCodeAccumulator, theAddedCodes, theInclude, system, theAdd, theCodeCounter);
return; return;
} }
@ -649,7 +648,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
for (Object next : jpaQuery.getResultList()) { for (Object next : jpaQuery.getResultList()) {
count.incrementAndGet(); count.incrementAndGet();
TermConcept concept = (TermConcept) next; TermConcept concept = (TermConcept) next;
addCodeIfNotAlreadyAdded(theExpansionComponent, theAddedCodes, concept, theAdd, theCodeCounter); addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, concept, theAdd, theCodeCounter);
} }
@ -670,24 +669,21 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
if (theInclude.getConcept().isEmpty() == false) { if (theInclude.getConcept().isEmpty() == false) {
for (ValueSet.ConceptReferenceComponent next : theInclude.getConcept()) { for (ValueSet.ConceptReferenceComponent next : theInclude.getConcept()) {
String nextCode = next.getCode(); String nextCode = next.getCode();
if (isNotBlank(nextCode) && !theAddedCodes.contains(nextCode)) { if (isNoneBlank(system, nextCode) && !theAddedCodes.contains(system + "|" + nextCode)) {
CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode); CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode);
if (code != null) { if (code != null) {
if (theAdd && theAddedCodes.add(nextCode)) { if (theAdd && theAddedCodes.add(system + "|" + nextCode)) {
ValueSet.ValueSetExpansionContainsComponent contains = theExpansionComponent.addContains(); theValueSetCodeAccumulator.includeCode(system, nextCode, code.getDisplay());
contains.setCode(nextCode);
contains.setSystem(system);
contains.setDisplay(code.getDisplay());
} }
if (!theAdd && theAddedCodes.remove(nextCode)) { if (!theAdd && theAddedCodes.remove(system + "|" + nextCode)) {
removeCodeFromExpansion(system, nextCode, theExpansionComponent); theValueSetCodeAccumulator.excludeCode(system, nextCode);
} }
} }
} }
} }
} else { } else {
List<CodeSystem.ConceptDefinitionComponent> concept = codeSystemFromContext.getConcept(); List<CodeSystem.ConceptDefinitionComponent> concept = codeSystemFromContext.getConcept();
addConceptsToList(theExpansionComponent, theAddedCodes, system, concept, theAdd); addConceptsToList(theValueSetCodeAccumulator, theAddedCodes, system, concept, theAdd);
} }
} }
@ -702,12 +698,12 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
myConceptDao myConceptDao
.findByCodeSystemAndCode(codeSystem.getCurrentVersion(), nextConcept.getCode()) .findByCodeSystemAndCode(codeSystem.getCurrentVersion(), nextConcept.getCode())
.ifPresent(concept -> .ifPresent(concept ->
addCodeIfNotAlreadyAdded(theExpansionComponent, theAddedCodes, concept, theAdd, theCodeCounter) addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, concept, theAdd, theCodeCounter)
); );
} }
if (!theAdd && theAddedCodes.remove(nextConcept.getCode())) { if (isNoneBlank(nextConcept.getSystem(), nextConcept.getCode()) && !theAdd && theAddedCodes.remove(nextConcept.getSystem() + "|" + nextConcept.getCode())) {
removeCodeFromExpansion(nextConcept.getSystem(), nextConcept.getCode(), theExpansionComponent); theValueSetCodeAccumulator.excludeCode(nextConcept.getSystem(), nextConcept.getCode());
} }
} }
@ -717,9 +713,11 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
} }
} }
private void expandWithoutHibernateSearch(ValueSet.ValueSetExpansionComponent theExpansionComponent, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theInclude, String theSystem, boolean theAdd, AtomicInteger theCodeCounter) { private void expandWithoutHibernateSearch(IValueSetCodeAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theInclude, String theSystem, boolean theAdd, AtomicInteger theCodeCounter) {
ourLog.trace("Hibernate search is not enabled"); ourLog.trace("Hibernate search is not enabled");
Validate.isTrue(theExpansionComponent.getParameter().isEmpty(), "Can not expand ValueSet with parameters - Hibernate Search is not enabled on this server."); if (theValueSetCodeAccumulator instanceof ValueSetExpansionComponentWithCodeAccumulator) {
Validate.isTrue(((ValueSetExpansionComponentWithCodeAccumulator) theValueSetCodeAccumulator).getParameter().isEmpty(), "Can not expand ValueSet with parameters - Hibernate Search is not enabled on this server.");
}
Validate.isTrue(theInclude.getFilter().isEmpty(), "Can not expand ValueSet with filters - Hibernate Search is not enabled on this server."); Validate.isTrue(theInclude.getFilter().isEmpty(), "Can not expand ValueSet with filters - Hibernate Search is not enabled on this server.");
Validate.isTrue(isNotBlank(theSystem), "Can not expand ValueSet without explicit system - Hibernate Search is not enabled on this server."); Validate.isTrue(isNotBlank(theSystem), "Can not expand ValueSet without explicit system - Hibernate Search is not enabled on this server.");
@ -727,7 +725,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
if (!theSystem.equals(theInclude.getSystem())) { if (!theSystem.equals(theInclude.getSystem())) {
continue; continue;
} }
addCodeIfNotAlreadyAdded(theExpansionComponent, theAddedCodes, null, theAdd, theCodeCounter, theSystem, next.getCode(), next.getDisplay()); addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, null, theAdd, theCodeCounter, theSystem, next.getCode(), next.getDisplay());
} }
} }
@ -1038,14 +1036,6 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
} }
private void removeCodeFromExpansion(String theCodeSystem, String theCode, ValueSet.ValueSetExpansionComponent theExpansionComponent) {
theExpansionComponent
.getContains()
.removeIf(t ->
theCodeSystem.equals(t.getSystem()) &&
theCode.equals(t.getCode()));
}
private int saveConcept(TermConcept theConcept) { private int saveConcept(TermConcept theConcept) {
int retVal = 0; int retVal = 0;
@ -1144,7 +1134,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
List<TermCodeSystemVersion> existing = myCodeSystemVersionDao.findByCodeSystemResource(theCodeSystemResourcePid); List<TermCodeSystemVersion> existing = myCodeSystemVersionDao.findByCodeSystemResource(theCodeSystemResourcePid);
/* /*
* For now we always delete old versions.. At some point it would be nice to allow configuration to keep old versions * For now we always delete old versions. At some point it would be nice to allow configuration to keep old versions.
*/ */
ourLog.info("Deleting old code system versions"); ourLog.info("Deleting old code system versions");
@ -1318,8 +1308,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
TermConceptMapGroupElement termConceptMapGroupElement; TermConceptMapGroupElement termConceptMapGroupElement;
for (ConceptMap.SourceElementComponent element : group.getElement()) { for (ConceptMap.SourceElementComponent element : group.getElement()) {
if (isBlank(element.getCode())) { if (isBlank(element.getCode())) {
// FIXME: JA - send this to an interceptor message so it can be // FIXME: JA - send this to an interceptor message so it can be output
// output
continue; continue;
} }
termConceptMapGroupElement = new TermConceptMapGroupElement(); termConceptMapGroupElement = new TermConceptMapGroupElement();
@ -1386,26 +1375,53 @@ 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); myValueSetDao.save(termValueSet);
int codesSaved = 0; int conceptsSaved = 0;
int designationsSaved = 0;
// FIXME: DM 2019-07-15 - Here we should call expandValueSet(ValueSet theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator).
// FIXME: DM 2019-07-15 - We need an implementation IValueSetCodeAccumulator that saves ValueSetConcept records and their children.
ValueSet expandedValueSet = expandValueSet(theValueSet); ValueSet expandedValueSet = expandValueSet(theValueSet);
if (expandedValueSet.hasExpansion()) { if (expandedValueSet.hasExpansion()) {
if (expandedValueSet.getExpansion().hasTotal() && expandedValueSet.getExpansion().getTotal() > 0) { if (expandedValueSet.getExpansion().hasTotal() && expandedValueSet.getExpansion().getTotal() > 0) {
TermValueSetCode code; TermValueSetConcept concept;
for (ValueSet.ValueSetExpansionContainsComponent contains : expandedValueSet.getExpansion().getContains()) { for (ValueSet.ValueSetExpansionContainsComponent contains : expandedValueSet.getExpansion().getContains()) {
ValidateUtil.isNotBlankOrThrowInvalidRequest(contains.getSystem(), "ValueSet contains a code with no system value"); ValidateUtil.isNotBlankOrThrowInvalidRequest(contains.getSystem(), "ValueSet contains a concept with no system value");
ValidateUtil.isNotBlankOrThrowInvalidRequest(contains.getCode(), "ValueSet contains a code with no code value"); ValidateUtil.isNotBlankOrThrowInvalidRequest(contains.getCode(), "ValueSet contains a concept with no code value");
code = new TermValueSetCode(); concept = new TermValueSetConcept();
code.setValueSet(termValueSet); concept.setValueSet(termValueSet);
code.setSystem(contains.getSystem()); concept.setSystem(contains.getSystem());
code.setCode(contains.getCode()); concept.setCode(contains.getCode());
code.setDisplay(contains.hasDisplay() ? contains.getDisplay() : null); concept.setDisplay(contains.hasDisplay() ? contains.getDisplay() : null);
myValueSetCodeDao.save(code); myValueSetConceptDao.save(concept);
if (codesSaved++ % 250 == 0) { TermValueSetConceptDesignation designation;
ourLog.info("Have pre-expanded {} codes in ValueSet", codesSaved); for (ValueSet.ConceptReferenceDesignationComponent containedDesignation : contains.getDesignation()) {
myValueSetCodeDao.flush(); ValidateUtil.isNotBlankOrThrowInvalidRequest(containedDesignation.getValue(), "ValueSet contains a concept designation with no value");
designation = new TermValueSetConceptDesignation();
designation.setConcept(concept);
designation.setLanguage(containedDesignation.hasLanguage() ? containedDesignation.getLanguage() : null);
if (containedDesignation.hasUse()) {
designation.setUseSystem(containedDesignation.getUse().hasSystem() ? containedDesignation.getUse().getSystem() : null);
designation.setUseCode(containedDesignation.getUse().hasCode() ? containedDesignation.getUse().getCode() : null);
designation.setUseDisplay(containedDesignation.getUse().hasDisplay() ? containedDesignation.getUse().getDisplay() : null);
}
designation.setValue(containedDesignation.getValue());
myValueSetConceptDesignationDao.save(designation);
if (designationsSaved++ % 250 == 0) {
ourLog.info("Have pre-expanded {} designations in ValueSet", designationsSaved);
myValueSetConceptDesignationDao.flush();
}
}
// TODO: DM 2019-07-16 - We need TermValueSetConceptProperty, similar to TermConceptProperty.
// TODO: DM 2019-07-16 - We should also populate TermValueSetConceptProperty entities here.
if (conceptsSaved++ % 250 == 0) {
ourLog.info("Have pre-expanded {} concepts in ValueSet", conceptsSaved);
myValueSetConceptDao.flush();
} }
} }
} }

View File

@ -86,6 +86,11 @@ public class HapiTerminologySvcDstu2 extends BaseHapiTerminologySvcImpl {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator) {
throw new UnsupportedOperationException();
}
@Override @Override
public List<VersionIndependentConcept> expandValueSet(String theValueSet) { public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();

View File

@ -25,8 +25,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/* /*
* #%L * #%L
@ -171,6 +170,19 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen
} }
} }
@Override
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator) {
ValueSet valueSetToExpand = (ValueSet) theValueSetToExpand;
try {
org.hl7.fhir.r4.model.ValueSet valueSetToExpandR4;
valueSetToExpandR4 = VersionConvertor_30_40.convertValueSet(valueSetToExpand);
super.expandValueSet(valueSetToExpandR4, theValueSetCodeAccumulator);
} catch (FHIRException e) {
throw new InternalErrorException(e);
}
}
@Override @Override
public List<VersionIndependentConcept> expandValueSet(String theValueSet) { public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
ValueSet vs = myValidationSupport.fetchResource(myContext, ValueSet.class, theValueSet); ValueSet vs = myValidationSupport.fetchResource(myContext, ValueSet.class, theValueSet);

View File

@ -131,6 +131,11 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
return super.expandValueSet(valueSetToExpand); return super.expandValueSet(valueSetToExpand);
} }
@Override
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator) {
ValueSet valueSetToExpand = (ValueSet) theValueSetToExpand;
super.expandValueSet(valueSetToExpand, theValueSetCodeAccumulator);
}
@Override @Override
public ValueSetExpander.ValueSetExpansionOutcome expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) { public ValueSetExpander.ValueSetExpansionOutcome expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {

View File

@ -41,11 +41,15 @@ public interface IHapiTerminologySvc {
ValueSet expandValueSet(ValueSet theValueSetToExpand); ValueSet expandValueSet(ValueSet theValueSetToExpand);
void expandValueSet(ValueSet theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator);
/** /**
* Version independent * Version independent
*/ */
IBaseResource expandValueSet(IBaseResource theValueSetToExpand); IBaseResource expandValueSet(IBaseResource theValueSetToExpand);
void expandValueSet(IBaseResource theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator);
List<VersionIndependentConcept> expandValueSet(String theValueSet); List<VersionIndependentConcept> expandValueSet(String theValueSet);
Optional<TermConcept> findCode(String theCodeSystem, String theCode); Optional<TermConcept> findCode(String theCodeSystem, String theCode);

View File

@ -0,0 +1,35 @@
package ca.uhn.fhir.jpa.term;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
import java.util.Collection;
public interface IValueSetCodeAccumulator {
void includeCode(String theSystem, String theCode, String theDisplay);
void includeCodeWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations);
void excludeCode(String theSystem, String theCode);
}

View File

@ -0,0 +1,65 @@
package ca.uhn.fhir.jpa.term;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
import org.hl7.fhir.r4.model.ValueSet;
import java.util.Collection;
public class ValueSetExpansionComponentWithCodeAccumulator extends ValueSet.ValueSetExpansionComponent implements IValueSetCodeAccumulator {
@Override
public void includeCode(String theSystem, String theCode, String theDisplay) {
ValueSet.ValueSetExpansionContainsComponent contains = this.addContains();
contains.setSystem(theSystem);
contains.setCode(theCode);
contains.setDisplay(theDisplay);
}
@Override
public void includeCodeWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations) {
ValueSet.ValueSetExpansionContainsComponent contains = this.addContains();
contains.setSystem(theSystem);
contains.setCode(theCode);
contains.setDisplay(theDisplay);
if (theDesignations != null) {
for (TermConceptDesignation termConceptDesignation : theDesignations) {
contains
.addDesignation()
.setValue(termConceptDesignation.getValue())
.setLanguage(termConceptDesignation.getLanguage())
.getUse()
.setSystem(termConceptDesignation.getUseSystem())
.setCode(termConceptDesignation.getUseCode())
.setDisplay(termConceptDesignation.getUseDisplay());
}
}
}
@Override
public void excludeCode(String theSystem, String theCode) {
this
.getContains()
.removeIf(t ->
theSystem.equals(t.getSystem()) &&
theCode.equals(t.getCode()));
}
}

View File

@ -16,7 +16,6 @@ import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc; import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry; import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc; import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
import ca.uhn.fhir.jpa.subscription.SubscriptionInterceptorLoader;
import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl; import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc; import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.jpa.util.ResourceCountCache; import ca.uhn.fhir.jpa.util.ResourceCountCache;
@ -27,7 +26,6 @@ import ca.uhn.fhir.parser.StrictErrorHandler;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
@ -59,7 +57,6 @@ import java.io.InputStream;
import java.util.Map; import java.util.Map;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestDstu3Config.class}) @ContextConfiguration(classes = {TestDstu3Config.class})
@ -240,6 +237,10 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
@Qualifier("myTaskDaoDstu3") @Qualifier("myTaskDaoDstu3")
protected IFhirResourceDao<Task> myTaskDao; protected IFhirResourceDao<Task> myTaskDao;
@Autowired @Autowired
protected ITermConceptDao myTermConceptDao;
@Autowired
protected ITermCodeSystemDao myTermCodeSystemDao;
@Autowired
protected IHapiTerminologySvc myTermSvc; protected IHapiTerminologySvc myTermSvc;
@Autowired @Autowired
protected PlatformTransactionManager myTransactionMgr; protected PlatformTransactionManager myTransactionMgr;

View File

@ -130,6 +130,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
@Autowired @Autowired
protected ITermConceptDao myTermConceptDao; protected ITermConceptDao myTermConceptDao;
@Autowired @Autowired
protected ITermConceptDesignationDao myTermConceptDesignationDao;
@Autowired
@Qualifier("myConditionDaoR4") @Qualifier("myConditionDaoR4")
protected IFhirResourceDao<Condition> myConditionDao; protected IFhirResourceDao<Condition> myConditionDao;
@Autowired @Autowired
@ -293,7 +295,9 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
@Autowired @Autowired
protected ITermValueSetDao myTermValueSetDao; protected ITermValueSetDao myTermValueSetDao;
@Autowired @Autowired
protected ITermValueSetCodeDao myTermValueSetCodeDao; protected ITermValueSetConceptDao myTermValueSetConceptDao;
@Autowired
protected ITermValueSetConceptDesignationDao myTermValueSetConceptDesignationDao;
@Autowired @Autowired
protected ITermConceptMapDao myTermConceptMapDao; protected ITermConceptMapDao myTermConceptMapDao;
@Autowired @Autowired

View File

@ -1,12 +1,12 @@
package ca.uhn.fhir.jpa.term; package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao;
import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test; import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.entity.TermCodeSystem;
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.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
@ -19,7 +19,11 @@ import org.hl7.fhir.r4.model.ValueSet;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -30,11 +34,13 @@ import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
private static final Logger ourLog = LoggerFactory.getLogger(TerminologySvcImplDstu3Test.class);
private static final String CS_URL = "http://example.com/my_code_system"; private static final String CS_URL = "http://example.com/my_code_system";
private static final String CS_URL_2 = "http://example.com/my_code_system2"; private static final String CS_URL_2 = "http://example.com/my_code_system2";
@Autowired
private ITermCodeSystemDao myTermCodeSystemDao; private IIdType myExtensionalCsId;
private IIdType myExtensionalVsId;
@After @After
public void after() { public void after() {
@ -76,6 +82,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
childAAB.addPropertyString("propA", "valueAAB"); childAAB.addPropertyString("propA", "valueAAB");
childAAB.addPropertyString("propB", "foo"); childAAB.addPropertyString("propB", "foo");
childAAB.addDesignation() childAAB.addDesignation()
.setLanguage("D1L")
.setUseSystem("D1S") .setUseSystem("D1S")
.setUseCode("D1C") .setUseCode("D1C")
.setUseDisplay("D1D") .setUseDisplay("D1D")
@ -546,13 +553,13 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
assertEquals("childAAB", concept.getCode()); assertEquals("childAAB", concept.getCode());
assertEquals("http://example.com/my_code_system", concept.getSystem()); assertEquals("http://example.com/my_code_system", concept.getSystem());
assertEquals(null, concept.getDisplay()); assertEquals(null, concept.getDisplay());
assertEquals("D1L", concept.getDesignation().get(0).getLanguage());
assertEquals("D1S", concept.getDesignation().get(0).getUse().getSystem()); assertEquals("D1S", concept.getDesignation().get(0).getUse().getSystem());
assertEquals("D1C", concept.getDesignation().get(0).getUse().getCode()); assertEquals("D1C", concept.getDesignation().get(0).getUse().getCode());
assertEquals("D1D", concept.getDesignation().get(0).getUse().getDisplay()); assertEquals("D1D", concept.getDesignation().get(0).getUse().getDisplay());
assertEquals("D1V", concept.getDesignation().get(0).getValue()); assertEquals("D1V", concept.getDesignation().get(0).getValue());
} }
@Test @Test
public void testStoreCodeSystemInvalidCyclicLoop() { public void testStoreCodeSystemInvalidCyclicLoop() {
CodeSystem codeSystem = new CodeSystem(); CodeSystem codeSystem = new CodeSystem();
@ -585,6 +592,103 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
} }
} }
@Test
public void testStoreTermCodeSystemAndNestedChildren() {
IIdType codeSystemId = createCodeSystem();
CodeSystem codeSystemResource = myCodeSystemDao.read(codeSystemId);
ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystemResource));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(codeSystemId.getIdPartAsLong());
assertEquals(CS_URL, codeSystem.getCodeSystemUri());
assertEquals("SYSTEM NAME", codeSystem.getName());
TermCodeSystemVersion codeSystemVersion = codeSystem.getCurrentVersion();
assertEquals(9, codeSystemVersion.getConcepts().size());
List<TermConcept> concepts = myTermConceptDao.findByCodeSystemVersion(codeSystemVersion);
TermConcept parentWithNoChildrenA = concepts.get(0);
assertEquals("ParentWithNoChildrenA", parentWithNoChildrenA.getCode());
assertNull(parentWithNoChildrenA.getDisplay());
assertEquals(0, parentWithNoChildrenA.getChildren().size());
assertEquals(0, parentWithNoChildrenA.getParents().size());
assertEquals(0, parentWithNoChildrenA.getDesignations().size());
assertEquals(0, parentWithNoChildrenA.getProperties().size());
TermConcept parentWithNoChildrenB = concepts.get(1);
assertEquals("ParentWithNoChildrenB", parentWithNoChildrenB.getCode());
assertNull(parentWithNoChildrenB.getDisplay());
assertEquals(0, parentWithNoChildrenB.getChildren().size());
assertEquals(0, parentWithNoChildrenB.getParents().size());
assertEquals(0, parentWithNoChildrenB.getDesignations().size());
assertEquals(0, parentWithNoChildrenB.getProperties().size());
TermConcept parentWithNoChildrenC = concepts.get(2);
assertEquals("ParentWithNoChildrenC", parentWithNoChildrenC.getCode());
assertNull(parentWithNoChildrenC.getDisplay());
assertEquals(0, parentWithNoChildrenC.getChildren().size());
assertEquals(0, parentWithNoChildrenC.getParents().size());
assertEquals(0, parentWithNoChildrenC.getDesignations().size());
assertEquals(0, parentWithNoChildrenC.getProperties().size());
TermConcept parentA = concepts.get(3);
assertEquals("ParentA", parentA.getCode());
assertNull(parentA.getDisplay());
assertEquals(2, parentA.getChildren().size());
assertEquals(0, parentA.getParents().size());
assertEquals(0, parentA.getDesignations().size());
assertEquals(0, parentA.getProperties().size());
TermConcept childAA = concepts.get(4);
assertEquals("childAA", childAA.getCode());
assertNull(childAA.getDisplay());
assertEquals(2, childAA.getChildren().size());
assertEquals(1, childAA.getParents().size());
assertSame(parentA, childAA.getParents().iterator().next().getParent());
assertEquals(0, childAA.getDesignations().size());
assertEquals(0, childAA.getProperties().size());
TermConcept childAAA = concepts.get(5);
assertEquals("childAAA", childAAA.getCode());
assertNull(childAAA.getDisplay());
assertEquals(0, childAAA.getChildren().size());
assertEquals(1, childAAA.getParents().size());
assertSame(childAA, childAAA.getParents().iterator().next().getParent());
assertEquals(0, childAAA.getDesignations().size());
assertEquals(2, childAAA.getProperties().size());
TermConcept childAAB = concepts.get(6);
assertEquals("childAAB", childAAB.getCode());
assertNull(childAAB.getDisplay());
assertEquals(0, childAAB.getChildren().size());
assertEquals(1, childAAB.getParents().size());
assertSame(childAA, childAAB.getParents().iterator().next().getParent());
assertEquals(1, childAAB.getDesignations().size());
assertEquals(2, childAAB.getProperties().size());
TermConcept childAB = concepts.get(7);
assertEquals("childAB", childAB.getCode());
assertNull(childAB.getDisplay());
assertEquals(0, childAB.getChildren().size());
assertEquals(1, childAB.getParents().size());
assertSame(parentA, childAB.getParents().iterator().next().getParent());
assertEquals(0, childAB.getDesignations().size());
assertEquals(0, childAB.getProperties().size());
TermConcept parentB = concepts.get(8);
assertEquals("ParentB", parentB.getCode());
assertNull(parentB.getDisplay());
assertEquals(0, parentB.getChildren().size());
assertEquals(0, parentB.getParents().size());
assertEquals(0, parentB.getDesignations().size());
assertEquals(0, parentB.getProperties().size());
}
});
}
/** /**
* Check that a custom ValueSet against a custom CodeSystem expands correctly * Check that a custom ValueSet against a custom CodeSystem expands correctly
*/ */

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test; import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
import ca.uhn.fhir.jpa.entity.*; import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
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 org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
@ -10,6 +11,7 @@ import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence; import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
import org.junit.*; import org.junit.*;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.mockito.Mock;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionStatus;
@ -21,6 +23,9 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
public class TerminologySvcImplR4Test extends BaseJpaR4Test { public class TerminologySvcImplR4Test extends BaseJpaR4Test {
private static final Logger ourLog = LoggerFactory.getLogger(TerminologySvcImplR4Test.class); private static final Logger ourLog = LoggerFactory.getLogger(TerminologySvcImplR4Test.class);
@ -30,6 +35,9 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
private IIdType myExtensionalCsId; private IIdType myExtensionalCsId;
private IIdType myExtensionalVsId; private IIdType myExtensionalVsId;
@Mock
IValueSetCodeAccumulator myValueSetCodeAccumulator;
@Before @Before
public void before() { public void before() {
myDaoConfig.setAllowExternalReferences(true); myDaoConfig.setAllowExternalReferences(true);
@ -40,6 +48,57 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences()); myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental()); myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental());
} }
private IIdType createCodeSystem() {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(CS_URL);
codeSystem.setContent(CodeSystem.CodeSystemContentMode.NOTPRESENT);
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
ResourceTable table = myResourceTableDao.findById(id.getIdPartAsLong()).orElseThrow(IllegalArgumentException::new);
TermCodeSystemVersion cs = new TermCodeSystemVersion();
cs.setResource(table);
TermConcept parent;
parent = new TermConcept(cs, "ParentWithNoChildrenA");
cs.getConcepts().add(parent);
parent = new TermConcept(cs, "ParentWithNoChildrenB");
cs.getConcepts().add(parent);
parent = new TermConcept(cs, "ParentWithNoChildrenC");
cs.getConcepts().add(parent);
TermConcept parentA = new TermConcept(cs, "ParentA");
cs.getConcepts().add(parentA);
TermConcept childAA = new TermConcept(cs, "childAA");
parentA.addChild(childAA, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
TermConcept childAAA = new TermConcept(cs, "childAAA");
childAAA.addPropertyString("propA", "valueAAA");
childAAA.addPropertyString("propB", "foo");
childAA.addChild(childAAA, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
TermConcept childAAB = new TermConcept(cs, "childAAB");
childAAB.addPropertyString("propA", "valueAAB");
childAAB.addPropertyString("propB", "foo");
childAAB.addDesignation()
.setUseSystem("D1S")
.setUseCode("D1C")
.setUseDisplay("D1D")
.setValue("D1V");
childAA.addChild(childAAB, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
TermConcept childAB = new TermConcept(cs, "childAB");
parentA.addChild(childAB, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
TermConcept parentB = new TermConcept(cs, "ParentB");
cs.getConcepts().add(parentB);
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, "SYSTEM NAME", cs);
return id;
}
private void createAndPersistConceptMap() { private void createAndPersistConceptMap() {
ConceptMap conceptMap = createConceptMap(); ConceptMap conceptMap = createConceptMap();
@ -60,11 +119,21 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
loadAndPersistValueSet(); loadAndPersistValueSet();
} }
private void loadAndPersistCodeSystemAndValueSetWithDesignations() throws IOException {
loadAndPersistCodeSystemWithDesignations();
loadAndPersistValueSet();
}
private void loadAndPersistCodeSystem() throws IOException { private void loadAndPersistCodeSystem() throws IOException {
CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml"); CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
persistCodeSystem(codeSystem); persistCodeSystem(codeSystem);
} }
private void loadAndPersistCodeSystemWithDesignations() throws IOException {
CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs-with-designations.xml");
persistCodeSystem(codeSystem);
}
private void persistCodeSystem(CodeSystem theCodeSystem) { private void persistCodeSystem(CodeSystem theCodeSystem) {
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override @Override
@ -202,6 +271,173 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
loadAndPersistValueSet(); loadAndPersistValueSet();
} }
@Test
public void testExpandValueSetWithValueSetCodeAccumulator() {
createCodeSystem();
ValueSet vs = new ValueSet();
ValueSet.ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(CS_URL);
myTermSvc.expandValueSet(vs, myValueSetCodeAccumulator);
verify(myValueSetCodeAccumulator, times(9)).includeCodeWithDesignations(anyString(), anyString(), nullable(String.class), anyCollection());
}
@Test
public void testStoreTermCodeSystemAndChildren() throws Exception {
loadAndPersistCodeSystemWithDesignations();
CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId);
ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(myExtensionalCsId.getIdPartAsLong());
assertEquals("http://acme.org", codeSystem.getCodeSystemUri());
assertNull(codeSystem.getName());
TermCodeSystemVersion codeSystemVersion = codeSystem.getCurrentVersion();
assertEquals(24, codeSystemVersion.getConcepts().size());
List<TermConcept> concepts = myTermConceptDao.findByCodeSystemVersion(codeSystemVersion);
TermConcept concept = concepts.get(0);
assertEquals("8450-9", concept.getCode());
assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
assertEquals(1, concept.getDesignations().size());
TermConceptDesignation designation = concept.getDesignations().iterator().next();
assertEquals("nl", designation.getLanguage());
assertEquals("http://snomed.info/sct", designation.getUseSystem());
assertEquals("900000000000013009", designation.getUseCode());
assertEquals("Synonym", designation.getUseDisplay());
assertEquals("Systolische bloeddruk - expiratie", designation.getValue());
concept = concepts.get(1);
assertEquals("11378-7", concept.getCode());
assertEquals("Systolic blood pressure at First encounter", concept.getDisplay());
assertEquals(0, concept.getDesignations().size());
// ...
concept = concepts.get(22);
assertEquals("8491-3", concept.getCode());
assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay());
assertEquals(1, concept.getDesignations().size());
designation = concept.getDesignations().iterator().next();
assertEquals("nl", designation.getLanguage());
assertEquals("http://snomed.info/sct", designation.getUseSystem());
assertEquals("900000000000013009", designation.getUseCode());
assertEquals("Synonym", designation.getUseDisplay());
assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue());
concept = concepts.get(23);
assertEquals("8492-1", concept.getCode());
assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay());
assertEquals(0, concept.getDesignations().size());
}
});
}
@Test
public void testStoreTermCodeSystemAndNestedChildren() {
IIdType codeSystemId = createCodeSystem();
CodeSystem codeSystemResource = myCodeSystemDao.read(codeSystemId);
ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystemResource));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(codeSystemId.getIdPartAsLong());
assertEquals(CS_URL, codeSystem.getCodeSystemUri());
assertEquals("SYSTEM NAME", codeSystem.getName());
TermCodeSystemVersion codeSystemVersion = codeSystem.getCurrentVersion();
assertEquals(9, codeSystemVersion.getConcepts().size());
List<TermConcept> concepts = myTermConceptDao.findByCodeSystemVersion(codeSystemVersion);
TermConcept parentWithNoChildrenA = concepts.get(0);
assertEquals("ParentWithNoChildrenA", parentWithNoChildrenA.getCode());
assertNull(parentWithNoChildrenA.getDisplay());
assertEquals(0, parentWithNoChildrenA.getChildren().size());
assertEquals(0, parentWithNoChildrenA.getParents().size());
assertEquals(0, parentWithNoChildrenA.getDesignations().size());
assertEquals(0, parentWithNoChildrenA.getProperties().size());
TermConcept parentWithNoChildrenB = concepts.get(1);
assertEquals("ParentWithNoChildrenB", parentWithNoChildrenB.getCode());
assertNull(parentWithNoChildrenB.getDisplay());
assertEquals(0, parentWithNoChildrenB.getChildren().size());
assertEquals(0, parentWithNoChildrenB.getParents().size());
assertEquals(0, parentWithNoChildrenB.getDesignations().size());
assertEquals(0, parentWithNoChildrenB.getProperties().size());
TermConcept parentWithNoChildrenC = concepts.get(2);
assertEquals("ParentWithNoChildrenC", parentWithNoChildrenC.getCode());
assertNull(parentWithNoChildrenC.getDisplay());
assertEquals(0, parentWithNoChildrenC.getChildren().size());
assertEquals(0, parentWithNoChildrenC.getParents().size());
assertEquals(0, parentWithNoChildrenC.getDesignations().size());
assertEquals(0, parentWithNoChildrenC.getProperties().size());
TermConcept parentA = concepts.get(3);
assertEquals("ParentA", parentA.getCode());
assertNull(parentA.getDisplay());
assertEquals(2, parentA.getChildren().size());
assertEquals(0, parentA.getParents().size());
assertEquals(0, parentA.getDesignations().size());
assertEquals(0, parentA.getProperties().size());
TermConcept childAA = concepts.get(4);
assertEquals("childAA", childAA.getCode());
assertNull(childAA.getDisplay());
assertEquals(2, childAA.getChildren().size());
assertEquals(1, childAA.getParents().size());
assertSame(parentA, childAA.getParents().iterator().next().getParent());
assertEquals(0, childAA.getDesignations().size());
assertEquals(0, childAA.getProperties().size());
TermConcept childAAA = concepts.get(5);
assertEquals("childAAA", childAAA.getCode());
assertNull(childAAA.getDisplay());
assertEquals(0, childAAA.getChildren().size());
assertEquals(1, childAAA.getParents().size());
assertSame(childAA, childAAA.getParents().iterator().next().getParent());
assertEquals(0, childAAA.getDesignations().size());
assertEquals(2, childAAA.getProperties().size());
TermConcept childAAB = concepts.get(6);
assertEquals("childAAB", childAAB.getCode());
assertNull(childAAB.getDisplay());
assertEquals(0, childAAB.getChildren().size());
assertEquals(1, childAAB.getParents().size());
assertSame(childAA, childAAB.getParents().iterator().next().getParent());
assertEquals(1, childAAB.getDesignations().size());
assertEquals(2, childAAB.getProperties().size());
TermConcept childAB = concepts.get(7);
assertEquals("childAB", childAB.getCode());
assertNull(childAB.getDisplay());
assertEquals(0, childAB.getChildren().size());
assertEquals(1, childAB.getParents().size());
assertSame(parentA, childAB.getParents().iterator().next().getParent());
assertEquals(0, childAB.getDesignations().size());
assertEquals(0, childAB.getProperties().size());
TermConcept parentB = concepts.get(8);
assertEquals("ParentB", parentB.getCode());
assertNull(parentB.getDisplay());
assertEquals(0, parentB.getChildren().size());
assertEquals(0, parentB.getParents().size());
assertEquals(0, parentB.getDesignations().size());
assertEquals(0, parentB.getProperties().size());
}
});
}
@Test @Test
public void testStoreTermConceptMapAndChildren() { public void testStoreTermConceptMapAndChildren() {
createAndPersistConceptMap(); createAndPersistConceptMap();
@ -384,7 +620,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
public void testStoreTermValueSetAndChildren() throws Exception { public void testStoreTermValueSetAndChildren() throws Exception {
myDaoConfig.setPreExpandValueSetsExperimental(true); myDaoConfig.setPreExpandValueSetsExperimental(true);
loadAndPersistCodeSystemAndValueSet(); loadAndPersistCodeSystemAndValueSetWithDesignations();
CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId);
ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem));
@ -406,33 +642,51 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
ourLog.info("ValueSet:\n" + valueSet.toString()); ourLog.info("ValueSet:\n" + valueSet.toString());
assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", valueSet.getUrl()); assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", valueSet.getUrl());
assertEquals("Terminology Services Connectation #1 Extensional case #2", valueSet.getName()); assertEquals("Terminology Services Connectation #1 Extensional case #2", valueSet.getName());
assertEquals(codeSystem.getConcept().size(), valueSet.getCodes().size()); assertEquals(codeSystem.getConcept().size(), valueSet.getConcepts().size());
TermValueSetCode code = valueSet.getCodes().get(0); TermValueSetConcept concept = valueSet.getConcepts().get(0);
ourLog.info("Code:\n" + code.toString()); ourLog.info("Code:\n" + concept.toString());
assertEquals("http://acme.org", code.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("8450-9", code.getCode()); assertEquals("8450-9", concept.getCode());
assertEquals("Systolic blood pressure--expiration", code.getDisplay()); assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
assertEquals(1, concept.getDesignations().size());
code = valueSet.getCodes().get(1); TermValueSetConceptDesignation designation = concept.getDesignations().get(0);
ourLog.info("Code:\n" + code.toString()); assertEquals("nl", designation.getLanguage());
assertEquals("http://acme.org", code.getSystem()); assertEquals("http://snomed.info/sct", designation.getUseSystem());
assertEquals("11378-7", code.getCode()); assertEquals("900000000000013009", designation.getUseCode());
assertEquals("Systolic blood pressure at First encounter", code.getDisplay()); assertEquals("Synonym", designation.getUseDisplay());
assertEquals("Systolische bloeddruk - expiratie", designation.getValue());
concept = valueSet.getConcepts().get(1);
ourLog.info("Code:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem());
assertEquals("11378-7", concept.getCode());
assertEquals("Systolic blood pressure at First encounter", concept.getDisplay());
assertEquals(0, concept.getDesignations().size());
// ... // ...
code = valueSet.getCodes().get(22); concept = valueSet.getConcepts().get(22);
ourLog.info("Code:\n" + code.toString()); ourLog.info("Code:\n" + concept.toString());
assertEquals("http://acme.org", code.getSystem()); assertEquals("http://acme.org", concept.getSystem());
assertEquals("8491-3", code.getCode()); assertEquals("8491-3", concept.getCode());
assertEquals("Systolic blood pressure 1 hour minimum", code.getDisplay()); assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay());
assertEquals(1, concept.getDesignations().size());
code = valueSet.getCodes().get(23); designation = concept.getDesignations().get(0);
ourLog.info("Code:\n" + code.toString()); assertEquals("nl", designation.getLanguage());
assertEquals("http://acme.org", code.getSystem()); assertEquals("http://snomed.info/sct", designation.getUseSystem());
assertEquals("8492-1", code.getCode()); assertEquals("900000000000013009", designation.getUseCode());
assertEquals("Systolic blood pressure 8 hour minimum", code.getDisplay()); assertEquals("Synonym", designation.getUseDisplay());
assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue());
concept = valueSet.getConcepts().get(23);
ourLog.info("Code:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem());
assertEquals("8492-1", concept.getCode());
assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay());
assertEquals(0, concept.getDesignations().size());
} }
}); });
} }

View File

@ -0,0 +1,117 @@
<CodeSystem xmlns="http://hl7.org/fhir">
<url value="http://acme.org" />
<concept>
<code value="8450-9" />
<display value="Systolic blood pressure--expiration" />
<designation>
<language value="nl"/>
<use>
<system value="http://snomed.info/sct"/>
<code value="900000000000013009"/>
<display value="Synonym"/>
</use>
<value value="Systolische bloeddruk - expiratie"/>
</designation>
</concept>
<concept>
<code value="11378-7" />
<display value="Systolic blood pressure at First encounter" />
</concept>
<concept>
<code value="8493-9" />
<display value="Systolic blood pressure 10 hour minimum" />
</concept>
<concept>
<code value="8494-7" />
<display value="Systolic blood pressure 12 hour minimum" />
</concept>
<concept>
<code value="8495-4" />
<display value="Systolic blood pressure 24 hour minimum" />
</concept>
<concept>
<code value="8451-7" />
<display value="Systolic blood pressure--inspiration" />
</concept>
<concept>
<code value="8452-5" />
<display value="Systolic blood pressure.inspiration - expiration" />
</concept>
<concept>
<code value="8459-0" />
<display value="Systolic blood pressure--sitting" />
</concept>
<concept>
<code value="8460-8" />
<display value="Systolic blood pressure--standing" />
</concept>
<concept>
<code value="8461-6" />
<display value="Systolic blood pressure--supine" />
</concept>
<concept>
<code value="8479-8" />
<display value="Systolic blood pressure by palpation" />
</concept>
<concept>
<code value="8480-6" />
<display value="Systolic blood pressure" />
</concept>
<concept>
<code value="8481-4" />
<display value="Systolic blood pressure 1 hour maximum" />
</concept>
<concept>
<code value="8482-2" />
<display value="Systolic blood pressure 8 hour maximum" />
</concept>
<concept>
<code value="8483-0" />
<display value="Systolic blood pressure 10 hour maximum" />
</concept>
<concept>
<code value="8484-8" />
<display value="Systolic blood pressure 12 hour maximum" />
</concept>
<concept>
<code value="8485-5" />
<display value="Systolic blood pressure 24 hour maximum" />
</concept>
<concept>
<code value="8486-3" />
<display value="Systolic blood pressure 1 hour mean" />
</concept>
<concept>
<code value="8487-1" />
<display value="Systolic blood pressure 8 hour mean" />
</concept>
<concept>
<code value="8488-9" />
<display value="Systolic blood pressure 10 hour mean" />
</concept>
<concept>
<code value="8489-7" />
<display value="Systolic blood pressure 12 hour mean" />
</concept>
<concept>
<code value="8490-5" />
<display value="Systolic blood pressure 24 hour mean" />
</concept>
<concept>
<code value="8491-3" />
<display value="Systolic blood pressure 1 hour minimum" />
<designation>
<language value="nl"/>
<use>
<system value="http://snomed.info/sct"/>
<code value="900000000000013009"/>
<display value="Synonym"/>
</use>
<value value="Systolische bloeddruk minimaal 1 uur"/>
</designation>
</concept>
<concept>
<code value="8492-1" />
<display value="Systolic blood pressure 8 hour minimum" />
</concept>
</CodeSystem>

View File

@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.migrate.tasks;
import ca.uhn.fhir.jpa.entity.TermCodeSystem; import ca.uhn.fhir.jpa.entity.TermCodeSystem;
import ca.uhn.fhir.jpa.entity.TermConcept; import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermValueSet; import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation;
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum; import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
import ca.uhn.fhir.jpa.migrate.taskdef.AddColumnTask; import ca.uhn.fhir.jpa.migrate.taskdef.AddColumnTask;
import ca.uhn.fhir.jpa.migrate.taskdef.ArbitrarySqlTask; import ca.uhn.fhir.jpa.migrate.taskdef.ArbitrarySqlTask;
@ -96,23 +97,43 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
.references("HFJ_RESOURCE", "RES_ID"); .references("HFJ_RESOURCE", "RES_ID");
termValueSetTable.addColumn("NAME").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermValueSet.MAX_NAME_LENGTH); termValueSetTable.addColumn("NAME").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermValueSet.MAX_NAME_LENGTH);
// TermValueSetCode // TermValueSetConcept
version.startSectionWithMessage("Processing table: TRM_VALUESET_CODE"); version.startSectionWithMessage("Processing table: TRM_VALUESET_CONCEPT");
version.addIdGenerator("SEQ_VALUESET_CODE_PID"); version.addIdGenerator("SEQ_VALUESET_CONCEPT_PID");
Builder.BuilderAddTableByColumns termValueSetCodeTable = version.addTableByColumns("TRM_VALUESET_CODE", "PID"); Builder.BuilderAddTableByColumns termValueSetConceptTable = version.addTableByColumns("TRM_VALUESET_CONCEPT", "PID");
termValueSetCodeTable.addColumn("PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); termValueSetConceptTable.addColumn("PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
termValueSetCodeTable.addColumn("VALUESET_PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); termValueSetConceptTable.addColumn("VALUESET_PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
termValueSetCodeTable termValueSetConceptTable
.addForeignKey("FK_TRM_VALUESET_PID") .addForeignKey("FK_TRM_VALUESET_PID")
.toColumn("VALUESET_PID") .toColumn("VALUESET_PID")
.references("TRM_VALUESET", "PID"); .references("TRM_VALUESET", "PID");
termValueSetCodeTable.addColumn("SYSTEM").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermCodeSystem.MAX_URL_LENGTH); termValueSetConceptTable.addColumn("SYSTEM").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermCodeSystem.MAX_URL_LENGTH);
termValueSetCodeTable.addColumn("CODE").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermConcept.MAX_CODE_LENGTH); termValueSetConceptTable.addColumn("CODE").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermConcept.MAX_CODE_LENGTH);
termValueSetCodeTable termValueSetConceptTable
.addIndex("IDX_VALUESET_CODE_CS_CD") .addIndex("IDX_VALUESET_CONCEPT_CS_CD")
.unique(false) .unique(false)
.withColumns("SYSTEM", "CODE"); .withColumns("SYSTEM", "CODE");
termValueSetCodeTable.addColumn("DISPLAY").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermConcept.MAX_DESC_LENGTH); termValueSetConceptTable.addColumn("DISPLAY").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermConcept.MAX_DESC_LENGTH);
// TermValueSetConceptDesignation
version.startSectionWithMessage("Processing table: TRM_VALUESET_C_DESIGNATION");
version.addIdGenerator("SEQ_VALUESET_C_DSGNTN_PID");
Builder.BuilderAddTableByColumns termValueSetConceptDesignationTable = version.addTableByColumns("TRM_VALUESET_C_DESIGNATION", "PID");
termValueSetConceptDesignationTable.addColumn("PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
termValueSetConceptDesignationTable.addColumn("VALUESET_CONCEPT_PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
termValueSetConceptDesignationTable
.addForeignKey("FK_TRM_VALUESET_CONCEPT_PID")
.toColumn("VALUESET_CONCEPT_PID")
.references("TRM_VALUESET_CONCEPT", "PID");
termValueSetConceptDesignationTable.addColumn("LANG").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermValueSetConceptDesignation.MAX_LENGTH);
termValueSetConceptDesignationTable.addColumn("USE_SYSTEM").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermValueSetConceptDesignation.MAX_LENGTH);
termValueSetConceptDesignationTable.addColumn("USE_CODE").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermValueSetConceptDesignation.MAX_LENGTH);
termValueSetConceptDesignationTable.addColumn("USE_DISPLAY").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermValueSetConceptDesignation.MAX_LENGTH);
termValueSetConceptDesignationTable.addColumn("VAL").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermValueSetConceptDesignation.MAX_LENGTH);
termValueSetConceptDesignationTable
.addIndex("IDX_VALUESET_C_DSGNTN_VAL")
.unique(false)
.withColumns("VAL");
} }

View File

@ -284,6 +284,13 @@
profiles via the $snapshot operation, and will automatically generate a snapshot when profiles via the $snapshot operation, and will automatically generate a snapshot when
needed for validation. needed for validation.
</action> </action>
<action type="add">
Creating/updating CodeSystems now persist <![CDATA[<code>CodeSystem.concept.designation</code>]]> to
the terminology tables.
</action>
<action type="add">
Expanded ValueSets now populate <![CDATA[<code>ValueSet.expansion.contains.designation.language</code>]]>.
</action>
</release> </release>
<release version="3.8.0" date="2019-05-30" description="Hippo"> <release version="3.8.0" date="2019-05-30" description="Hippo">
<action type="fix"> <action type="fix">