1111import com .carrotsearch .randomizedtesting .annotations .ParametersFactory ;
1212
1313import org .elasticsearch .common .Rounding ;
14+ import org .elasticsearch .common .time .DateUtils ;
1415import org .elasticsearch .index .mapper .DateFieldMapper ;
1516import org .elasticsearch .logging .LogManager ;
1617import org .elasticsearch .xpack .esql .core .expression .Expression ;
1920import org .elasticsearch .xpack .esql .expression .function .AbstractScalarFunctionTestCase ;
2021import org .elasticsearch .xpack .esql .expression .function .TestCaseSupplier ;
2122import org .hamcrest .Matcher ;
23+ import org .hamcrest .Matchers ;
2224
2325import java .time .Duration ;
2426import java .time .Instant ;
2931import java .util .function .Supplier ;
3032
3133import static org .hamcrest .Matchers .equalTo ;
32- import static org .hamcrest .Matchers .hasSize ;
3334
3435public class TBucketTests extends AbstractScalarFunctionTestCase {
3536 public TBucketTests (@ Name ("TestCase" ) Supplier <TestCaseSupplier .TestCase > testCaseSupplier ) {
@@ -55,6 +56,20 @@ public static Iterable<Object[]> parameters() {
5556 Duration .ofDays (1L ),
5657 "[86400000 in Z][fixed]"
5758 );
59+ dateNanosCasesWithSpan (
60+ suppliers ,
61+ "fixed date nanos with period" ,
62+ () -> DateUtils .toLong (Instant .parse ("2023-01-01T00:00:00.00Z" )),
63+ DataType .DATE_PERIOD ,
64+ Period .ofYears (1 )
65+ );
66+ dateNanosCasesWithSpan (
67+ suppliers ,
68+ "fixed date nanos with duration" ,
69+ () -> DateUtils .toLong (Instant .parse ("2023-02-17T09:00:00.00Z" )),
70+ DataType .TIME_DURATION ,
71+ Duration .ofDays (1L )
72+ );
5873 return parameterSuppliersFromTypedData (suppliers );
5974 }
6075
@@ -69,7 +84,7 @@ private static void dateCasesWithSpan(
6984 suppliers .add (new TestCaseSupplier (name , List .of (spanType , DataType .DATETIME ), () -> {
7085 List <TestCaseSupplier .TypedData > args = new ArrayList <>();
7186 args .add (new TestCaseSupplier .TypedData (span , spanType , "buckets" ).forceLiteral ());
72- args .add (new TestCaseSupplier .TypedData (date .getAsLong (), DataType .DATETIME , "field " ));
87+ args .add (new TestCaseSupplier .TypedData (date .getAsLong (), DataType .DATETIME , "@timestamp " ));
7388
7489 return new TestCaseSupplier .TestCase (
7590 args ,
@@ -80,7 +95,38 @@ private static void dateCasesWithSpan(
8095 }));
8196 }
8297
98+ private static void dateNanosCasesWithSpan (
99+ List <TestCaseSupplier > suppliers ,
100+ String name ,
101+ LongSupplier date ,
102+ DataType spanType ,
103+ Object span
104+ ) {
105+ suppliers .add (new TestCaseSupplier (name , List .of (spanType , DataType .DATE_NANOS ), () -> {
106+ List <TestCaseSupplier .TypedData > args = new ArrayList <>();
107+ args .add (new TestCaseSupplier .TypedData (span , spanType , "buckets" ).forceLiteral ());
108+ args .add (new TestCaseSupplier .TypedData (date .getAsLong (), DataType .DATE_NANOS , "@timestamp" ));
109+ return new TestCaseSupplier .TestCase (
110+ args ,
111+ Matchers .startsWith ("DateTruncDateNanosEvaluator[fieldVal=Attribute[channel=0], rounding=Rounding[" ),
112+ DataType .DATE_NANOS ,
113+ resultsMatcher (args )
114+ );
115+ }));
116+ }
117+
83118 private static Matcher <Object > resultsMatcher (List <TestCaseSupplier .TypedData > typedData ) {
119+ if (typedData .get (1 ).type () == DataType .DATE_NANOS ) {
120+ long nanos = ((Number ) typedData .get (1 ).data ()).longValue ();
121+ long expected = DateUtils .toNanoSeconds (
122+ Rounding .builder (Rounding .DateTimeUnit .DAY_OF_MONTH ).build ().prepareForUnknown ().round (DateUtils .toMilliSeconds (nanos ))
123+ );
124+ LogManager .getLogger (getTestClass ()).info ("Expected: " + DateUtils .toInstant (expected ));
125+ LogManager .getLogger (getTestClass ()).info ("Input: " + DateUtils .toInstant (nanos ));
126+ return equalTo (expected );
127+ }
128+
129+ // For DATETIME, we use the millis value directly
84130 long millis = ((Number ) typedData .get (1 ).data ()).longValue ();
85131 long expected = Rounding .builder (Rounding .DateTimeUnit .DAY_OF_MONTH ).build ().prepareForUnknown ().round (millis );
86132 LogManager .getLogger (getTestClass ()).info ("Expected: " + Instant .ofEpochMilli (expected ));
@@ -98,9 +144,16 @@ protected boolean canSerialize() {
98144 return false ;
99145 }
100146
101- public static List <DataType > signatureTypes (List <DataType > testCaseTypes ) {
102- assertThat (testCaseTypes , hasSize (2 ));
103- assertThat (testCaseTypes .get (1 ), equalTo (DataType .DATETIME ));
104- return List .of (testCaseTypes .get (0 ));
105- }
147+ // TODO: With this method commented the V3Doc fails
148+ // public static List<DataType> signatureTypes(List<DataType> testCaseTypes) {
149+ // // DATE_PERIOD, DATETIME
150+ // // DATE_PERIOD, DATE_NANOS
151+ //
152+ // // TIME_DURATION, DATETIME
153+ // // TIME_DURATION, DATE_NANOS
154+ //
155+ // assertThat(testCaseTypes, hasSize(2));
156+ // // assertThat(testCaseTypes.get(1), anyOf(equalTo(DataType.DATE_NANOS), equalTo(DataType.DATETIME)));
157+ // return List.of(testCaseTypes.get(0), testCaseTypes.get(1));
158+ // }
106159}
0 commit comments