Backport
This commit is contained in:
parent
df8d2cd797
commit
abbb191928
|
@ -1,5 +1,3 @@
|
|||
package ca.uhn.fhir.model.api;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
|
@ -19,6 +17,7 @@ package ca.uhn.fhir.model.api;
|
|||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
package ca.uhn.fhir.model.api;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
|
@ -26,6 +25,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
|
|||
import org.hl7.fhir.instance.model.api.IBaseCoding;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A single tag
|
||||
|
@ -59,7 +59,7 @@ public class Tag extends BaseElement implements IElement, IBaseCoding {
|
|||
private String myScheme;
|
||||
private String myTerm;
|
||||
private String myVersion;
|
||||
private boolean myUserSelected;
|
||||
private Boolean myUserSelected;
|
||||
|
||||
public Tag() {
|
||||
}
|
||||
|
@ -114,40 +114,23 @@ public class Tag extends BaseElement implements IElement, IBaseCoding {
|
|||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
|
||||
Tag other = (Tag) obj;
|
||||
if (myScheme == null) {
|
||||
if (other.myScheme != null)
|
||||
return false;
|
||||
} else if (!myScheme.equals(other.myScheme))
|
||||
return false;
|
||||
|
||||
if (myTerm == null) {
|
||||
if (other.myTerm != null)
|
||||
return false;
|
||||
} else if (!myTerm.equals(other.myTerm))
|
||||
return false;
|
||||
|
||||
if (myVersion == null) {
|
||||
if (other.getVersion() != null)
|
||||
return false;
|
||||
} else if (!myVersion.equals(other.getVersion()))
|
||||
return false;
|
||||
|
||||
if (myUserSelected != other.getUserSelected())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return
|
||||
Objects.equals(myScheme, other.myScheme) &&
|
||||
Objects.equals(myTerm, other.myTerm) &&
|
||||
Objects.equals(myVersion, other.myVersion) &&
|
||||
Objects.equals(myUserSelected, other.myUserSelected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((myScheme == null) ? 0 : myScheme.hashCode());
|
||||
result = prime * result + ((myTerm == null) ? 0 : myTerm.hashCode());
|
||||
result = prime * result + ((myVersion == null) ? 0 : myVersion.hashCode());
|
||||
result = prime * result + Boolean.hashCode(myUserSelected);
|
||||
result = prime * result + Objects.hashCode(myScheme);
|
||||
result = prime * result + Objects.hashCode(myTerm);
|
||||
result = prime * result + Objects.hashCode(myVersion);
|
||||
result = prime * result + Objects.hashCode(myUserSelected);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -237,7 +220,9 @@ public class Tag extends BaseElement implements IElement, IBaseCoding {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean getUserSelected() { return myUserSelected; }
|
||||
public boolean getUserSelected() { return myUserSelected != null && myUserSelected; }
|
||||
|
||||
public Boolean getUserSelectedBoolean() { return myUserSelected; }
|
||||
|
||||
@Override
|
||||
public IBaseCoding setUserSelected(boolean theUserSelected) {
|
||||
|
@ -245,4 +230,8 @@ public class Tag extends BaseElement implements IElement, IBaseCoding {
|
|||
return this;
|
||||
}
|
||||
|
||||
public void setUserSelectedBoolean(Boolean theUserSelected) {
|
||||
myUserSelected = theUserSelected;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -725,73 +725,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
if (theResource instanceof IResource) {
|
||||
IResource resource = (IResource) theResource;
|
||||
// Object securityLabelRawObj =
|
||||
|
||||
List<BaseCodingDt> securityLabels = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.SECURITY_LABELS);
|
||||
List<? extends IIdType> profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
|
||||
profiles = super.getProfileTagsForEncoding(resource, profiles);
|
||||
|
||||
TagList tags = getMetaTagsForEncoding(resource, theEncodeContext);
|
||||
InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
|
||||
IdDt resourceId = resource.getId();
|
||||
String versionIdPart = resourceId.getVersionIdPart();
|
||||
if (isBlank(versionIdPart)) {
|
||||
versionIdPart = ResourceMetadataKeyEnum.VERSION.get(resource);
|
||||
}
|
||||
List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> extensionMetadataKeys = getExtensionMetadataKeys(resource);
|
||||
|
||||
if (super.shouldEncodeResourceMeta(resource) && (ElementUtil.isEmpty(versionIdPart, updated, securityLabels, tags, profiles) == false) || !extensionMetadataKeys.isEmpty()) {
|
||||
beginObject(theEventWriter, "meta");
|
||||
|
||||
if (shouldEncodePath(resource, "meta.versionId")) {
|
||||
writeOptionalTagWithTextNode(theEventWriter, "versionId", versionIdPart);
|
||||
}
|
||||
if (shouldEncodePath(resource, "meta.lastUpdated")) {
|
||||
writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", updated);
|
||||
}
|
||||
|
||||
if (profiles != null && profiles.isEmpty() == false) {
|
||||
beginArray(theEventWriter, "profile");
|
||||
for (IIdType profile : profiles) {
|
||||
if (profile != null && isNotBlank(profile.getValue())) {
|
||||
theEventWriter.write(profile.getValue());
|
||||
}
|
||||
}
|
||||
theEventWriter.endArray();
|
||||
}
|
||||
|
||||
if (securityLabels.isEmpty() == false) {
|
||||
beginArray(theEventWriter, "security");
|
||||
for (BaseCodingDt securityLabel : securityLabels) {
|
||||
theEventWriter.beginObject();
|
||||
theEncodeContext.pushPath("security", false);
|
||||
encodeCompositeElementChildrenToStreamWriter(resDef, resource, securityLabel, theEventWriter, theContainedResource, null, theEncodeContext);
|
||||
theEncodeContext.popPath();
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
theEventWriter.endArray();
|
||||
}
|
||||
|
||||
if (tags != null && tags.isEmpty() == false) {
|
||||
beginArray(theEventWriter, "tag");
|
||||
for (Tag tag : tags) {
|
||||
if (tag.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
theEventWriter.beginObject();
|
||||
writeOptionalTagWithTextNode(theEventWriter, "system", tag.getScheme());
|
||||
writeOptionalTagWithTextNode(theEventWriter, "code", tag.getTerm());
|
||||
writeOptionalTagWithTextNode(theEventWriter, "display", tag.getLabel());
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
theEventWriter.endArray();
|
||||
}
|
||||
|
||||
addExtensionMetadata(theResDef, theResource, theContainedResource, extensionMetadataKeys, resDef, theEventWriter, theEncodeContext);
|
||||
|
||||
theEventWriter.endObject(); // end meta
|
||||
}
|
||||
parseMetaForDSTU2(theResDef, theResource, theEventWriter, theContainedResource, theEncodeContext, resDef);
|
||||
}
|
||||
|
||||
encodeCompositeElementToStreamWriter(theResDef, theResource, theResource, theEventWriter, theContainedResource, new CompositeChildElement(resDef, theEncodeContext), theEncodeContext);
|
||||
|
@ -799,6 +733,77 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
theEventWriter.endObject();
|
||||
}
|
||||
|
||||
private void parseMetaForDSTU2(RuntimeResourceDefinition theResDef, IBaseResource theResource, BaseJsonLikeWriter theEventWriter, boolean theContainedResource, EncodeContext theEncodeContext, RuntimeResourceDefinition resDef) throws IOException {
|
||||
IResource resource = (IResource) theResource;
|
||||
// Object securityLabelRawObj =
|
||||
|
||||
List<BaseCodingDt> securityLabels = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.SECURITY_LABELS);
|
||||
List<? extends IIdType> profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
|
||||
profiles = super.getProfileTagsForEncoding(resource, profiles);
|
||||
|
||||
TagList tags = getMetaTagsForEncoding(resource, theEncodeContext);
|
||||
InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
|
||||
IdDt resourceId = resource.getId();
|
||||
String versionIdPart = resourceId.getVersionIdPart();
|
||||
if (isBlank(versionIdPart)) {
|
||||
versionIdPart = ResourceMetadataKeyEnum.VERSION.get(resource);
|
||||
}
|
||||
List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> extensionMetadataKeys = getExtensionMetadataKeys(resource);
|
||||
|
||||
if (super.shouldEncodeResourceMeta(resource) && (ElementUtil.isEmpty(versionIdPart, updated, securityLabels, tags, profiles) == false) || !extensionMetadataKeys.isEmpty()) {
|
||||
beginObject(theEventWriter, "meta");
|
||||
|
||||
if (shouldEncodePath(resource, "meta.versionId")) {
|
||||
writeOptionalTagWithTextNode(theEventWriter, "versionId", versionIdPart);
|
||||
}
|
||||
if (shouldEncodePath(resource, "meta.lastUpdated")) {
|
||||
writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", updated);
|
||||
}
|
||||
|
||||
if (profiles != null && profiles.isEmpty() == false) {
|
||||
beginArray(theEventWriter, "profile");
|
||||
for (IIdType profile : profiles) {
|
||||
if (profile != null && isNotBlank(profile.getValue())) {
|
||||
theEventWriter.write(profile.getValue());
|
||||
}
|
||||
}
|
||||
theEventWriter.endArray();
|
||||
}
|
||||
|
||||
if (securityLabels.isEmpty() == false) {
|
||||
beginArray(theEventWriter, "security");
|
||||
for (BaseCodingDt securityLabel : securityLabels) {
|
||||
theEventWriter.beginObject();
|
||||
theEncodeContext.pushPath("security", false);
|
||||
encodeCompositeElementChildrenToStreamWriter(resDef, resource, securityLabel, theEventWriter, theContainedResource, null, theEncodeContext);
|
||||
theEncodeContext.popPath();
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
theEventWriter.endArray();
|
||||
}
|
||||
|
||||
if (tags != null && tags.isEmpty() == false) {
|
||||
beginArray(theEventWriter, "tag");
|
||||
for (Tag tag : tags) {
|
||||
if (tag.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
theEventWriter.beginObject();
|
||||
writeOptionalTagWithTextNode(theEventWriter, "system", tag.getScheme());
|
||||
writeOptionalTagWithTextNode(theEventWriter, "code", tag.getTerm());
|
||||
writeOptionalTagWithTextNode(theEventWriter, "display", tag.getLabel());
|
||||
// wipmb should we be writing the new properties here? There must be another path.
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
theEventWriter.endArray();
|
||||
}
|
||||
|
||||
addExtensionMetadata(theResDef, theResource, theContainedResource, extensionMetadataKeys, resDef, theEventWriter, theEncodeContext);
|
||||
|
||||
theEventWriter.endObject(); // end meta
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void addExtensionMetadata(RuntimeResourceDefinition theResDef, IBaseResource theResource,
|
||||
boolean theContainedResource,
|
||||
|
|
|
@ -120,7 +120,9 @@ public enum VersionEnum {
|
|||
V6_4_4,
|
||||
V6_4_5,
|
||||
V6_5_0,
|
||||
V6_6_0
|
||||
V6_6_0,
|
||||
V6_7_0,
|
||||
V6_8_0
|
||||
;
|
||||
|
||||
public static VersionEnum latestVersion() {
|
||||
|
|
|
@ -27,7 +27,7 @@ public class TagTest {
|
|||
@Test
|
||||
public void testHashCode() {
|
||||
Tag tag1 = new Tag().setScheme("scheme").setTerm("term").setLabel("label");
|
||||
assertEquals(-1029266947, tag1.hashCode());
|
||||
assertEquals(-1029268184, tag1.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -273,7 +273,9 @@ public class VersionCanonicalizer {
|
|||
retVal.setSystem(coding.getSystem());
|
||||
retVal.setDisplay(coding.getDisplay());
|
||||
retVal.setVersion(coding.getVersion());
|
||||
retVal.setUserSelected( ! coding.getUserSelectedElement().isEmpty() && coding.getUserSelected() );
|
||||
if (!coding.getUserSelectedElement().isEmpty()) {
|
||||
retVal.setUserSelected( coding.getUserSelected() );
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
|
|
@ -245,6 +245,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
private IFulltextSearchSvc myFulltextSearchSvc;
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTransactionManager;
|
||||
|
||||
protected final CodingSpy myCodingSpy = new CodingSpy();
|
||||
|
||||
@Autowired
|
||||
protected IJpaStorageResourceParser myJpaStorageResourceParser;
|
||||
|
||||
|
@ -279,7 +282,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
if (tagList != null) {
|
||||
for (Tag next : tagList) {
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.TAG, next.getScheme(), next.getTerm(),
|
||||
next.getLabel(), next.getVersion(), next.getUserSelected());
|
||||
next.getLabel(), next.getVersion(), myCodingSpy.getBooleanObject(next));
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
allDefs.add(tag);
|
||||
|
@ -319,7 +322,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
if (tagList != null) {
|
||||
for (IBaseCoding next : tagList) {
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.TAG, next.getSystem(), next.getCode(),
|
||||
next.getDisplay(), next.getVersion(), next.getUserSelected());
|
||||
next.getDisplay(), next.getVersion(), myCodingSpy.getBooleanObject(next));
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
theAllTags.add(tag);
|
||||
|
@ -331,7 +334,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(), null, null);
|
||||
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.SECURITY_LABEL, next.getSystem(), next.getCode(), next.getDisplay(), next.getVersion(), myCodingSpy.getBooleanObject(next));
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
theAllTags.add(tag);
|
||||
|
@ -390,7 +393,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
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);
|
||||
|
@ -421,6 +423,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
String theVersion, Boolean theUserSelected) {
|
||||
|
||||
TypedQuery<TagDefinition> q = buildTagQuery(theTagType, theScheme, theTerm, theVersion, theUserSelected);
|
||||
q.setMaxResults(1);
|
||||
|
||||
TransactionTemplate template = new TransactionTemplate(myTransactionManager);
|
||||
template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
|
@ -462,7 +465,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
"Tag read/write failed: "
|
||||
+ ex.getMessage() + ". "
|
||||
+ "This is not a failure on its own, "
|
||||
+ "but could be useful information in the result of an actual failure."
|
||||
+ "but could be useful information in the result of an actual failure.", ex
|
||||
);
|
||||
throwables.add(ex);
|
||||
}
|
||||
|
@ -521,9 +524,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
? 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")));
|
||||
predicates.add( isNull(theUserSelected)
|
||||
? builder.isNull(from.get("myUserSelected"))
|
||||
: builder.equal(from.get("myUserSelected"), theUserSelected));
|
||||
|
||||
cq.where(predicates.toArray(new Predicate[0]));
|
||||
return myEntityManager.createQuery(cq);
|
||||
|
@ -552,7 +555,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns true if the resource has changed (either the contents or the tags)
|
||||
* Returns {@literal true} if the resource has changed (either the contents or the tags)
|
||||
*/
|
||||
protected EncodedResource populateResourceIntoEntity(TransactionDetails theTransactionDetails, RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, boolean thePerformIndexing) {
|
||||
if (theEntity.getResourceType() == null) {
|
||||
|
@ -794,6 +797,18 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
|
||||
});
|
||||
|
||||
// Update the resource to contain the old tags
|
||||
allTagsOld.forEach(tag -> {
|
||||
IBaseCoding iBaseCoding = theResource.getMeta()
|
||||
.addTag()
|
||||
.setCode(tag.getTag().getCode())
|
||||
.setSystem(tag.getTag().getSystem())
|
||||
.setVersion(tag.getTag().getVersion());
|
||||
if (tag.getTag().getUserSelected() != null) {
|
||||
iBaseCoding.setUserSelected(tag.getTag().getUserSelected());
|
||||
}
|
||||
});
|
||||
|
||||
theEntity.setHasTags(!allTagsNew.isEmpty());
|
||||
return !allTagsOld.equals(allTagsNew);
|
||||
}
|
||||
|
|
|
@ -763,6 +763,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (!hasTag) {
|
||||
theEntity.setHasTags(true);
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceEncodingEnum;
|
|||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTag;
|
||||
import ca.uhn.fhir.jpa.model.entity.TagDefinition;
|
||||
import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
|
||||
import ca.uhn.fhir.jpa.partition.IPartitionLookupSvc;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
|
@ -73,6 +74,7 @@ import java.util.List;
|
|||
|
||||
import static ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.cleanProvenanceSourceUri;
|
||||
import static ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.decodeResource;
|
||||
import static java.util.Objects.nonNull;
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
|
@ -348,19 +350,26 @@ public class JpaStorageResourceParser implements IJpaStorageResourceParser {
|
|||
List<IBaseCoding> securityLabels = new ArrayList<>();
|
||||
List<IdDt> profiles = new ArrayList<>();
|
||||
for (BaseTag next : theTagList) {
|
||||
switch (next.getTag().getTagType()) {
|
||||
TagDefinition nextTag = next.getTag();
|
||||
switch (nextTag.getTagType()) {
|
||||
case PROFILE:
|
||||
profiles.add(new IdDt(next.getTag().getCode()));
|
||||
profiles.add(new IdDt(nextTag.getCode()));
|
||||
break;
|
||||
case SECURITY_LABEL:
|
||||
IBaseCoding secLabel = (IBaseCoding) myContext.getVersion().newCodingDt();
|
||||
secLabel.setSystem(next.getTag().getSystem());
|
||||
secLabel.setCode(next.getTag().getCode());
|
||||
secLabel.setDisplay(next.getTag().getDisplay());
|
||||
secLabel.setSystem(nextTag.getSystem());
|
||||
secLabel.setCode(nextTag.getCode());
|
||||
secLabel.setDisplay(nextTag.getDisplay());
|
||||
// wipmb these technically support userSelected and version
|
||||
securityLabels.add(secLabel);
|
||||
break;
|
||||
case TAG:
|
||||
tagList.add(new Tag(next.getTag().getSystem(), next.getTag().getCode(), next.getTag().getDisplay()));
|
||||
// wipmb check xml, etc.
|
||||
Tag e = new Tag(nextTag.getSystem(), nextTag.getCode(), nextTag.getDisplay());
|
||||
e.setVersion(nextTag.getVersion());
|
||||
// careful! These are Boolean, not boolean.
|
||||
e.setUserSelectedBoolean(nextTag.getUserSelected());
|
||||
tagList.add(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -432,7 +441,12 @@ public class JpaStorageResourceParser implements IJpaStorageResourceParser {
|
|||
tag.setCode(next.getTag().getCode());
|
||||
tag.setDisplay(next.getTag().getDisplay());
|
||||
tag.setVersion(next.getTag().getVersion());
|
||||
tag.setUserSelected(next.getTag().getUserSelected());
|
||||
Boolean userSelected = next.getTag().getUserSelected();
|
||||
// the tag is created with a null userSelected, but the api is primitive boolean.
|
||||
// Only update if we are non-null.
|
||||
if (nonNull(userSelected)) {
|
||||
tag.setUserSelected(userSelected);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
package ca.uhn.fhir.jpa.migrate.tasks;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -19,8 +17,11 @@ package ca.uhn.fhir.jpa.migrate.tasks;
|
|||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
package ca.uhn.fhir.jpa.migrate.tasks;
|
||||
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.entity.BulkExportJobEntity;
|
||||
import ca.uhn.fhir.jpa.entity.BulkImportJobEntity;
|
||||
import ca.uhn.fhir.jpa.entity.Search;
|
||||
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||
import ca.uhn.fhir.jpa.migrate.taskdef.ArbitrarySqlTask;
|
||||
|
@ -37,8 +38,11 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
|||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.model.entity.SearchParamPresentEntity;
|
||||
import ca.uhn.fhir.util.ClasspathUtil;
|
||||
import ca.uhn.fhir.util.VersionEnum;
|
||||
import software.amazon.awssdk.utils.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
|
@ -49,7 +53,8 @@ import java.util.Optional;
|
|||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings({"SqlNoDataSourceInspection", "SpellCheckingInspection"})
|
||||
|
||||
@SuppressWarnings({"SqlNoDataSourceInspection", "SpellCheckingInspection", "java:S1192"})
|
||||
public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||
|
||||
// H2, Derby, MariaDB, and MySql automatically add indexes to foreign keys
|
||||
|
@ -87,13 +92,51 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
|||
init600(); // 20211102 -
|
||||
init610();
|
||||
init620();
|
||||
init630();
|
||||
init640();
|
||||
init640_after_20230126();
|
||||
init660();
|
||||
init680();
|
||||
}
|
||||
|
||||
protected void init640() {
|
||||
protected void init680() {
|
||||
Builder version = forVersion(VersionEnum.V6_8_0);
|
||||
|
||||
// HAPI-FHIR #4801 - Add New Index On HFJ_RESOURCE
|
||||
Builder.BuilderWithTableName resourceTable = version.onTable("HFJ_RESOURCE");
|
||||
resourceTable
|
||||
.addIndex("20230502.1", "IDX_RES_RESID_UPDATED")
|
||||
.unique(false)
|
||||
.online(true)
|
||||
.withColumns("RES_ID", "RES_UPDATED", "PARTITION_ID");
|
||||
|
||||
Builder.BuilderWithTableName tagDefTable = version.onTable("HFJ_TAG_DEF");
|
||||
tagDefTable.dropIndex("20230505.1", "IDX_TAGDEF_TYPESYSCODEVERUS");
|
||||
|
||||
tagDefTable.dropIndex("20230505.2", "IDX_TAG_DEF_TP_CD_SYS");
|
||||
tagDefTable
|
||||
.addIndex("20230505.3", "IDX_TAG_DEF_TP_CD_SYS")
|
||||
.unique(false)
|
||||
.online(false)
|
||||
.withColumns("TAG_TYPE", "TAG_CODE", "TAG_SYSTEM", "TAG_ID", "TAG_VERSION", "TAG_USER_SELECTED");
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected void init660() {
|
||||
Builder version = forVersion(VersionEnum.V6_6_0);
|
||||
|
||||
// fix Postgres clob types - that stupid oid driver problem is still there
|
||||
// BT2_JOB_INSTANCE.PARAMS_JSON_LOB
|
||||
version.onTable("BT2_JOB_INSTANCE")
|
||||
.migratePostgresTextClobToBinaryClob("20230208.1", "PARAMS_JSON_LOB");
|
||||
// BT2_JOB_INSTANCE.REPORT
|
||||
version.onTable("BT2_JOB_INSTANCE")
|
||||
.migratePostgresTextClobToBinaryClob("20230208.2", "REPORT");
|
||||
// BT2_WORK_CHUNK.CHUNK_DATA
|
||||
version.onTable("BT2_WORK_CHUNK")
|
||||
.migratePostgresTextClobToBinaryClob("20230208.3", "CHUNK_DATA");
|
||||
|
||||
{
|
||||
Builder.BuilderWithTableName tagDefTable = version.onTable("HFJ_TAG_DEF");
|
||||
|
||||
|
@ -120,6 +163,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
|||
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_UUID")
|
||||
|
@ -137,20 +181,20 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
|||
.type(ColumnTypeEnum.STRING, 36);
|
||||
|
||||
|
||||
Builder.BuilderAddTableByColumns resSearchUrlTable = version.addTableByColumns("20230227.1", "HFJ_RES_SEARCH_URL", "RES_SEARCH_URL");
|
||||
Builder.BuilderAddTableByColumns resSearchUrlTable = version.addTableByColumns("20230227.1","HFJ_RES_SEARCH_URL", "RES_SEARCH_URL");
|
||||
|
||||
resSearchUrlTable.addColumn("RES_SEARCH_URL").nonNullable().type(ColumnTypeEnum.STRING, 768);
|
||||
resSearchUrlTable.addColumn("RES_ID").nonNullable().type(ColumnTypeEnum.LONG);
|
||||
resSearchUrlTable.addColumn( "RES_SEARCH_URL").nonNullable().type(ColumnTypeEnum.STRING, 768);
|
||||
resSearchUrlTable.addColumn( "RES_ID").nonNullable().type(ColumnTypeEnum.LONG);
|
||||
|
||||
resSearchUrlTable.addColumn("CREATED_TIME").nonNullable().type(ColumnTypeEnum.DATE_TIMESTAMP);
|
||||
resSearchUrlTable.addColumn( "CREATED_TIME").nonNullable().type(ColumnTypeEnum.DATE_TIMESTAMP);
|
||||
|
||||
resSearchUrlTable.addIndex("20230227.2", "IDX_RESSEARCHURL_RES").unique(false).withColumns("RES_ID");
|
||||
resSearchUrlTable.addIndex("20230227.3", "IDX_RESSEARCHURL_TIME").unique(false).withColumns("CREATED_TIME");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void init630() {
|
||||
protected void init640() {
|
||||
Builder version = forVersion(VersionEnum.V6_3_0);
|
||||
|
||||
// start forced_id inline migration
|
||||
|
@ -171,6 +215,15 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
|||
.onlyAppliesToPlatforms(NON_AUTOMATIC_FK_INDEX_PLATFORMS);
|
||||
}
|
||||
|
||||
protected void init640_after_20230126() {
|
||||
Builder version = forVersion(VersionEnum.V6_3_0);
|
||||
{ //We added this constraint when userSelected and Version were added. It is no longer necessary.
|
||||
Builder.BuilderWithTableName tagDefTable = version.onTable("HFJ_TAG_DEF");
|
||||
tagDefTable.dropIndex("20230503.1", "IDX_TAGDEF_TYPESYSCODEVERUS");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void init620() {
|
||||
Builder version = forVersion(VersionEnum.V6_2_0);
|
||||
|
||||
|
|
|
@ -47,11 +47,7 @@ import java.util.Collection;
|
|||
@Table(
|
||||
name = "HFJ_TAG_DEF",
|
||||
indexes = {
|
||||
@Index(name = "IDX_TAG_DEF_TP_CD_SYS", columnList = "TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_ID"),
|
||||
},
|
||||
uniqueConstraints = {
|
||||
@UniqueConstraint(name = "IDX_TAGDEF_TYPESYSCODEVERUS",
|
||||
columnNames = {"TAG_TYPE", "TAG_SYSTEM", "TAG_CODE", "TAG_VERSION", "TAG_USER_SELECTED"})
|
||||
@Index(name = "IDX_TAG_DEF_TP_CD_SYS", columnList = "TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_ID, TAG_VERSION, TAG_USER_SELECTED"),
|
||||
}
|
||||
)
|
||||
public class TagDefinition implements Serializable {
|
||||
|
@ -162,14 +158,16 @@ public class TagDefinition implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning - this is nullable, while IBaseCoding getUserSelected isn't.
|
||||
* wipmb maybe rename?
|
||||
*/
|
||||
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;
|
||||
return myUserSelected;
|
||||
}
|
||||
|
||||
public void setUserSelected(Boolean theUserSelected) {
|
||||
myUserSelected = theUserSelected != null && theUserSelected;
|
||||
myUserSelected = theUserSelected;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ 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 ch.qos.logback.classic.Level;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
|
@ -41,6 +42,8 @@ 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.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
|
@ -153,6 +156,30 @@ public class FhirResourceDaoR4MetaTest extends BaseJpaR4Test {
|
|||
assertEquals("bar", patient2.getMeta().getSecurityFirstRep().getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure round-trips with tags don't add a userSelected property.
|
||||
* wipmb tag userSelected test
|
||||
* Verify https://github.com/hapifhir/hapi-fhir/issues/4819
|
||||
*/
|
||||
@Test
|
||||
void testAddTag_userSelectedStaysNull() {
|
||||
// given
|
||||
Patient patient1 = new Patient();
|
||||
patient1.getMeta().addTag().setSystem("http://foo").setCode("bar");
|
||||
patient1.setActive(true);
|
||||
IIdType pid1 = myPatientDao.create(patient1).getId();
|
||||
|
||||
// when
|
||||
var patientReadback = myPatientDao.read(pid1);
|
||||
ourLog.debug(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(patientReadback));
|
||||
|
||||
// then
|
||||
var tag = patientReadback.getMeta().getTag().get(0);
|
||||
assertNotNull(tag);
|
||||
assertNull(tag.getUserSelectedElement().asStringValue());
|
||||
}
|
||||
|
||||
|
||||
@Nested
|
||||
public class TestTagWithVersionAndUserSelected {
|
||||
|
||||
|
@ -204,6 +231,7 @@ public class FhirResourceDaoR4MetaTest extends BaseJpaR4Test {
|
|||
.setSystem(expectedSystem1)
|
||||
.setCode(expectedCode1)
|
||||
.setDisplay(expectedDisplay1);
|
||||
assertNull(newTag.getUserSelectedElement().asStringValue());
|
||||
assertFalse(newTag.getUserSelected());
|
||||
newTag.setVersion(expectedVersion1)
|
||||
.setUserSelected(expectedUserSelected1);
|
||||
|
|
|
@ -5,6 +5,8 @@ import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
|||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.model.entity.TagDefinition;
|
||||
import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
|
||||
|
@ -96,6 +98,33 @@ public class FhirResourceDaoR4UpdateTest extends BaseJpaR4Test {
|
|||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTagCollision() {
|
||||
TagDefinition def = new TagDefinition();
|
||||
def.setTagType(TagTypeEnum.TAG);
|
||||
def.setSystem("system");
|
||||
def.setCode("coding");
|
||||
def.setDisplay("display");
|
||||
def.setUserSelected(null);
|
||||
|
||||
|
||||
Patient p = new Patient();
|
||||
p.getMeta().addTag("system", "coding", "display");
|
||||
|
||||
myMemoryCacheService.invalidateAllCaches();
|
||||
myPatientDao.create(p, new SystemRequestDetails());
|
||||
//inject conflicting.
|
||||
myTagDefinitionDao.saveAndFlush(def);
|
||||
myMemoryCacheService.invalidateAllCaches();
|
||||
|
||||
myPatientDao.create(p, new SystemRequestDetails());
|
||||
myMemoryCacheService.invalidateAllCaches();
|
||||
|
||||
myPatientDao.create(p, new SystemRequestDetails());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateAndUpdateWithoutRequest() {
|
||||
String methodName = "testUpdateByUrl";
|
||||
|
|
Loading…
Reference in New Issue