Work on sort support in JPA

This commit is contained in:
jamesagnew 2015-03-09 08:01:13 -04:00
parent da1d49a108
commit 5fd987c497
5 changed files with 112 additions and 31 deletions

View File

@ -107,18 +107,20 @@ public class SortSpec {
* Sets the chained sort specification, or <code>null</code> if none. If multiple sort parameters are chained
* (indicating a sub-sort), the second level sort is chained via this property.
*/
public void setChain(SortSpec theChain) {
public SortSpec setChain(SortSpec theChain) {
if (theChain == this) {
throw new IllegalArgumentException("Can not chain this to itself");
}
myChain = theChain;
return this;
}
/**
* Sets the actual name of the search param to sort by
*/
public void setParamName(String theFieldName) {
public SortSpec setParamName(String theFieldName) {
myParamName = theFieldName;
return this;
}
/**
@ -126,8 +128,9 @@ public class SortSpec {
* means {@link SortOrderEnum#ASC} according to the <a
* href="http://hl7.org/implement/standards/fhir/search.html#sort">FHIR specification</a>)
*/
public void setOrder(SortOrderEnum theOrder) {
public SortSpec setOrder(SortOrderEnum theOrder) {
myOrder = theOrder;
return this;
}
}

View File

@ -51,6 +51,7 @@ import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.IBaseResource;
import org.springframework.beans.factory.annotation.Autowired;
@ -96,6 +97,7 @@ import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.CompositeParam;
import ca.uhn.fhir.rest.param.DateParam;
@ -871,21 +873,34 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
throw new InvalidRequestException("Unknown sort parameter '" + theSort.getParamName() + "'");
}
String joinAttrName = "myParamsString";
String sortAttrName = "myValueExact";
String joinAttrName;
String sortAttrName;
switch (param.getParamType()) {
case STRING: {
From<?, ?> stringJoin = theFrom.join(joinAttrName, JoinType.LEFT);
Predicate p = theBuilder.equal(stringJoin.get("myParamName"), theSort.getParamName());
Predicate pn = theBuilder.isNull(stringJoin.get("myParamName"));
thePredicates.add(theBuilder.or(p, pn));
theOrders.add(theBuilder.asc(stringJoin.get(sortAttrName)));
case STRING:
joinAttrName = "myParamsString";
sortAttrName = "myValueExact";
break;
}
case DATE:
joinAttrName = "myParamsDate";
sortAttrName = "myValueLow";
break;
default:
throw new NotImplementedException("This server does not support _sort specifications of type " + param.getParamType() + " - Can't serve _sort=" + theSort.getParamName());
}
createSort(theBuilder, theFrom, theSort.getChain(), theOrders, thePredicates);
From<?, ?> stringJoin = theFrom.join(joinAttrName, JoinType.LEFT);
// Predicate p = theBuilder.equal(stringJoin.get("myParamName"), theSort.getParamName());
// Predicate pn = theBuilder.isNull(stringJoin.get("myParamName"));
// thePredicates.add(theBuilder.or(p, pn));
if (theSort.getOrder() == null || theSort.getOrder() == SortOrderEnum.ASC) {
theOrders.add(theBuilder.asc(stringJoin.get(sortAttrName)));
}else {
theOrders.add(theBuilder.desc(stringJoin.get(sortAttrName)));
}
createSort(theBuilder, theFrom, theSort.getChain(), theOrders, null);
}
@Override

View File

@ -28,9 +28,13 @@ import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
//@formatter:off
@Entity
@Table(name = "HFJ_SPIDX_DATE" /*, indexes= {@Index(name="IDX_SP_DATE", columnList= "SP_VALUE_LOW,SP_VALUE_HIGH")}*/)
@org.hibernate.annotations.Table(appliesTo = "HFJ_SPIDX_DATE", indexes= {@org.hibernate.annotations.Index(name="IDX_SP_DATE", columnNames= {"RES_TYPE", "SP_NAME", "SP_VALUE_LOW","SP_VALUE_HIGH"})})
@org.hibernate.annotations.Table(appliesTo = "HFJ_SPIDX_DATE", indexes= {
@org.hibernate.annotations.Index(name="IDX_SP_DATE", columnNames= {"RES_TYPE", "SP_NAME", "SP_VALUE_LOW","SP_VALUE_HIGH"})
})
//@formatter:on
public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchParam {
private static final long serialVersionUID = 1L;

View File

@ -1,11 +1,6 @@
package ca.uhn.fhir.jpa.dao;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@ -60,6 +55,7 @@ import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.CompositeParam;
import ca.uhn.fhir.rest.param.DateParam;
@ -303,11 +299,11 @@ public class FhirResourceDaoTest {
{
Set<Long> found = ourObservationDao.searchForIds(Observation.SP_DATE, new DateParam(">2001-01-02"));
assertThat(found, contains(id2.getIdPartAsLong()));
assertThat(found, hasItem(id2.getIdPartAsLong()));
}
{
Set<Long> found = ourObservationDao.searchForIds(Observation.SP_DATE, new DateParam(">2016-01-02"));
assertThat(found, not(contains(id2.getIdPartAsLong())));
assertThat(found, not(hasItem(id2.getIdPartAsLong())));
}
}
@ -722,14 +718,23 @@ public class FhirResourceDaoTest {
@Test
public void testPersistSearchParamDate() {
List<Patient> found = toList(ourPatientDao.search(Patient.SP_BIRTHDATE, new DateParam(QuantityCompararatorEnum.GREATERTHAN, "2000-01-01")));
int initialSize2000 = found.size();
found = toList(ourPatientDao.search(Patient.SP_BIRTHDATE, new DateParam(QuantityCompararatorEnum.GREATERTHAN, "2002-01-01")));
int initialSize2002 = found.size();
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.setBirthDate(new DateDt("2001-01-01"));
ourPatientDao.create(patient);
List<Patient> found = toList(ourPatientDao.search(Patient.SP_BIRTHDATE, new DateParam(QuantityCompararatorEnum.GREATERTHAN, "2000-01-01")));
assertEquals(1, found.size());
found = toList(ourPatientDao.search(Patient.SP_BIRTHDATE, new DateParam(QuantityCompararatorEnum.GREATERTHAN, "2000-01-01")));
assertEquals(1 + initialSize2000, found.size());
found = toList(ourPatientDao.search(Patient.SP_BIRTHDATE, new DateParam(QuantityCompararatorEnum.GREATERTHAN, "2002-01-01")));
assertEquals(initialSize2002, found.size());
// If this throws an exception, that would be an acceptable outcome as well..
found = toList(ourPatientDao.search(Patient.SP_BIRTHDATE + "AAAA", new DateParam(QuantityCompararatorEnum.GREATERTHAN, "2000-01-01")));
@ -1487,35 +1492,86 @@ public class FhirResourceDaoTest {
}
@Test
public void testSort() {
public void testSortByString() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testSort001");
p.addIdentifier().setSystem("urn:system").setValue("testSortByString");
p.addName().addFamily("testSortF1").addGiven("testSortG1");
IdDt id1 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
// Create out of order
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testSort001");
p.addIdentifier().setSystem("urn:system").setValue("testSortByString");
p.addName().addFamily("testSortF3").addGiven("testSortG3");
IdDt id3 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testSort001");
p.addIdentifier().setSystem("urn:system").setValue("testSortByString");
p.addName().addFamily("testSortF2").addGiven("testSortG2");
IdDt id2 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testSort001");
p.addIdentifier().setSystem("urn:system").setValue("testSortByString");
IdDt id4 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
SearchParameterMap pm = new SearchParameterMap();
pm.add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", "testSort001"));
pm.add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", "testSortByString"));
pm.setSort(new SortSpec(Patient.SP_FAMILY));
List<IdDt> actual = toUnqualifiedVersionlessIds(ourPatientDao.search(pm));
assertEquals(4, actual.size());
assertThat(actual, contains(id1, id2, id3, id4));
}
@Test
public void testSortByDate() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testtestSortByDate");
p.addName().addFamily("testSortF1").addGiven("testSortG1");
p.setBirthDate(new DateDt("2001-01-01"));
IdDt id1 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
// Create out of order
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testtestSortByDate");
p.addName().addFamily("testSortF2").addGiven("testSortG2");
p.setBirthDate(new DateDt("2001-01-03"));
IdDt id3 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testtestSortByDate");
p.addName().addFamily("testSortF3").addGiven("testSortG3");
p.setBirthDate(new DateDt("2001-01-02"));
IdDt id2 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testtestSortByDate");
IdDt id4 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
List<IdDt> actual;
SearchParameterMap pm;
pm = new SearchParameterMap();
pm.add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", "testtestSortByDate"));
pm.setSort(new SortSpec(Patient.SP_BIRTHDATE));
actual = toUnqualifiedVersionlessIds(ourPatientDao.search(pm));
assertEquals(4, actual.size());
assertThat(actual, contains(id1, id2, id3, id4));
pm = new SearchParameterMap();
pm.add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", "testtestSortByDate"));
pm.setSort(new SortSpec(Patient.SP_BIRTHDATE).setOrder(SortOrderEnum.ASC));
actual = toUnqualifiedVersionlessIds(ourPatientDao.search(pm));
assertEquals(4, actual.size());
assertThat(actual, contains(id1, id2, id3, id4));
pm = new SearchParameterMap();
pm.add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", "testtestSortByDate"));
pm.setSort(new SortSpec(Patient.SP_BIRTHDATE).setOrder(SortOrderEnum.DESC));
actual = toUnqualifiedVersionlessIds(ourPatientDao.search(pm));
assertEquals(4, actual.size());
assertThat(actual, contains(id4, id3, id2, id1));
}
@Test
public void testStoreUnversionedResources() {
Organization o1 = new Organization();

View File

@ -113,7 +113,10 @@
});
$("#outerForm").attr("action", "search").submit();
});
$(document).ready(function() {
// If the user clicks "back", re-activate the button
$('#search-btn').prop('disabled', false);
});
</script>
<br clear="all"/>