diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java index 6168d8fe5e4..8d75b767a37 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java @@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.dao; import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor; import ca.uhn.fhir.jpa.model.entity.ModelConfig; import ca.uhn.fhir.jpa.model.entity.ResourceEncodingEnum; +import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate; import ca.uhn.fhir.jpa.search.warm.WarmCacheEntry; import ca.uhn.fhir.jpa.searchparam.SearchParamConstants; import ca.uhn.fhir.rest.api.SearchTotalModeEnum; @@ -99,6 +100,10 @@ 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 */ @@ -1907,6 +1912,44 @@ public class DaoConfig { setPreExpandValueSetsDefaultCount(Math.min(getPreExpandValueSetsDefaultCount(), getPreExpandValueSetsMaxCount())); } + /** + *

+ * 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()} + *

+ * Default is {@literal true} beginning in HAPI FHIR 4.3. + *

+ * + * @since 4.3 + */ + public void setUseOrdinalDatesForDayPrecisionSearches(boolean theUseOrdinalDates) { + myUseOrdinalDatesForDayPrecisionSearches = theUseOrdinalDates; + } + + /** + *

+ * 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()} + *

+ * Default is {@literal true} beginning in HAPI FHIR 4.3. + *

+ * + * @since 4.3 + */ + public boolean getUseOrdinalDatesForDayPrecisionSearches() { + return myUseOrdinalDatesForDayPrecisionSearches; + } + public enum StoreMetaSourceInformationEnum { NONE(false, false), SOURCE_URI(true, false), diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderDate.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderDate.java index eebf0f2987f..fc182a9162b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderDate.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderDate.java @@ -140,7 +140,9 @@ public class PredicateBuilderDate extends BasePredicateBuilder implements IPredi DateParam lowerBound = theRange.getLowerBound(); DateParam upperBound = theRange.getUpperBound(); - boolean isOrdinalComparison = isNullOrDayPrecision(lowerBound) && isNullOrDayPrecision(upperBound); + Integer lowerBoundAsOrdinal = theRange.getLowerBoundAsDateInteger(); + Integer upperBoundAsOrdinal = theRange.getUpperBoundAsDateInteger(); + boolean isOrdinalComparison = isNullOrDayPrecision(lowerBound) && isNullOrDayPrecision(upperBound) && myDaoConfig.getUseOrdinalDatesForDayPrecisionSearches(); Predicate lt = null; Predicate gt = null; Predicate lb = null; @@ -152,7 +154,7 @@ public class PredicateBuilderDate extends BasePredicateBuilder implements IPredi } //im like 80% sure this should be ub and not lb, as it is an UPPER bound. if (isOrdinalComparison) { - lb = theBuilder.lessThan(theFrom.get("myValueLowDateOrdinal"), theRange.getLowerBoundAsDateInteger()); + lb = theBuilder.lessThan(theFrom.get("myValueLowDateOrdinal"), lowerBoundAsOrdinal); } else { lb = theBuilder.lessThan(theFrom.get("myValueLow"), lowerBoundInstant); } diff --git a/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java b/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java index 6ea71e54b73..98778c257f2 100644 --- a/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java +++ b/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java @@ -64,10 +64,11 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { version.onTable("HFJ_RES_VER").modifyColumn("20200220.1", "RES_ID").nonNullable().failureAllowed().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); // - // Add support for integer comparisons during day-granularity date search. + // Add support for integer comparisons during day-precision date search. Builder.BuilderWithTableName spidxDate = version.onTable("HFJ_SPIDX_DATE"); spidxDate.addColumn("20200225.1", "SP_VALUE_LOW_DATE_ORDINAL").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.INT); spidxDate.addColumn("20200225.2", "SP_VALUE_HIGH_DATE_ORDINAL").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.INT); + spidxDate.addTask(new CalculateOrdinalDatesTask(VersionEnum.V4_3_0, "20200225.3") .setColumnName("SP_VALUE_LOW_DATE_ORDINAL") //It doesn't matter which of the two we choose as they will both be null. .addCalculator("SP_VALUE_LOW_DATE_ORDINAL", t -> ResourceIndexedSearchParamDate.calculateOrdinalValue(t.getDate("SP_VALUE_LOW"))) diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamDate.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamDate.java index c5ffe82375a..17d011d4e0c 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamDate.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamDate.java @@ -111,6 +111,14 @@ public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchPar this.myValueLowDateOrdinal = generateOrdinalDateInteger(theLow); } + public Integer getValueLowDateOrdinal() { + return myValueLowDateOrdinal; + } + + public Integer getValueHighDateOrdinal() { + return myValueHighDateOrdinal; + } + @Override @PrePersist public void calculateHashes() {