Skip to content

Commit

Permalink
Improve error message on unique constraint violation (hapifhir#2182)
Browse files Browse the repository at this point in the history
* Improve error message on unique constraint violation

* Add changelog

* Test fixes

* Test fix
  • Loading branch information
jamesagnew authored and HananAwwad committed Jan 6, 2021
1 parent b0f16db commit 1aa64d3
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 8 deletions.
Expand Up @@ -80,7 +80,7 @@ ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.invalidMatchUrlMultipleMatches=Invalid match
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.transactionOperationWithMultipleMatchFailure=Failed to {0} resource with match URL "{1}" because this search matched {2} resources
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.transactionOperationFailedNoId=Failed to {0} resource in transaction because no ID was provided
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.transactionOperationFailedUnknownId=Failed to {0} resource in transaction because no resource could be found with ID {1}
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.uniqueIndexConflictFailure=Can not create resource of type {0} as it would create a duplicate index matching query: {1} (existing index belongs to {2})
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.uniqueIndexConflictFailure=Can not create resource of type {0} as it would create a duplicate unique index matching query: {1} (existing index belongs to {2}, new unique index created by {3})

ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao.transactionContainsMultipleWithDuplicateId=Transaction bundle contains multiple resources with ID: {0}
ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao.transactionEntryHasInvalidVerb=Transaction bundle entry has missing or invalid HTTP Verb specified in Bundle.entry({1}).request.method. Found value: "{0}"
Expand Down
@@ -0,0 +1,5 @@
---
type: add
issue: 2182
title: "When a unique index SearchParametr violation is blocked, the error message will now include the ID of the relevant
SearchParameter, in order to make troubleshooting easier."
Expand Up @@ -206,7 +206,7 @@ private void extractCompositeStringUniques(ResourceTable theEntity, ResourceInde
for (String nextQueryString : queryStringsToPopulate) {
if (isNotBlank(nextQueryString)) {
ourLog.trace("Adding composite unique SP: {}", nextQueryString);
theParams.myCompositeStringUniques.add(new ResourceIndexedCompositeStringUnique(theEntity, nextQueryString));
theParams.myCompositeStringUniques.add(new ResourceIndexedCompositeStringUnique(theEntity, nextQueryString, next.getId()));
}
}
}
Expand Down Expand Up @@ -289,7 +289,13 @@ public void storeCompositeStringUniques(ResourceIndexedSearchParams theParams, R
if (myDaoConfig.isUniqueIndexesCheckedBeforeSave()) {
ResourceIndexedCompositeStringUnique existing = myResourceIndexedCompositeStringUniqueDao.findByQueryString(next.getIndexString());
if (existing != null) {
String msg = myContext.getLocalizer().getMessage(BaseHapiFhirDao.class, "uniqueIndexConflictFailure", theEntity.getResourceType(), next.getIndexString(), existing.getResource().getIdDt().toUnqualifiedVersionless().getValue());

String searchParameterId = "(unknown)";
if (next.getSearchParameterId() != null) {
searchParameterId = next.getSearchParameterId().toUnqualifiedVersionless().getValue();
}

String msg = myContext.getLocalizer().getMessage(BaseHapiFhirDao.class, "uniqueIndexConflictFailure", theEntity.getResourceType(), next.getIndexString(), existing.getResource().getIdDt().toUnqualifiedVersionless().getValue(), searchParameterId);
throw new PreconditionFailedException(msg);
}
}
Expand Down
Expand Up @@ -139,7 +139,7 @@ public void testCreateWithUniqueConstraint() {
myPatientDao.create(p);
} catch (PreconditionFailedException e) {
// expected - This is as a result of the unique SP
assertThat(e.getMessage(), containsString("duplicate index matching query: Patient?gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale"));
assertThat(e.getMessage(), containsString("duplicate unique index matching query: Patient?gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale"));
} catch (ResourceVersionConflictException e) {
// expected - This is as a result of the unique SP
assertThat(e.getMessage(), containsString("would have resulted in a duplicate value for a unique index"));
Expand Down
Expand Up @@ -803,7 +803,7 @@ public void testDuplicateUniqueValuesAreRejectedWithChecking_TestingEnabled() {
myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
fail();
} catch (PreconditionFailedException e) {
assertEquals("Can not create resource of type Patient as it would create a duplicate index matching query: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale (existing index belongs to Patient/" + id1.getIdPart() + ")", e.getMessage());
assertEquals("Can not create resource of type Patient as it would create a duplicate unique index matching query: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale (existing index belongs to Patient/" + id1.getIdPart() + ", new unique index created by SearchParameter/patient-gender-birthdate)", e.getMessage());
}
}

Expand Down Expand Up @@ -1510,7 +1510,7 @@ public void testDuplicateUniqueValuesAreRejected() {
myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
fail();
} catch (PreconditionFailedException e) {
// good
assertThat(e.getMessage(), containsString("new unique index created by SearchParameter/patient-gender-birthdate"));
}

Patient pt2 = new Patient();
Expand All @@ -1525,7 +1525,7 @@ public void testDuplicateUniqueValuesAreRejected() {
myPatientDao.update(pt2);
fail();
} catch (PreconditionFailedException e) {
// good
assertThat(e.getMessage(), containsString("new unique index created by SearchParameter/patient-gender-birthdate"));
}

}
Expand Down
Expand Up @@ -26,6 +26,7 @@
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.instance.model.api.IIdType;

import javax.persistence.*;

Expand Down Expand Up @@ -59,6 +60,8 @@ public class ResourceIndexedCompositeStringUnique extends BasePartitionable impl
@SuppressWarnings("unused")
@Column(name = PartitionablePartitionId.PARTITION_ID, insertable = false, updatable = false, nullable = true)
private Integer myPartitionIdValue;
@Transient
private IIdType mySearchParameterId;

/**
* Constructor
Expand All @@ -70,10 +73,11 @@ public ResourceIndexedCompositeStringUnique() {
/**
* Constructor
*/
public ResourceIndexedCompositeStringUnique(ResourceTable theResource, String theIndexString) {
public ResourceIndexedCompositeStringUnique(ResourceTable theResource, String theIndexString, IIdType theSearchParameterId) {
setResource(theResource);
setIndexString(theIndexString);
setPartitionId(theResource.getPartitionId());
setSearchParameterId(theSearchParameterId);
}

@Override
Expand Down Expand Up @@ -131,4 +135,18 @@ public String toString() {
.append("partition", getPartitionId())
.toString();
}

/**
* Note: This field is not persisted, so it will only be populated for new indexes
*/
public void setSearchParameterId(IIdType theSearchParameterId) {
mySearchParameterId = theSearchParameterId;
}

/**
* Note: This field is not persisted, so it will only be populated for new indexes
*/
public IIdType getSearchParameterId() {
return mySearchParameterId;
}
}

0 comments on commit 1aa64d3

Please sign in to comment.