Work on sort support in JPA
This commit is contained in:
parent
da1d49a108
commit
5fd987c497
|
@ -107,18 +107,20 @@ public class SortSpec {
|
||||||
* Sets the chained sort specification, or <code>null</code> if none. If multiple sort parameters are chained
|
* 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.
|
* (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) {
|
if (theChain == this) {
|
||||||
throw new IllegalArgumentException("Can not chain this to itself");
|
throw new IllegalArgumentException("Can not chain this to itself");
|
||||||
}
|
}
|
||||||
myChain = theChain;
|
myChain = theChain;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the actual name of the search param to sort by
|
* Sets the actual name of the search param to sort by
|
||||||
*/
|
*/
|
||||||
public void setParamName(String theFieldName) {
|
public SortSpec setParamName(String theFieldName) {
|
||||||
myParamName = theFieldName;
|
myParamName = theFieldName;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,8 +128,9 @@ public class SortSpec {
|
||||||
* means {@link SortOrderEnum#ASC} according to the <a
|
* means {@link SortOrderEnum#ASC} according to the <a
|
||||||
* href="http://hl7.org/implement/standards/fhir/search.html#sort">FHIR specification</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;
|
myOrder = theOrder;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ import javax.persistence.criteria.Path;
|
||||||
import javax.persistence.criteria.Predicate;
|
import javax.persistence.criteria.Predicate;
|
||||||
import javax.persistence.criteria.Root;
|
import javax.persistence.criteria.Root;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.hl7.fhir.instance.model.IBaseResource;
|
import org.hl7.fhir.instance.model.IBaseResource;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||||
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
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.api.SortSpec;
|
||||||
import ca.uhn.fhir.rest.param.CompositeParam;
|
import ca.uhn.fhir.rest.param.CompositeParam;
|
||||||
import ca.uhn.fhir.rest.param.DateParam;
|
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() + "'");
|
throw new InvalidRequestException("Unknown sort parameter '" + theSort.getParamName() + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
String joinAttrName = "myParamsString";
|
String joinAttrName;
|
||||||
String sortAttrName = "myValueExact";
|
String sortAttrName;
|
||||||
|
|
||||||
switch (param.getParamType()) {
|
switch (param.getParamType()) {
|
||||||
case STRING: {
|
case STRING:
|
||||||
From<?, ?> stringJoin = theFrom.join(joinAttrName, JoinType.LEFT);
|
joinAttrName = "myParamsString";
|
||||||
Predicate p = theBuilder.equal(stringJoin.get("myParamName"), theSort.getParamName());
|
sortAttrName = "myValueExact";
|
||||||
Predicate pn = theBuilder.isNull(stringJoin.get("myParamName"));
|
|
||||||
thePredicates.add(theBuilder.or(p, pn));
|
|
||||||
theOrders.add(theBuilder.asc(stringJoin.get(sortAttrName)));
|
|
||||||
break;
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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, thePredicates);
|
createSort(theBuilder, theFrom, theSort.getChain(), theOrders, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -28,9 +28,13 @@ import javax.persistence.Table;
|
||||||
import javax.persistence.Temporal;
|
import javax.persistence.Temporal;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "HFJ_SPIDX_DATE" /*, indexes= {@Index(name="IDX_SP_DATE", columnList= "SP_VALUE_LOW,SP_VALUE_HIGH")}*/)
|
@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 {
|
public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchParam {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
package ca.uhn.fhir.jpa.dao;
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.contains;
|
import static org.hamcrest.Matchers.*;
|
||||||
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.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotEquals;
|
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.InstantDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
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.api.SortSpec;
|
||||||
import ca.uhn.fhir.rest.param.CompositeParam;
|
import ca.uhn.fhir.rest.param.CompositeParam;
|
||||||
import ca.uhn.fhir.rest.param.DateParam;
|
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"));
|
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"));
|
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
|
@Test
|
||||||
public void testPersistSearchParamDate() {
|
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 patient = new Patient();
|
||||||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||||
patient.setBirthDate(new DateDt("2001-01-01"));
|
patient.setBirthDate(new DateDt("2001-01-01"));
|
||||||
|
|
||||||
ourPatientDao.create(patient);
|
ourPatientDao.create(patient);
|
||||||
|
|
||||||
List<Patient> found = toList(ourPatientDao.search(Patient.SP_BIRTHDATE, new DateParam(QuantityCompararatorEnum.GREATERTHAN, "2000-01-01")));
|
found = toList(ourPatientDao.search(Patient.SP_BIRTHDATE, new DateParam(QuantityCompararatorEnum.GREATERTHAN, "2000-01-01")));
|
||||||
assertEquals(1, found.size());
|
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..
|
// 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")));
|
found = toList(ourPatientDao.search(Patient.SP_BIRTHDATE + "AAAA", new DateParam(QuantityCompararatorEnum.GREATERTHAN, "2000-01-01")));
|
||||||
|
@ -1487,35 +1492,86 @@ public class FhirResourceDaoTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSort() {
|
public void testSortByString() {
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addIdentifier().setSystem("urn:system").setValue("testSort001");
|
p.addIdentifier().setSystem("urn:system").setValue("testSortByString");
|
||||||
p.addName().addFamily("testSortF1").addGiven("testSortG1");
|
p.addName().addFamily("testSortF1").addGiven("testSortG1");
|
||||||
IdDt id1 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
|
IdDt id1 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
// Create out of order
|
// Create out of order
|
||||||
p = new Patient();
|
p = new Patient();
|
||||||
p.addIdentifier().setSystem("urn:system").setValue("testSort001");
|
p.addIdentifier().setSystem("urn:system").setValue("testSortByString");
|
||||||
p.addName().addFamily("testSortF3").addGiven("testSortG3");
|
p.addName().addFamily("testSortF3").addGiven("testSortG3");
|
||||||
IdDt id3 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
|
IdDt id3 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
p = new Patient();
|
p = new Patient();
|
||||||
p.addIdentifier().setSystem("urn:system").setValue("testSort001");
|
p.addIdentifier().setSystem("urn:system").setValue("testSortByString");
|
||||||
p.addName().addFamily("testSortF2").addGiven("testSortG2");
|
p.addName().addFamily("testSortF2").addGiven("testSortG2");
|
||||||
IdDt id2 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
|
IdDt id2 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
p = new Patient();
|
p = new Patient();
|
||||||
p.addIdentifier().setSystem("urn:system").setValue("testSort001");
|
p.addIdentifier().setSystem("urn:system").setValue("testSortByString");
|
||||||
IdDt id4 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
|
IdDt id4 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
SearchParameterMap pm = new SearchParameterMap();
|
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));
|
pm.setSort(new SortSpec(Patient.SP_FAMILY));
|
||||||
List<IdDt> actual = toUnqualifiedVersionlessIds(ourPatientDao.search(pm));
|
List<IdDt> actual = toUnqualifiedVersionlessIds(ourPatientDao.search(pm));
|
||||||
assertEquals(4, actual.size());
|
assertEquals(4, actual.size());
|
||||||
assertThat(actual, contains(id1, id2, id3, id4));
|
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
|
@Test
|
||||||
public void testStoreUnversionedResources() {
|
public void testStoreUnversionedResources() {
|
||||||
Organization o1 = new Organization();
|
Organization o1 = new Organization();
|
||||||
|
|
|
@ -110,10 +110,13 @@
|
||||||
this.name = this.id;
|
this.name = this.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$("#outerForm").attr("action", "search").submit();
|
$("#outerForm").attr("action", "search").submit();
|
||||||
});
|
});
|
||||||
$('#search-btn').prop('disabled', false);
|
$(document).ready(function() {
|
||||||
|
// If the user clicks "back", re-activate the button
|
||||||
|
$('#search-btn').prop('disabled', false);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<br clear="all"/>
|
<br clear="all"/>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue