Port changes to master from release branch 6_4 (#4785)
* Start porting changes to master that were lost from the release branch. * Add remainder of tag changes from release branch. * Changelog changes. * Fix schema migration. * Remove duplicate lines. * Update core to 6.0.1. * Fixes for new core. * Bump to snapshot 19 to mirror James' changes. * Fix migration tasks. * Fix some of the tests due to the core upgrade. * Fix rest of tests.
This commit is contained in:
parent
81854baa02
commit
79c96dc1bb
|
@ -19,8 +19,6 @@
|
|||
*/
|
||||
package ca.uhn.fhir.model.api;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 4786
|
||||
jira: SMILE-4688
|
||||
title: "With default configuration, Resource meta.tag properties: `userSelected` and `version`, were not stored in the database.
|
||||
This is now fixed."
|
|
@ -147,6 +147,7 @@ import javax.persistence.PersistenceContextType;
|
|||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.xml.stream.events.Characters;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
|
@ -163,7 +164,9 @@ import java.util.Set;
|
|||
import java.util.StringTokenizer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Objects.isNull;
|
||||
import static java.util.Objects.nonNull;
|
||||
import static org.apache.commons.lang3.BooleanUtils.isFalse;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.left;
|
||||
|
@ -279,7 +282,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(theResource);
|
||||
if (tagList != null) {
|
||||
for (Tag next : tagList) {
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.TAG, next.getScheme(), next.getTerm(), next.getLabel());
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.TAG, next.getScheme(), next.getTerm(),
|
||||
next.getLabel(), next.getVersion(), next.getUserSelected());
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
allDefs.add(tag);
|
||||
|
@ -291,7 +295,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
List<BaseCodingDt> securityLabels = ResourceMetadataKeyEnum.SECURITY_LABELS.get(theResource);
|
||||
if (securityLabels != null) {
|
||||
for (BaseCodingDt next : securityLabels) {
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.SECURITY_LABEL, next.getSystemElement().getValue(), next.getCodeElement().getValue(), next.getDisplayElement().getValue());
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.SECURITY_LABEL, next.getSystemElement().getValue(),
|
||||
next.getCodeElement().getValue(), next.getDisplayElement().getValue(), null, null);
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
allDefs.add(tag);
|
||||
|
@ -303,7 +308,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
List<IdDt> profiles = ResourceMetadataKeyEnum.PROFILES.get(theResource);
|
||||
if (profiles != null) {
|
||||
for (IIdType next : profiles) {
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null);
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null, null, null);
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
allDefs.add(tag);
|
||||
|
@ -317,7 +322,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
List<? extends IBaseCoding> tagList = theResource.getMeta().getTag();
|
||||
if (tagList != null) {
|
||||
for (IBaseCoding next : tagList) {
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.TAG, next.getSystem(), next.getCode(), next.getDisplay());
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.TAG, next.getSystem(), next.getCode(),
|
||||
next.getDisplay(), next.getVersion(), next.getUserSelected());
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
theAllTags.add(tag);
|
||||
|
@ -329,7 +335,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
List<? extends IBaseCoding> securityLabels = theResource.getMeta().getSecurity();
|
||||
if (securityLabels != null) {
|
||||
for (IBaseCoding next : securityLabels) {
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.SECURITY_LABEL, next.getSystem(), next.getCode(), next.getDisplay());
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.SECURITY_LABEL, next.getSystem(), next.getCode(), next.getDisplay(), null, null);
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
theAllTags.add(tag);
|
||||
|
@ -341,7 +347,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
List<? extends IPrimitiveType<String>> profiles = theResource.getMeta().getProfile();
|
||||
if (profiles != null) {
|
||||
for (IPrimitiveType<String> next : profiles) {
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null);
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null, null, null);
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
theAllTags.add(tag);
|
||||
|
@ -379,22 +385,25 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
/**
|
||||
* <code>null</code> will only be returned if the scheme and tag are both blank
|
||||
*/
|
||||
protected TagDefinition getTagOrNull(TransactionDetails theTransactionDetails, TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) {
|
||||
protected TagDefinition getTagOrNull(TransactionDetails theTransactionDetails, TagTypeEnum theTagType, String theScheme,
|
||||
String theTerm, String theLabel, String theVersion, Boolean theUserSelected) {
|
||||
if (isBlank(theScheme) && isBlank(theTerm) && isBlank(theLabel)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MemoryCacheService.TagDefinitionCacheKey key = toTagDefinitionMemoryCacheKey(theTagType, theScheme, theTerm);
|
||||
MemoryCacheService.TagDefinitionCacheKey key = toTagDefinitionMemoryCacheKey(theTagType, theScheme, theTerm, theVersion, theUserSelected);
|
||||
|
||||
TagDefinition retVal = myMemoryCacheService.getIfPresent(MemoryCacheService.CacheEnum.TAG_DEFINITION, key);
|
||||
|
||||
if (retVal == null) {
|
||||
HashMap<MemoryCacheService.TagDefinitionCacheKey, TagDefinition> resolvedTagDefinitions = theTransactionDetails.getOrCreateUserData(HapiTransactionService.XACT_USERDATA_KEY_RESOLVED_TAG_DEFINITIONS, HashMap::new);
|
||||
HashMap<MemoryCacheService.TagDefinitionCacheKey, TagDefinition> resolvedTagDefinitions = theTransactionDetails
|
||||
.getOrCreateUserData(HapiTransactionService.XACT_USERDATA_KEY_RESOLVED_TAG_DEFINITIONS, HashMap::new);
|
||||
|
||||
retVal = resolvedTagDefinitions.get(key);
|
||||
|
||||
if (retVal == null) {
|
||||
// actual DB hit(s) happen here
|
||||
retVal = getOrCreateTag(theTagType, theScheme, theTerm, theLabel);
|
||||
retVal = getOrCreateTag(theTagType, theScheme, theTerm, theLabel, theVersion, theUserSelected);
|
||||
|
||||
TransactionSynchronization sync = new AddTagDefinitionToCacheAfterCommitSynchronization(key, retVal);
|
||||
TransactionSynchronizationManager.registerSynchronization(sync);
|
||||
|
@ -412,26 +421,10 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
* <p>
|
||||
* Can also throw an InternalErrorException if something bad happens.
|
||||
*/
|
||||
private TagDefinition getOrCreateTag(TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) {
|
||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<TagDefinition> cq = builder.createQuery(TagDefinition.class);
|
||||
Root<TagDefinition> from = cq.from(TagDefinition.class);
|
||||
private TagDefinition getOrCreateTag(TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel,
|
||||
String theVersion, Boolean theUserSelected) {
|
||||
|
||||
if (isNotBlank(theScheme)) {
|
||||
cq.where(
|
||||
builder.and(
|
||||
builder.equal(from.get("myTagType"), theTagType),
|
||||
builder.equal(from.get("mySystem"), theScheme),
|
||||
builder.equal(from.get("myCode"), theTerm)));
|
||||
} else {
|
||||
cq.where(
|
||||
builder.and(
|
||||
builder.equal(from.get("myTagType"), theTagType),
|
||||
builder.isNull(from.get("mySystem")),
|
||||
builder.equal(from.get("myCode"), theTerm)));
|
||||
}
|
||||
|
||||
TypedQuery<TagDefinition> q = myEntityManager.createQuery(cq);
|
||||
TypedQuery<TagDefinition> q = buildTagQuery(theTagType, theScheme, theTerm, theVersion, theUserSelected);
|
||||
|
||||
TransactionTemplate template = new TransactionTemplate(myTransactionManager);
|
||||
template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
|
@ -453,6 +446,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
val = q.getSingleResult();
|
||||
} catch (NoResultException e) {
|
||||
val = new TagDefinition(theTagType, theScheme, theTerm, theLabel);
|
||||
val.setVersion(theVersion);
|
||||
val.setUserSelected(theUserSelected);
|
||||
myEntityManager.persist(val);
|
||||
}
|
||||
return val;
|
||||
|
@ -510,6 +505,34 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
return retVal;
|
||||
}
|
||||
|
||||
private TypedQuery<TagDefinition> buildTagQuery(TagTypeEnum theTagType, String theScheme, String theTerm,
|
||||
String theVersion, Boolean theUserSelected) {
|
||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<TagDefinition> cq = builder.createQuery(TagDefinition.class);
|
||||
Root<TagDefinition> from = cq.from(TagDefinition.class);
|
||||
|
||||
List<Predicate> predicates = new ArrayList<>();
|
||||
predicates.add(
|
||||
builder.and(
|
||||
builder.equal(from.get("myTagType"), theTagType),
|
||||
builder.equal(from.get("myCode"), theTerm)));
|
||||
|
||||
predicates.add( isBlank(theScheme)
|
||||
? builder.isNull(from.get("mySystem"))
|
||||
: builder.equal(from.get("mySystem"), theScheme));
|
||||
|
||||
predicates.add( isBlank(theVersion)
|
||||
? builder.isNull(from.get("myVersion"))
|
||||
: builder.equal(from.get("myVersion"), theVersion));
|
||||
|
||||
predicates.add( isNull(theUserSelected) || isFalse(theUserSelected)
|
||||
? builder.isFalse(from.get("myUserSelected"))
|
||||
: builder.isTrue(from.get("myUserSelected")));
|
||||
|
||||
cq.where(predicates.toArray(new Predicate[0]));
|
||||
return myEntityManager.createQuery(cq);
|
||||
}
|
||||
|
||||
|
||||
void incrementId(T theResource, ResourceTable theSavedEntity, IIdType theResourceId) {
|
||||
String newVersion;
|
||||
|
@ -761,10 +784,10 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
}
|
||||
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
|
||||
if (def.isStandardType() == false) {
|
||||
if ( ! def.isStandardType()) {
|
||||
String profile = def.getResourceProfile("");
|
||||
if (isNotBlank(profile)) {
|
||||
TagDefinition profileDef = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, profile, null);
|
||||
TagDefinition profileDef = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, profile, null, null, null);
|
||||
|
||||
ResourceTag tag = theEntity.addTag(profileDef);
|
||||
allDefs.add(tag);
|
||||
|
@ -797,7 +820,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
theResource.getMeta()
|
||||
.addTag()
|
||||
.setCode(tag.getTag().getCode())
|
||||
.setSystem(tag.getTag().getSystem());
|
||||
.setSystem(tag.getTag().getSystem())
|
||||
.setVersion(tag.getTag().getVersion())
|
||||
.setUserSelected(tag.getTag().getUserSelected());
|
||||
});
|
||||
|
||||
theEntity.setHasTags(!allTagsNew.isEmpty());
|
||||
|
@ -1604,8 +1629,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
}
|
||||
|
||||
@Nonnull
|
||||
public static MemoryCacheService.TagDefinitionCacheKey toTagDefinitionMemoryCacheKey(TagTypeEnum theTagType, String theScheme, String theTerm) {
|
||||
return new MemoryCacheService.TagDefinitionCacheKey(theTagType, theScheme, theTerm);
|
||||
public static MemoryCacheService.TagDefinitionCacheKey toTagDefinitionMemoryCacheKey(
|
||||
TagTypeEnum theTagType, String theScheme, String theTerm, String theVersion, Boolean theUserSelected) {
|
||||
return new MemoryCacheService.TagDefinitionCacheKey(theTagType, theScheme, theTerm, theVersion, theUserSelected);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -824,9 +824,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
boolean hasTag = false;
|
||||
for (BaseTag next : new ArrayList<>(theEntity.getTags())) {
|
||||
if (ObjectUtil.equals(next.getTag().getTagType(), nextDef.getTagType()) &&
|
||||
ObjectUtil.equals(next.getTag().getSystem(), nextDef.getSystem()) &&
|
||||
ObjectUtil.equals(next.getTag().getCode(), nextDef.getCode())) {
|
||||
if (Objects.equals(next.getTag().getTagType(), nextDef.getTagType()) &&
|
||||
Objects.equals(next.getTag().getSystem(), nextDef.getSystem()) &&
|
||||
Objects.equals(next.getTag().getCode(), nextDef.getCode()) &&
|
||||
Objects.equals(next.getTag().getVersion(), nextDef.getVersion()) &&
|
||||
Objects.equals(next.getTag().getUserSelected(), nextDef.getUserSelected())) {
|
||||
hasTag = true;
|
||||
break;
|
||||
}
|
||||
|
@ -835,7 +837,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
if (!hasTag) {
|
||||
theEntity.setHasTags(true);
|
||||
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, nextDef.getTagType(), nextDef.getSystem(), nextDef.getCode(), nextDef.getDisplay());
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, nextDef.getTagType(), nextDef.getSystem(),
|
||||
nextDef.getCode(), nextDef.getDisplay(), nextDef.getVersion(), nextDef.getUserSelected());
|
||||
if (def != null) {
|
||||
BaseTag newEntity = theEntity.addTag(def);
|
||||
if (newEntity.getTagId() == null) {
|
||||
|
|
|
@ -433,6 +433,8 @@ public class JpaStorageResourceParser implements IJpaStorageResourceParser {
|
|||
tag.setSystem(next.getTag().getSystem());
|
||||
tag.setCode(next.getTag().getCode());
|
||||
tag.setDisplay(next.getTag().getDisplay());
|
||||
tag.setVersion(next.getTag().getVersion());
|
||||
tag.setUserSelected(next.getTag().getUserSelected());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,6 +111,33 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
|||
version.onTable("BT2_WORK_CHUNK")
|
||||
.migratePostgresTextClobToBinaryClob("20230208.3", "CHUNK_DATA");
|
||||
|
||||
{
|
||||
Builder.BuilderWithTableName tagDefTable = version.onTable("HFJ_TAG_DEF");
|
||||
|
||||
// add columns
|
||||
tagDefTable
|
||||
.addColumn("20230209.1", "TAG_VERSION")
|
||||
.nullable()
|
||||
.type(ColumnTypeEnum.STRING, 30);
|
||||
tagDefTable
|
||||
.addColumn("20230209.2", "TAG_USER_SELECTED")
|
||||
.nullable()
|
||||
.type(ColumnTypeEnum.BOOLEAN);
|
||||
|
||||
// Update indexing
|
||||
tagDefTable.dropIndex("20230209.3", "IDX_TAGDEF_TYPESYSCODE");
|
||||
|
||||
tagDefTable.dropIndex("20230209.4", "IDX_TAGDEF_TYPESYSCODEVERUS");
|
||||
Map<DriverTypeEnum, String> addTagDefConstraint = new HashMap<>();
|
||||
addTagDefConstraint.put(DriverTypeEnum.H2_EMBEDDED, "ALTER TABLE HFJ_TAG_DEF ADD CONSTRAINT IDX_TAGDEF_TYPESYSCODEVERUS UNIQUE (TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_VERSION, TAG_USER_SELECTED)");
|
||||
addTagDefConstraint.put(DriverTypeEnum.MARIADB_10_1, "ALTER TABLE HFJ_TAG_DEF ADD CONSTRAINT IDX_TAGDEF_TYPESYSCODEVERUS UNIQUE (TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_VERSION, TAG_USER_SELECTED)");
|
||||
addTagDefConstraint.put(DriverTypeEnum.MSSQL_2012, "ALTER TABLE HFJ_TAG_DEF ADD CONSTRAINT IDX_TAGDEF_TYPESYSCODEVERUS UNIQUE (TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_VERSION, TAG_USER_SELECTED)");
|
||||
addTagDefConstraint.put(DriverTypeEnum.MYSQL_5_7, "ALTER TABLE HFJ_TAG_DEF ADD CONSTRAINT IDX_TAGDEF_TYPESYSCODEVERUS UNIQUE (TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_VERSION, TAG_USER_SELECTED)");
|
||||
addTagDefConstraint.put(DriverTypeEnum.ORACLE_12C, "ALTER TABLE HFJ_TAG_DEF ADD CONSTRAINT IDX_TAGDEF_TYPESYSCODEVERUS UNIQUE (TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_VERSION, TAG_USER_SELECTED)");
|
||||
addTagDefConstraint.put(DriverTypeEnum.POSTGRES_9_4, "ALTER TABLE HFJ_TAG_DEF ADD CONSTRAINT IDX_TAGDEF_TYPESYSCODEVERUS UNIQUE (TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_VERSION, TAG_USER_SELECTED)");
|
||||
version.executeRawSql("20230209.5", addTagDefConstraint);
|
||||
}
|
||||
|
||||
version
|
||||
.onTable(Search.HFJ_SEARCH)
|
||||
.addColumn("20230215.1", Search.SEARCH_UUID)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
package ca.uhn.fhir.jpa.model.entity;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
|
@ -48,7 +49,8 @@ import java.util.Collection;
|
|||
@Index(name = "IDX_TAG_DEF_TP_CD_SYS", columnList = "TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_ID"),
|
||||
},
|
||||
uniqueConstraints = {
|
||||
@UniqueConstraint(name = "IDX_TAGDEF_TYPESYSCODE", columnNames = {"TAG_TYPE", "TAG_SYSTEM", "TAG_CODE"})
|
||||
@UniqueConstraint(name = "IDX_TAGDEF_TYPESYSCODEVERUS",
|
||||
columnNames = {"TAG_TYPE", "TAG_SYSTEM", "TAG_CODE", "TAG_VERSION", "TAG_USER_SELECTED"})
|
||||
}
|
||||
)
|
||||
public class TagDefinition implements Serializable {
|
||||
|
@ -56,22 +58,35 @@ public class TagDefinition implements Serializable {
|
|||
private static final long serialVersionUID = 1L;
|
||||
@Column(name = "TAG_CODE", length = 200)
|
||||
private String myCode;
|
||||
|
||||
@Column(name = "TAG_DISPLAY", length = 200)
|
||||
private String myDisplay;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_TAGDEF_ID")
|
||||
@SequenceGenerator(name = "SEQ_TAGDEF_ID", sequenceName = "SEQ_TAGDEF_ID")
|
||||
@Column(name = "TAG_ID")
|
||||
private Long myId;
|
||||
|
||||
@OneToMany(cascade = {}, fetch = FetchType.LAZY, mappedBy = "myTag")
|
||||
private Collection<ResourceTag> myResources;
|
||||
|
||||
@OneToMany(cascade = {}, fetch = FetchType.LAZY, mappedBy = "myTag")
|
||||
private Collection<ResourceHistoryTag> myResourceVersions;
|
||||
|
||||
@Column(name = "TAG_SYSTEM", length = 200)
|
||||
private String mySystem;
|
||||
|
||||
@Column(name = "TAG_TYPE", nullable = false)
|
||||
@Enumerated(EnumType.ORDINAL)
|
||||
private TagTypeEnum myTagType;
|
||||
|
||||
@Column(name = "TAG_VERSION", length = 30)
|
||||
private String myVersion;
|
||||
|
||||
@Column(name = "TAG_USER_SELECTED")
|
||||
private Boolean myUserSelected;
|
||||
|
||||
@Transient
|
||||
private transient Integer myHashCode;
|
||||
|
||||
|
@ -132,6 +147,31 @@ public class TagDefinition implements Serializable {
|
|||
myHashCode = null;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return myVersion;
|
||||
}
|
||||
|
||||
public void setVersion(String theVersion) {
|
||||
setVersionAfterTrim(theVersion);
|
||||
}
|
||||
|
||||
private void setVersionAfterTrim(String theVersion) {
|
||||
if (theVersion != null) {
|
||||
myVersion = StringUtils.truncate(theVersion, 30);
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean getUserSelected() {
|
||||
// TODO: LD: this is not ideal as we are implicitly assuming null is false.
|
||||
// Ideally we should fix IBaseCoding to return wrapper Boolean but that will involve another core/hapi release
|
||||
return myUserSelected != null ? myUserSelected : false;
|
||||
}
|
||||
|
||||
public void setUserSelected(Boolean theUserSelected) {
|
||||
myUserSelected = theUserSelected != null && theUserSelected;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
|
@ -150,6 +190,8 @@ public class TagDefinition implements Serializable {
|
|||
b.append(myTagType, other.myTagType);
|
||||
b.append(mySystem, other.mySystem);
|
||||
b.append(myCode, other.myCode);
|
||||
b.append(myVersion, other.myVersion);
|
||||
b.append(myUserSelected, other.myUserSelected);
|
||||
}
|
||||
|
||||
return b.isEquals();
|
||||
|
@ -162,6 +204,8 @@ public class TagDefinition implements Serializable {
|
|||
b.append(myTagType);
|
||||
b.append(mySystem);
|
||||
b.append(myCode);
|
||||
b.append(myVersion);
|
||||
b.append(myUserSelected);
|
||||
myHashCode = b.toHashCode();
|
||||
}
|
||||
return myHashCode;
|
||||
|
@ -174,6 +218,8 @@ public class TagDefinition implements Serializable {
|
|||
retVal.append("system", mySystem);
|
||||
retVal.append("code", myCode);
|
||||
retVal.append("display", myDisplay);
|
||||
retVal.append("version", myVersion);
|
||||
retVal.append("userSelected", myUserSelected);
|
||||
return retVal.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,11 @@ public class TagDefinitionTest {
|
|||
def.setCode("my_code");
|
||||
def.setSystem("my_system");
|
||||
def.setDisplay("my_display");
|
||||
assertEquals("TagDefinition[id=<null>,system=my_system,code=my_code,display=my_display]", def.toString());
|
||||
def.setVersion("V 1.0");
|
||||
def.setUserSelected(true);
|
||||
assertEquals(
|
||||
"TagDefinition[id=<null>,system=my_system,code=my_code,display=my_display,version=V 1.0,userSelected=true]",
|
||||
def.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -39,7 +43,8 @@ public class TagDefinitionTest {
|
|||
def.setCode("my_code");
|
||||
def.setSystem("my_system");
|
||||
def.setDisplay("my_display");
|
||||
assertEquals (-2125810377,def.hashCode());
|
||||
assertEquals (-2125810377,def.hashCode());
|
||||
def.setVersion("V 1.0");
|
||||
def.setUserSelected(true);
|
||||
assertEquals (434167707,def.hashCode());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,8 +63,8 @@ public class ExpandResourcesStepJpaTest extends BaseJpaR4Test {
|
|||
.boxed()
|
||||
.map(t -> {
|
||||
Patient p = new Patient();
|
||||
p.getMeta().addTag().setSystem("http://static").setCode("tag");
|
||||
p.getMeta().addTag().setSystem("http://dynamic").setCode("tag" + t);
|
||||
p.getMeta().addTag().setSystem("http://static").setCode("tag").setUserSelected(true).setVersion("1");
|
||||
p.getMeta().addTag().setSystem("http://dynamic").setCode("tag" + t).setUserSelected(true).setVersion("1");
|
||||
return myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
}).toList();
|
||||
assertEquals(count, ids.size());
|
||||
|
@ -89,10 +89,8 @@ public class ExpandResourcesStepJpaTest extends BaseJpaR4Test {
|
|||
verify(mySink, times(1)).accept(myWorkChunkCaptor.capture());
|
||||
ExpandedResourcesList expandedResourceList = myWorkChunkCaptor.getValue();
|
||||
assertEquals(10, expandedResourceList.getStringifiedResources().size());
|
||||
assertThat(expandedResourceList.getStringifiedResources().get(0), containsString("{\"system\":\"http://static\",\"code\":\"tag\"}"));
|
||||
assertThat(expandedResourceList.getStringifiedResources().get(0), containsString("{\"system\":\"http://dynamic\",\"code\":\"tag0\"}"));
|
||||
assertThat(expandedResourceList.getStringifiedResources().get(1), containsString("{\"system\":\"http://static\",\"code\":\"tag\"}"));
|
||||
assertThat(expandedResourceList.getStringifiedResources().get(1), containsString("{\"system\":\"http://dynamic\",\"code\":\"tag1\"}"));
|
||||
assertThat(expandedResourceList.getStringifiedResources().get(0), containsString("{\"system\":\"http://static\",\"version\":\"1\",\"code\":\"tag\",\"userSelected\":true}"));
|
||||
assertThat(expandedResourceList.getStringifiedResources().get(1), containsString("{\"system\":\"http://static\",\"version\":\"1\",\"code\":\"tag\",\"userSelected\":true}"));
|
||||
|
||||
// Verify query counts
|
||||
assertEquals(theExpectedSelectQueries, myCaptureQueriesListener.countSelectQueries());
|
||||
|
|
|
@ -78,12 +78,14 @@ public class BaseHapiFhirDaoTest {
|
|||
TagTypeEnum theEnum,
|
||||
String theScheme,
|
||||
String theTerm,
|
||||
String theLabel) {
|
||||
String theLabel,
|
||||
String theVersion,
|
||||
Boolean theUserSelected ) {
|
||||
// we need to init synchronization due to what
|
||||
// the underlying class is doing
|
||||
try {
|
||||
TransactionSynchronizationManager.initSynchronization();
|
||||
return super.getTagOrNull(theDetails, theEnum, theScheme, theTerm, theLabel);
|
||||
return super.getTagOrNull(theDetails, theEnum, theScheme, theTerm, theLabel, theVersion, theUserSelected);
|
||||
} finally {
|
||||
TransactionSynchronizationManager.clearSynchronization();
|
||||
}
|
||||
|
@ -176,12 +178,13 @@ public class BaseHapiFhirDaoTest {
|
|||
String scheme = "http://localhost";
|
||||
String term = "code123";
|
||||
String label = "hollow world";
|
||||
String version = "v1.0";
|
||||
Boolean userSelected = true;
|
||||
String raceConditionError = "Entity exists; if this is logged, you have race condition issues!";
|
||||
|
||||
TagDefinition tagDefinition = new TagDefinition(tagType,
|
||||
scheme,
|
||||
term,
|
||||
label);
|
||||
TagDefinition tagDefinition = new TagDefinition(tagType, scheme, term, label);
|
||||
tagDefinition.setVersion(version);
|
||||
tagDefinition.setUserSelected(userSelected);
|
||||
|
||||
// mock objects
|
||||
CriteriaBuilder builder = getMockedCriteriaBuilder();
|
||||
|
@ -271,7 +274,7 @@ public class BaseHapiFhirDaoTest {
|
|||
Runnable task = () -> {
|
||||
latch.countDown();
|
||||
try {
|
||||
TagDefinition retTag = myTestDao.getTagOrNull(new TransactionDetails(), tagType, scheme, term, label);
|
||||
TagDefinition retTag = myTestDao.getTagOrNull(new TransactionDetails(), tagType, scheme, term, label, version, userSelected);
|
||||
outcomes.put(retTag.hashCode(), retTag);
|
||||
counter.incrementAndGet();
|
||||
} catch (Exception ex) {
|
||||
|
@ -331,6 +334,8 @@ public class BaseHapiFhirDaoTest {
|
|||
String scheme = "http://localhost";
|
||||
String term = "code123";
|
||||
String label = "hollow world";
|
||||
String version = "v1.0";
|
||||
Boolean userSelected = true;
|
||||
TransactionDetails transactionDetails = new TransactionDetails();
|
||||
String exMsg = "Hi there";
|
||||
String readError = "No read for you";
|
||||
|
@ -359,7 +364,7 @@ public class BaseHapiFhirDaoTest {
|
|||
|
||||
// test
|
||||
try {
|
||||
myTestDao.getTagOrNull(transactionDetails, tagType, scheme, term, label);
|
||||
myTestDao.getTagOrNull(transactionDetails, tagType, scheme, term, label, version, userSelected);
|
||||
fail();
|
||||
} catch (Exception ex) {
|
||||
// verify
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTag;
|
||||
import ca.uhn.fhir.jpa.model.entity.TagDefinition;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.system.HapiTestSystemProperties;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
import org.hl7.fhir.r4.model.InstantType;
|
||||
import org.hl7.fhir.r4.model.Meta;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
|
@ -14,12 +19,16 @@ import org.hl7.fhir.r4.model.StringType;
|
|||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
@ -29,7 +38,9 @@ import java.util.stream.Collectors;
|
|||
import static ca.uhn.fhir.rest.api.Constants.PARAM_TAG;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.junit.jupiter.api.Assertions.assertAll;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
|
@ -142,6 +153,163 @@ public class FhirResourceDaoR4MetaTest extends BaseJpaR4Test {
|
|||
assertEquals("bar", patient2.getMeta().getSecurityFirstRep().getCode());
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class TestTagWithVersionAndUserSelected {
|
||||
|
||||
private static final String expectedSystem1 = "http://foo";
|
||||
private static final String expectedCode1 = "code1";
|
||||
private static final String expectedVersion1 = "testVersion1";
|
||||
private static final String expectedDisplay1 = "Test1";
|
||||
private static final boolean expectedUserSelected1 = true;
|
||||
|
||||
private static final String expectedSystem2 = "http://another.system";
|
||||
private static final String expectedCode2 = "code2";
|
||||
private static final String expectedVersion2 = "testVersion2";
|
||||
private static final String expectedDisplay2 = "Test2";
|
||||
private static final boolean expectedUserSelected2 = false;
|
||||
|
||||
private static final class TagQtyExpectations {
|
||||
public int theTagQty;
|
||||
public int theTagV1Qty;
|
||||
public int theTagV2Qty;
|
||||
|
||||
public TagQtyExpectations(int theTheTagV1Qty, int theTheTagV2Qty) {
|
||||
theTagQty = theTheTagV1Qty + theTheTagV2Qty;
|
||||
theTagV1Qty = theTheTagV1Qty;
|
||||
theTagV2Qty = theTheTagV2Qty;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<JpaStorageSettings.TagStorageModeEnum, TagQtyExpectations> expectedTagCountMap = Map.of(
|
||||
JpaStorageSettings.TagStorageModeEnum.INLINE, new TagQtyExpectations(0, 1),
|
||||
JpaStorageSettings.TagStorageModeEnum.NON_VERSIONED, new TagQtyExpectations(1, 1),
|
||||
JpaStorageSettings.TagStorageModeEnum.VERSIONED, new TagQtyExpectations(1, 1)
|
||||
);
|
||||
|
||||
private static final Map<JpaStorageSettings.TagStorageModeEnum, TagQtyExpectations> expectedHistoryTagCountMap = Map.of(
|
||||
JpaStorageSettings.TagStorageModeEnum.INLINE, new TagQtyExpectations(0, 0),
|
||||
JpaStorageSettings.TagStorageModeEnum.NON_VERSIONED, new TagQtyExpectations(0, 0),
|
||||
JpaStorageSettings.TagStorageModeEnum.VERSIONED, new TagQtyExpectations(2, 1)
|
||||
);
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(JpaStorageSettings.TagStorageModeEnum.class)
|
||||
public void testAddTagWithVersionAndUserSelected(JpaStorageSettings.TagStorageModeEnum theTagStorageModeEnum) {
|
||||
|
||||
myStorageSettings.setTagStorageMode(theTagStorageModeEnum);
|
||||
|
||||
final Patient savedPatient = new Patient();
|
||||
final Coding newTag = savedPatient.getMeta()
|
||||
.addTag()
|
||||
.setSystem(expectedSystem1)
|
||||
.setCode(expectedCode1)
|
||||
.setDisplay(expectedDisplay1);
|
||||
assertFalse(newTag.getUserSelected());
|
||||
newTag.setVersion(expectedVersion1)
|
||||
.setUserSelected(expectedUserSelected1);
|
||||
savedPatient.setActive(true);
|
||||
final IIdType pid1 = myPatientDao.create(savedPatient, new SystemRequestDetails()).getId().toVersionless();
|
||||
|
||||
final Patient retrievedPatient = myPatientDao.read(pid1, new SystemRequestDetails());
|
||||
validateSavedPatientTags(retrievedPatient);
|
||||
|
||||
// Update the patient to create a ResourceHistoryTag record
|
||||
final List<Coding> tagsFromDbPatient = retrievedPatient.getMeta().getTag();
|
||||
assertEquals(1, tagsFromDbPatient.size());
|
||||
|
||||
tagsFromDbPatient.get(0)
|
||||
.setCode(expectedCode2)
|
||||
.setSystem(expectedSystem2)
|
||||
.setVersion(expectedVersion2)
|
||||
.setDisplay(expectedDisplay2)
|
||||
.setUserSelected(expectedUserSelected2);
|
||||
|
||||
myPatientDao.update(retrievedPatient, new SystemRequestDetails());
|
||||
final Patient retrievedUpdatedPatient = myPatientDao.read(pid1, new SystemRequestDetails());
|
||||
|
||||
final Meta meta = retrievedUpdatedPatient.getMeta();
|
||||
final List<Coding> tags = meta.getTag();
|
||||
tags.forEach(innerTag -> ourLog.info("TAGS: version: {}, userSelected: {}, code: {}, display: {}, system: {}",
|
||||
innerTag.getVersion(), innerTag.getUserSelected(), innerTag.getCode(), innerTag.getDisplay(), innerTag.getSystem()));
|
||||
final Coding tagFirstRep = meta.getTagFirstRep();
|
||||
ourLog.info("TAG FIRST REP: version: {}, userSelected: {}, code: {}, display: {}, system: {}",
|
||||
tagFirstRep.getVersion(), tagFirstRep.getUserSelected(), tagFirstRep.getCode(), tagFirstRep.getDisplay(), tagFirstRep.getSystem());
|
||||
|
||||
TagQtyExpectations expectedCounts = expectedTagCountMap.get(theTagStorageModeEnum);
|
||||
validateUpdatedPatientTags(expectedCounts, tags);
|
||||
|
||||
final List<ResourceHistoryTag> resourceHistoryTags2 = myResourceHistoryTagDao.findAll();
|
||||
|
||||
resourceHistoryTags2.forEach(historyTag -> {
|
||||
final TagDefinition tag = historyTag.getTag();
|
||||
ourLog.info("tagId: {}, resourceId: {}, version: {}, userSelected: {}, system: {}, code: {}, display: {}",
|
||||
historyTag.getTagId(), historyTag.getResourceId(), /*tag.getVersion()*/ null, /*tag.getUserSelected()*/ null, tag.getSystem(), tag.getCode(), tag.getDisplay());
|
||||
});
|
||||
|
||||
TagQtyExpectations expectedHistoryCounts = expectedHistoryTagCountMap.get(theTagStorageModeEnum);
|
||||
validateHistoryTags(expectedHistoryCounts, resourceHistoryTags2);
|
||||
}
|
||||
|
||||
|
||||
private void validateSavedPatientTags(Patient thePatient) {
|
||||
assertAll(
|
||||
() -> assertEquals(1, thePatient.getMeta().getTag().size()),
|
||||
() -> assertEquals(0, thePatient.getMeta().getSecurity().size()),
|
||||
() -> assertEquals(0, thePatient.getMeta().getProfile().size()),
|
||||
|
||||
() -> assertEquals(expectedSystem1, thePatient.getMeta().getTagFirstRep().getSystem()),
|
||||
() -> assertTrue(thePatient.getMeta().getTagFirstRep().getUserSelected()),
|
||||
() -> assertEquals(expectedCode1, thePatient.getMeta().getTagFirstRep().getCode()),
|
||||
() -> assertEquals(expectedVersion1, thePatient.getMeta().getTagFirstRep().getVersion()),
|
||||
() -> assertEquals(expectedUserSelected1, thePatient.getMeta().getTagFirstRep().getUserSelected())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private void validateUpdatedPatientTags(TagQtyExpectations theExpectedCounts, List<Coding> tags) {
|
||||
assertAll(
|
||||
() -> assertEquals(theExpectedCounts.theTagQty, tags.size()),
|
||||
() -> assertEquals(theExpectedCounts.theTagV1Qty, tags.stream()
|
||||
.filter(tag -> expectedSystem1.equals(tag.getSystem()))
|
||||
.filter(tag -> expectedCode1.equals(tag.getCode()))
|
||||
.filter(tag -> expectedDisplay1.equals(tag.getDisplay()))
|
||||
.filter(tag -> expectedVersion1.equals(tag.getVersion()))
|
||||
.filter(tag -> expectedUserSelected1 == tag.getUserSelected())
|
||||
.count()),
|
||||
() -> assertEquals(theExpectedCounts.theTagV2Qty, tags.stream()
|
||||
.filter(tag -> expectedSystem2.equals(tag.getSystem()))
|
||||
.filter(tag -> expectedCode2.equals(tag.getCode()))
|
||||
.filter(tag -> expectedDisplay2.equals(tag.getDisplay()))
|
||||
.filter(tag -> expectedVersion2.equals(tag.getVersion()))
|
||||
.filter(tag -> expectedUserSelected2 == tag.getUserSelected())
|
||||
.count())
|
||||
);
|
||||
}
|
||||
|
||||
private void validateHistoryTags(TagQtyExpectations theExpectedHistoryCounts, List<ResourceHistoryTag> theHistoryTags) {
|
||||
// validating this way because tags are a set so can be in any order
|
||||
assertAll(
|
||||
() -> assertEquals(theExpectedHistoryCounts.theTagQty, theHistoryTags.size()),
|
||||
() -> assertEquals(theExpectedHistoryCounts.theTagV1Qty, theHistoryTags.stream()
|
||||
.filter(resourceHistoryTag -> expectedSystem1.equals(resourceHistoryTag.getTag().getSystem()))
|
||||
.filter(resourceHistoryTag -> expectedCode1.equals(resourceHistoryTag.getTag().getCode()))
|
||||
.filter(resourceHistoryTag -> expectedDisplay1.equals(resourceHistoryTag.getTag().getDisplay()))
|
||||
.filter(resourceHistoryTag -> expectedVersion1.equals(resourceHistoryTag.getTag().getVersion()))
|
||||
.filter(resourceHistoryTag -> expectedUserSelected1 == resourceHistoryTag.getTag().getUserSelected())
|
||||
.count()),
|
||||
() -> assertEquals(theExpectedHistoryCounts.theTagV2Qty, theHistoryTags.stream()
|
||||
.filter(resourceHistoryTag -> expectedSystem2.equals(resourceHistoryTag.getTag().getSystem()))
|
||||
.filter(resourceHistoryTag -> expectedCode2.equals(resourceHistoryTag.getTag().getCode()))
|
||||
.filter(resourceHistoryTag -> expectedDisplay2.equals(resourceHistoryTag.getTag().getDisplay()))
|
||||
.filter(resourceHistoryTag -> expectedVersion2.equals(resourceHistoryTag.getTag().getVersion()))
|
||||
.filter(resourceHistoryTag -> expectedUserSelected2 == resourceHistoryTag.getTag().getUserSelected())
|
||||
.count())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Disabled // TODO JA: This test fails regularly, need to get a dedicated connection pool for tag creation
|
||||
@Test
|
||||
|
|
|
@ -47,13 +47,18 @@ class MemoryCacheServiceTest {
|
|||
String system = "http://example.com";
|
||||
TagTypeEnum type = TagTypeEnum.TAG;
|
||||
String code = "t";
|
||||
String version = "Ver 3.0";
|
||||
Boolean userSelected = true;
|
||||
|
||||
MemoryCacheService.TagDefinitionCacheKey cacheKey = new MemoryCacheService.TagDefinitionCacheKey(type, system, code);
|
||||
MemoryCacheService.TagDefinitionCacheKey cacheKey = new MemoryCacheService.TagDefinitionCacheKey(
|
||||
type, system, code, version, userSelected);
|
||||
|
||||
TagDefinition retVal = mySvc.getIfPresent(MemoryCacheService.CacheEnum.TAG_DEFINITION, cacheKey);
|
||||
assertThat(retVal, nullValue());
|
||||
|
||||
TagDefinition tagDef = new TagDefinition(type, system, code, "theLabel");
|
||||
tagDef.setVersion(version);
|
||||
tagDef.setUserSelected(userSelected);
|
||||
mySvc.put(MemoryCacheService.CacheEnum.TAG_DEFINITION, cacheKey, tagDef);
|
||||
|
||||
retVal = mySvc.getIfPresent(MemoryCacheService.CacheEnum.TAG_DEFINITION, cacheKey);
|
||||
|
|
|
@ -216,16 +216,22 @@ public class MemoryCacheService {
|
|||
private final TagTypeEnum myType;
|
||||
private final String mySystem;
|
||||
private final String myCode;
|
||||
private final String myVersion;
|
||||
private Boolean myUserSelected;
|
||||
private final int myHashCode;
|
||||
|
||||
public TagDefinitionCacheKey(TagTypeEnum theType, String theSystem, String theCode) {
|
||||
public TagDefinitionCacheKey(TagTypeEnum theType, String theSystem, String theCode, String theVersion, Boolean theUserSelected) {
|
||||
myType = theType;
|
||||
mySystem = theSystem;
|
||||
myCode = theCode;
|
||||
myVersion = theVersion;
|
||||
myUserSelected = theUserSelected;
|
||||
myHashCode = new HashCodeBuilder(17, 37)
|
||||
.append(myType)
|
||||
.append(mySystem)
|
||||
.append(myCode)
|
||||
.append(myVersion)
|
||||
.append(myUserSelected)
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
|
|
|
@ -222,7 +222,7 @@ public final class HapiWorkerContext extends I18nBase implements IWorkerContext
|
|||
|
||||
@Override
|
||||
public ValidationResult validateCode(ValidationOptions theOptions, String code, ValueSet vs) {
|
||||
ValidationOptions options = theOptions.guessSystem();
|
||||
ValidationOptions options = theOptions.withGuessSystem();
|
||||
return validateCode(options, null, code, null, vs);
|
||||
}
|
||||
|
||||
|
|
|
@ -90,6 +90,16 @@ public final class HapiWorkerContext extends I18nBase implements IWorkerContext
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchSupplementedCodeSystem(String theS) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchSupplementedCodeSystem(String theS, String theS1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<String> getResourceNames() {
|
||||
|
@ -131,7 +141,7 @@ public final class HapiWorkerContext extends I18nBase implements IWorkerContext
|
|||
}
|
||||
}
|
||||
|
||||
return new ValidationResult(IssueSeverity.ERROR, null);
|
||||
return new ValidationResult(IssueSeverity.ERROR, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -170,7 +180,7 @@ public final class HapiWorkerContext extends I18nBase implements IWorkerContext
|
|||
severity = IssueSeverity.fromCode(result.getSeverityCode());
|
||||
}
|
||||
ConceptDefinitionComponent definition = new ConceptDefinitionComponent().setCode(result.getCode());
|
||||
return new ValidationResult(severity, result.getMessage(), theSystem, definition);
|
||||
return new ValidationResult(severity, result.getMessage(), theSystem, definition, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -189,11 +199,11 @@ public final class HapiWorkerContext extends I18nBase implements IWorkerContext
|
|||
ConceptDefinitionComponent definition = new ConceptDefinitionComponent();
|
||||
definition.setCode(theCode);
|
||||
definition.setDisplay(outcome.getDisplay());
|
||||
return new ValidationResult(theSystem, definition);
|
||||
return new ValidationResult(theSystem, definition, null);
|
||||
}
|
||||
|
||||
return new ValidationResult(IssueSeverity.ERROR, "Unknown code[" + theCode + "] in system[" +
|
||||
Constants.codeSystemWithDefaultDescription(theSystem) + "]");
|
||||
Constants.codeSystemWithDefaultDescription(theSystem) + "]", null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -244,15 +244,16 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
if (isNotBlank(code)) {
|
||||
retVal = new ValidationResult(theSystem, new org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent()
|
||||
.setCode(code)
|
||||
.setDisplay(display));
|
||||
.setDisplay(display),
|
||||
null);
|
||||
} else if (isNotBlank(issueSeverity)) {
|
||||
retVal = new ValidationResult(ValidationMessage.IssueSeverity.fromCode(issueSeverity), message, ValueSetExpander.TerminologyServiceErrorClass.UNKNOWN);
|
||||
retVal = new ValidationResult(ValidationMessage.IssueSeverity.fromCode(issueSeverity), message, ValueSetExpander.TerminologyServiceErrorClass.UNKNOWN, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (retVal == null) {
|
||||
retVal = new ValidationResult(ValidationMessage.IssueSeverity.ERROR, "Validation failed");
|
||||
retVal = new ValidationResult(ValidationMessage.IssueSeverity.ERROR, "Validation failed", null);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
@ -329,6 +330,16 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchSupplementedCodeSystem(String system) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchSupplementedCodeSystem(String system, String version) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Resource> T fetchResource(Class<T> class_, String uri) {
|
||||
|
||||
|
@ -558,7 +569,7 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
return validationResultsOk.get(0);
|
||||
}
|
||||
|
||||
return new ValidationResult(ValidationMessage.IssueSeverity.ERROR, null);
|
||||
return new ValidationResult(ValidationMessage.IssueSeverity.ERROR, null, null);
|
||||
}
|
||||
|
||||
public void invalidateCaches() {
|
||||
|
|
|
@ -1098,7 +1098,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
assertEquals(2, errors.getMessages().size());
|
||||
assertThat(errors.getMessages().get(0).getMessage(), containsString("A code with no system has no defined meaning. A system should be provided"));
|
||||
assertThat(errors.getMessages().get(0).getLocationString(), containsString("QuestionnaireResponse.item[0].answer[0]"));
|
||||
assertThat(errors.getMessages().get(1).getMessage(), containsString("The value provided (null::code1) is not in the options value set in the questionnaire"));
|
||||
assertThat(errors.getMessages().get(1).getMessage(), containsString("The code provided code1 in the system null) is not in the options value set (ValueSet[http://somevalueset]) in the questionnaire: Validation failed"));
|
||||
assertThat(errors.getMessages().get(1).getLocationString(), containsString("QuestionnaireResponse.item[0].answer[0]"));
|
||||
|
||||
qa = new QuestionnaireResponse();
|
||||
|
@ -1111,7 +1111,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
assertEquals(2, errors.getMessages().size());
|
||||
assertThat(errors.getMessages().get(0).getMessage(), containsString("A code with no system has no defined meaning. A system should be provided"));
|
||||
assertThat(errors.getMessages().get(0).getLocationString(), containsString("QuestionnaireResponse.item[0].answer[0]"));
|
||||
assertThat(errors.getMessages().get(1).getMessage(), containsString("The value provided (null::code1) is not in the options value set in the questionnaire"));
|
||||
assertThat(errors.getMessages().get(1).getMessage(), containsString("The code provided code1 in the system null) is not in the options value set (ValueSet[http://somevalueset]) in the questionnaire: Validation failed"));
|
||||
assertThat(errors.getMessages().get(1).getLocationString(), containsString("QuestionnaireResponse.item[0].answer[0]"));
|
||||
|
||||
qa = new QuestionnaireResponse();
|
||||
|
@ -1120,7 +1120,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
qa.addItem().setLinkId("link0").addAnswer().setValue(new Coding().setSystem("http://system").setCode(null));
|
||||
errors = myVal.validateWithResult(qa);
|
||||
ourLog.info(errors.toString());
|
||||
assertThat(errors.toString(), containsString("The value provided (http://system::null) is not in the options value set in the questionnaire"));
|
||||
assertThat(errors.toString(), containsString("ValidationResult{messageCount=1, isSuccessful=false, description="));
|
||||
assertThat(errors.toString(), containsString("QuestionnaireResponse.item[0].answer[0]"));
|
||||
|
||||
// Wrong type
|
||||
|
|
|
@ -44,7 +44,7 @@ public class CustomResourceGenerationTest extends BaseTest {
|
|||
|
||||
assertEquals(3, result.getMessages().size());
|
||||
assertEquals("Error parsing JSON: the primitive value must be a boolean", result.getMessages().get(0).getMessage());
|
||||
assertEquals("This property must be an Array, not a Primitive property", result.getMessages().get(1).getMessage());
|
||||
assertEquals("The property name must be a JSON Array, not a Primitive property (at CustomResource)", result.getMessages().get(1).getMessage());
|
||||
assertEquals("Unrecognized property 'id1'", result.getMessages().get(2).getMessage());
|
||||
|
||||
}
|
||||
|
|
|
@ -432,7 +432,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
|
|||
ValidationResult result = val.validateWithResult(operationDefinition);
|
||||
List<SingleValidationMessage> all = logResultsAndReturnAll(result);
|
||||
assertFalse(result.isSuccessful());
|
||||
assertEquals("This property must be an Array, not a Primitive property", all.get(0).getMessage());
|
||||
assertEquals("The property resource must be a JSON Array, not a Primitive property (at OperationDefinition)", all.get(0).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -57,7 +57,7 @@ public class HapiWorkerContextTest extends BaseTest {
|
|||
// Built-in Codes
|
||||
|
||||
vs.setUrl("http://hl7.org/fhir/ValueSet/fm-status");
|
||||
ValidationOptions options = new ValidationOptions().guessSystem();
|
||||
ValidationOptions options = new ValidationOptions().withGuessSystem();
|
||||
outcome = workerCtx.validateCode(options, "active", vs);
|
||||
assertEquals(true, outcome.isOk(), outcome.getMessage());
|
||||
|
||||
|
|
|
@ -609,7 +609,7 @@ public class QuestionnaireResponseValidatorR4Test {
|
|||
errors = myVal.validateWithResult(qa);
|
||||
ourLog.info(errors.toString());
|
||||
// This is set in InstanceValidator#validateAnswerCode
|
||||
assertThat(errors.toString(), containsString(" The value provided (http://system::null) is not in the options value set"));
|
||||
assertThat(errors.toString(), containsString("ValidationResult{messageCount=1, isSuccessful=false, description='"));
|
||||
assertThat(errors.toString(), containsString("QuestionnaireResponse.item[0].answer[0]"));
|
||||
|
||||
// Wrong type
|
||||
|
|
|
@ -377,7 +377,7 @@ public class FhirInstanceValidatorR4BTest extends BaseTest {
|
|||
ValidationResult result = val.validateWithResult(operationDefinition);
|
||||
List<SingleValidationMessage> all = logResultsAndReturnAll(result);
|
||||
assertFalse(result.isSuccessful());
|
||||
assertEquals("This property must be an Array, not a Primitive property", all.get(0).getMessage());
|
||||
assertEquals("The property resource must be a JSON Array, not a Primitive property (at OperationDefinition)", all.get(0).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -581,7 +581,7 @@ public class QuestionnaireResponseValidatorR5Test {
|
|||
errors = myVal.validateWithResult(qa);
|
||||
ourLog.info(errors.toString());
|
||||
// This is set in InstanceValidator#validateAnswerCode
|
||||
assertThat(errors.toString(), containsString(" The value provided (http://system::null) is not in the options value set"));
|
||||
assertThat(errors.toString(), containsString("ValidationResult{messageCount=1, isSuccessful=false, description="));
|
||||
assertThat(errors.toString(), containsString("QuestionnaireResponse.item[0].answer[0]"));
|
||||
|
||||
// Wrong type
|
||||
|
|
Loading…
Reference in New Issue