|
31 | 31 | import org.elasticsearch.xpack.esql.core.type.InvalidMappedField; |
32 | 32 | import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; |
33 | 33 | import org.elasticsearch.xpack.esql.expression.function.scalar.conditional.Case; |
| 34 | +import org.elasticsearch.xpack.esql.expression.function.scalar.math.RoundTo; |
34 | 35 | import org.elasticsearch.xpack.esql.expression.function.scalar.nulls.Coalesce; |
35 | 36 | import org.elasticsearch.xpack.esql.expression.function.scalar.string.StartsWith; |
36 | 37 | import org.elasticsearch.xpack.esql.expression.function.scalar.string.regex.RLike; |
|
51 | 52 | import org.elasticsearch.xpack.esql.plan.logical.MvExpand; |
52 | 53 | import org.elasticsearch.xpack.esql.plan.logical.Project; |
53 | 54 | import org.elasticsearch.xpack.esql.plan.logical.Row; |
| 55 | +import org.elasticsearch.xpack.esql.plan.logical.TopN; |
54 | 56 | import org.elasticsearch.xpack.esql.plan.logical.UnaryPlan; |
55 | 57 | import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject; |
56 | 58 | import org.elasticsearch.xpack.esql.plan.logical.local.LocalRelation; |
|
83 | 85 | import static org.elasticsearch.xpack.esql.EsqlTestUtils.unboundLogicalOptimizerContext; |
84 | 86 | import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning; |
85 | 87 | import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; |
| 88 | +import static org.elasticsearch.xpack.esql.core.type.DataType.DATETIME; |
86 | 89 | import static org.hamcrest.Matchers.contains; |
87 | 90 | import static org.hamcrest.Matchers.equalTo; |
88 | 91 | import static org.hamcrest.Matchers.hasSize; |
@@ -774,6 +777,89 @@ public void testGroupingByMissingFields() { |
774 | 777 | as(eval.child(), EsRelation.class); |
775 | 778 | } |
776 | 779 |
|
| 780 | + public void testSubstituteDateTruncInEvalWithRoundTo() { |
| 781 | + var plan = plan(""" |
| 782 | + from test |
| 783 | + | sort hire_date |
| 784 | + | eval x = date_trunc(1 day, hire_date) |
| 785 | + | keep emp_no, hire_date, x |
| 786 | + | limit 5 |
| 787 | + """); |
| 788 | + |
| 789 | + // create a SearchStats with min and max millis |
| 790 | + Map<String, Object> minValue = Map.of("hire_date", 1697804103360L); // 2023-10-20T12:15:03.360Z |
| 791 | + Map<String, Object> maxValue = Map.of("hire_date", 1698069301543L); // 2023-10-23T13:55:01.543Z |
| 792 | + SearchStats searchStats = new EsqlTestUtils.TestSearchStatsWithMinMax(minValue, maxValue); |
| 793 | + |
| 794 | + LogicalPlan localPlan = localPlan(plan, searchStats); |
| 795 | + Project project = as(localPlan, Project.class); |
| 796 | + TopN topN = as(project.child(), TopN.class); |
| 797 | + Eval eval = as(topN.child(), Eval.class); |
| 798 | + List<Alias> fields = eval.fields(); |
| 799 | + assertEquals(1, fields.size()); |
| 800 | + Alias a = fields.get(0); |
| 801 | + assertEquals("x", a.name()); |
| 802 | + RoundTo roundTo = as(a.child(), RoundTo.class); |
| 803 | + FieldAttribute fa = as(roundTo.field(), FieldAttribute.class); |
| 804 | + assertEquals("hire_date", fa.name()); |
| 805 | + assertEquals(DATETIME, fa.dataType()); |
| 806 | + assertEquals(4, roundTo.points().size()); // 4 days |
| 807 | + EsRelation relation = as(eval.child(), EsRelation.class); |
| 808 | + } |
| 809 | + |
| 810 | + public void testSubstituteDateTruncInAggWithRoundTo() { |
| 811 | + var plan = plan(""" |
| 812 | + from test |
| 813 | + | stats count(*) by x = date_trunc(1 day, hire_date) |
| 814 | + """); |
| 815 | + |
| 816 | + // create a SearchStats with min and max millis |
| 817 | + Map<String, Object> minValue = Map.of("hire_date", 1697804103360L); // 2023-10-20T12:15:03.360Z |
| 818 | + Map<String, Object> maxValue = Map.of("hire_date", 1698069301543L); // 2023-10-23T13:55:01.543Z |
| 819 | + SearchStats searchStats = new EsqlTestUtils.TestSearchStatsWithMinMax(minValue, maxValue); |
| 820 | + |
| 821 | + LogicalPlan localPlan = localPlan(plan, searchStats); |
| 822 | + Limit limit = as(localPlan, Limit.class); |
| 823 | + Aggregate aggregate = as(limit.child(), Aggregate.class); |
| 824 | + Eval eval = as(aggregate.child(), Eval.class); |
| 825 | + List<Alias> fields = eval.fields(); |
| 826 | + assertEquals(1, fields.size()); |
| 827 | + Alias a = fields.get(0); |
| 828 | + assertEquals("x", a.name()); |
| 829 | + RoundTo roundTo = as(a.child(), RoundTo.class); |
| 830 | + FieldAttribute fa = as(roundTo.field(), FieldAttribute.class); |
| 831 | + assertEquals("hire_date", fa.name()); |
| 832 | + assertEquals(DATETIME, fa.dataType()); |
| 833 | + assertEquals(4, roundTo.points().size()); // 4 days |
| 834 | + EsRelation relation = as(eval.child(), EsRelation.class); |
| 835 | + } |
| 836 | + |
| 837 | + public void testSubstituteBucketInAggWithRoundTo() { |
| 838 | + var plan = plan(""" |
| 839 | + from test |
| 840 | + | stats count(*) by x = bucket(hire_date, 1 day) |
| 841 | + """); |
| 842 | + // create a SearchStats with min and max millis |
| 843 | + Map<String, Object> minValue = Map.of("hire_date", 1697804103360L); // 2023-10-20T12:15:03.360Z |
| 844 | + Map<String, Object> maxValue = Map.of("hire_date", 1698069301543L); // 2023-10-23T13:55:01.543Z |
| 845 | + SearchStats searchStats = new EsqlTestUtils.TestSearchStatsWithMinMax(minValue, maxValue); |
| 846 | + |
| 847 | + LogicalPlan localPlan = localPlan(plan, searchStats); |
| 848 | + Limit limit = as(localPlan, Limit.class); |
| 849 | + Aggregate aggregate = as(limit.child(), Aggregate.class); |
| 850 | + Eval eval = as(aggregate.child(), Eval.class); |
| 851 | + List<Alias> fields = eval.fields(); |
| 852 | + assertEquals(1, fields.size()); |
| 853 | + Alias a = fields.get(0); |
| 854 | + assertEquals("x", a.name()); |
| 855 | + RoundTo roundTo = as(a.child(), RoundTo.class); |
| 856 | + FieldAttribute fa = as(roundTo.field(), FieldAttribute.class); |
| 857 | + assertEquals("hire_date", fa.name()); |
| 858 | + assertEquals(DATETIME, fa.dataType()); |
| 859 | + assertEquals(4, roundTo.points().size()); // 4 days |
| 860 | + EsRelation relation = as(eval.child(), EsRelation.class); |
| 861 | + } |
| 862 | + |
777 | 863 | private IsNotNull isNotNull(Expression field) { |
778 | 864 | return new IsNotNull(EMPTY, field); |
779 | 865 | } |
|
0 commit comments