diff --git a/warehouse/query-core/src/main/java/datawave/query/config/ShardQueryConfiguration.java b/warehouse/query-core/src/main/java/datawave/query/config/ShardQueryConfiguration.java index 59260b1dcda..c5d4e293afc 100644 --- a/warehouse/query-core/src/main/java/datawave/query/config/ShardQueryConfiguration.java +++ b/warehouse/query-core/src/main/java/datawave/query/config/ShardQueryConfiguration.java @@ -515,6 +515,18 @@ public class ShardQueryConfiguration extends GenericQueryConfiguration implement */ private double fieldIndexHoleMinThreshold = 1.0d; + /** + * The set of date types that, if the query's end date is the current date, will NOT result in any date range adjustments or the addition of a + * SHARDS_AND_DAYS hint. + */ + private Set noExpansionIfCurrent = Collections.emptySet(); + + /** + * Whether the SHARDS_AND_DAYS hint should be allowed for the query. This will be set to false iff the query specified a date type, and the date type is + * present in {@link #noExpansionIfCurrent}, and the query's end date is the current date. + */ + private boolean shardsAndDaysHintAllowed = true; + /** * Default constructor */ @@ -753,6 +765,8 @@ public void copyFrom(ShardQueryConfiguration other) { this.setUseQueryTreeScanHintRules(other.isUseQueryTreeScanHintRules()); this.setQueryTreeScanHintRules(other.getQueryTreeScanHintRules()); this.setFieldIndexHoleMinThreshold(other.getFieldIndexHoleMinThreshold()); + this.setNoExpansionIfCurrent(other.getNoExpansionIfCurrent() == null ? null : Sets.newHashSet(other.getNoExpansionIfCurrent())); + this.setShardsAndDaysHintAllowed(other.isShardsAndDaysHintAllowed()); } /** @@ -2791,12 +2805,15 @@ public void setSortQueryPostIndexWithTermCounts(boolean sortQueryPostIndexWithTe @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (o == null || getClass() != o.getClass()) + } + if (o == null || getClass() != o.getClass()) { return false; - if (!super.equals(o)) + } + if (!super.equals(o)) { return false; + } // @formatter:off ShardQueryConfiguration that = (ShardQueryConfiguration) o; return isTldQuery() == that.isTldQuery() && @@ -2995,7 +3012,9 @@ public boolean equals(Object o) { isSortQueryPreIndexWithImpliedCounts() == isSortQueryPreIndexWithImpliedCounts() && isSortQueryPreIndexWithFieldCounts() == isSortQueryPreIndexWithFieldCounts() && isSortQueryPostIndexWithTermCounts() == isSortQueryPostIndexWithTermCounts() && - isSortQueryPostIndexWithFieldCounts() == isSortQueryPostIndexWithFieldCounts(); + isSortQueryPostIndexWithFieldCounts() == isSortQueryPostIndexWithFieldCounts() && + Objects.equals(getNoExpansionIfCurrent(), that.getNoExpansionIfCurrent()) && + isShardsAndDaysHintAllowed() == that.isShardsAndDaysHintAllowed(); // @formatter:on } @@ -3199,7 +3218,9 @@ public int hashCode() { isSortQueryPreIndexWithImpliedCounts(), isSortQueryPreIndexWithFieldCounts(), isSortQueryPostIndexWithTermCounts(), - isSortQueryPostIndexWithFieldCounts() + isSortQueryPostIndexWithFieldCounts(), + getNoExpansionIfCurrent(), + isShardsAndDaysHintAllowed() ); // @formatter:on } @@ -3234,4 +3255,20 @@ public long getMaxAnyFieldScanTimeMillis() { public void setMaxAnyFieldScanTimeMillis(long maxAnyFieldScanTimeMillis) { this.maxAnyFieldScanTimeMillis = maxAnyFieldScanTimeMillis; } + + public Set getNoExpansionIfCurrent() { + return noExpansionIfCurrent; + } + + public void setNoExpansionIfCurrent(Set noExpansionIfCurrent) { + this.noExpansionIfCurrent = noExpansionIfCurrent; + } + + public boolean isShardsAndDaysHintAllowed() { + return shardsAndDaysHintAllowed; + } + + public void setShardsAndDaysHintAllowed(boolean shardsAndDaysHintAllowed) { + this.shardsAndDaysHintAllowed = shardsAndDaysHintAllowed; + } } diff --git a/warehouse/query-core/src/main/java/datawave/query/planner/DefaultQueryPlanner.java b/warehouse/query-core/src/main/java/datawave/query/planner/DefaultQueryPlanner.java index 5ddefaec6b7..df8988963d5 100644 --- a/warehouse/query-core/src/main/java/datawave/query/planner/DefaultQueryPlanner.java +++ b/warehouse/query-core/src/main/java/datawave/query/planner/DefaultQueryPlanner.java @@ -834,15 +834,18 @@ protected ASTJexlScript updateQueryTree(ScannerFactory scannerFactory, MetadataH throw new DatawaveFatalQueryException("Found incorrectly marked bounded ranges"); } - if (optionsMap.containsKey(QueryParameters.SHARDS_AND_DAYS)) { - config.setQueryTree(timedAddShardsAndDaysFromOptions(timers, config.getQueryTree(), optionsMap)); - } else { - // look for the shards and days hint in the query settings - // the shards and days hint cannot always be specified in the query string when using certain query parsers - Parameter parameter = settings.findParameter(QueryParameters.SHARDS_AND_DAYS); - if (StringUtils.isNotBlank(parameter.getParameterValue())) { - optionsMap.put(QueryParameters.SHARDS_AND_DAYS, parameter.getParameterValue()); + // Do not add a SHARDS_AND_DAYS hint if it is specifically not allowed. This was checked and updated when timedIncludeDateFilters was called. + if (config.isShardsAndDaysHintAllowed()) { + if (optionsMap.containsKey(QueryParameters.SHARDS_AND_DAYS)) { config.setQueryTree(timedAddShardsAndDaysFromOptions(timers, config.getQueryTree(), optionsMap)); + } else { + // look for the shards and days hint in the query settings + // the shards and days hint cannot always be specified in the query string when using certain query parsers + Parameter parameter = settings.findParameter(QueryParameters.SHARDS_AND_DAYS); + if (StringUtils.isNotBlank(parameter.getParameterValue())) { + optionsMap.put(QueryParameters.SHARDS_AND_DAYS, parameter.getParameterValue()); + config.setQueryTree(timedAddShardsAndDaysFromOptions(timers, config.getQueryTree(), optionsMap)); + } } } @@ -2113,57 +2116,73 @@ public ASTJexlScript addDateFilters(final ASTJexlScript queryTree, ScannerFactor } } - // if we are using something other than the default of EVENT date - // time, then we need to modify the query - if (!dateType.equals(defaultDateType)) { + // Get the set of date types that should not be expanded if the end date is the current date. + // @formatter:off + Set noExpansionIfCurrent = config.getNoExpansionIfCurrent() == null ? Collections.emptySet() : + config.getNoExpansionIfCurrent().stream() + .map(String::trim) + .map(String::toUpperCase) + .collect(Collectors.toSet()); + // @formatter:on - log.info("Using the date index for " + dateType); - // if no date index helper configured, then we are in error - if (dateIndexHelper == null) { - throw new DatawaveQueryException("Requested date range of type " + dateType + " but no date index is configured"); - } - // get all of the fields used for this date type - DateIndexHelper.DateTypeDescription dateIndexData = dateIndexHelper.getTypeDescription(dateType, config.getBeginDate(), config.getEndDate(), - config.getDatatypeFilter()); - if (dateIndexData.getFields().isEmpty()) { - log.warn("The specified date type: " + dateType + " is unknown for the specified data types"); - // If this is the case, then essentially we have no dates to search. Adding the filter function with _NO_FIELD_ will have the desired effect. - // Also it will be understandable from the plan as to why no results were returned. - dateIndexData.getFields().add(Constants.NO_FIELD); - } - log.info("Adding date filters for the following fields: " + dateIndexData.getFields()); - // now for each field, add an expression to filter that date - List andChildren = new ArrayList<>(); - for (int i = 0; i < queryTree.jjtGetNumChildren(); i++) { - if (queryTree.jjtGetChild(i) instanceof ASTAndNode) { - andChildren.add(queryTree.jjtGetChild(i)); + // If the date type is one marked for no expansion if current, and the query's end date is the current date, do not add any date filters, and do not + // allow a SHARDS_AND_DAYS hint to be added later. + if (config.getNoExpansionIfCurrent().contains(dateType) && DateUtils.isSameDay(new Date(), config.getEndDate())) { + log.info("Query end date equals current date and date type " + dateType + + " is marked for no expansion if current. SHARDS_AND_DAYS hint will be forbidden."); + config.setShardsAndDaysHintAllowed(false); + } else { + // If we are using something other than the default of EVENT date time, then we need to modify the query. + if (!dateType.equals(defaultDateType)) { + log.info("Using the date index for " + dateType); + // if no date index helper configured, then we are in error + if (dateIndexHelper == null) { + throw new DatawaveQueryException("Requested date range of type " + dateType + " but no date index is configured"); + } + // get all of the fields used for this date type + DateIndexHelper.DateTypeDescription dateIndexData = dateIndexHelper.getTypeDescription(dateType, config.getBeginDate(), config.getEndDate(), + config.getDatatypeFilter()); + if (dateIndexData.getFields().isEmpty()) { + log.warn("The specified date type: " + dateType + " is unknown for the specified data types"); + // If this is the case, then essentially we have no dates to search. Adding the filter function with _NO_FIELD_ will have the desired + // effect. + // Also it will be understandable from the plan as to why no results were returned. + dateIndexData.getFields().add(Constants.NO_FIELD); + } + log.info("Adding date filters for the following fields: " + dateIndexData.getFields()); + // now for each field, add an expression to filter that date + List andChildren = new ArrayList<>(); + for (int i = 0; i < queryTree.jjtGetNumChildren(); i++) { + if (queryTree.jjtGetChild(i) instanceof ASTAndNode) { + andChildren.add(queryTree.jjtGetChild(i)); + } else { + andChildren.add(JexlNodeFactory.createExpression(queryTree.jjtGetChild(i))); + } + } + List orChildren = new ArrayList<>(); + for (String field : dateIndexData.getFields()) { + orChildren.add(createDateFilter(dateType, field, config.getBeginDate(), config.getEndDate())); + } + if (orChildren.size() > 1) { + andChildren.add(JexlNodeFactory.createOrNode(orChildren)); } else { - andChildren.add(JexlNodeFactory.createExpression(queryTree.jjtGetChild(i))); + andChildren.addAll(orChildren); } - } - List orChildren = new ArrayList<>(); - for (String field : dateIndexData.getFields()) { - orChildren.add(createDateFilter(dateType, field, config.getBeginDate(), config.getEndDate())); - } - if (orChildren.size() > 1) { - andChildren.add(JexlNodeFactory.createOrNode(orChildren)); + JexlNode andNode = JexlNodeFactory.createAndNode(andChildren); + JexlNodeFactory.setChildren(queryTree, Collections.singleton(andNode)); + + // now lets update the query parameters with the correct start and + // end dates + log.info("Remapped " + dateType + " dates [" + config.getBeginDate() + "," + config.getEndDate() + "] to EVENT dates " + + dateIndexData.getBeginDate() + "," + dateIndexData.getEndDate()); + + // reset the dates in the configuration, no need to reset then in + // the Query settings object + config.setBeginDate(dateIndexData.getBeginDate()); + config.setEndDate(dateIndexData.getEndDate()); } else { - andChildren.addAll(orChildren); + log.info("Date index not needed for this query"); } - JexlNode andNode = JexlNodeFactory.createAndNode(andChildren); - JexlNodeFactory.setChildren(queryTree, Collections.singleton(andNode)); - - // now lets update the query parameters with the correct start and - // end dates - log.info("Remapped " + dateType + " dates [" + config.getBeginDate() + "," + config.getEndDate() + "] to EVENT dates " - + dateIndexData.getBeginDate() + "," + dateIndexData.getEndDate()); - - // reset the dates in the configuration, no need to reset then in - // the Query settings object - config.setBeginDate(dateIndexData.getBeginDate()); - config.setEndDate(dateIndexData.getEndDate()); - } else { - log.info("Date index not needed for this query"); } return queryTree; @@ -2447,16 +2466,18 @@ public List getShuffledIvaratoCacheDirConfigs(ShardQuery */ protected IteratorSetting getQueryIterator(MetadataHelper metadataHelper, ShardQueryConfiguration config, String queryString, Boolean isFullTable, boolean isPreload) throws DatawaveQueryException { - if (null == settingFuture) + if (null == settingFuture) { settingFuture = loadQueryIterator(metadataHelper, config, isFullTable, isPreload); - if (settingFuture.isDone()) + } + if (settingFuture.isDone()) { try { return settingFuture.get(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e.getCause()); } - else + } else { return null; + } } public void configureTypeMappings(ShardQueryConfiguration config, IteratorSetting cfg, MetadataHelper metadataHelper, boolean compressMappings) diff --git a/warehouse/query-core/src/main/java/datawave/query/tables/ShardQueryLogic.java b/warehouse/query-core/src/main/java/datawave/query/tables/ShardQueryLogic.java index 5f0421bcb51..c9c9ea8d2bb 100644 --- a/warehouse/query-core/src/main/java/datawave/query/tables/ShardQueryLogic.java +++ b/warehouse/query-core/src/main/java/datawave/query/tables/ShardQueryLogic.java @@ -2990,4 +2990,12 @@ public void setFieldIndexHoleMinThreshold(double fieldIndexHoleMinThreshold) { public double getFieldIndexHoleMinThreshold(int fieldIndexHoleMinThreshold) { return getConfig().getFieldIndexHoleMinThreshold(); } + + public Set getNoExpansionIfCurrent() { + return getConfig().getNoExpansionIfCurrent(); + } + + public void setNoExpansionIfCurrent(Set noExpansionIfCurrent) { + getConfig().setNoExpansionIfCurrent(noExpansionIfCurrent); + } } diff --git a/warehouse/query-core/src/test/java/datawave/query/config/ShardQueryConfigurationTest.java b/warehouse/query-core/src/test/java/datawave/query/config/ShardQueryConfigurationTest.java index 69a8254a77f..f21b53b2793 100644 --- a/warehouse/query-core/src/test/java/datawave/query/config/ShardQueryConfigurationTest.java +++ b/warehouse/query-core/src/test/java/datawave/query/config/ShardQueryConfigurationTest.java @@ -596,6 +596,12 @@ public void setUp() throws Exception { updatedValues.put("useQueryTreeScanHintRules", true); defaultValues.put("queryTreeScanHintRules", Collections.emptyList()); updatedValues.put("queryTreeScanHintRules", Collections.singletonList(new IvaratorScanHint())); + + defaultValues.put("noExpansionIfCurrent", Collections.emptySet()); + updatedValues.put("noExpansionIfCurrent", Collections.singleton("EVENT")); + + defaultValues.put("shardsAndDaysHintAllowed", true); + updatedValues.put("shardsAndDaysHintAllowed", false); } private Query createQuery(String query) { diff --git a/warehouse/query-core/src/test/java/datawave/query/planner/DefaultQueryPlannerTest.java b/warehouse/query-core/src/test/java/datawave/query/planner/DefaultQueryPlannerTest.java new file mode 100644 index 00000000000..06599ae51d5 --- /dev/null +++ b/warehouse/query-core/src/test/java/datawave/query/planner/DefaultQueryPlannerTest.java @@ -0,0 +1,207 @@ +package datawave.query.planner; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Set; + +import org.apache.accumulo.core.client.TableNotFoundException; +import org.apache.commons.jexl3.parser.ASTJexlScript; +import org.apache.commons.jexl3.parser.ParseException; +import org.apache.commons.lang3.time.DateUtils; +import org.easymock.EasyMock; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import datawave.ingest.mapreduce.handler.dateindex.DateIndexUtil; +import datawave.microservice.query.Query; +import datawave.microservice.query.QueryImpl; +import datawave.query.QueryParameters; +import datawave.query.config.ShardQueryConfiguration; +import datawave.query.exceptions.DatawaveQueryException; +import datawave.query.jexl.JexlASTHelper; +import datawave.query.tables.ScannerFactory; +import datawave.query.util.DateIndexHelper; +import datawave.query.util.MetadataHelper; +import datawave.query.util.MockDateIndexHelper; +import datawave.test.JexlNodeAssert; +import datawave.util.time.DateHelper; + +class DefaultQueryPlannerTest { + + /** + * Contains tests for + * {@link DefaultQueryPlanner#addDateFilters(ASTJexlScript, ScannerFactory, MetadataHelper, DateIndexHelper, ShardQueryConfiguration, Query)} + */ + @Nested + class DateFilterTests { + + private final SimpleDateFormat filterFormat = new SimpleDateFormat("yyyyMMdd:HH:mm:ss:SSSZ"); + + private DefaultQueryPlanner planner; + private ShardQueryConfiguration config; + private QueryImpl settings; + private MockDateIndexHelper dateIndexHelper; + private ASTJexlScript queryTree; + + @BeforeEach + void setUp() throws ParseException { + planner = new DefaultQueryPlanner(); + config = new ShardQueryConfiguration(); + settings = new QueryImpl(); + dateIndexHelper = new MockDateIndexHelper(); + } + + /** + * Verify that when the date type is the default date type, and is part of the {@link ShardQueryConfiguration#noExpansionIfCurrent} types, and the + * query's end date is the current date, that no date filters are added and SHARDS_AND_DAYS hints are forbidden. + */ + @Test + void testDefaultDateTypeMarkedForNoExpansionAndEndDateIsCurrDate() throws Exception { + queryTree = JexlASTHelper.parseJexlQuery("FOO == 'bar'"); + config.setDefaultDateTypeName("EVENT"); + config.setNoExpansionIfCurrent(Set.of("EVENT")); + + Date beginDate = DateHelper.parse("20241001"); + config.setBeginDate(beginDate); + Date endDate = new Date(); + config.setEndDate(endDate); + + ASTJexlScript actual = addDateFilters(); + + JexlNodeAssert.assertThat(actual).isEqualTo("FOO == 'bar'"); + Assertions.assertFalse(config.isShardsAndDaysHintAllowed()); + Assertions.assertEquals(beginDate, config.getBeginDate()); + Assertions.assertEquals(endDate, config.getEndDate()); + } + + /** + * Verify that when a date type is given via parameters that is part of the {@link ShardQueryConfiguration#noExpansionIfCurrent} types, and the query's + * end date is the current date, that no date filters are added and SHARDS_AND_DAYS hints are forbidden. + */ + @Test + void testParamDateTypeMarkedForNoExpansionAndEndDateIsCurrDate() throws Exception { + queryTree = JexlASTHelper.parseJexlQuery("FOO == 'bar'"); + config.setDefaultDateTypeName("EVENT"); + config.setNoExpansionIfCurrent(Set.of("SPECIAL_EVENT")); + + Date beginDate = DateHelper.parse("20241001"); + config.setBeginDate(beginDate); + Date endDate = new Date(); + config.setEndDate(endDate); + + settings.addParameter(QueryParameters.DATE_RANGE_TYPE, "SPECIAL_EVENT"); + + ASTJexlScript actual = addDateFilters(); + + JexlNodeAssert.assertThat(actual).isEqualTo("FOO == 'bar'"); + Assertions.assertFalse(config.isShardsAndDaysHintAllowed()); + Assertions.assertEquals(beginDate, config.getBeginDate()); + Assertions.assertEquals(endDate, config.getEndDate()); + } + + /** + * Verify that when the date type is the default date type, and is part of the {@link ShardQueryConfiguration#noExpansionIfCurrent} types, but the + * query's end date is not the current date, that no date filters are added and SHARDS_AND_DAYS hints are allowed. + */ + @Test + void testDefaultDateTypeMarkedForNoExpansionAndEndDateIsNotCurrDate() throws Exception { + queryTree = JexlASTHelper.parseJexlQuery("FOO == 'bar'"); + config.setDefaultDateTypeName("EVENT"); + config.setNoExpansionIfCurrent(Set.of("EVENT")); + + Date beginDate = DateHelper.parse("20241001"); + config.setBeginDate(beginDate); + Date endDate = DateHelper.parse("20241010"); + config.setEndDate(endDate); + + ASTJexlScript actual = addDateFilters(); + + JexlNodeAssert.assertThat(actual).isEqualTo("FOO == 'bar'"); + Assertions.assertTrue(config.isShardsAndDaysHintAllowed()); + Assertions.assertEquals(beginDate, config.getBeginDate()); + Assertions.assertEquals(endDate, config.getEndDate()); + } + + /** + * Verify that when a date type is given via parameters that is part of the {@link ShardQueryConfiguration#noExpansionIfCurrent} types, but the query's + * end date is not the current date, that date filters are added and SHARDS_AND_DAYS hints are allowed. + */ + @Test + void testParamDateTypeMarkedForNoExpansionAndEndDateIsNotCurrDate() throws Exception { + queryTree = JexlASTHelper.parseJexlQuery("FOO == 'bar'"); + config.setDefaultDateTypeName("EVENT"); + config.setNoExpansionIfCurrent(Set.of("SPECIAL_EVENT")); + Date beginDate = DateHelper.parse("20241009"); + config.setBeginDate(beginDate); + Date endDate = DateHelper.parse("20241011"); + config.setEndDate(endDate); + settings.addParameter(QueryParameters.DATE_RANGE_TYPE, "SPECIAL_EVENT"); + dateIndexHelper.addEntry("20241010", "SPECIAL_EVENT", "wiki", "FOO", "20241010_shard"); + + ASTJexlScript actual = addDateFilters(); + + JexlNodeAssert.assertThat(actual).hasExactQueryString( + "(FOO == 'bar') && filter:betweenDates(FOO, '" + filterFormat.format(beginDate) + "', '" + filterFormat.format(endDate) + "')"); + Assertions.assertTrue(config.isShardsAndDaysHintAllowed()); + Assertions.assertEquals(DateIndexUtil.getBeginDate("20241010"), config.getBeginDate()); + Assertions.assertEquals(DateIndexUtil.getEndDate("20241010"), config.getEndDate()); + } + + /** + * Verify that when the date type is the default date type, and is not part of the {@link ShardQueryConfiguration#noExpansionIfCurrent} types, and the + * query's end date is the current date, that no date filters are added and SHARDS_AND_DAYS hints are allowed. + */ + @Test + void testDefaultDateTypeIsNotMarkedForNoExpansionAndEndDateNotCurrDate() throws Exception { + queryTree = JexlASTHelper.parseJexlQuery("FOO == 'bar'"); + config.setDefaultDateTypeName("EVENT"); + config.setNoExpansionIfCurrent(Set.of("OTHER_EVENT")); + + Date beginDate = DateHelper.parse("20241001"); + config.setBeginDate(beginDate); + Date endDate = DateHelper.parse("20241010"); + config.setEndDate(endDate); + + ASTJexlScript actual = addDateFilters(); + + JexlNodeAssert.assertThat(actual).isEqualTo("FOO == 'bar'"); + Assertions.assertTrue(config.isShardsAndDaysHintAllowed()); + Assertions.assertEquals(beginDate, config.getBeginDate()); + Assertions.assertEquals(endDate, config.getEndDate()); + } + + /** + * Verify that when a date type is given via parameters that is not part of the {@link ShardQueryConfiguration#noExpansionIfCurrent} types, and the + * query's end date is the current date, that date filters are added and SHARDS_AND_DAYS hints are allowed. + */ + @Test + void testParamDateTypeIsNotMarkedForNoExpansionAndEndDateIsCurrDate() throws Exception { + queryTree = JexlASTHelper.parseJexlQuery("FOO == 'bar'"); + config.setDefaultDateTypeName("EVENT"); + config.setNoExpansionIfCurrent(Set.of("OTHER_EVENT")); + config.setBeginDate(DateHelper.parse("20241009")); + Date beginDate = DateHelper.parse("20241001"); + config.setBeginDate(beginDate); + Date endDate = new Date(); + config.setEndDate(endDate); + + settings.addParameter(QueryParameters.DATE_RANGE_TYPE, "SPECIAL_EVENT"); + dateIndexHelper.addEntry("20241010", "SPECIAL_EVENT", "wiki", "FOO", "20241010_shard"); + + ASTJexlScript actual = addDateFilters(); + + JexlNodeAssert.assertThat(actual).hasExactQueryString( + "(FOO == 'bar') && filter:betweenDates(FOO, '" + filterFormat.format(beginDate) + "', '" + filterFormat.format(endDate) + "')"); + Assertions.assertTrue(config.isShardsAndDaysHintAllowed()); + Assertions.assertEquals(DateIndexUtil.getBeginDate("20241010"), config.getBeginDate()); + Assertions.assertEquals(DateIndexUtil.getEndDate("20241010"), config.getEndDate()); + } + + private ASTJexlScript addDateFilters() throws TableNotFoundException, DatawaveQueryException { + return planner.addDateFilters(queryTree, null, null, dateIndexHelper, config, settings); + } + } +}