diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ValidateUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ValidateUtil.java
index 6b5df86e696..8d234d690bb 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ValidateUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ValidateUtil.java
@@ -23,7 +23,7 @@ package ca.uhn.fhir.util;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
-import static org.apache.commons.lang3.StringUtils.isBlank;
+import static org.apache.commons.lang3.StringUtils.*;
public class ValidateUtil {
@@ -37,7 +37,7 @@ public class ValidateUtil {
}
/**
- * Throws {@link IllegalArgumentException} if theValue is <= theMinimum
+ * Throws {@link IllegalArgumentException} if theValue is < theMinimum
*/
public static void isGreaterThanOrEqualTo(long theValue, long theMinimum, String theMessage) {
if (theValue < theMinimum) {
@@ -45,6 +45,12 @@ public class ValidateUtil {
}
}
+ public static void isNotBlankOrThrowIllegalArgument(String theString, String theMessage) {
+ if (isBlank(theString)) {
+ throw new IllegalArgumentException(theMessage);
+ }
+ }
+
public static void isNotBlankOrThrowInvalidRequest(String theString, String theMessage) {
if (isBlank(theString)) {
throw new InvalidRequestException(theMessage);
@@ -57,6 +63,12 @@ public class ValidateUtil {
}
}
+ public static void isNotTooLongOrThrowIllegalArgument(String theString, int theMaxLength, String theMessage) {
+ if (length(theString) > theMaxLength) {
+ throw new IllegalArgumentException(theMessage);
+ }
+ }
+
public static void isTrueOrThrowInvalidRequest(boolean theSuccess, String theMessage) {
if (theSuccess == false) {
throw new InvalidRequestException(theMessage);
diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
index 5838eb9baf1..45d5426bda2 100644
--- a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
+++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
@@ -115,8 +115,9 @@ ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor.noParam=Note that cascadi
ca.uhn.fhir.jpa.provider.BaseJpaProvider.cantCombintAtAndSince=Unable to combine _at and _since parameters for history operation
+ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateCodeSystemUrl=Can not create multiple CodeSystem resources with CodeSystem.url "{0}", already have one with resource ID: {1}
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateConceptMapUrl=Can not create multiple ConceptMap resources with ConceptMap.url "{0}", already have one with resource ID: {1}
-ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateCodeSystemUri=Can not create multiple code systems with URI "{0}", already have one with resource ID: {1}
+ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateValueSetUrl=Can not create multiple ValueSet resources with ValueSet.url "{0}", already have one with resource ID: {1}
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted!
ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils.failedToApplyPatch=Failed to apply JSON patch to {0}: {1}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java
index 1a149a9134e..d8df260f116 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java
@@ -145,6 +145,10 @@ public class DaoConfig {
private boolean myEnableInMemorySubscriptionMatching = true;
private boolean myEnforceReferenceTargetTypes = true;
private ClientIdStrategyEnum myResourceClientIdStrategy = ClientIdStrategyEnum.ALPHANUMERIC;
+ /**
+ * EXPERIMENTAL - Do not use in production! Do not change default of {@code false}!
+ */
+ private boolean myPreExpandValueSetsExperimental = false;
/**
* Constructor
@@ -1600,6 +1604,34 @@ public class DaoConfig {
myModelConfig.setWebsocketContextPath(theWebsocketContextPath);
}
+ /**
+ * EXPERIMENTAL - Do not use in production!
+ *
+ * If set to {@code true}, ValueSets and expansions are stored in terminology tables. This is to facilitate
+ * future optimization of the $expand operation on large ValueSets.
+ *
+ *
+ * The default value for this setting is {@code false}.
+ *
+ */
+ public boolean isPreExpandValueSetsExperimental() {
+ return myPreExpandValueSetsExperimental;
+ }
+
+ /**
+ * EXPERIMENTAL - Do not use in production!
+ *
+ * If set to {@code true}, ValueSets and expansions are stored in terminology tables. This is to facilitate
+ * future optimization of the $expand operation on large ValueSets.
+ *
+ *
+ * The default value for this setting is {@code false}.
+ *
+ */
+ public void setPreExpandValueSetsExperimental(boolean thePreExpandValueSetsExperimental) {
+ myPreExpandValueSetsExperimental = thePreExpandValueSetsExperimental;
+ }
+
public enum IndexEnabledEnum {
ENABLED,
DISABLED
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemDao.java
index 5fe695bc06c..3a672f8a312 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemDao.java
@@ -34,7 +34,7 @@ public interface ITermCodeSystemDao extends JpaRepository
TermCodeSystem findByCodeSystemUri(@Param("code_system_uri") String theCodeSystemUri);
@Query("SELECT cs FROM TermCodeSystem cs WHERE cs.myResourcePid = :resource_pid")
- TermCodeSystem findByResourcePid(@Param("resource_pid") Long theReourcePid);
+ TermCodeSystem findByResourcePid(@Param("resource_pid") Long theResourcePid);
@Query("SELECT cs FROM TermCodeSystem cs WHERE cs.myCurrentVersion.myId = :csv_pid")
Optional findWithCodeSystemVersionAsCurrentVersion(@Param("csv_pid") Long theCodeSystemVersionPid);
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetCodeDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetCodeDao.java
new file mode 100644
index 00000000000..5702aceb846
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetCodeDao.java
@@ -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.TermValueSetCode;
+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 ITermValueSetCodeDao extends JpaRepository {
+
+ @Query("DELETE FROM TermValueSetCode vsc WHERE vsc.myValueSet.myId = :pid")
+ @Modifying
+ void deleteTermValueSetCodesByValueSetId(@Param("pid") Long theValueSetId);
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetDao.java
new file mode 100644
index 00000000000..087dcefe70e
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetDao.java
@@ -0,0 +1,43 @@
+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.TermValueSet;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import java.util.Optional;
+
+public interface ITermValueSetDao extends JpaRepository {
+
+ @Query("DELETE FROM TermValueSet vs WHERE vs.myId = :pid")
+ @Modifying
+ void deleteTermValueSetById(@Param("pid") Long theId);
+
+ @Query("SELECT vs FROM TermValueSet vs WHERE vs.myResourcePid = :resource_pid")
+ Optional findByResourcePid(@Param("resource_pid") Long theResourcePid);
+
+ @Query("SELECT vs FROM TermValueSet vs WHERE vs.myUrl = :url")
+ Optional findByUrl(@Param("url") String theUrl);
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoValueSetDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoValueSetDstu3.java
index 93116549405..2f83a634c66 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoValueSetDstu3.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoValueSetDstu3.java
@@ -23,11 +23,15 @@ package ca.uhn.fhir.jpa.dao.dstu3;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem.LookupCodeResult;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
+import ca.uhn.fhir.jpa.model.entity.ResourceTable;
+import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.jpa.util.LogicUtil;
import ca.uhn.fhir.rest.api.server.RequestDetails;
+import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.ElementUtil;
import org.apache.commons.codec.binary.StringUtils;
+import org.hl7.fhir.convertors.VersionConvertor_30_40;
import org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext;
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
import org.hl7.fhir.dstu3.model.*;
@@ -37,6 +41,8 @@ import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
+import org.hl7.fhir.exceptions.FHIRException;
+import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.slf4j.Logger;
@@ -45,14 +51,18 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import java.util.Collections;
+import java.util.Date;
import java.util.List;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3 implements IFhirResourceDaoValueSet {
-
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoValueSetDstu3.class);
+
+ @Autowired
+ private IHapiTerminologySvc myHapiTerminologySvc;
+
@Autowired
@Qualifier("myJpaValidationSupportChainDstu3")
private IValidationSupport myValidationSupport;
@@ -295,4 +305,26 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3
// nothing
}
+ @Override
+ protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
+ boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
+ ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
+
+ if (myDaoConfig.isPreExpandValueSetsExperimental()) {
+ if (retVal.getDeleted() == null) {
+ try {
+ ValueSet valueSet = (ValueSet) theResource;
+ org.hl7.fhir.r4.model.ValueSet converted = VersionConvertor_30_40.convertValueSet(valueSet);
+ myHapiTerminologySvc.storeTermValueSetAndChildren(retVal, converted);
+ } catch (FHIRException fe) {
+ throw new InternalErrorException(fe);
+ }
+ } else {
+ myHapiTerminologySvc.deleteValueSetAndChildren(retVal);
+ }
+ }
+
+ return retVal;
+ }
+
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/ExpungeEverythingService.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/ExpungeEverythingService.java
index b704bb0668e..feaf1a820a9 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/ExpungeEverythingService.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/ExpungeEverythingService.java
@@ -74,6 +74,8 @@ public class ExpungeEverythingService {
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceLink.class));
counter.addAndGet(doExpungeEverythingQuery(txTemplate, SearchResult.class));
counter.addAndGet(doExpungeEverythingQuery(txTemplate, SearchInclude.class));
+ counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermValueSetCode.class));
+ counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermValueSet.class));
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermConceptParentChildLink.class));
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermConceptMapGroupElementTarget.class));
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermConceptMapGroupElement.class));
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoValueSetR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoValueSetR4.java
index c1c685ceb00..68e78e778db 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoValueSetR4.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoValueSetR4.java
@@ -20,34 +20,43 @@ package ca.uhn.fhir.jpa.dao.r4;
* #L%
*/
-import static org.apache.commons.lang3.StringUtils.isBlank;
-import static org.apache.commons.lang3.StringUtils.isNotBlank;
-
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.commons.codec.binary.StringUtils;
-import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
-import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
-import org.hl7.fhir.r4.model.*;
-import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
-import org.hl7.fhir.r4.model.ValueSet.*;
-import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
-import org.hl7.fhir.instance.model.api.IIdType;
-import org.hl7.fhir.instance.model.api.IPrimitiveType;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem.LookupCodeResult;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
+import ca.uhn.fhir.jpa.model.entity.ResourceTable;
+import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.jpa.util.LogicUtil;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.ElementUtil;
+import org.apache.commons.codec.binary.StringUtils;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.instance.model.api.IIdType;
+import org.hl7.fhir.instance.model.api.IPrimitiveType;
+import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
+import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
+import org.hl7.fhir.r4.model.*;
+import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
+import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
+import org.hl7.fhir.r4.model.ValueSet.ConceptSetFilterComponent;
+import org.hl7.fhir.r4.model.ValueSet.FilterOperator;
+import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
+import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import static org.apache.commons.lang3.StringUtils.isBlank;
+import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4 implements IFhirResourceDaoValueSet {
+ @Autowired
+ private IHapiTerminologySvc myHapiTerminologySvc;
+
@Autowired
@Qualifier("myJpaValidationSupportChainR4")
private IValidationSupport myValidationSupport;
@@ -296,4 +305,21 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4 imple
// nothing
}
+ @Override
+ protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
+ boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
+ ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
+
+ if (myDaoConfig.isPreExpandValueSetsExperimental()) {
+ if (retVal.getDeleted() == null) {
+ ValueSet valueSet = (ValueSet) theResource;
+ myHapiTerminologySvc.storeTermValueSetAndChildren(retVal, valueSet);
+ } else {
+ myHapiTerminologySvc.deleteValueSetAndChildren(retVal);
+ }
+ }
+
+ return retVal;
+ }
+
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystem.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystem.java
index fd23f3f4065..6d468b49ae6 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystem.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystem.java
@@ -21,13 +21,16 @@ package ca.uhn.fhir.jpa.entity;
*/
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
+import ca.uhn.fhir.util.ValidateUtil;
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;
//@formatter:off
@Table(name = "TRM_CODESYSTEM", uniqueConstraints = {
@@ -37,9 +40,11 @@ import static org.apache.commons.lang3.StringUtils.left;
//@formatter:on
public class TermCodeSystem implements Serializable {
private static final long serialVersionUID = 1L;
- public static final int CS_NAME_LENGTH = 200;
- @Column(name = "CODE_SYSTEM_URI", nullable = false)
+ private static final int MAX_NAME_LENGTH = 200;
+ static final int MAX_URL_LENGTH = 200;
+
+ @Column(name = "CODE_SYSTEM_URI", nullable = false, length = MAX_URL_LENGTH)
private String myCodeSystemUri;
@OneToOne()
@@ -55,7 +60,7 @@ public class TermCodeSystem implements Serializable {
private ResourceTable myResource;
@Column(name = "RES_ID", insertable = false, updatable = false)
private Long myResourcePid;
- @Column(name = "CS_NAME", nullable = true)
+ @Column(name = "CS_NAME", nullable = true, length = MAX_NAME_LENGTH)
private String myName;
public String getCodeSystemUri() {
@@ -66,16 +71,21 @@ public class TermCodeSystem implements Serializable {
return myName;
}
- public void setCodeSystemUri(String theCodeSystemUri) {
+ public TermCodeSystem setCodeSystemUri(@Nonnull String theCodeSystemUri) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theCodeSystemUri, "theCodeSystemUri must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCodeSystemUri, MAX_URL_LENGTH,
+ "URI exceeds maximum length (" + MAX_URL_LENGTH + "): " + length(theCodeSystemUri));
myCodeSystemUri = theCodeSystemUri;
+ return this;
}
public TermCodeSystemVersion getCurrentVersion() {
return myCurrentVersion;
}
- public void setCurrentVersion(TermCodeSystemVersion theCurrentVersion) {
+ public TermCodeSystem setCurrentVersion(TermCodeSystemVersion theCurrentVersion) {
myCurrentVersion = theCurrentVersion;
+ return this;
}
public Long getPid() {
@@ -86,12 +96,14 @@ public class TermCodeSystem implements Serializable {
return myResource;
}
- public void setName(String theName) {
- myName = left(theName, CS_NAME_LENGTH);
+ public TermCodeSystem setName(String theName) {
+ myName = left(theName, MAX_NAME_LENGTH);
+ return this;
}
- public void setResource(ResourceTable theResource) {
+ public TermCodeSystem setResource(ResourceTable theResource) {
myResource = theResource;
+ return this;
}
@Override
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java
index 2bd272cb6a5..969710901ea 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java
@@ -22,12 +22,15 @@ package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.util.CoverageIgnore;
+import ca.uhn.fhir.util.ValidateUtil;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
+import static org.apache.commons.lang3.StringUtils.length;
+
//@formatter:off
@Table(name = "TRM_CODESYSTEM_VER"
// Note, we used to have a constraint named IDX_CSV_RESOURCEPID_AND_VER (don't reuse this)
@@ -37,6 +40,8 @@ import java.util.Collection;
public class TermCodeSystemVersion implements Serializable {
private static final long serialVersionUID = 1L;
+ static final int MAX_VERSION_LENGTH = 200;
+
@OneToMany(fetch = FetchType.LAZY, mappedBy = "myCodeSystem")
private Collection myConcepts;
@@ -50,7 +55,7 @@ public class TermCodeSystemVersion implements Serializable {
@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", nullable = false, updatable = false, foreignKey = @ForeignKey(name = "FK_CODESYSVER_RES_ID"))
private ResourceTable myResource;
- @Column(name = "CS_VERSION_ID", nullable = true, updatable = false)
+ @Column(name = "CS_VERSION_ID", nullable = true, updatable = false, length = MAX_VERSION_LENGTH)
private String myCodeSystemVersionId;
/**
* This was added in HAPI FHIR 3.3.0 and is nullable just to avoid migration
@@ -104,16 +109,21 @@ public class TermCodeSystemVersion implements Serializable {
return myCodeSystem;
}
- public void setCodeSystem(TermCodeSystem theCodeSystem) {
+ public TermCodeSystemVersion setCodeSystem(TermCodeSystem theCodeSystem) {
myCodeSystem = theCodeSystem;
+ return this;
}
public String getCodeSystemVersionId() {
return myCodeSystemVersionId;
}
- public void setCodeSystemVersionId(String theCodeSystemVersionId) {
+ public TermCodeSystemVersion setCodeSystemVersionId(String theCodeSystemVersionId) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(
+ theCodeSystemVersionId, MAX_VERSION_LENGTH,
+ "Version ID exceeds maximum length (" + MAX_VERSION_LENGTH + "): " + length(theCodeSystemVersionId));
myCodeSystemVersionId = theCodeSystemVersionId;
+ return this;
}
public Collection getConcepts() {
@@ -131,8 +141,9 @@ public class TermCodeSystemVersion implements Serializable {
return myResource;
}
- public void setResource(ResourceTable theResource) {
+ public TermCodeSystemVersion setResource(ResourceTable theResource) {
myResource = theResource;
+ return this;
}
@Override
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java
index bfe8ee61f53..3a3158cc4bc 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java
@@ -1,25 +1,5 @@
package ca.uhn.fhir.jpa.entity;
-import ca.uhn.fhir.context.support.IContextValidationSupport;
-import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
-import ca.uhn.fhir.jpa.search.DeferConceptIndexingInterceptor;
-import ca.uhn.fhir.util.ValidateUtil;
-import org.apache.commons.lang3.Validate;
-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 org.hibernate.search.annotations.*;
-import org.hl7.fhir.r4.model.Coding;
-
-import javax.annotation.Nonnull;
-import javax.persistence.*;
-import javax.persistence.Index;
-import java.io.Serializable;
-import java.util.*;
-
-import static org.apache.commons.lang3.StringUtils.isNotBlank;
-
/*
* #%L
* HAPI FHIR JPA Server
@@ -40,6 +20,27 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* #L%
*/
+import ca.uhn.fhir.context.support.IContextValidationSupport;
+import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
+import ca.uhn.fhir.jpa.search.DeferConceptIndexingInterceptor;
+import ca.uhn.fhir.util.ValidateUtil;
+import org.apache.commons.lang3.Validate;
+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 org.hibernate.search.annotations.*;
+import org.hl7.fhir.r4.model.Coding;
+
+import javax.annotation.Nonnull;
+import javax.persistence.Index;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.*;
+
+import static org.apache.commons.lang3.StringUtils.left;
+import static org.apache.commons.lang3.StringUtils.length;
+
@Entity
@Indexed(interceptor = DeferConceptIndexingInterceptor.class)
@Table(name = "TRM_CONCEPT", uniqueConstraints = {
@@ -49,16 +50,17 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
@Index(name = "IDX_CONCEPT_UPDATED", columnList = "CONCEPT_UPDATED")
})
public class TermConcept implements Serializable {
- public static final int CODE_LENGTH = 500;
- protected static final int MAX_DESC_LENGTH = 400;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TermConcept.class);
private static final long serialVersionUID = 1L;
+ static final int MAX_CODE_LENGTH = 500;
+ static final int MAX_DESC_LENGTH = 400;
+
@OneToMany(fetch = FetchType.LAZY, mappedBy = "myParent", cascade = {})
private Collection myChildren;
- @Column(name = "CODE", length = CODE_LENGTH, nullable = false)
+ @Column(name = "CODE", nullable = false, length = MAX_CODE_LENGTH)
@Fields({@Field(name = "myCode", index = org.hibernate.search.annotations.Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "exactAnalyzer")),})
private String myCode;
@Temporal(TemporalType.TIMESTAMP)
@@ -70,7 +72,7 @@ public class TermConcept implements Serializable {
@Column(name = "CODESYSTEM_PID", insertable = false, updatable = false)
@Fields({@Field(name = "myCodeSystemVersionPid")})
private long myCodeSystemVersionPid;
- @Column(name = "DISPLAY", length = MAX_DESC_LENGTH, nullable = true)
+ @Column(name = "DISPLAY", nullable = true, length = MAX_DESC_LENGTH)
@Fields({
@Field(name = "myDisplay", index = org.hibernate.search.annotations.Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "standardAnalyzer")),
@Field(name = "myDisplayEdgeNGram", index = org.hibernate.search.annotations.Index.YES, store = Store.NO, analyze = Analyze.YES, analyzer = @Analyzer(definition = "autocompleteEdgeAnalyzer")),
@@ -187,20 +189,24 @@ public class TermConcept implements Serializable {
return myCode;
}
- public void setCode(String theCode) {
- ValidateUtil.isNotBlankOrThrowInvalidRequest(theCode, "Code must not be null or empty");
+ public TermConcept setCode(@Nonnull String theCode) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theCode, "theCode must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCode, MAX_CODE_LENGTH,
+ "Code exceeds maximum length (" + MAX_CODE_LENGTH + "): " + length(theCode));
myCode = theCode;
+ return this;
}
public TermCodeSystemVersion getCodeSystemVersion() {
return myCodeSystem;
}
- public void setCodeSystemVersion(TermCodeSystemVersion theCodeSystemVersion) {
+ public TermConcept setCodeSystemVersion(TermCodeSystemVersion theCodeSystemVersion) {
myCodeSystem = theCodeSystemVersion;
if (theCodeSystemVersion.getPid() != null) {
myCodeSystemVersionPid = theCodeSystemVersion.getPid();
}
+ return this;
}
public List getCodingProperties(String thePropertyName) {
@@ -231,10 +237,7 @@ public class TermConcept implements Serializable {
}
public TermConcept setDisplay(String theDisplay) {
- myDisplay = theDisplay;
- if (isNotBlank(theDisplay) && theDisplay.length() > MAX_DESC_LENGTH) {
- myDisplay = myDisplay.substring(0, MAX_DESC_LENGTH);
- }
+ myDisplay = left(theDisplay, MAX_DESC_LENGTH);
return this;
}
@@ -246,8 +249,9 @@ public class TermConcept implements Serializable {
return myIndexStatus;
}
- public void setIndexStatus(Long theIndexStatus) {
+ public TermConcept setIndexStatus(Long theIndexStatus) {
myIndexStatus = theIndexStatus;
+ return this;
}
public String getParentPidsAsString() {
@@ -272,8 +276,9 @@ public class TermConcept implements Serializable {
return mySequence;
}
- public void setSequence(Integer theSequence) {
+ public TermConcept setSequence(Integer theSequence) {
mySequence = theSequence;
+ return this;
}
public List getStringProperties(String thePropertyName) {
@@ -300,8 +305,9 @@ public class TermConcept implements Serializable {
return myUpdated;
}
- public void setUpdated(Date theUpdated) {
+ public TermConcept setUpdated(Date theUpdated) {
myUpdated = theUpdated;
+ return this;
}
@Override
@@ -355,8 +361,9 @@ public class TermConcept implements Serializable {
myParentPids = b.toString();
}
- public void setParentPids(String theParentPids) {
+ public TermConcept setParentPids(String theParentPids) {
myParentPids = theParentPids;
+ return this;
}
@Override
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptDesignation.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptDesignation.java
index 9741d4377b4..4aeea98ccae 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptDesignation.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptDesignation.java
@@ -20,16 +20,24 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
+import ca.uhn.fhir.util.ValidateUtil;
+
+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;
+
@Entity
@Table(name = "TRM_CONCEPT_DESIG", uniqueConstraints = {
}, indexes = {
})
public class TermConceptDesignation implements Serializable {
-
private static final long serialVersionUID = 1L;
+
+ private static final int MAX_LENGTH = 500;
+
@ManyToOne
@JoinColumn(name = "CONCEPT_PID", referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_CONCEPTDESIG_CONCEPT"))
private TermConcept myConcept;
@@ -38,15 +46,15 @@ public class TermConceptDesignation implements Serializable {
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_DESIG_PID")
@Column(name = "PID")
private Long myId;
- @Column(name = "LANG", length = 500, nullable = true)
+ @Column(name = "LANG", nullable = true, length = MAX_LENGTH)
private String myLanguage;
- @Column(name = "USE_SYSTEM", length = 500, nullable = true)
+ @Column(name = "USE_SYSTEM", nullable = true, length = MAX_LENGTH)
private String myUseSystem;
- @Column(name = "USE_CODE", length = 500, nullable = true)
+ @Column(name = "USE_CODE", nullable = true, length = MAX_LENGTH)
private String myUseCode;
- @Column(name = "USE_DISPLAY", length = 500, nullable = true)
+ @Column(name = "USE_DISPLAY", nullable = true, length = MAX_LENGTH)
private String myUseDisplay;
- @Column(name = "VAL", length = 500, nullable = false)
+ @Column(name = "VAL", nullable = false, length = MAX_LENGTH)
private String myValue;
/**
* TODO: Make this non-null
@@ -62,6 +70,8 @@ public class TermConceptDesignation implements Serializable {
}
public TermConceptDesignation setLanguage(String theLanguage) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theLanguage, MAX_LENGTH,
+ "Language exceeds maximum length (" + MAX_LENGTH + "): " + length(theLanguage));
myLanguage = theLanguage;
return this;
}
@@ -71,6 +81,8 @@ public class TermConceptDesignation implements Serializable {
}
public TermConceptDesignation setUseCode(String theUseCode) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theUseCode, MAX_LENGTH,
+ "Use code exceeds maximum length (" + MAX_LENGTH + "): " + length(theUseCode));
myUseCode = theUseCode;
return this;
}
@@ -80,7 +92,7 @@ public class TermConceptDesignation implements Serializable {
}
public TermConceptDesignation setUseDisplay(String theUseDisplay) {
- myUseDisplay = theUseDisplay;
+ myUseDisplay = left(theUseDisplay, MAX_LENGTH);
return this;
}
@@ -89,6 +101,9 @@ public class TermConceptDesignation implements Serializable {
}
public TermConceptDesignation setUseSystem(String theUseSystem) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theUseSystem, MAX_LENGTH,
+ "Use system exceeds maximum length (" + MAX_LENGTH + "): " + length(theUseSystem));
+
myUseSystem = theUseSystem;
return this;
}
@@ -97,7 +112,10 @@ public class TermConceptDesignation implements Serializable {
return myValue;
}
- public TermConceptDesignation setValue(String theValue) {
+ public TermConceptDesignation 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;
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMap.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMap.java
index fd67f26716c..24e1dda2797 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMap.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMap.java
@@ -21,19 +21,27 @@ package ca.uhn.fhir.jpa.entity;
*/
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
+import ca.uhn.fhir.util.ValidateUtil;
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 java.util.ArrayList;
import java.util.List;
+import static org.apache.commons.lang3.StringUtils.length;
+
@Entity
@Table(name = "TRM_CONCEPT_MAP", uniqueConstraints = {
@UniqueConstraint(name = "IDX_CONCEPT_MAP_URL", columnNames = {"URL"})
})
public class TermConceptMap implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ static final int MAX_URL_LENGTH = 200;
+
@Id()
@SequenceGenerator(name = "SEQ_CONCEPT_MAP_PID", sequenceName = "SEQ_CONCEPT_MAP_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_MAP_PID")
@@ -47,13 +55,13 @@ public class TermConceptMap implements Serializable {
@Column(name = "RES_ID", insertable = false, updatable = false)
private Long myResourcePid;
- @Column(name = "SOURCE_URL", nullable = true, length = 200)
+ @Column(name = "SOURCE_URL", nullable = true, length = TermValueSet.MAX_URL_LENGTH)
private String mySource;
- @Column(name = "TARGET_URL", nullable = true, length = 200)
+ @Column(name = "TARGET_URL", nullable = true, length = TermValueSet.MAX_URL_LENGTH)
private String myTarget;
- @Column(name = "URL", length = 200, nullable = false)
+ @Column(name = "URL", nullable = false, length = MAX_URL_LENGTH)
private String myUrl;
@OneToMany(mappedBy = "myConceptMap")
@@ -75,47 +83,58 @@ public class TermConceptMap implements Serializable {
return myResource;
}
- public void setResource(ResourceTable resource) {
- myResource = resource;
+ public TermConceptMap setResource(ResourceTable theResource) {
+ myResource = theResource;
+ return this;
}
public Long getResourcePid() {
return myResourcePid;
}
- public void setResourcePid(Long resourcePid) {
- myResourcePid = resourcePid;
+ public TermConceptMap setResourcePid(Long theResourcePid) {
+ myResourcePid = theResourcePid;
+ return this;
}
public String getSource() {
return mySource;
}
- public void setSource(String source) {
- mySource = source;
+ public TermConceptMap setSource(String theSource) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theSource, TermValueSet.MAX_URL_LENGTH,
+ "Source exceeds maximum length (" + TermValueSet.MAX_URL_LENGTH + "): " + length(theSource));
+ mySource = theSource;
+ return this;
}
public String getTarget() {
return myTarget;
}
- public void setTarget(String target) {
- myTarget = target;
+ public TermConceptMap setTarget(String theTarget) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theTarget, TermValueSet.MAX_URL_LENGTH,
+ "Target exceeds maximum length (" + TermValueSet.MAX_URL_LENGTH + "): " + length(theTarget));
+ myTarget = theTarget;
+ return this;
}
public String getUrl() {
return myUrl;
}
- public void setUrl(String theUrl) {
+ public TermConceptMap setUrl(@Nonnull String theUrl) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theUrl, "theUrl must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theUrl, MAX_URL_LENGTH,
+ "URL exceeds maximum length (" + MAX_URL_LENGTH + "): " + length(theUrl));
myUrl = theUrl;
+ return this;
}
@Override
public String toString() {
- return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("myId", myId)
- .append("myResource", myResource.toString())
.append(myResource != null ? ("myResource=" + myResource.toString()) : ("myResource=(null)"))
.append("myResourcePid", myResourcePid)
.append("mySource", mySource)
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroup.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroup.java
index 72d23359a0b..d11ae915f46 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroup.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroup.java
@@ -20,17 +20,23 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
+import ca.uhn.fhir.util.ValidateUtil;
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 java.util.ArrayList;
import java.util.List;
+import static org.apache.commons.lang3.StringUtils.length;
+
@Entity
@Table(name = "TRM_CONCEPT_MAP_GROUP")
public class TermConceptMapGroup implements Serializable {
+ private static final long serialVersionUID = 1L;
+
@Id()
@SequenceGenerator(name = "SEQ_CONCEPT_MAP_GROUP_PID", sequenceName = "SEQ_CONCEPT_MAP_GROUP_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_MAP_GROUP_PID")
@@ -41,36 +47,37 @@ public class TermConceptMapGroup implements Serializable {
@JoinColumn(name = "CONCEPT_MAP_PID", nullable = false, referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_TCMGROUP_CONCEPTMAP"))
private TermConceptMap myConceptMap;
- @Column(name = "SOURCE_URL", nullable = false, length = 200)
+ @Column(name = "SOURCE_URL", nullable = false, length = TermCodeSystem.MAX_URL_LENGTH)
private String mySource;
- @Column(name = "SOURCE_VERSION", length = 100)
+ @Column(name = "SOURCE_VERSION", nullable = true, length = TermCodeSystemVersion.MAX_VERSION_LENGTH)
private String mySourceVersion;
- @Column(name = "TARGET_URL", nullable = false, length = 200)
+ @Column(name = "TARGET_URL", nullable = false, length = TermCodeSystem.MAX_URL_LENGTH)
private String myTarget;
- @Column(name = "TARGET_VERSION", length = 100)
+ @Column(name = "TARGET_VERSION", nullable = true, length = TermCodeSystemVersion.MAX_VERSION_LENGTH)
private String myTargetVersion;
@OneToMany(mappedBy = "myConceptMapGroup")
private List myConceptMapGroupElements;
- @Column(name= "CONCEPT_MAP_URL", length = 200, nullable = true)
+ @Column(name= "CONCEPT_MAP_URL", nullable = true, length = TermConceptMap.MAX_URL_LENGTH)
private String myConceptMapUrl;
- @Column(name= "SOURCE_VS", length = 200, nullable = true)
+ @Column(name= "SOURCE_VS", nullable = true, length = TermValueSet.MAX_URL_LENGTH)
private String mySourceValueSet;
- @Column(name= "TARGET_VS", length = 200, nullable = true)
+ @Column(name= "TARGET_VS", nullable = true, length = TermValueSet.MAX_URL_LENGTH)
private String myTargetValueSet;
public TermConceptMap getConceptMap() {
return myConceptMap;
}
- public void setConceptMap(TermConceptMap theTermConceptMap) {
+ public TermConceptMapGroup setConceptMap(TermConceptMap theTermConceptMap) {
myConceptMap = theTermConceptMap;
+ return this;
}
public List getConceptMapGroupElements() {
@@ -96,8 +103,12 @@ public class TermConceptMapGroup implements Serializable {
return mySource;
}
- public void setSource(String theSource) {
+ public TermConceptMapGroup setSource(@Nonnull String theSource) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theSource, "theSource must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theSource, TermCodeSystem.MAX_URL_LENGTH,
+ "Source exceeds maximum length (" + TermCodeSystem.MAX_URL_LENGTH + "): " + length(theSource));
this.mySource = theSource;
+ return this;
}
public String getSourceValueSet() {
@@ -111,16 +122,23 @@ public class TermConceptMapGroup implements Serializable {
return mySourceVersion;
}
- public void setSourceVersion(String theSourceVersion) {
+ public TermConceptMapGroup setSourceVersion(String theSourceVersion) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theSourceVersion, TermCodeSystemVersion.MAX_VERSION_LENGTH,
+ "Source version ID exceeds maximum length (" + TermCodeSystemVersion.MAX_VERSION_LENGTH + "): " + length(theSourceVersion));
mySourceVersion = theSourceVersion;
+ return this;
}
public String getTarget() {
return myTarget;
}
- public void setTarget(String theTarget) {
+ public TermConceptMapGroup setTarget(@Nonnull String theTarget) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theTarget, "theTarget must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theTarget, TermCodeSystem.MAX_URL_LENGTH,
+ "Target exceeds maximum length (" + TermCodeSystem.MAX_URL_LENGTH + "): " + length(theTarget));
this.myTarget = theTarget;
+ return this;
}
public String getTargetValueSet() {
@@ -134,13 +152,16 @@ public class TermConceptMapGroup implements Serializable {
return myTargetVersion;
}
- public void setTargetVersion(String theTargetVersion) {
+ public TermConceptMapGroup setTargetVersion(String theTargetVersion) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theTargetVersion, TermCodeSystemVersion.MAX_VERSION_LENGTH,
+ "Target version ID exceeds maximum length (" + TermCodeSystemVersion.MAX_VERSION_LENGTH + "): " + length(theTargetVersion));
myTargetVersion = theTargetVersion;
+ return this;
}
@Override
public String toString() {
- return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("myId", myId)
.append(myConceptMap != null ? ("myConceptMap - id=" + myConceptMap.getId()) : ("myConceptMap=(null)"))
.append("mySource", mySource)
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElement.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElement.java
index d36689129ae..f182b16165e 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElement.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElement.java
@@ -20,22 +20,28 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
-import org.apache.commons.lang3.Validate;
+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 java.util.ArrayList;
import java.util.List;
+import static org.apache.commons.lang3.StringUtils.left;
+import static org.apache.commons.lang3.StringUtils.length;
+
@Entity
@Table(name = "TRM_CONCEPT_MAP_GRP_ELEMENT", indexes = {
@Index(name = "IDX_CNCPT_MAP_GRP_CD", columnList = "SOURCE_CODE")
})
public class TermConceptMapGroupElement implements Serializable {
+ private static final long serialVersionUID = 1L;
+
@Id()
@SequenceGenerator(name = "SEQ_CONCEPT_MAP_GRP_ELM_PID", sequenceName = "SEQ_CONCEPT_MAP_GRP_ELM_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_MAP_GRP_ELM_PID")
@@ -46,7 +52,7 @@ public class TermConceptMapGroupElement implements Serializable {
@JoinColumn(name = "CONCEPT_MAP_GROUP_PID", nullable = false, referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_TCMGELEMENT_GROUP"))
private TermConceptMapGroup myConceptMapGroup;
- @Column(name = "SOURCE_CODE", nullable = false, length = TermConcept.CODE_LENGTH)
+ @Column(name = "SOURCE_CODE", nullable = false, length = TermConcept.MAX_CODE_LENGTH)
private String myCode;
@Column(name = "SOURCE_DISPLAY", length = TermConcept.MAX_DESC_LENGTH)
@@ -55,33 +61,37 @@ public class TermConceptMapGroupElement implements Serializable {
@OneToMany(mappedBy = "myConceptMapGroupElement")
private List myConceptMapGroupElementTargets;
- @Column(name = "CONCEPT_MAP_URL", length = 200)
+ @Column(name = "CONCEPT_MAP_URL", nullable = true, length = TermConceptMap.MAX_URL_LENGTH)
private String myConceptMapUrl;
- @Column(name = "SYSTEM_URL", length = 200)
+ @Column(name = "SYSTEM_URL", nullable = true, length = TermCodeSystem.MAX_URL_LENGTH)
private String mySystem;
- @Column(name = "SYSTEM_VERSION", length = 200)
+ @Column(name = "SYSTEM_VERSION", nullable = true, length = TermCodeSystemVersion.MAX_VERSION_LENGTH)
private String mySystemVersion;
- @Column(name = "VALUESET_URL", length = 200)
+ @Column(name = "VALUESET_URL", nullable = true, length = TermValueSet.MAX_URL_LENGTH)
private String myValueSet;
public String getCode() {
return myCode;
}
- public void setCode(String theCode) {
- Validate.notBlank(theCode, "theCode must not be blank");
+ public TermConceptMapGroupElement setCode(@Nonnull String theCode) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theCode, "theCode must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCode, TermConcept.MAX_CODE_LENGTH,
+ "Code exceeds maximum length (" + TermConcept.MAX_CODE_LENGTH + "): " + length(theCode));
myCode = theCode;
+ return this;
}
public TermConceptMapGroup getConceptMapGroup() {
return myConceptMapGroup;
}
- public void setConceptMapGroup(TermConceptMapGroup theTermConceptMapGroup) {
+ public TermConceptMapGroupElement setConceptMapGroup(TermConceptMapGroup theTermConceptMapGroup) {
myConceptMapGroup = theTermConceptMapGroup;
+ return this;
}
public List getConceptMapGroupElementTargets() {
@@ -103,8 +113,9 @@ public class TermConceptMapGroupElement implements Serializable {
return myDisplay;
}
- public void setDisplay(String theDisplay) {
- myDisplay = theDisplay;
+ public TermConceptMapGroupElement setDisplay(String theDisplay) {
+ myDisplay = left(theDisplay, TermConcept.MAX_DESC_LENGTH);
+ return this;
}
public Long getId() {
@@ -158,7 +169,7 @@ public class TermConceptMapGroupElement implements Serializable {
@Override
public String toString() {
- return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("myId", myId)
.append(myConceptMapGroup != null ? ("myConceptMapGroup - id=" + myConceptMapGroup.getId()) : ("myConceptMapGroup=(null)"))
.append("myCode", myCode)
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElementTarget.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElementTarget.java
index 754161ca0a9..d463f7dddfb 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElementTarget.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElementTarget.java
@@ -20,20 +20,28 @@ package ca.uhn.fhir.jpa.entity;
* #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 org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
+import javax.annotation.Nonnull;
import javax.persistence.*;
import java.io.Serializable;
+import static org.apache.commons.lang3.StringUtils.length;
+
@Entity
@Table(name = "TRM_CONCEPT_MAP_GRP_ELM_TGT", indexes = {
@Index(name = "IDX_CNCPT_MP_GRP_ELM_TGT_CD", columnList = "TARGET_CODE")
})
public class TermConceptMapGroupElementTarget implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ static final int MAX_EQUIVALENCE_LENGTH = 50;
+
@Id()
@SequenceGenerator(name = "SEQ_CNCPT_MAP_GRP_ELM_TGT_PID", sequenceName = "SEQ_CNCPT_MAP_GRP_ELM_TGT_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CNCPT_MAP_GRP_ELM_TGT_PID")
@@ -44,31 +52,38 @@ public class TermConceptMapGroupElementTarget implements Serializable {
@JoinColumn(name = "CONCEPT_MAP_GRP_ELM_PID", nullable = false, referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_TCMGETARGET_ELEMENT"))
private TermConceptMapGroupElement myConceptMapGroupElement;
- @Column(name = "TARGET_CODE", nullable = false, length = TermConcept.CODE_LENGTH)
+ @Column(name = "TARGET_CODE", nullable = false, length = TermConcept.MAX_CODE_LENGTH)
private String myCode;
- @Column(name = "TARGET_DISPLAY", length = TermConcept.MAX_DESC_LENGTH)
+ @Column(name = "TARGET_DISPLAY", nullable = true, length = TermConcept.MAX_DESC_LENGTH)
private String myDisplay;
@Enumerated(EnumType.STRING)
- @Column(name = "TARGET_EQUIVALENCE", length = 50)
+ @Column(name = "TARGET_EQUIVALENCE", nullable = true, length = MAX_EQUIVALENCE_LENGTH)
private ConceptMapEquivalence myEquivalence;
- @Column(name = "CONCEPT_MAP_URL", length = 200)
+ @Column(name = "CONCEPT_MAP_URL", nullable = true, length = TermConceptMap.MAX_URL_LENGTH)
private String myConceptMapUrl;
- @Column(name = "SYSTEM_URL", length = 200)
+
+ @Column(name = "SYSTEM_URL", nullable = true, length = TermCodeSystem.MAX_URL_LENGTH)
private String mySystem;
- @Column(name = "SYSTEM_VERSION", length = 200)
+
+ @Column(name = "SYSTEM_VERSION", nullable = true, length = TermCodeSystemVersion.MAX_VERSION_LENGTH)
private String mySystemVersion;
- @Column(name = "VALUESET_URL", length = 200)
+
+ @Column(name = "VALUESET_URL", nullable = true, length = TermValueSet.MAX_URL_LENGTH)
private String myValueSet;
public String getCode() {
return myCode;
}
- public void setCode(String theCode) {
+ public TermConceptMapGroupElementTarget setCode(@Nonnull String theCode) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theCode, "theCode must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCode, TermConcept.MAX_CODE_LENGTH,
+ "Code exceeds maximum length (" + TermConcept.MAX_CODE_LENGTH + "): " + length(theCode));
myCode = theCode;
+ return this;
}
public TermConceptMapGroupElement getConceptMapGroupElement() {
@@ -90,16 +105,18 @@ public class TermConceptMapGroupElementTarget implements Serializable {
return myDisplay;
}
- public void setDisplay(String theDisplay) {
+ public TermConceptMapGroupElementTarget setDisplay(String theDisplay) {
myDisplay = theDisplay;
+ return this;
}
public ConceptMapEquivalence getEquivalence() {
return myEquivalence;
}
- public void setEquivalence(ConceptMapEquivalence theEquivalence) {
+ public TermConceptMapGroupElementTarget setEquivalence(ConceptMapEquivalence theEquivalence) {
myEquivalence = theEquivalence;
+ return this;
}
public Long getId() {
@@ -155,7 +172,7 @@ public class TermConceptMapGroupElementTarget implements Serializable {
@Override
public String toString() {
- return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("myId", myId)
.append(myConceptMapGroupElement != null ? ("myConceptMapGroupElement - id=" + myConceptMapGroupElement.getId()) : ("myConceptMapGroupElement=(null)"))
.append("myCode", myCode)
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptParentChildLink.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptParentChildLink.java
index dfb380d605e..c7d38eed131 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptParentChildLink.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptParentChildLink.java
@@ -20,21 +20,9 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
+import javax.persistence.*;
import java.io.Serializable;
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
-import javax.persistence.ForeignKey;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToOne;
-import javax.persistence.SequenceGenerator;
-import javax.persistence.Table;
-
@Entity
@Table(name = "TRM_CONCEPT_PC_LINK")
public class TermConceptParentChildLink implements Serializable {
@@ -136,20 +124,24 @@ public class TermConceptParentChildLink implements Serializable {
return result;
}
- public void setChild(TermConcept theChild) {
+ public TermConceptParentChildLink setChild(TermConcept theChild) {
myChild = theChild;
+ return this;
}
- public void setCodeSystem(TermCodeSystemVersion theCodeSystem) {
+ public TermConceptParentChildLink setCodeSystem(TermCodeSystemVersion theCodeSystem) {
myCodeSystem = theCodeSystem;
+ return this;
}
- public void setParent(TermConcept theParent) {
+ public TermConceptParentChildLink setParent(TermConcept theParent) {
myParent = theParent;
+ return this;
}
- public void setRelationshipType(RelationshipTypeEnum theRelationshipType) {
+ public TermConceptParentChildLink setRelationshipType(RelationshipTypeEnum theRelationshipType) {
myRelationshipType = theRelationshipType;
+ return this;
}
public enum RelationshipTypeEnum {
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java
index 517dc1b70f1..144fc1ae632 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java
@@ -20,21 +20,29 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
+import ca.uhn.fhir.util.ValidateUtil;
+import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.validator.constraints.NotBlank;
+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;
+
@Entity
@Table(name = "TRM_CONCEPT_PROPERTY", uniqueConstraints = {
}, indexes = {
})
public class TermConceptProperty implements Serializable {
-
- static final int MAX_PROPTYPE_ENUM_LENGTH = 6;
private static final long serialVersionUID = 1L;
+
+ private static final int MAX_LENGTH = 500;
+ static final int MAX_PROPTYPE_ENUM_LENGTH = 6;
+
@ManyToOne
@JoinColumn(name = "CONCEPT_PID", referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_CONCEPTPROP_CONCEPT"))
private TermConcept myConcept;
@@ -51,22 +59,22 @@ public class TermConceptProperty implements Serializable {
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_PROP_PID")
@Column(name = "PID")
private Long myId;
- @Column(name = "PROP_KEY", length = 500, nullable = false)
+ @Column(name = "PROP_KEY", nullable = false, length = MAX_LENGTH)
@NotBlank
private String myKey;
- @Column(name = "PROP_VAL", length = 500, nullable = true)
+ @Column(name = "PROP_VAL", nullable = true, length = MAX_LENGTH)
private String myValue;
- @Column(name = "PROP_TYPE", length = MAX_PROPTYPE_ENUM_LENGTH, nullable = false)
+ @Column(name = "PROP_TYPE", nullable = false, length = MAX_PROPTYPE_ENUM_LENGTH)
private TermConceptPropertyTypeEnum myType;
/**
* Relevant only for properties of type {@link TermConceptPropertyTypeEnum#CODING}
*/
- @Column(name = "PROP_CODESYSTEM", length = 500, nullable = true)
+ @Column(name = "PROP_CODESYSTEM", length = MAX_LENGTH, nullable = true)
private String myCodeSystem;
/**
* Relevant only for properties of type {@link TermConceptPropertyTypeEnum#CODING}
*/
- @Column(name = "PROP_DISPLAY", length = 500, nullable = true)
+ @Column(name = "PROP_DISPLAY", length = MAX_LENGTH, nullable = true)
private String myDisplay;
/**
@@ -80,6 +88,8 @@ public class TermConceptProperty implements Serializable {
* Relevant only for properties of type {@link TermConceptPropertyTypeEnum#CODING}
*/
public TermConceptProperty setCodeSystem(String theCodeSystem) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCodeSystem, MAX_LENGTH,
+ "Property code system exceeds maximum length (" + MAX_LENGTH + "): " + length(theCodeSystem));
myCodeSystem = theCodeSystem;
return this;
}
@@ -95,7 +105,7 @@ public class TermConceptProperty implements Serializable {
* Relevant only for properties of type {@link TermConceptPropertyTypeEnum#CODING}
*/
public TermConceptProperty setDisplay(String theDisplay) {
- myDisplay = theDisplay;
+ myDisplay = left(theDisplay, MAX_LENGTH);
return this;
}
@@ -103,15 +113,20 @@ public class TermConceptProperty implements Serializable {
return myKey;
}
- public void setKey(String theKey) {
+ public TermConceptProperty setKey(@Nonnull String theKey) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theKey, "theKey must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theKey, MAX_LENGTH,
+ "Code exceeds maximum length (" + MAX_LENGTH + "): " + length(theKey));
myKey = theKey;
+ return this;
}
public TermConceptPropertyTypeEnum getType() {
return myType;
}
- public TermConceptProperty setType(TermConceptPropertyTypeEnum theType) {
+ public TermConceptProperty setType(@Nonnull TermConceptPropertyTypeEnum theType) {
+ Validate.notNull(theType);
myType = theType;
return this;
}
@@ -128,8 +143,9 @@ public class TermConceptProperty implements Serializable {
* This will contain the value for a {@link TermConceptPropertyTypeEnum#STRING string}
* property, and the code for a {@link TermConceptPropertyTypeEnum#CODING coding} property.
*/
- public void setValue(String theValue) {
- myValue = theValue;
+ public TermConceptProperty setValue(String theValue) {
+ myValue = left(theValue, MAX_LENGTH);
+ return this;
}
public TermConceptProperty setCodeSystemVersion(TermCodeSystemVersion theCodeSystemVersion) {
@@ -137,8 +153,9 @@ public class TermConceptProperty implements Serializable {
return this;
}
- public void setConcept(TermConcept theConcept) {
+ public TermConceptProperty setConcept(TermConcept theConcept) {
myConcept = theConcept;
+ return this;
}
@Override
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSet.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSet.java
new file mode 100644
index 00000000000..d53d6d07191
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSet.java
@@ -0,0 +1,144 @@
+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.jpa.model.entity.ResourceTable;
+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 java.util.ArrayList;
+import java.util.List;
+
+import static org.apache.commons.lang3.StringUtils.left;
+import static org.apache.commons.lang3.StringUtils.length;
+
+@Table(name = "TRM_VALUESET", uniqueConstraints = {
+ @UniqueConstraint(name = "IDX_VALUESET_URL", columnNames = {"URL"})
+})
+@Entity()
+public class TermValueSet implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private static final int MAX_NAME_LENGTH = 200;
+ static final int MAX_URL_LENGTH = 200;
+
+ @Id()
+ @SequenceGenerator(name = "SEQ_VALUESET_PID", sequenceName = "SEQ_VALUESET_PID")
+ @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_VALUESET_PID")
+ @Column(name = "PID")
+ private Long myId;
+
+ @Column(name = "URL", nullable = false, length = MAX_URL_LENGTH)
+ private String myUrl;
+
+ @OneToOne()
+ @JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", nullable = false, updatable = false, foreignKey = @ForeignKey(name = "FK_TRMVALUESET_RES"))
+ private ResourceTable myResource;
+
+ @Column(name = "RES_ID", insertable = false, updatable = false)
+ private Long myResourcePid;
+
+ @Column(name = "NAME", nullable = true, length = MAX_NAME_LENGTH)
+ private String myName;
+
+ @OneToMany(mappedBy = "myValueSet")
+ private List myCodes;
+
+ public Long getId() {
+ return myId;
+ }
+
+ public String getUrl() {
+ return myUrl;
+ }
+
+ public TermValueSet setUrl(@Nonnull String theUrl) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theUrl, "theUrl must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theUrl, MAX_URL_LENGTH,
+ "URL exceeds maximum length (" + MAX_URL_LENGTH + "): " + length(theUrl));
+ myUrl = theUrl;
+ return this;
+ }
+
+ public ResourceTable getResource() {
+ return myResource;
+ }
+
+ public TermValueSet setResource(ResourceTable theResource) {
+ myResource = theResource;
+ return this;
+ }
+
+ public String getName() {
+ return myName;
+ }
+
+ public TermValueSet setName(String theName) {
+ myName = left(theName, MAX_NAME_LENGTH);
+ return this;
+ }
+
+ public List getCodes() {
+ if (myCodes == null) {
+ myCodes = new ArrayList<>();
+ }
+
+ return myCodes;
+ }
+
+ @Override
+ public boolean equals(Object theO) {
+ if (this == theO) return true;
+
+ if (!(theO instanceof TermValueSet)) return false;
+
+ TermValueSet that = (TermValueSet) theO;
+
+ return new EqualsBuilder()
+ .append(getUrl(), that.getUrl())
+ .isEquals();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder(17, 37)
+ .append(getUrl())
+ .toHashCode();
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
+ .append("myId", myId)
+ .append("myUrl", myUrl)
+ .append(myResource != null ? ("myResource=" + myResource.toString()) : ("myResource=(null)"))
+ .append("myResourcePid", myResourcePid)
+ .append("myName", myName)
+ .append(myCodes != null ? ("myCodes - size=" + myCodes.size()) : ("myCodes=(null)"))
+ .toString();
+ }
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetCode.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetCode.java
new file mode 100644
index 00000000000..88fc16f5b1f
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetCode.java
@@ -0,0 +1,166 @@
+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_CODE", indexes = {
+ @Index(name = "IDX_VALUESET_CODE_CS_CD", columnList = "SYSTEM, CODE")
+})
+@Entity()
+public class TermValueSetCode implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @Id()
+ @SequenceGenerator(name = "SEQ_VALUESET_CODE_PID", sequenceName = "SEQ_VALUESET_CODE_PID")
+ @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_VALUESET_CODE_PID")
+ @Column(name = "PID")
+ private Long myId;
+
+ @ManyToOne()
+ @JoinColumn(name = "VALUESET_PID", referencedColumnName = "PID", nullable = false, foreignKey = @ForeignKey(name = "FK_TRM_VALUESET_PID"))
+ private TermValueSet myValueSet;
+
+ @Transient
+ private String myValueSetUrl;
+
+ @Transient
+ private String myValueSetName;
+
+ @Column(name = "SYSTEM", nullable = false, length = TermCodeSystem.MAX_URL_LENGTH)
+ private String mySystem;
+
+ @Column(name = "CODE", nullable = false, length = TermConcept.MAX_CODE_LENGTH)
+ private String myCode;
+
+ @Column(name = "DISPLAY", nullable = true, length = TermConcept.MAX_DESC_LENGTH)
+ private String myDisplay;
+
+ public Long getId() {
+ return myId;
+ }
+
+ public TermValueSet getValueSet() {
+ return myValueSet;
+ }
+
+ public TermValueSetCode setValueSet(TermValueSet theValueSet) {
+ myValueSet = theValueSet;
+ return this;
+ }
+
+ public String getValueSetUrl() {
+ if (myValueSetUrl == null) {
+ myValueSetUrl = getValueSet().getUrl();
+ }
+
+ return myValueSetUrl;
+ }
+
+ public String getValueSetName() {
+ if (myValueSetName == null) {
+ myValueSetName = getValueSet().getName();
+ }
+
+ return myValueSetName;
+ }
+
+ public String getSystem() {
+ return mySystem;
+ }
+
+ public TermValueSetCode setSystem(@Nonnull String theSystem) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theSystem, "theSystem must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theSystem, TermCodeSystem.MAX_URL_LENGTH,
+ "System exceeds maximum length (" + TermCodeSystem.MAX_URL_LENGTH + "): " + length(theSystem));
+ mySystem = theSystem;
+ return this;
+ }
+
+ public String getCode() {
+ return myCode;
+ }
+
+ public TermValueSetCode setCode(@Nonnull String theCode) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theCode, "theCode must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCode, TermConcept.MAX_CODE_LENGTH,
+ "Code exceeds maximum length (" + TermConcept.MAX_CODE_LENGTH + "): " + length(theCode));
+ myCode = theCode;
+ return this;
+ }
+
+ public String getDisplay() {
+ return myDisplay;
+ }
+
+ public TermValueSetCode setDisplay(String theDisplay) {
+ myDisplay = left(theDisplay, TermConcept.MAX_DESC_LENGTH);
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object theO) {
+ if (this == theO) return true;
+
+ if (!(theO instanceof TermValueSetCode)) return false;
+
+ TermValueSetCode that = (TermValueSetCode) theO;
+
+ return new EqualsBuilder()
+ .append(getValueSetUrl(), that.getValueSetUrl())
+ .append(getSystem(), that.getSystem())
+ .append(getCode(), that.getCode())
+ .isEquals();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder(17, 37)
+ .append(getValueSetUrl())
+ .append(getSystem())
+ .append(getCode())
+ .toHashCode();
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
+ .append("myId", myId)
+ .append(myValueSet != null ? ("myValueSet - id=" + myValueSet.getId()) : ("myValueSet=(null)"))
+ .append("myValueSetUrl", this.getValueSetUrl())
+ .append("myValueSetName", this.getValueSetName())
+ .append("mySystem", mySystem)
+ .append("myCode", myCode)
+ .append("myDisplay", myDisplay)
+ .toString();
+ }
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java
index ba55a3712e9..165f1918d60 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java
@@ -119,6 +119,10 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
@Autowired
protected ITermConceptDesignationDao myConceptDesignationDao;
@Autowired
+ protected ITermValueSetDao myValueSetDao;
+ @Autowired
+ protected ITermValueSetCodeDao myValueSetCodeDao;
+ @Autowired
protected FhirContext myContext;
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
protected EntityManager myEntityManager;
@@ -388,6 +392,31 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
deleteConceptMap(theResourceTable);
}
+ public void deleteValueSet(ResourceTable theResourceTable) {
+ // Get existing entity so it can be deleted.
+ Optional optionalExistingTermValueSetById = myValueSetDao.findByResourcePid(theResourceTable.getId());
+
+ if (optionalExistingTermValueSetById.isPresent()) {
+ TermValueSet existingTermValueSet = optionalExistingTermValueSetById.get();
+
+ ourLog.info("Deleting existing TermValueSet {} and its children...", existingTermValueSet.getId());
+ myValueSetCodeDao.deleteTermValueSetCodesByValueSetId(existingTermValueSet.getId());
+ myValueSetDao.deleteTermValueSetById(existingTermValueSet.getId());
+ ourLog.info("Done deleting existing TermValueSet {} and its children.", existingTermValueSet.getId());
+
+ ourLog.info("Flushing...");
+ myValueSetCodeDao.flush();
+ myValueSetDao.flush();
+ ourLog.info("Done flushing.");
+ }
+ }
+
+ @Override
+ @Transactional
+ public void deleteValueSetAndChildren(ResourceTable theResourceTable) {
+ deleteValueSet(theResourceTable);
+ }
+
private void doDelete(String theDescriptor, Supplier> theLoader, Supplier theCounter, JpaRepository theDao) {
int count;
ourLog.info(" * Deleting {}", theDescriptor);
@@ -690,7 +719,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
private void expandWithoutHibernateSearch(ValueSet.ValueSetExpansionComponent theExpansionComponent, Set theAddedCodes, ValueSet.ConceptSetComponent theInclude, String theSystem, boolean theAdd, AtomicInteger theCodeCounter) {
ourLog.trace("Hibernate search is not enabled");
- Validate.isTrue(theExpansionComponent.getParameter().isEmpty(), "Can not exapnd ValueSet with parameters - Hibernate Search is not enabled on this server.");
+ Validate.isTrue(theExpansionComponent.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(isNotBlank(theSystem), "Can not expand ValueSet without explicit system - Hibernate Search is not enabled on this server.");
@@ -1144,7 +1173,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
myCodeSystemDao.save(codeSystem);
} else {
if (!ObjectUtil.equals(codeSystem.getResource().getId(), theCodeSystemVersion.getResource().getId())) {
- String msg = myContext.getLocalizer().getMessage(BaseHapiTerminologySvcImpl.class, "cannotCreateDuplicateCodeSystemUri", theSystemUri,
+ String msg = myContext.getLocalizer().getMessage(BaseHapiTerminologySvcImpl.class, "cannotCreateDuplicateCodeSystemUrl", theSystemUri,
codeSystem.getResource().getIdDt().toUnqualifiedVersionless().getValue());
throw new UnprocessableEntityException(msg);
}
@@ -1310,7 +1339,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
myConceptMapGroupElementTargetDao.save(termConceptMapGroupElementTarget);
if (codesSaved++ % 250 == 0) {
- ourLog.info("Have saved {} codes in conceptmap", codesSaved);
+ ourLog.info("Have saved {} codes in ConceptMap", codesSaved);
myConceptMapGroupElementTargetDao.flush();
}
}
@@ -1334,6 +1363,69 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
ourLog.info("Done storing TermConceptMap.");
}
+ @Override
+ @Transactional
+ public void storeTermValueSetAndChildren(ResourceTable theResourceTable, ValueSet theValueSet) {
+ ourLog.info("Storing TermValueSet {}", theValueSet.getIdElement().getValue());
+
+ ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied");
+ ValidateUtil.isNotBlankOrThrowUnprocessableEntity(theValueSet.getUrl(), "ValueSet has no value for ValueSet.url");
+
+ TermValueSet termValueSet = new TermValueSet();
+ termValueSet.setResource(theResourceTable);
+ termValueSet.setUrl(theValueSet.getUrl());
+ termValueSet.setName(theValueSet.hasName() ? theValueSet.getName() : null);
+
+ // We delete old versions; we don't support versioned ValueSets.
+ deleteValueSet(theResourceTable);
+
+ /*
+ * Do the upload.
+ */
+ String url = termValueSet.getUrl();
+ Optional optionalExistingTermValueSetByUrl = myValueSetDao.findByUrl(url);
+ if (!optionalExistingTermValueSetByUrl.isPresent()) {
+ myValueSetDao.save(termValueSet);
+ int codesSaved = 0;
+
+ ValueSet expandedValueSet = expandValueSet(theValueSet);
+ if (expandedValueSet.hasExpansion()) {
+ if (expandedValueSet.getExpansion().hasTotal() && expandedValueSet.getExpansion().getTotal() > 0) {
+ TermValueSetCode code;
+ for (ValueSet.ValueSetExpansionContainsComponent contains : expandedValueSet.getExpansion().getContains()) {
+ ValidateUtil.isNotBlankOrThrowInvalidRequest(contains.getSystem(), "ValueSet contains a code with no system value");
+ ValidateUtil.isNotBlankOrThrowInvalidRequest(contains.getCode(), "ValueSet contains a code with no code value");
+
+ code = new TermValueSetCode();
+ code.setValueSet(termValueSet);
+ code.setSystem(contains.getSystem());
+ code.setCode(contains.getCode());
+ code.setDisplay(contains.hasDisplay() ? contains.getDisplay() : null);
+ myValueSetCodeDao.save(code);
+
+ if (codesSaved++ % 250 == 0) {
+ ourLog.info("Have pre-expanded {} codes in ValueSet", codesSaved);
+ myValueSetCodeDao.flush();
+ }
+ }
+ }
+ }
+
+ } else {
+ TermValueSet existingTermValueSet = optionalExistingTermValueSetByUrl.get();
+
+ String msg = myContext.getLocalizer().getMessage(
+ BaseHapiTerminologySvcImpl.class,
+ "cannotCreateDuplicateValueSetUrl",
+ url,
+ existingTermValueSet.getResource().getIdDt().toUnqualifiedVersionless().getValue());
+
+ throw new UnprocessableEntityException(msg);
+ }
+
+ ourLog.info("Done storing TermValueSet.");
+ }
+
@Override
public IFhirResourceDaoCodeSystem.SubsumesResult subsumes(IPrimitiveType theCodeA, IPrimitiveType theCodeB, IPrimitiveType theSystem, IBaseCoding theCodingA, IBaseCoding theCodingB) {
VersionIndependentConcept conceptA = toConcept(theCodeA, theSystem, theCodingA);
@@ -1581,9 +1673,9 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
private int validateConceptForStorage(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, ArrayList theConceptsStack,
IdentityHashMap theAllConcepts) {
- ValidateUtil.isTrueOrThrowInvalidRequest(theConcept.getCodeSystemVersion() != null, "CodesystemValue is null");
+ ValidateUtil.isTrueOrThrowInvalidRequest(theConcept.getCodeSystemVersion() != null, "CodeSystemVersion is null");
ValidateUtil.isTrueOrThrowInvalidRequest(theConcept.getCodeSystemVersion() == theCodeSystem, "CodeSystems are not equal");
- ValidateUtil.isNotBlankOrThrowInvalidRequest(theConcept.getCode(), "Codesystem contains a code with no code value");
+ ValidateUtil.isNotBlankOrThrowInvalidRequest(theConcept.getCode(), "CodeSystem contains a code with no code value");
if (theConceptsStack.contains(theConcept.getCode())) {
throw new InvalidRequestException("CodeSystem contains circular reference around code " + theConcept.getCode());
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java
index cc861e27f7f..4d50f75afb5 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java
@@ -81,8 +81,12 @@ public interface IHapiTerminologySvc {
void deleteConceptMapAndChildren(ResourceTable theResourceTable);
+ void deleteValueSetAndChildren(ResourceTable theResourceTable);
+
void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap);
+ void storeTermValueSetAndChildren(ResourceTable theResourceTable, ValueSet theValueSet);
+
boolean supportsSystem(String theCodeSystem);
List translate(TranslationRequest theTranslationRequest);
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3TerminologyTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3TerminologyTest.java
index b03e0b09148..64390e9a671 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3TerminologyTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3TerminologyTest.java
@@ -1,31 +1,13 @@
package ca.uhn.fhir.jpa.dao.dstu3;
-import static org.hamcrest.Matchers.containsInAnyOrder;
-import static org.hamcrest.Matchers.containsStringIgnoringCase;
-import static org.hamcrest.Matchers.empty;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-
-import java.util.*;
-
-import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl;
-import org.hl7.fhir.dstu3.model.*;
-import org.hl7.fhir.dstu3.model.AllergyIntolerance.AllergyIntoleranceCategory;
-import org.hl7.fhir.dstu3.model.AllergyIntolerance.AllergyIntoleranceClinicalStatus;
-import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
-import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
-import org.hl7.fhir.dstu3.model.ValueSet.*;
-import org.hl7.fhir.instance.model.api.IIdType;
-import org.junit.*;
-import org.springframework.beans.factory.annotation.Autowired;
-
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem.LookupCodeResult;
-import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
-import ca.uhn.fhir.jpa.model.entity.*;
-import ca.uhn.fhir.jpa.entity.*;
+import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
+import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
+import ca.uhn.fhir.jpa.model.entity.ResourceTable;
+import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
+import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.param.TokenParam;
@@ -35,6 +17,25 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult;
+import org.hl7.fhir.dstu3.model.*;
+import org.hl7.fhir.dstu3.model.AllergyIntolerance.AllergyIntoleranceCategory;
+import org.hl7.fhir.dstu3.model.AllergyIntolerance.AllergyIntoleranceClinicalStatus;
+import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
+import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
+import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent;
+import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
+import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
+import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
+import org.hl7.fhir.instance.model.api.IIdType;
+import org.junit.*;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
@@ -226,7 +227,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
myCodeSystemDao.create(codeSystem, mySrd);
fail();
} catch (UnprocessableEntityException e) {
- assertEquals("Can not create multiple code systems with URI \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/" + id.getIdPart(), e.getMessage());
+ assertEquals("Can not create multiple CodeSystem resources with CodeSystem.url \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/" + id.getIdPart(), e.getMessage());
}
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java
index e3d27011253..877d0601247 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java
@@ -118,6 +118,10 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
@Qualifier("myCodeSystemDaoR4")
protected IFhirResourceDaoCodeSystem myCodeSystemDao;
@Autowired
+ protected ITermCodeSystemDao myTermCodeSystemDao;
+ @Autowired
+ protected ITermCodeSystemVersionDao myTermCodeSystemVersionDao;
+ @Autowired
@Qualifier("myCompartmentDefinitionDaoR4")
protected IFhirResourceDao myCompartmentDefinitionDao;
@Autowired
@@ -287,6 +291,10 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
@Qualifier("myValueSetDaoR4")
protected IFhirResourceDaoValueSet myValueSetDao;
@Autowired
+ protected ITermValueSetDao myTermValueSetDao;
+ @Autowired
+ protected ITermValueSetCodeDao myTermValueSetCodeDao;
+ @Autowired
protected ITermConceptMapDao myTermConceptMapDao;
@Autowired
protected ITermConceptMapGroupElementTargetDao myTermConceptMapGroupElementTargetDao;
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TerminologyTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TerminologyTest.java
index 589f593c373..e362d462251 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TerminologyTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TerminologyTest.java
@@ -222,7 +222,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
myCodeSystemDao.create(codeSystem, mySrd);
fail();
} catch (UnprocessableEntityException e) {
- assertEquals("Can not create multiple code systems with URI \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/" + id.getIdPart(), e.getMessage());
+ assertEquals("Can not create multiple CodeSystem resources with CodeSystem.url \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/" + id.getIdPart(), e.getMessage());
}
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValueSetTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValueSetTest.java
index 2a10ef2f9c6..cf3d7ce0bd6 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValueSetTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValueSetTest.java
@@ -1,34 +1,20 @@
package ca.uhn.fhir.jpa.dao.r4;
-import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.stringContainsInOrder;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-
-import org.hl7.fhir.r4.model.CodeSystem;
-import org.hl7.fhir.r4.model.CodeType;
-import org.hl7.fhir.r4.model.CodeableConcept;
-import org.hl7.fhir.r4.model.Coding;
-import org.hl7.fhir.r4.model.IdType;
-import org.hl7.fhir.r4.model.Parameters;
-import org.hl7.fhir.r4.model.StringType;
-import org.hl7.fhir.r4.model.UriType;
-import org.hl7.fhir.r4.model.ValueSet;
+import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
+import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
+import org.hl7.fhir.r4.model.*;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.transaction.annotation.Transactional;
-import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
-import ca.uhn.fhir.util.TestUtil;
+import java.io.IOException;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
@@ -224,7 +210,7 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
@Test
- public void testValiedateCodeAgainstBuiltInValueSetAndCodeSystemWithValidCode() {
+ public void testValidateCodeAgainstBuiltInValueSetAndCodeSystemWithValidCode() {
IPrimitiveType display = null;
Coding coding = null;
CodeableConcept codeableConcept = null;
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java
index e7006342458..3089835220d 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java
@@ -177,7 +177,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, "SYSTEM NAME", cs);
fail();
} catch (UnprocessableEntityException e) {
- assertThat(e.getMessage(), containsString("Can not create multiple code systems with URI \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/"));
+ assertThat(e.getMessage(), containsString("Can not create multiple CodeSystem resources with CodeSystem.url \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/"));
}
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java
index 785de25822c..e1ebe208e36 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java
@@ -2,17 +2,12 @@ package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
-import ca.uhn.fhir.jpa.entity.TermConceptMap;
-import ca.uhn.fhir.jpa.entity.TermConceptMapGroup;
-import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement;
-import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget;
+import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.instance.model.api.IIdType;
-import org.hl7.fhir.r4.model.CanonicalType;
-import org.hl7.fhir.r4.model.ConceptMap;
+import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
-import org.hl7.fhir.r4.model.UriType;
import org.junit.*;
import org.junit.rules.ExpectedException;
import org.slf4j.Logger;
@@ -21,6 +16,7 @@ import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
+import java.io.IOException;
import java.util.List;
import java.util.Optional;
@@ -31,6 +27,8 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Rule
public final ExpectedException expectedException = ExpectedException.none();
private IIdType myConceptMapId;
+ private IIdType myExtensionalCsId;
+ private IIdType myExtensionalVsId;
@Before
public void before() {
@@ -40,6 +38,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@After
public void after() {
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
+ myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental());
}
private void createAndPersistConceptMap() {
@@ -56,6 +55,39 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
});
}
+ private void loadAndPersistCodeSystemAndValueSet() throws IOException {
+ loadAndPersistCodeSystem();
+ loadAndPersistValueSet();
+ }
+
+ private void loadAndPersistCodeSystem() throws IOException {
+ CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
+ persistCodeSystem(codeSystem);
+ }
+
+ private void persistCodeSystem(CodeSystem theCodeSystem) {
+ new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
+ @Override
+ protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
+ myExtensionalCsId = myCodeSystemDao.create(theCodeSystem, mySrd).getId().toUnqualifiedVersionless();
+ }
+ });
+ }
+
+ private void loadAndPersistValueSet() throws IOException {
+ ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
+ persistValueSet(valueSet);
+ }
+
+ private void persistValueSet(ValueSet theValueSet) {
+ new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
+ @Override
+ protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
+ myExtensionalVsId = myValueSetDao.create(theValueSet, mySrd).getId().toUnqualifiedVersionless();
+ }
+ });
+ }
+
@Test
public void testCreateConceptMapWithMissingSourceSystem() {
ConceptMap conceptMap = new ConceptMap();
@@ -137,6 +169,16 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
}
+ @Test
+ public void testDuplicateCodeSystemUrls() throws Exception {
+ loadAndPersistCodeSystem();
+
+ expectedException.expect(UnprocessableEntityException.class);
+ expectedException.expectMessage("Can not create multiple CodeSystem resources with CodeSystem.url \"http://acme.org\", already have one with resource ID: CodeSystem/" + myExtensionalCsId.getIdPart());
+
+ loadAndPersistCodeSystem();
+ }
+
@Test
public void testDuplicateConceptMapUrls() {
createAndPersistConceptMap();
@@ -147,6 +189,19 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
createAndPersistConceptMap();
}
+ @Test
+ public void testDuplicateValueSetUrls() throws Exception {
+ myDaoConfig.setPreExpandValueSetsExperimental(true);
+
+ // DM 2019-03-05 - We pre-load our custom CodeSystem otherwise pre-expansion of the ValueSet will fail.
+ loadAndPersistCodeSystemAndValueSet();
+
+ expectedException.expect(UnprocessableEntityException.class);
+ expectedException.expectMessage("Can not create multiple ValueSet resources with ValueSet.url \"http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2\", already have one with resource ID: ValueSet/" + myExtensionalVsId.getIdPart());
+
+ loadAndPersistValueSet();
+ }
+
@Test
public void testStoreTermConceptMapAndChildren() {
createAndPersistConceptMap();
@@ -325,6 +380,63 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
});
}
+ @Test
+ public void testStoreTermValueSetAndChildren() throws Exception {
+ myDaoConfig.setPreExpandValueSetsExperimental(true);
+
+ loadAndPersistCodeSystemAndValueSet();
+
+ CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId);
+ ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem));
+
+ ValueSet valueSet = myValueSetDao.read(myExtensionalVsId);
+ ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet));
+
+ new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
+ @Override
+ protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
+ Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong());
+ assertTrue(optionalValueSetByResourcePid.isPresent());
+
+ Optional optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
+ assertTrue(optionalValueSetByUrl.isPresent());
+
+ TermValueSet valueSet = optionalValueSetByUrl.get();
+ assertSame(optionalValueSetByResourcePid.get(), valueSet);
+ ourLog.info("ValueSet:\n" + valueSet.toString());
+ assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", valueSet.getUrl());
+ assertEquals("Terminology Services Connectation #1 Extensional case #2", valueSet.getName());
+ assertEquals(codeSystem.getConcept().size(), valueSet.getCodes().size());
+
+ TermValueSetCode code = valueSet.getCodes().get(0);
+ ourLog.info("Code:\n" + code.toString());
+ assertEquals("http://acme.org", code.getSystem());
+ assertEquals("8450-9", code.getCode());
+ assertEquals("Systolic blood pressure--expiration", code.getDisplay());
+
+ code = valueSet.getCodes().get(1);
+ ourLog.info("Code:\n" + code.toString());
+ assertEquals("http://acme.org", code.getSystem());
+ assertEquals("11378-7", code.getCode());
+ assertEquals("Systolic blood pressure at First encounter", code.getDisplay());
+
+ // ...
+
+ code = valueSet.getCodes().get(22);
+ ourLog.info("Code:\n" + code.toString());
+ assertEquals("http://acme.org", code.getSystem());
+ assertEquals("8491-3", code.getCode());
+ assertEquals("Systolic blood pressure 1 hour minimum", code.getDisplay());
+
+ code = valueSet.getCodes().get(23);
+ ourLog.info("Code:\n" + code.toString());
+ assertEquals("http://acme.org", code.getSystem());
+ assertEquals("8492-1", code.getCode());
+ assertEquals("Systolic blood pressure 8 hour minimum", code.getDisplay());
+ }
+ });
+ }
+
@Test
public void testTranslateByCodeSystemsAndSourceCodeOneToMany() {
createAndPersistConceptMap();
diff --git a/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java b/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java
index 852e9204c22..163c11a0626 100644
--- a/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java
+++ b/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java
@@ -75,6 +75,41 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks {
.renameColumn("mySystem", "SYSTEM_URL")
.renameColumn("mySystemVersion", "SYSTEM_VERSION")
.renameColumn("myValueSet", "VALUESET_URL");
+
+ // TermValueSet
+ version.startSectionWithMessage("Processing table: TRM_VALUESET");
+ version.addIdGenerator("SEQ_VALUESET_PID");
+ Builder.BuilderAddTableByColumns termValueSetTable = version.addTableByColumns("TRM_VALUESET", "PID");
+ termValueSetTable.addColumn("PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
+ termValueSetTable.addColumn("URL").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING);
+ termValueSetTable
+ .addIndex("IDX_VALUESET_URL")
+ .unique(true)
+ .withColumns("URL");
+ termValueSetTable.addColumn("RES_ID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
+ termValueSetTable
+ .addForeignKey("FK_TRMVALUESET_RES")
+ .toColumn("RES_ID")
+ .references("HFJ_RESOURCE", "RES_ID");
+ termValueSetTable.addColumn("NAME").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING);
+
+ // TermValueSetCode
+ version.startSectionWithMessage("Processing table: TRM_VALUESET_CODE");
+ version.addIdGenerator("SEQ_VALUESET_CODE_PID");
+ Builder.BuilderAddTableByColumns termValueSetCodeTable = version.addTableByColumns("TRM_VALUESET_CODE", "PID");
+ termValueSetCodeTable.addColumn("PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
+ termValueSetCodeTable.addColumn("VALUESET_PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
+ termValueSetCodeTable
+ .addForeignKey("FK_TRM_VALUESET_PID")
+ .toColumn("VALUESET_PID")
+ .references("TRM_VALUESET", "PID");
+ termValueSetCodeTable.addColumn("SYSTEM").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING);
+ termValueSetCodeTable.addColumn("CODE").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING);
+ termValueSetCodeTable
+ .addIndex("IDX_VALUESET_CODE_CS_CD")
+ .unique(false)
+ .withColumns("SYSTEM", "CODE");
+ termValueSetCodeTable.addColumn("DISPLAY").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING);
}
diff --git a/src/site/xdoc/doc_jpa.xml b/src/site/xdoc/doc_jpa.xml
index dfee8e9ab03..6628949f4e1 100644
--- a/src/site/xdoc/doc_jpa.xml
+++ b/src/site/xdoc/doc_jpa.xml
@@ -276,7 +276,7 @@ public DaoConfig daoConfig() {
If the client knows that they will only want a small number of results
(for example, a UI containing 20 results is being shown and the client
knows that they will never load the next page of results) the client
- may also use the nostore
directive along with a HAPI FHIR
+ may also use the no-store
directive along with a HAPI FHIR
extension called max-results
in order to specify that
only the given number of results should be fetched. This directive
disabled paging entirely for the request and causes the request to
@@ -285,7 +285,7 @@ public DaoConfig daoConfig() {
- Cache-Control: nostore, max-results=20
+ Cache-Control: no-store, max-results=20