Add date ordinals to subscription matching checker
This commit is contained in:
parent
2dc94de6bb
commit
f86a4c9fa1
|
@ -100,10 +100,6 @@ public class DaoConfig {
|
|||
*/
|
||||
private boolean myAllowInlineMatchUrlReferences = true;
|
||||
private boolean myAllowMultipleDelete;
|
||||
/**
|
||||
* Update setter javadoc if default changes.
|
||||
*/
|
||||
private boolean myUseOrdinalDatesForDayPrecisionSearches = true;
|
||||
/**
|
||||
* update setter javadoc if default changes
|
||||
*/
|
||||
|
@ -1912,43 +1908,7 @@ public class DaoConfig {
|
|||
setPreExpandValueSetsDefaultCount(Math.min(getPreExpandValueSetsDefaultCount(), getPreExpandValueSetsMaxCount()));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Should searches use the integer field {@code SP_VALUE_LOW_DATE_ORDINAL} and {@code SP_VALUE_HIGH_DATE_ORDINAL} in
|
||||
* {@link ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate} when resolving searches where all predicates are using
|
||||
* precision of {@link ca.uhn.fhir.model.api.TemporalPrecisionEnum#DAY}.
|
||||
*
|
||||
* For example, if enabled, the search of {@code Observation?date=2020-02-25} will cause the date to be collapsed down to an
|
||||
* ordinal {@code 20200225}. It would then be compared against {@link ResourceIndexedSearchParamDate#getValueLowDateOrdinal()}
|
||||
* and {@link ResourceIndexedSearchParamDate#getValueHighDateOrdinal()}
|
||||
* </p>
|
||||
* Default is {@literal true} beginning in HAPI FHIR 4.3.
|
||||
* </p>
|
||||
*
|
||||
* @since 4.3
|
||||
*/
|
||||
public void setUseOrdinalDatesForDayPrecisionSearches(boolean theUseOrdinalDates) {
|
||||
myUseOrdinalDatesForDayPrecisionSearches = theUseOrdinalDates;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Should searches use the integer field {@code SP_VALUE_LOW_DATE_ORDINAL} and {@code SP_VALUE_HIGH_DATE_ORDINAL} in
|
||||
* {@link ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate} when resolving searches where all predicates are using
|
||||
* precision of {@link ca.uhn.fhir.model.api.TemporalPrecisionEnum#DAY}.
|
||||
*
|
||||
* For example, if enabled, the search of {@code Observation?date=2020-02-25} will cause the date to be collapsed down to an
|
||||
* integer representing the ordinal date {@code 20200225}. It would then be compared against {@link ResourceIndexedSearchParamDate#getValueLowDateOrdinal()}
|
||||
* and {@link ResourceIndexedSearchParamDate#getValueHighDateOrdinal()}
|
||||
* </p>
|
||||
* Default is {@literal true} beginning in HAPI FHIR 4.3.
|
||||
* </p>
|
||||
*
|
||||
* @since 4.3
|
||||
*/
|
||||
public boolean getUseOrdinalDatesForDayPrecisionSearches() {
|
||||
return myUseOrdinalDatesForDayPrecisionSearches;
|
||||
}
|
||||
|
||||
public enum StoreMetaSourceInformationEnum {
|
||||
NONE(false, false),
|
||||
|
|
|
@ -50,6 +50,7 @@ abstract class BasePredicateBuilder {
|
|||
@Autowired
|
||||
DaoConfig myDaoConfig;
|
||||
|
||||
|
||||
boolean myDontUseHashesForSearch;
|
||||
final IDao myCallingDao;
|
||||
final CriteriaBuilder myBuilder;
|
||||
|
|
|
@ -171,7 +171,7 @@ public class PredicateBuilderDate extends BasePredicateBuilder implements IPredi
|
|||
* If all present search parameters are of DAY precision, and {@link DaoConfig#getUseOrdinalDatesForDayPrecisionSearches()} is true,
|
||||
* then we attempt to use the ordinal field for date comparisons instead of the date field.
|
||||
*/
|
||||
boolean isOrdinalComparison = isNullOrDayPrecision(lowerBound) && isNullOrDayPrecision(upperBound) && myDaoConfig.getUseOrdinalDatesForDayPrecisionSearches();
|
||||
boolean isOrdinalComparison = isNullOrDayPrecision(lowerBound) && isNullOrDayPrecision(upperBound) && myDaoConfig.getModelConfig().getUseOrdinalDatesForDayPrecisionSearches();
|
||||
|
||||
Predicate lt = null;
|
||||
Predicate gt = null;
|
||||
|
|
|
@ -884,10 +884,10 @@ public class InMemorySubscriptionMatcherR4Test {
|
|||
public void testDateSearchParametersShouldBeTimezoneIndependent() {
|
||||
|
||||
List<Observation> nlist = new ArrayList<>();
|
||||
nlist.add(createObservationWithEffective("NO1", "2011-01-02T23:00:00-11:30"));
|
||||
nlist.add(createObservationWithEffective("NO2", "2011-01-03T00:00:00+01:00"));
|
||||
|
||||
List<Observation> ylist = new ArrayList<>();
|
||||
nlist.add(createObservationWithEffective("YES00", "2011-01-02T23:00:00-11:30"));
|
||||
ylist.add(createObservationWithEffective("YES01", "2011-01-02T00:00:00-11:30"));
|
||||
ylist.add(createObservationWithEffective("YES02", "2011-01-02T00:00:00-10:00"));
|
||||
ylist.add(createObservationWithEffective("YES03", "2011-01-02T00:00:00-09:00"));
|
||||
|
|
|
@ -133,7 +133,7 @@ public abstract class BaseResourceIndexedSearchParam extends BaseResourceIndex {
|
|||
|
||||
public abstract IQueryParameterType toQueryParameterType();
|
||||
|
||||
public boolean matches(IQueryParameterType theParam) {
|
||||
public boolean matches(IQueryParameterType theParam, boolean theUseOrdinalDatesForDayComparison) {
|
||||
throw new UnsupportedOperationException("No parameter matcher for " + theParam);
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,10 @@ public class ModelConfig {
|
|||
private String myEmailFromAddress = "noreply@unknown.com";
|
||||
private boolean mySubscriptionMatchingEnabled = true;
|
||||
private String myWebsocketContextPath = DEFAULT_WEBSOCKET_CONTEXT_PATH;
|
||||
/**
|
||||
* Update setter javadoc if default changes.
|
||||
*/
|
||||
private boolean myUseOrdinalDatesForDayPrecisionSearches = true;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -257,7 +261,6 @@ public class ModelConfig {
|
|||
myTreatReferencesAsLogical = new HashSet<>();
|
||||
}
|
||||
myTreatReferencesAsLogical.add(theTreatReferencesAsLogical);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -340,13 +343,12 @@ public class ModelConfig {
|
|||
return mySubscriptionMatchingEnabled;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is true) the server will match incoming resources against active subscriptions
|
||||
* and send them to the subscription channel. If set to <code>false</code> no matching or sending occurs.
|
||||
* @since 3.7.0
|
||||
*/
|
||||
|
||||
|
||||
public void setSubscriptionMatchingEnabled(boolean theSubscriptionMatchingEnabled) {
|
||||
mySubscriptionMatchingEnabled = theSubscriptionMatchingEnabled;
|
||||
}
|
||||
|
@ -388,6 +390,43 @@ public class ModelConfig {
|
|||
myWebsocketContextPath = theWebsocketContextPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Should searches use the integer field {@code SP_VALUE_LOW_DATE_ORDINAL} and {@code SP_VALUE_HIGH_DATE_ORDINAL} in
|
||||
* {@link ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate} when resolving searches where all predicates are using
|
||||
* precision of {@link ca.uhn.fhir.model.api.TemporalPrecisionEnum#DAY}.
|
||||
*
|
||||
* For example, if enabled, the search of {@code Observation?date=2020-02-25} will cause the date to be collapsed down to an
|
||||
* ordinal {@code 20200225}. It would then be compared against {@link ResourceIndexedSearchParamDate#getValueLowDateOrdinal()}
|
||||
* and {@link ResourceIndexedSearchParamDate#getValueHighDateOrdinal()}
|
||||
* </p>
|
||||
* Default is {@literal true} beginning in HAPI FHIR 4.3.
|
||||
* </p>
|
||||
*
|
||||
* @since 4.3
|
||||
*/
|
||||
public void setUseOrdinalDatesForDayPrecisionSearches(boolean theUseOrdinalDates) {
|
||||
myUseOrdinalDatesForDayPrecisionSearches = theUseOrdinalDates;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Should searches use the integer field {@code SP_VALUE_LOW_DATE_ORDINAL} and {@code SP_VALUE_HIGH_DATE_ORDINAL} in
|
||||
* {@link ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate} when resolving searches where all predicates are using
|
||||
* precision of {@link ca.uhn.fhir.model.api.TemporalPrecisionEnum#DAY}.
|
||||
*
|
||||
* For example, if enabled, the search of {@code Observation?date=2020-02-25} will cause the date to be collapsed down to an
|
||||
* integer representing the ordinal date {@code 20200225}. It would then be compared against {@link ResourceIndexedSearchParamDate#getValueLowDateOrdinal()}
|
||||
* and {@link ResourceIndexedSearchParamDate#getValueHighDateOrdinal()}
|
||||
* </p>
|
||||
* Default is {@literal true} beginning in HAPI FHIR 4.3.
|
||||
* </p>
|
||||
*
|
||||
* @since 4.3
|
||||
*/
|
||||
public boolean getUseOrdinalDatesForDayPrecisionSearches() {
|
||||
return myUseOrdinalDatesForDayPrecisionSearches;
|
||||
}
|
||||
private static void validateTreatBaseUrlsAsLocal(String theUrl) {
|
||||
Validate.notBlank(theUrl, "Base URL must not be null or empty");
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ import org.hibernate.search.annotations.Field;
|
|||
import org.hl7.fhir.r4.model.DateTimeType;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
@Embeddable
|
||||
|
@ -238,21 +237,33 @@ public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchPar
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(IQueryParameterType theParam) {
|
||||
public boolean matches(IQueryParameterType theParam, boolean theUseOrdinalDatesForDayComparison) {
|
||||
if (!(theParam instanceof DateParam)) {
|
||||
return false;
|
||||
}
|
||||
DateParam dateParam = (DateParam) theParam;
|
||||
DateRangeParam range = new DateRangeParam(dateParam);
|
||||
|
||||
|
||||
|
||||
|
||||
boolean result;
|
||||
if (theUseOrdinalDatesForDayComparison) {
|
||||
result = matchesOrdinalDateBounds(range);
|
||||
} else {
|
||||
result = matchesDateBounds(range);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean matchesDateBounds(DateRangeParam range) {
|
||||
Date lowerBound = range.getLowerBoundAsInstant();
|
||||
Date upperBound = range.getUpperBoundAsInstant();
|
||||
|
||||
if (lowerBound == null && upperBound == null) {
|
||||
// should never happen
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean result = true;
|
||||
if (lowerBound != null) {
|
||||
result &= (myValueLow.after(lowerBound) || myValueLow.equals(lowerBound));
|
||||
|
@ -265,8 +276,27 @@ public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchPar
|
|||
return result;
|
||||
}
|
||||
|
||||
private boolean matchesOrdinalDateBounds(DateRangeParam range) {
|
||||
boolean result = true;
|
||||
Integer lowerBoundAsDateInteger = range.getLowerBoundAsDateInteger();
|
||||
Integer upperBoundAsDateInteger = range.getUpperBoundAsDateInteger();
|
||||
if (upperBoundAsDateInteger == null && lowerBoundAsDateInteger == null) {
|
||||
return false;
|
||||
}
|
||||
if (lowerBoundAsDateInteger != null) {
|
||||
result &= (myValueLowDateOrdinal.equals(lowerBoundAsDateInteger) || myValueLowDateOrdinal > lowerBoundAsDateInteger);
|
||||
result &= (myValueHighDateOrdinal.equals(lowerBoundAsDateInteger) || myValueHighDateOrdinal > lowerBoundAsDateInteger);
|
||||
}
|
||||
if (upperBoundAsDateInteger != null) {
|
||||
result &= (myValueHighDateOrdinal.equals(upperBoundAsDateInteger) || myValueHighDateOrdinal < upperBoundAsDateInteger);
|
||||
result &= (myValueLowDateOrdinal.equals(upperBoundAsDateInteger) || myValueLowDateOrdinal < upperBoundAsDateInteger);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static Long calculateOrdinalValue(Date theDate) {
|
||||
return (long) DateUtils.convertDatetoDayInteger(theDate);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ public class ResourceIndexedSearchParamNumber extends BaseResourceIndexedSearchP
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(IQueryParameterType theParam) {
|
||||
public boolean matches(IQueryParameterType theParam, boolean theUseOrdinalDatesForDayComparison) {
|
||||
if (!(theParam instanceof NumberParam)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -237,7 +237,7 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(IQueryParameterType theParam) {
|
||||
public boolean matches(IQueryParameterType theParam, boolean theUseOrdinalDatesForDayComparison) {
|
||||
if (!(theParam instanceof QuantityParam)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -314,7 +314,7 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(IQueryParameterType theParam) {
|
||||
public boolean matches(IQueryParameterType theParam, boolean theUseOrdinalDatesForDayComparison) {
|
||||
if (!(theParam instanceof StringParam)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -239,7 +239,7 @@ public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchPa
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(IQueryParameterType theParam) {
|
||||
public boolean matches(IQueryParameterType theParam, boolean theUseOrdinalDatesForDayComparison) {
|
||||
if (!(theParam instanceof TokenParam)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -188,7 +188,7 @@ public class ResourceIndexedSearchParamUri extends BaseResourceIndexedSearchPara
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(IQueryParameterType theParam) {
|
||||
public boolean matches(IQueryParameterType theParam, boolean theUseOrdinalDatesForDayComparison) {
|
||||
if (!(theParam instanceof UriParam)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -217,7 +217,7 @@ public final class ResourceIndexedSearchParams {
|
|||
return myPopulatedResourceLinkParameters;
|
||||
}
|
||||
|
||||
public boolean matchParam(String theResourceName, String theParamName, RuntimeSearchParam theParamDef, IQueryParameterType theParam) {
|
||||
public boolean matchParam(String theResourceName, String theParamName, RuntimeSearchParam theParamDef, IQueryParameterType theParam, boolean theUseOrdinalDatesForDayComparison) {
|
||||
if (theParamDef == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ public final class ResourceIndexedSearchParams {
|
|||
}
|
||||
Predicate<BaseResourceIndexedSearchParam> namedParamPredicate = param ->
|
||||
param.getParamName().equalsIgnoreCase(theParamName) &&
|
||||
param.matches(theParam);
|
||||
param.matches(theParam, theUseOrdinalDatesForDayComparison);
|
||||
|
||||
return resourceParams.stream().anyMatch(namedParamPredicate);
|
||||
}
|
||||
|
|
|
@ -202,7 +202,7 @@ public class InMemoryResourceMatcher {
|
|||
if (theSearchParams == null) {
|
||||
return InMemoryMatchResult.successfulMatch();
|
||||
} else {
|
||||
return InMemoryMatchResult.fromBoolean(theAndOrParams.stream().anyMatch(nextAnd -> matchParams(theResourceName, theParamName, theParamDef, nextAnd, theSearchParams)));
|
||||
return InMemoryMatchResult.fromBoolean(theAndOrParams.stream().anyMatch(nextAnd -> matchParams(theResourceName, theParamName, theParamDef, nextAnd, theSearchParams, myModelConfig.getUseOrdinalDatesForDayPrecisionSearches())));
|
||||
}
|
||||
case COMPOSITE:
|
||||
case HAS:
|
||||
|
@ -219,11 +219,11 @@ public class InMemoryResourceMatcher {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean matchParams(String theResourceName, String theParamName, RuntimeSearchParam paramDef, List<? extends IQueryParameterType> theNextAnd, ResourceIndexedSearchParams theSearchParams) {
|
||||
private boolean matchParams(String theResourceName, String theParamName, RuntimeSearchParam paramDef, List<? extends IQueryParameterType> theNextAnd, ResourceIndexedSearchParams theSearchParams, boolean theUseOrdinalDatesForDayComparison) {
|
||||
if (paramDef.getParamType() == RestSearchParameterTypeEnum.REFERENCE) {
|
||||
stripBaseUrlsFromReferenceParams(theNextAnd);
|
||||
}
|
||||
return theNextAnd.stream().anyMatch(token -> theSearchParams.matchParam(theResourceName, theParamName, paramDef, token));
|
||||
return theNextAnd.stream().anyMatch(token -> theSearchParams.matchParam(theResourceName, theParamName, paramDef, token, theUseOrdinalDatesForDayComparison));
|
||||
}
|
||||
|
||||
private void stripBaseUrlsFromReferenceParams(List<? extends IQueryParameterType> theNextAnd) {
|
||||
|
|
Loading…
Reference in New Issue