Merge remote-tracking branch 'remotes/origin/master' into ks-20200203-remove-search-lastused

This commit is contained in:
Ken Stevens 2020-02-03 11:33:15 -05:00
commit 3c46595e81
10 changed files with 118 additions and 41 deletions

View File

@ -65,6 +65,7 @@ import org.apache.commons.lang3.Validate;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.query.Query;
import org.hl7.fhir.dstu3.model.Location;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.Logger;
@ -160,6 +161,10 @@ public class SearchBuilder implements ISearchBuilder {
// Remove any empty parameters
theParams.clean();
if (myResourceType == Location.class) {
theParams.setLocationDistance();
}
/*
* Check if there is a unique key associated with the set
* of parameters passed in
@ -181,7 +186,6 @@ public class SearchBuilder implements ISearchBuilder {
}
@Override
public Iterator<Long> createCountQuery(SearchParameterMap theParams, String theSearchUuid, RequestDetails theRequest) {
init(theParams, theSearchUuid);

View File

@ -21,8 +21,6 @@ package ca.uhn.fhir.jpa.dao.data;
*/
import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
@ -37,6 +35,4 @@ public interface ITermValueSetConceptDesignationDao extends JpaRepository<TermVa
@Modifying
void deleteByTermValueSetId(@Param("pid") Long theValueSetId);
@Query("SELECT vscd FROM TermValueSetConceptDesignation vscd WHERE vscd.myConcept.myId = :pid")
Slice<TermValueSetConceptDesignation> findByTermValueSetConceptId(Pageable thePage, @Param("pid") Long theValueSetConceptId);
}

View File

@ -33,9 +33,7 @@ import java.io.Serializable;
import static org.apache.commons.lang3.StringUtils.left;
import static org.apache.commons.lang3.StringUtils.length;
@Table(name = "TRM_VALUESET_C_DESIGNATION", indexes = {
@Index(name = "IDX_VALUESET_C_DSGNTN_VAL", columnList = "VAL")
})
@Table(name = "TRM_VALUESET_C_DESIGNATION")
@Entity()
public class TermValueSetConceptDesignation implements Serializable {
private static final long serialVersionUID = 1L;

View File

@ -5,6 +5,7 @@ import ca.uhn.fhir.jpa.dao.data.ISearchDao;
import ca.uhn.fhir.jpa.entity.Search;
import ca.uhn.fhir.jpa.provider.r4.ResourceProviderR4Test;
import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
import ca.uhn.fhir.jpa.util.CoordCalculatorTest;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.UriDt;
@ -65,6 +66,7 @@ import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
@ -4278,6 +4280,55 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
}
@Test
public void testNearSearchApproximate() {
Location loc = new Location();
double latitude = CoordCalculatorTest.LATITUDE_UHN;
double longitude = CoordCalculatorTest.LONGITUDE_UHN;
Location.LocationPositionComponent position = new Location.LocationPositionComponent().setLatitude(latitude).setLongitude(longitude);
loc.setPosition(position);
IIdType locId = ourClient.create().resource(loc).execute().getId().toUnqualifiedVersionless();
{ // In the box
double bigEnoughDistance = CoordCalculatorTest.DISTANCE_KM_CHIN_TO_UHN * 2;
String url = "/Location?" +
Location.SP_NEAR + "=" + CoordCalculatorTest.LATITUDE_CHIN + URLEncoder.encode(":") + CoordCalculatorTest.LONGITUDE_CHIN +
"&" +
Location.SP_NEAR_DISTANCE + "=" + bigEnoughDistance + URLEncoder.encode("|http://unitsofmeasure.org|km");
Bundle actual = ourClient
.search()
.byUrl(ourServerBase + "/" + url)
.encodedJson()
.prettyPrint()
.returnBundle(Bundle.class)
.execute();
assertEquals(1, actual.getEntry().size());
assertEquals(locId.getIdPart(), actual.getEntry().get(0).getResource().getIdElement().getIdPart());
}
{ // Outside the box
double tooSmallDistance = CoordCalculatorTest.DISTANCE_KM_CHIN_TO_UHN / 2;
String url = "/Location?" +
Location.SP_NEAR + "=" + CoordCalculatorTest.LATITUDE_CHIN + URLEncoder.encode(":") + CoordCalculatorTest.LONGITUDE_CHIN +
"&" +
Location.SP_NEAR_DISTANCE + "=" + tooSmallDistance + URLEncoder.encode("|http://unitsofmeasure.org|km");
myCaptureQueriesListener.clear();
Bundle actual = ourClient
.search()
.byUrl(ourServerBase + "/" + url)
.encodedJson()
.prettyPrint()
.returnBundle(Bundle.class)
.execute();
myCaptureQueriesListener.logSelectQueries();
assertEquals(0, actual.getEntry().size());
}
}
private String toStr(Date theDate) {
return new InstantDt(theDate).getValueAsString();
}

View File

@ -58,6 +58,7 @@ public class MatchUrlServiceTest extends BaseJpaTest {
Location.SP_NEAR + "=1000.0:2000.0" +
"&" +
Location.SP_NEAR_DISTANCE + "=" + kmDistance + "|http://unitsofmeasure.org|km", ourCtx.getResourceDefinition("Location"));
map.setLocationDistance();
QuantityParam nearDistanceParam = map.getNearDistanceParam();
assertEquals(1, map.size());
@ -74,6 +75,8 @@ public class MatchUrlServiceTest extends BaseJpaTest {
"&" +
Location.SP_NEAR_DISTANCE + "=2|http://unitsofmeasure.org|km",
ourCtx.getResourceDefinition("Location"));
map.setLocationDistance();
fail();
} catch (IllegalArgumentException e) {
assertEquals("Only one " + Location.SP_NEAR_DISTANCE + " parameter may be present", e.getMessage());
@ -89,7 +92,8 @@ public class MatchUrlServiceTest extends BaseJpaTest {
"," +
"2|http://unitsofmeasure.org|km",
ourCtx.getResourceDefinition("Location"));
map.setLoadSynchronous(true);
map.setLocationDistance();
fail();
} catch (IllegalArgumentException e) {
assertEquals("Only one " + Location.SP_NEAR_DISTANCE + " parameter may be present", e.getMessage());

View File

@ -190,6 +190,10 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
// TermConceptProperty
version.startSectionWithMessage("Processing table: TRM_CONCEPT_PROPERTY");
version.onTable("TRM_CONCEPT_PROPERTY").addColumn("20191002.9", "PROP_VAL_LOB").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.BLOB);
// TermValueSetConceptDesignation
version.onTable("TRM_VALUESET_C_DESIGNATION").dropIndex("20200202.1", "IDX_VALUESET_C_DSGNTN_VAL").failureAllowed();
}
protected void init400() { // 20190401 - 20190814
@ -328,10 +332,13 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
termValueSetConceptDesignationTable.addColumn("USE_CODE").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 500);
termValueSetConceptDesignationTable.addColumn("USE_DISPLAY").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 500);
termValueSetConceptDesignationTable.addColumn("VAL").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 500);
// This index turned out not to be needed so it is disabled
termValueSetConceptDesignationTable
.addIndex("20190801.6", "IDX_VALUESET_C_DSGNTN_VAL")
.unique(false)
.withColumns("VAL");
.withColumns("VAL")
.doNothing();
// TermCodeSystemVersion
version.startSectionWithMessage("Processing table: TRM_CODESYSTEM_VER");

View File

@ -158,20 +158,22 @@ public class Builder {
return myTableName;
}
public void dropIndex(String theVersion, String theIndexName) {
dropIndexOptional(false, theVersion, theIndexName);
public BuilderCompleteTask dropIndex(String theVersion, String theIndexName) {
BaseTask task = dropIndexOptional(false, theVersion, theIndexName);
return new BuilderCompleteTask(task);
}
public void dropIndexStub(String theVersion, String theIndexName) {
dropIndexOptional(true, theVersion, theIndexName);
}
private void dropIndexOptional(boolean theDoNothing, String theVersion, String theIndexName) {
private DropIndexTask dropIndexOptional(boolean theDoNothing, String theVersion, String theIndexName) {
DropIndexTask task = new DropIndexTask(myRelease, theVersion);
task.setIndexName(theIndexName);
task.setTableName(myTableName);
task.setDoNothing(theDoNothing);
addTask(task);
return task;
}
public void renameIndex(String theVersion, String theOldIndexName, String theNewIndexName) {
@ -286,11 +288,12 @@ public class Builder {
withColumnsOptional(true, theColumnNames);
}
public void withColumns(String... theColumnNames) {
withColumnsOptional(false, theColumnNames);
public BuilderCompleteTask withColumns(String... theColumnNames) {
BaseTask task = withColumnsOptional(false, theColumnNames);
return new BuilderCompleteTask(task);
}
private void withColumnsOptional(boolean theDoNothing, String... theColumnNames) {
private AddIndexTask withColumnsOptional(boolean theDoNothing, String... theColumnNames) {
AddIndexTask task = new AddIndexTask(myRelease, myVersion);
task.setTableName(myTableName);
task.setIndexName(myIndexName);
@ -298,6 +301,7 @@ public class Builder {
task.setColumns(theColumnNames);
task.setDoNothing(theDoNothing);
addTask(task);
return task;
}
}
}
@ -463,6 +467,12 @@ public class Builder {
myTask.setFailureAllowed(true);
return this;
}
public BuilderCompleteTask doNothing() {
myTask.setDoNothing(true);
return this;
}
}
}

View File

@ -26,13 +26,11 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.dstu2.resource.Location;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.ParameterUtil;
import ca.uhn.fhir.rest.param.QuantityAndListParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.ReflectionUtil;
import ca.uhn.fhir.util.UrlUtil;
@ -115,9 +113,6 @@ public class MatchUrlService {
} else if (Constants.PARAM_SOURCE.equals(nextParamName)) {
IQueryParameterAnd<?> param = ParameterUtil.parseQueryParams(myContext, RestSearchParameterTypeEnum.TOKEN, nextParamName, paramList);
paramMap.add(nextParamName, param);
} else if (Location.SP_NEAR_DISTANCE.equals(nextParamName)) {
QuantityAndListParam nearDistanceAndListParam = (QuantityAndListParam) ParameterUtil.parseQueryParams(myContext, RestSearchParameterTypeEnum.QUANTITY, nextParamName, paramList);
paramMap.setNearDistanceParam(nearDistanceAndListParam);
} else if (nextParamName.startsWith("_")) {
// ignore these since they aren't search params (e.g. _sort)
} else {

View File

@ -5,15 +5,17 @@ import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.dstu2.resource.Location;
import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.QuantityParam;
import ca.uhn.fhir.util.ObjectUtil;
import ca.uhn.fhir.util.UrlUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hl7.fhir.dstu3.model.Location;
import java.io.Serializable;
import java.util.*;
@ -495,29 +497,38 @@ public class SearchParameterMap implements Serializable {
}
}
public void setNearDistanceParam(QuantityAndListParam theQuantityAndListParam) {
List<QuantityOrListParam> orTokens = theQuantityAndListParam.getValuesAsQueryTokens();
if (orTokens.isEmpty()) {
return;
}
if (orTokens.size() > 1) {
throw new IllegalArgumentException("Only one " + Location.SP_NEAR_DISTANCE + " parameter may be present");
}
QuantityOrListParam quantityOrListParam = orTokens.get(0);
List<QuantityParam> tokens = quantityOrListParam.getValuesAsQueryTokens();
if (tokens.isEmpty()) {
return;
}
if (tokens.size() > 1) {
throw new IllegalArgumentException("Only one " + Location.SP_NEAR_DISTANCE + " parameter may be present");
}
myNearDistanceParam = tokens.get(0);
public void setNearDistanceParam(QuantityParam theQuantityParam) {
myNearDistanceParam = theQuantityParam;
}
public QuantityParam getNearDistanceParam() {
return myNearDistanceParam;
}
public void setLocationDistance() {
if (containsKey(Location.SP_NEAR_DISTANCE)) {
List<List<IQueryParameterType>> paramAndList = get(Location.SP_NEAR_DISTANCE);
if (paramAndList.isEmpty()) {
return;
}
if (paramAndList.size() > 1) {
throw new IllegalArgumentException("Only one " + ca.uhn.fhir.model.dstu2.resource.Location.SP_NEAR_DISTANCE + " parameter may be present");
}
List<IQueryParameterType> paramOrList = paramAndList.get(0);
if (paramOrList.isEmpty()) {
return;
}
if (paramOrList.size() > 1) {
throw new IllegalArgumentException("Only one " + ca.uhn.fhir.model.dstu2.resource.Location.SP_NEAR_DISTANCE + " parameter may be present");
}
setNearDistanceParam((QuantityParam) paramOrList.get(0));
// Need to remove near-distance or it we'll get a hashcode predicate for it
remove(Location.SP_NEAR_DISTANCE);
}
}
public enum EverythingModeEnum {
/*
* Don't reorder! We rely on the ordinals

View File

@ -40,6 +40,7 @@ import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.MetaUtil;
import ca.uhn.fhir.util.UrlUtil;
import org.hl7.fhir.dstu3.model.Location;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
@ -88,7 +89,7 @@ public class InMemoryResourceMatcher {
if (searchParameterMap.getLastUpdated() != null) {
return InMemoryMatchResult.unsupportedFromParameterAndReason(Constants.PARAM_LASTUPDATED, InMemoryMatchResult.STANDARD_PARAMETER);
}
if (searchParameterMap.getNearDistanceParam() != null) {
if (searchParameterMap.containsKey(Location.SP_NEAR)) {
return InMemoryMatchResult.unsupportedFromReason(InMemoryMatchResult.LOCATION_NEAR);
}