diff --git a/docs/reference/query-languages/esql/_snippets/functions/description/to_aggregate_metric_double.md b/docs/reference/query-languages/esql/_snippets/functions/description/to_aggregate_metric_double.md deleted file mode 100644 index 144c427ff07cb..0000000000000 --- a/docs/reference/query-languages/esql/_snippets/functions/description/to_aggregate_metric_double.md +++ /dev/null @@ -1,6 +0,0 @@ -% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it. - -**Description** - -Encode a numeric to an aggregate_metric_double. - diff --git a/docs/reference/query-languages/esql/_snippets/functions/examples/to_lower.md b/docs/reference/query-languages/esql/_snippets/functions/examples/to_lower.md index f8ed6a7072437..cbab7915f6bf5 100644 --- a/docs/reference/query-languages/esql/_snippets/functions/examples/to_lower.md +++ b/docs/reference/query-languages/esql/_snippets/functions/examples/to_lower.md @@ -1,6 +1,6 @@ % This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it. -**Examples** +**Example** ```esql ROW message = "Some Text" @@ -11,12 +11,4 @@ ROW message = "Some Text" | --- | --- | | Some Text | some text | -```esql -ROW v = TO_LOWER(["Some", "Text"]) -``` - -| v:keyword | -| --- | -| ["some", "text"] | - diff --git a/docs/reference/query-languages/esql/_snippets/functions/layout/to_aggregate_metric_double.md b/docs/reference/query-languages/esql/_snippets/functions/layout/to_aggregate_metric_double.md deleted file mode 100644 index ed65b3d386bcd..0000000000000 --- a/docs/reference/query-languages/esql/_snippets/functions/layout/to_aggregate_metric_double.md +++ /dev/null @@ -1,23 +0,0 @@ -% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it. - -## `TO_AGGREGATE_METRIC_DOUBLE` [esql-to_aggregate_metric_double] -```{applies_to} -product: COMING 9.1 -``` - -**Syntax** - -:::{image} ../../../images/functions/to_aggregate_metric_double.svg -:alt: Embedded -:class: text-center -::: - - -:::{include} ../parameters/to_aggregate_metric_double.md -::: - -:::{include} ../description/to_aggregate_metric_double.md -::: - -:::{include} ../types/to_aggregate_metric_double.md -::: diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/to_aggregate_metric_double.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/to_aggregate_metric_double.md deleted file mode 100644 index 5204e46661d48..0000000000000 --- a/docs/reference/query-languages/esql/_snippets/functions/parameters/to_aggregate_metric_double.md +++ /dev/null @@ -1,7 +0,0 @@ -% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it. - -**Parameters** - -`number` -: Input value. The input can be a single-valued column or an expression. - diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/to_lower.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/to_lower.md index 29bfbc291af5e..122e76c5af875 100644 --- a/docs/reference/query-languages/esql/_snippets/functions/parameters/to_lower.md +++ b/docs/reference/query-languages/esql/_snippets/functions/parameters/to_lower.md @@ -3,5 +3,5 @@ **Parameters** `str` -: String expression. If `null`, the function returns `null`. The input can be a single- or multi-valued column or an expression. +: String expression. If `null`, the function returns `null`. diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/to_upper.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/to_upper.md index 29bfbc291af5e..122e76c5af875 100644 --- a/docs/reference/query-languages/esql/_snippets/functions/parameters/to_upper.md +++ b/docs/reference/query-languages/esql/_snippets/functions/parameters/to_upper.md @@ -3,5 +3,5 @@ **Parameters** `str` -: String expression. If `null`, the function returns `null`. The input can be a single- or multi-valued column or an expression. +: String expression. If `null`, the function returns `null`. diff --git a/docs/reference/query-languages/esql/images/functions/to_aggregate_metric_double.svg b/docs/reference/query-languages/esql/images/functions/to_aggregate_metric_double.svg deleted file mode 100644 index 12550278d6e36..0000000000000 --- a/docs/reference/query-languages/esql/images/functions/to_aggregate_metric_double.svg +++ /dev/null @@ -1 +0,0 @@ -TO_AGGREGATE_METRIC_DOUBLE(number) \ No newline at end of file diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/to_aggregate_metric_double.json b/docs/reference/query-languages/esql/kibana/definition/functions/to_aggregate_metric_double.json deleted file mode 100644 index 0336ca89e19e9..0000000000000 --- a/docs/reference/query-languages/esql/kibana/definition/functions/to_aggregate_metric_double.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "comment" : "This is generated by ESQL’s AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", - "type" : "scalar", - "name" : "to_aggregate_metric_double", - "description" : "Encode a numeric to an aggregate_metric_double.", - "signatures" : [ ], - "preview" : false, - "snapshot_only" : false -} diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/to_lower.json b/docs/reference/query-languages/esql/kibana/definition/functions/to_lower.json index fdff47a19e369..1b77709586a59 100644 --- a/docs/reference/query-languages/esql/kibana/definition/functions/to_lower.json +++ b/docs/reference/query-languages/esql/kibana/definition/functions/to_lower.json @@ -10,7 +10,7 @@ "name" : "str", "type" : "keyword", "optional" : false, - "description" : "String expression. If `null`, the function returns `null`. The input can be a single- or multi-valued column or an expression." + "description" : "String expression. If `null`, the function returns `null`." } ], "variadic" : false, @@ -22,7 +22,7 @@ "name" : "str", "type" : "text", "optional" : false, - "description" : "String expression. If `null`, the function returns `null`. The input can be a single- or multi-valued column or an expression." + "description" : "String expression. If `null`, the function returns `null`." } ], "variadic" : false, @@ -30,8 +30,7 @@ } ], "examples" : [ - "ROW message = \"Some Text\"\n| EVAL message_lower = TO_LOWER(message)", - "ROW v = TO_LOWER([\"Some\", \"Text\"])" + "ROW message = \"Some Text\"\n| EVAL message_lower = TO_LOWER(message)" ], "preview" : false, "snapshot_only" : false diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/to_upper.json b/docs/reference/query-languages/esql/kibana/definition/functions/to_upper.json index 422830552342c..efd6885ad350a 100644 --- a/docs/reference/query-languages/esql/kibana/definition/functions/to_upper.json +++ b/docs/reference/query-languages/esql/kibana/definition/functions/to_upper.json @@ -10,7 +10,7 @@ "name" : "str", "type" : "keyword", "optional" : false, - "description" : "String expression. If `null`, the function returns `null`. The input can be a single- or multi-valued column or an expression." + "description" : "String expression. If `null`, the function returns `null`." } ], "variadic" : false, @@ -22,7 +22,7 @@ "name" : "str", "type" : "text", "optional" : false, - "description" : "String expression. If `null`, the function returns `null`. The input can be a single- or multi-valued column or an expression." + "description" : "String expression. If `null`, the function returns `null`." } ], "variadic" : false, diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/to_aggregate_metric_double.md b/docs/reference/query-languages/esql/kibana/docs/functions/to_aggregate_metric_double.md deleted file mode 100644 index 0dea481d1a773..0000000000000 --- a/docs/reference/query-languages/esql/kibana/docs/functions/to_aggregate_metric_double.md +++ /dev/null @@ -1,7 +0,0 @@ - - -### TO_AGGREGATE_METRIC_DOUBLE -Encode a numeric to an aggregate_metric_double. - diff --git a/x-pack/plugin/esql/build.gradle b/x-pack/plugin/esql/build.gradle index fcbd72e9bacbd..70210571058be 100644 --- a/x-pack/plugin/esql/build.gradle +++ b/x-pack/plugin/esql/build.gradle @@ -167,6 +167,13 @@ tasks.named("test").configure { List kibana = kibanaTree.files.collect { it.name } int countKibana = kibana.size() + Closure replaceLinks = line -> { + // The kibana docs are not deployed to the normal docs location, so need absolute paths for internal references + line.replaceAll( + /\]\(\/reference\/([^)\s]+)\.md(#\S+)?\)/, + '](https://www.elastic.co/docs/reference/elasticsearch/$1$2)' + ) + } if (countKibana == 0) { logger.quiet("ESQL Docs: No function/operator kibana docs created. Skipping sync.") } else { @@ -181,6 +188,7 @@ tasks.named("test").configure { include '**/*.md', '**/*.json' } } + filter replaceLinks } } } diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/convert.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/convert.csv-spec index 49960d1b5b0f3..4acdbc7cc714c 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/convert.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/convert.csv-spec @@ -218,7 +218,8 @@ emp_no:integer | languages:integer | height:double convertToDatePeriod required_capability: cast_string_literal_to_temporal_amount //tag::castToDatePeriod[] -row x = "2024-01-01"::datetime | eval y = x + "3 DAYS"::date_period, z = x - to_dateperiod("3 days"); +ROW x = "2024-01-01"::datetime +| EVAL y = x + "3 DAYS"::date_period, z = x - TO_DATEPERIOD("3 days"); //end::castToDatePeriod[] //tag::castToDatePeriod-result[] @@ -230,7 +231,8 @@ x:datetime |y:datetime |z:datetime convertToTimeDuration required_capability: cast_string_literal_to_temporal_amount //tag::castToTimeDuration[] -row x = "2024-01-01"::datetime | eval y = x + "3 hours"::time_duration, z = x - to_timeduration("3 hours"); +ROW x = "2024-01-01"::datetime +| EVAL y = x + "3 hours"::time_duration, z = x - TO_TIMEDURATION("3 hours"); //end::castToTimeDuration[] //tag::castToTimeDuration-result[] diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec index e5cab8de8092b..1689a4f642b59 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec @@ -344,7 +344,8 @@ null docsDateDiff#[skip:-8.12.99, reason:date_diff added in 8.13] // tag::docsDateDiff[] -ROW date1 = TO_DATETIME("2023-12-02T11:00:00.000Z"), date2 = TO_DATETIME("2023-12-02T11:00:00.001Z") +ROW date1 = TO_DATETIME("2023-12-02T11:00:00.000Z"), + date2 = TO_DATETIME("2023-12-02T11:00:00.001Z") | EVAL dd_ms = DATE_DIFF("microseconds", date1, date2) // end::docsDateDiff[] ; @@ -425,12 +426,12 @@ evalDateDiffYearForDocs required_capability: date_diff_year_calendarial // tag::evalDateDiffYearForDocs[] -ROW end_23=TO_DATETIME("2023-12-31T23:59:59.999Z"), - start_24=TO_DATETIME("2024-01-01T00:00:00.000Z"), - end_24=TO_DATETIME("2024-12-31T23:59:59.999") -| EVAL end23_to_start24=DATE_DIFF("year", end_23, start_24) -| EVAL end23_to_end24=DATE_DIFF("year", end_23, end_24) -| EVAL start_to_end_24=DATE_DIFF("year", start_24, end_24) +ROW end_23 = TO_DATETIME("2023-12-31T23:59:59.999Z"), + start_24 = TO_DATETIME("2024-01-01T00:00:00.000Z"), + end_24 = TO_DATETIME("2024-12-31T23:59:59.999") +| EVAL end23_to_start24 = DATE_DIFF("year", end_23, start_24) +| EVAL end23_to_end24 = DATE_DIFF("year", end_23, end_24) +| EVAL start_to_end_24 = DATE_DIFF("year", start_24, end_24) // end::evalDateDiffYearForDocs[] ; @@ -1002,7 +1003,8 @@ date:date | year:long docsDateExtractBusinessHours // tag::docsDateExtractBusinessHours[] FROM sample_data -| WHERE DATE_EXTRACT("hour_of_day", @timestamp) < 9 AND DATE_EXTRACT("hour_of_day", @timestamp) >= 17 +| WHERE DATE_EXTRACT("hour_of_day", @timestamp) < 9 + AND DATE_EXTRACT("hour_of_day", @timestamp) >= 17 // end::docsDateExtractBusinessHours[] ; @@ -1214,16 +1216,20 @@ required_capability: agg_values mvAppendDates required_capability: fn_mv_append +// tag::mv_append_date[] FROM employees | WHERE emp_no == 10039 OR emp_no == 10040 | SORT emp_no -| EVAL dates = mv_append(birth_date, hire_date) +| EVAL dates = MV_APPEND(birth_date, hire_date) | KEEP emp_no, birth_date, hire_date, dates +// end::mv_append_date[] ; +// tag::mv_append_date-result[] emp_no:integer | birth_date:date | hire_date:date | dates:date 10039 | 1959-10-01T00:00:00Z | 1988-01-19T00:00:00Z | [1959-10-01T00:00:00Z, 1988-01-19T00:00:00Z] 10040 | null | 1993-02-14T00:00:00Z | null +// end::mv_append_date-result[] ; diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date_nanos.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date_nanos.csv-spec index fdc5683d07a99..7fcffb63a30f7 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date_nanos.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date_nanos.csv-spec @@ -619,11 +619,19 @@ date nanos less than required_capability: to_date_nanos required_capability: date_nanos_binary_comparison -FROM date_nanos | WHERE MV_MIN(nanos) < TO_DATE_NANOS("2023-10-23T12:27:28.948Z") AND millis > "2000-01-01" | SORT nanos DESC; +// tag::to_date_nanos[] +FROM date_nanos +| WHERE MV_MIN(nanos) < TO_DATE_NANOS("2023-10-23T12:27:28.948Z") + AND millis > "2000-01-01" +| SORT nanos DESC +// end::to_date_nanos[] +; +// tag::to_date_nanos-result[] millis:date | nanos:date_nanos | num:long 2023-10-23T12:15:03.360Z | 2023-10-23T12:15:03.360103847Z | 1698063303360103847 2023-10-23T12:15:03.360Z | 2023-10-23T12:15:03.360103847Z | 1698063303360103847 +// end::to_date_nanos-result[] ; date nanos less than, no mv min diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ip.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ip.csv-spec index ac211c1e6c49a..e8d59628c29fc 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ip.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ip.csv-spec @@ -548,8 +548,8 @@ beta | 127.0.0.1 ipPrefix required_capability: fn_ip_prefix //tag::ipPrefix[] -row ip4 = to_ip("1.2.3.4"), ip6 = to_ip("fe80::cae2:65ff:fece:feb9") -| eval ip4_prefix = ip_prefix(ip4, 24, 0), ip6_prefix = ip_prefix(ip6, 0, 112); +ROW ip4 = to_ip("1.2.3.4"), ip6 = TO_IP("fe80::cae2:65ff:fece:feb9") +| EVAL ip4_prefix = IP_PREFIX(ip4, 24, 0), ip6_prefix = IP_PREFIX(ip6, 0, 112); //end::ipPrefix[] //tag::ipPrefix-result[] diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/math.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/math.csv-spec index 8ccd78d04e076..757cab264a9e6 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/math.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/math.csv-spec @@ -237,7 +237,7 @@ base: double | value: double | s:double ; logofNegativeValue#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = 2.0, value = -2 +ROW base = 2.0, value = -2 | EVAL s = LOG(base, value); warning:Line 2:12: evaluation of [LOG(base, value)] failed, treating result as null. Only first 20 failures recorded. @@ -248,7 +248,7 @@ base: double | value: integer | s:double ; logofNegativeBase#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = -2, value = 2.0 +ROW base = -2, value = 2.0 | EVAL s = LOG(base, value); warning:Line 2:12: evaluation of [LOG(base, value)] failed, treating result as null. Only first 20 failures recorded. @@ -259,7 +259,7 @@ base: integer | value: double | s:double ; logofBaseOne#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = 1, value = 2 +ROW base = 1, value = 2 | EVAL s = LOG(base, value); warning:Line 2:12: evaluation of [LOG(base, value)] failed, treating result as null. Only first 20 failures recorded. @@ -270,7 +270,7 @@ base: integer | value: integer | s:double ; logofZero#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = 2.0, value = 0.0 +ROW base = 2.0, value = 0.0 | EVAL s = LOG(base, value); warning:Line 2:12: evaluation of [LOG(base, value)] failed, treating result as null. Only first 20 failures recorded. @@ -281,7 +281,7 @@ base:double | value:double | s:double ; logofNegativeZero#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = 2.0, value = -0.0 +ROW base = 2.0, value = -0.0 | EVAL s = LOG(base, value); warning:Line 2:12: evaluation of [LOG(base, value)] failed, treating result as null. Only first 20 failures recorded. @@ -292,7 +292,7 @@ base:double | value:double | s:double ; logofIntLong#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = 10, value = to_long(1000000000000) +ROW base = 10, value = to_long(1000000000000) | EVAL s = LOG(base, value); base:integer | value:long | s:double @@ -300,7 +300,7 @@ base:integer | value:long | s:double ; logofLongInt#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = to_long(1000000000000), value = 10 +ROW base = to_long(1000000000000), value = 10 | EVAL s = LOG(base, value); base:long | value:integer | s:double @@ -308,7 +308,7 @@ base:long | value:integer | s:double ; logofLongLong#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = to_long(1000000000000), value = to_long(1000000000000) +ROW base = to_long(1000000000000), value = to_long(1000000000000) | EVAL s = LOG(base, value); base:long | value:long | s:double @@ -316,7 +316,7 @@ base:long | value:long | s:double ; logofLongDouble#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = to_long(1000000000000), value = 10.0 +ROW base = to_long(1000000000000), value = 10.0 | EVAL s = LOG(base, value); base:long | value:double | s:double @@ -324,7 +324,7 @@ base:long | value:double | s:double ; logofDoubleLong#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = 10.0, value = to_long(1000000000000) +ROW base = 10.0, value = to_long(1000000000000) | EVAL s = LOG(base, value); base:double | value:long | s:double @@ -332,7 +332,7 @@ base:double | value:long | s:double ; logofLongUnsignedLong#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = to_long(1000000000000), value = to_ul(1000000000000000000) +ROW base = to_long(1000000000000), value = to_ul(1000000000000000000) | EVAL s = LOG(base, value); base:long | value:UNSIGNED_LONG | s:double @@ -340,7 +340,7 @@ base:long | value:UNSIGNED_LONG | s:double ; logofUnsignedLongLong#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = to_ul(1000000000000000000), value = to_long(1000000000000) +ROW base = to_ul(1000000000000000000), value = to_long(1000000000000) | EVAL s = LOG(base, value); base:UNSIGNED_LONG | value:long | s:double @@ -348,7 +348,7 @@ base:UNSIGNED_LONG | value:long | s:double ; logofIntUnsignedLong#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = 10, value = to_ul(1000000000000000000) +ROW base = 10, value = to_ul(1000000000000000000) | EVAL s = LOG(base, value); base:integer | value:UNSIGNED_LONG | s:double @@ -356,7 +356,7 @@ base:integer | value:UNSIGNED_LONG | s:double ; logofUnsignedLongInt#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = to_ul(1000000000000000000), value = 10 +ROW base = to_ul(1000000000000000000), value = 10 | EVAL s = LOG(base, value); base:UNSIGNED_LONG | value:integer | s:double @@ -364,7 +364,7 @@ base:UNSIGNED_LONG | value:integer | s:double ; logofUnsignedLongUnsignedLong#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = to_ul(1000000000000000000), value = to_ul(1000000000000000000) +ROW base = to_ul(1000000000000000000), value = to_ul(1000000000000000000) | EVAL s = LOG(base, value); base:UNSIGNED_LONG | value:UNSIGNED_LONG | s:double @@ -372,7 +372,7 @@ base:UNSIGNED_LONG | value:UNSIGNED_LONG | s:double ; logofUnsignedLongDouble#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = to_ul(1000000000000000000), value = 1000000000.0 +ROW base = to_ul(1000000000000000000), value = 1000000000.0 | EVAL s = LOG(base, value); base:UNSIGNED_LONG | value:double | s:double @@ -380,7 +380,7 @@ base:UNSIGNED_LONG | value:double | s:double ; logofDoubleUnsignedLong#[skip:-8.12.99,reason:new scalar function added in 8.13] -row base = 10.0, value = to_ul(1000000000000000000) +ROW base = 10.0, value = to_ul(1000000000000000000) | EVAL s = LOG(base, value); base:double | value:UNSIGNED_LONG | s:double @@ -389,7 +389,7 @@ base:double | value:UNSIGNED_LONG | s:double logofInt#[skip:-8.12.99,reason:new scalar function added in 8.13] // tag::logUnary[] -row value = 100 +ROW value = 100 | EVAL s = LOG(value); // end::logUnary[] @@ -400,7 +400,7 @@ value: integer | s:double ; logofLong#[skip:-8.12.99,reason:new scalar function added in 8.13] -row value = to_long(1000000000000) +ROW value = to_long(1000000000000) | EVAL s = LOG(value); value: long | s:double @@ -408,7 +408,7 @@ value: long | s:double ; logofUnsignedLong#[skip:-8.12.99,reason:new scalar function added in 8.13] -row value = to_ul(1000000000000000000) +ROW value = to_ul(1000000000000000000) | EVAL s = LOG(value); value: unsigned_long | s:double @@ -416,7 +416,7 @@ value: unsigned_long | s:double ; logofDouble#[skip:-8.12.99,reason:new scalar function added in 8.13] -row value = 1000000000000.0 +ROW value = 1000000000000.0 | EVAL s = LOG(value); value: double | s:double @@ -1323,7 +1323,7 @@ cbrt required_capability: fn_cbrt // tag::cbrt[] ROW d = 1000.0 -| EVAL c = cbrt(d) +| EVAL c = CBRT(d) // end::cbrt[] ; diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/stats.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/stats.csv-spec index b6c48ac0bb4b9..610baeca91c51 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/stats.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/stats.csv-spec @@ -2099,8 +2099,8 @@ FROM employees | STATS min = min(salary) by languages | SORT min + CASE(language weightedAvg required_capability: agg_weighted_avg -from employees -| stats w_avg_1 = weighted_avg(salary, 1), avg = avg(salary), w_avg_2 = weighted_avg(salary, height) +FROM employees +| STATS w_avg_1 = weighted_avg(salary, 1), avg = avg(salary), w_avg_2 = weighted_avg(salary, height) | EVAL w_avg_1 = ROUND(w_avg_1), avg = ROUND(avg), w_avg_2 = ROUND(w_avg_2) ; @@ -2112,7 +2112,7 @@ weightedAvgGrouping required_capability: agg_weighted_avg // tag::weighted-avg[] FROM employees -| STATS w_avg = WEIGHTED_AVG(salary, height) by languages +| STATS w_avg = WEIGHTED_AVG(salary, height) BY languages | EVAL w_avg = ROUND(w_avg) | KEEP w_avg, languages | SORT languages diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/string.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/string.csv-spec index 0019e22fce482..dc15644d927fa 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/string.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/string.csv-spec @@ -1722,9 +1722,9 @@ valuesGrouped required_capability: agg_values // tag::values-grouped[] - FROM employees +FROM employees | EVAL first_letter = SUBSTRING(first_name, 0, 1) -| STATS first_name=MV_SORT(VALUES(first_name)) BY first_letter +| STATS first_name = MV_SORT(VALUES(first_name)) BY first_letter | SORT first_letter // end::values-grouped[] ; @@ -1768,8 +1768,8 @@ M | [foo, bar] locate#[skip:-8.13.99,reason:new string function added in 8.14] // tag::locate[] -row a = "hello" -| eval a_ll = locate(a, "ll") +ROW a = "hello" +| EVAL a_ll = LOCATE(a, "ll") // end::locate[] ; @@ -1960,8 +1960,8 @@ base64Encode#[skip:-8.13.99,reason:new base64 function added in 8.14] required_capability: base64_decode_encode // tag::to_base64[] -row a = "elastic" -| eval e = to_base64(a) +ROW a = "elastic" +| EVAL e = TO_BASE64(a) // end::to_base64[] ; @@ -1975,8 +1975,8 @@ base64Decode#[skip:-8.13.99,reason:new base64 function added in 8.14] required_capability: base64_decode_encode // tag::from_base64[] -row a = "ZWxhc3RpYw==" -| eval d = from_base64(a) +ROW a = "ZWxhc3RpYw==" +| EVAL d = FROM_BASE64(a) // end::from_base64[] ; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java index 6677b757c8c6a..40b1b2b106d22 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java @@ -479,18 +479,20 @@ public static class ArgSignature { protected final String[] type; protected final String description; protected final boolean optional; + protected final boolean variadic; protected final DataType targetDataType; - public ArgSignature(String name, String[] type, String description, boolean optional, DataType targetDataType) { + public ArgSignature(String name, String[] type, String description, boolean optional, boolean variadic, DataType targetDataType) { this.name = name; this.type = type; this.description = description; this.optional = optional; + this.variadic = variadic; this.targetDataType = targetDataType; } - public ArgSignature(String name, String[] type, String description, boolean optional) { - this(name, type, description, optional, UNSUPPORTED); + public ArgSignature(String name, String[] type, String description, boolean optional, boolean variadic) { + this(name, type, description, optional, variadic, UNSUPPORTED); } public String name() { @@ -542,7 +544,7 @@ public static class MapArgSignature extends ArgSignature { private final Map mapParams; public MapArgSignature(String name, String description, boolean optional, Map mapParams) { - super(name, new String[] { "map" }, description, optional); + super(name, new String[] { "map" }, description, optional, false); this.mapParams = mapParams; } @@ -591,6 +593,13 @@ public List argNames() { return args.stream().map(ArgSignature::name).toList(); } + /** + * The signature of every argument. + */ + public List args() { + return args; + } + /** * The description of every argument. */ @@ -636,24 +645,25 @@ public static FunctionDescription description(FunctionDefinition def) { boolean variadic = false; for (int i = 1; i < params.length; i++) { // skipping 1st argument, the source if (Configuration.class.isAssignableFrom(params[i].getType()) == false) { - variadic |= List.class.isAssignableFrom(params[i].getType()); + boolean isList = List.class.isAssignableFrom(params[i].getType()); + variadic |= isList; MapParam mapParamInfo = params[i].getAnnotation(MapParam.class); // refactor this if (mapParamInfo != null) { args.add(mapParam(mapParamInfo)); } else { Param paramInfo = params[i].getAnnotation(Param.class); - args.add(paramInfo != null ? param(paramInfo) : paramWithoutAnnotation(params[i].getName())); + args.add(paramInfo != null ? param(paramInfo, isList) : paramWithoutAnnotation(params[i].getName())); } } } return new FunctionDescription(def.name(), args, returnType, functionDescription, variadic, functionInfo.type()); } - public static ArgSignature param(Param param) { + public static ArgSignature param(Param param, boolean variadic) { String[] type = removeUnderConstruction(param.type()); String desc = param.description().replace('\n', ' '); DataType targetDataType = getTargetType(type); - return new EsqlFunctionRegistry.ArgSignature(param.name(), type, desc, param.optional(), targetDataType); + return new EsqlFunctionRegistry.ArgSignature(param.name(), type, desc, param.optional(), variadic, targetDataType); } public static ArgSignature mapParam(MapParam mapParam) { @@ -671,7 +681,7 @@ public static ArgSignature mapParam(MapParam mapParam) { } public static ArgSignature paramWithoutAnnotation(String name) { - return new EsqlFunctionRegistry.ArgSignature(name, new String[] { "?" }, "", false, UNSUPPORTED); + return new EsqlFunctionRegistry.ArgSignature(name, new String[] { "?" }, "", false, false, UNSUPPORTED); } /** diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionAppliesTo.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionAppliesTo.java new file mode 100644 index 0000000000000..8d9fae9761935 --- /dev/null +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionAppliesTo.java @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.expression.function; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface FunctionAppliesTo { + FunctionAppliesToLifecycle lifeCycle() default FunctionAppliesToLifecycle.GA; + + String version() default ""; + + String description() default ""; +} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionAppliesToLifecycle.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionAppliesToLifecycle.java new file mode 100644 index 0000000000000..351c6d5b19fd7 --- /dev/null +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionAppliesToLifecycle.java @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.expression.function; + +public enum FunctionAppliesToLifecycle { + PREVIEW, + BETA, + DEVELOPMENT, + DEPRECATED, + COMING, + DISCONTINUED, + UNAVAILABLE, + GA +} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionInfo.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionInfo.java index 5c5c2f26279a0..bcc6f569e514f 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionInfo.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionInfo.java @@ -39,6 +39,11 @@ */ boolean preview() default false; + /** + * Whether this function applies to particular versions of Elasticsearch. + */ + FunctionAppliesTo[] appliesTo() default {}; + /** * The description of the function rendered in the docs and kibana's * json files that drive their IDE-like experience. These should be diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java index 3957a926d9ad2..2c76da4974f43 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java @@ -91,7 +91,7 @@ public class CountDistinct extends AggregateFunction implements OptionalArgument algorithm, which counts based on the hashes of the values with some interesting properties: - :::{include} /reference/data-analysis/aggregations/_snippets/search-aggregations-metrics-cardinality-aggregation-explanation.md + :::{include} /reference/aggregations/_snippets/search-aggregations-metrics-cardinality-aggregation-explanation.md ::: The `COUNT_DISTINCT` function takes an optional second parameter to configure diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java index b8758d3e3885d..4ac79f57dbc17 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java @@ -56,7 +56,7 @@ public class Percentile extends NumericAggregate implements SurrogateExpression appendix = """ ### `PERCENTILE` is (usually) approximate [esql-percentile-approximate] - :::{include} /reference/data-analysis/aggregations/_snippets/search-aggregations-metrics-percentile-aggregation-approximate.md + :::{include} /reference/aggregations/_snippets/search-aggregations-metrics-percentile-aggregation-approximate.md ::: ::::{warning} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java index 5e05c3a448295..7cda030d86039 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java @@ -23,6 +23,8 @@ import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; +import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo; +import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.FunctionType; import org.elasticsearch.xpack.esql.expression.function.Param; @@ -84,7 +86,8 @@ public class Values extends AggregateFunction implements ToAggregator { a [Circuit Breaker Error](docs-content://troubleshoot/elasticsearch/circuit-breaker-errors.md). ::::""", type = FunctionType.AGGREGATE, - examples = @Example(file = "string", tag = "values-grouped") + examples = @Example(file = "string", tag = "values-grouped"), + appliesTo = { @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.PREVIEW) } ) public Values( Source source, diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/Match.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/Match.java index bcb34f46847a5..f640114faa880 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/Match.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/Match.java @@ -32,6 +32,8 @@ import org.elasticsearch.xpack.esql.core.type.MultiTypeEsField; import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.Example; +import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo; +import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.MapParam; import org.elasticsearch.xpack.esql.expression.function.OptionalArgument; @@ -156,7 +158,13 @@ public class Match extends FullTextFunction implements OptionalArgument, PostOpt `MATCH` returns true if the provided query matches the row.""", examples = { @Example(file = "match-function", tag = "match-with-field"), - @Example(file = "match-function", tag = "match-with-named-function-params") } + @Example(file = "match-function", tag = "match-with-named-function-params") }, + appliesTo = { + @FunctionAppliesTo( + lifeCycle = FunctionAppliesToLifecycle.COMING, + version = "9.1.0", + description = "Support for optional named parameters is only available from 9.1.0" + ) } ) public Match( Source source, diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/QueryString.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/QueryString.java index 811b6ff6c6777..d426308eff775 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/QueryString.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/QueryString.java @@ -25,6 +25,8 @@ import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.core.type.DataTypeConverter; import org.elasticsearch.xpack.esql.expression.function.Example; +import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo; +import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.MapParam; import org.elasticsearch.xpack.esql.expression.function.OptionalArgument; @@ -116,7 +118,13 @@ public class QueryString extends FullTextFunction implements OptionalArgument { + "Returns true if the provided query string matches the row.", examples = { @Example(file = "qstr-function", tag = "qstr-with-field"), - @Example(file = "qstr-function", tag = "qstr-with-options") } + @Example(file = "qstr-function", tag = "qstr-with-options") }, + appliesTo = { + @FunctionAppliesTo( + lifeCycle = FunctionAppliesToLifecycle.COMING, + version = "9.1.0", + description = "Support for optional named parameters is only available from 9.1.0" + ) } ) public QueryString( Source source, diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDateNanos.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDateNanos.java index 837475fca7e74..006d3105159f8 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDateNanos.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDateNanos.java @@ -19,6 +19,7 @@ import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.core.type.DataTypeConverter; +import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; @@ -63,9 +64,10 @@ public class ToDateNanos extends AbstractConvertFunction { @FunctionInfo( returnType = "date_nanos", description = "Converts an input to a nanosecond-resolution date value (aka date_nanos).", - note = "The range for date nanos is 1970-01-01T00:00:00.000000000Z to 2262-04-11T23:47:16.854775807Z, attepting to convert" - + "values outside of that range will result in null with a warning.. Additionally, integers cannot be converted into date " - + "nanos, as the range of integer nanoseconds only covers about 2 seconds after epoch." + note = "The range for date nanos is 1970-01-01T00:00:00.000000000Z to 2262-04-11T23:47:16.854775807Z, attempting to convert " + + "values outside of that range will result in null with a warning. Additionally, integers cannot be converted into date " + + "nanos, as the range of integer nanoseconds only covers about 2 seconds after epoch.", + examples = { @Example(file = "date_nanos", tag = "to_date_nanos") } ) public ToDateNanos( Source source, diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAppend.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAppend.java index 7ec7d1b9b2eca..c60fb07704e2e 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAppend.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAppend.java @@ -25,6 +25,7 @@ import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; +import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; @@ -65,7 +66,8 @@ public class MvAppend extends EsqlScalarFunction implements EvaluatorMapper { "long", "unsigned_long", "version" }, - description = "Concatenates values of two multi-value fields." + description = "Concatenates values of two multi-value fields.", + examples = { @Example(file = "date", tag = "mv_append_date") } ) public MvAppend( Source source, diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLower.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLower.java index 084afb1b69996..125efc03916ab 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLower.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLower.java @@ -14,6 +14,8 @@ import org.elasticsearch.xpack.esql.core.tree.NodeInfo; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; +import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo; +import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput; @@ -27,7 +29,13 @@ public class ToLower extends ChangeCase { @FunctionInfo( returnType = { "keyword" }, description = "Returns a new string representing the input string converted to lower case.", - examples = @Example(file = "string", tag = "to_lower") + examples = @Example(file = "string", tag = "to_lower"), + appliesTo = { + @FunctionAppliesTo( + lifeCycle = FunctionAppliesToLifecycle.COMING, + version = "9.1.0", + description = "Support for multivalued parameters is only available from 9.1.0" + ) } ) public ToLower( Source source, diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpper.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpper.java index 4509404754f36..ec8fc8530274b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpper.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpper.java @@ -14,6 +14,8 @@ import org.elasticsearch.xpack.esql.core.tree.NodeInfo; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; +import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo; +import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput; @@ -27,7 +29,13 @@ public class ToUpper extends ChangeCase { @FunctionInfo( returnType = { "keyword" }, description = "Returns a new string representing the input string converted to upper case.", - examples = @Example(file = "string", tag = "to_upper") + examples = @Example(file = "string", tag = "to_upper"), + appliesTo = { + @FunctionAppliesTo( + lifeCycle = FunctionAppliesToLifecycle.COMING, + version = "9.1.0", + description = "Support for multivalued parameters is only available from 9.1.0" + ) } ) public ToUpper( Source source, diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java index a5717e26724f7..7fe6bbeddc1de 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java @@ -806,7 +806,7 @@ protected final void assertTypeResolutionFailure(Expression expression) { */ private static Map, DataType> signatures; - static Map, DataType> signatures(Class testClass) { + public static Map, DataType> signatures(Class testClass) { if (signatures != null && classGeneratingSignatures == testClass) { return signatures; } diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3Support.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3Support.java index 904b7f9aef6de..8181281d04f2f 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3Support.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3Support.java @@ -58,6 +58,7 @@ import java.util.Map; import java.util.Optional; import java.util.function.Function; +import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -67,7 +68,6 @@ import static org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase.definition; import static org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase.functionRegistered; import static org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase.shouldHideSignature; -import static org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase.signatures; import static org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry.mapParam; import static org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry.param; import static org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry.paramWithoutAnnotation; @@ -78,11 +78,9 @@ public abstract class DocsV3Support { "% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.\n\n"; static final String PREVIEW_CALLOUT = """ - ::::{warning} Do not use on production environments. This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. - :::: """; static FunctionDocsSupport forFunctions(String name, Class testClass) { @@ -142,7 +140,8 @@ public static void renderNegatedOperator( entry("esql-time-spans", "esql/esql-time-spans.md"), entry("esql-limitations", "esql/limitations.md"), entry("esql-function-named-params", "esql/esql-syntax.md"), - entry("query-dsl-query-string-query", "query-dsl/query-dsl-query-string-query.md") + entry("query-dsl-query-string-query", "query-dsl/query-dsl-query-string-query.md"), + entry("regexp-syntax", "query-dsl/regexp-syntax.md") ); // Static links to the commands file knownCommands = Map.ofEntries(entry("where", "where"), entry("stats-by", "stats")); @@ -191,7 +190,7 @@ public static void renderNegatedOperator( operatorEntry("match_operator", ":", MatchOperator.class, OperatorCategory.SEARCH) ); - enum OperatorCategory { + public enum OperatorCategory { BINARY, UNARY, LOGICAL, @@ -201,7 +200,7 @@ enum OperatorCategory { SEARCH } - record OperatorConfig(String name, String symbol, Class clazz, OperatorCategory category, boolean variadic) {} + public record OperatorConfig(String name, String symbol, Class clazz, OperatorCategory category, boolean variadic) {} private static Map.Entry operatorEntry( String name, @@ -220,13 +219,13 @@ private static Map.Entry operatorEntry(String name, Stri protected final String category; protected final String name; protected final Logger logger; - protected final Class testClass; + private final Supplier, DataType>> signatures; - private DocsV3Support(String category, String name, Class testClass) { + private DocsV3Support(String category, String name, Class testClass, Supplier, DataType>> signatures) { this.category = category; this.name = name; this.logger = LogManager.getLogger(testClass); - this.testClass = testClass; + this.signatures = signatures; } String replaceLinks(String text) { @@ -314,7 +313,7 @@ private String getLink(String key) { case "search-aggregations-bucket-histogram-aggregation" -> makeLink( key, "", - "/reference/data-analysis/aggregations/search-aggregations-bucket-histogram-aggregation.md" + "/reference/aggregations/search-aggregations-bucket-histogram-aggregation.md" ); default -> throw new IllegalArgumentException("Invalid link key <<" + key + ">>"); }; @@ -379,7 +378,7 @@ private void writeToTempDir(Path dir, String extension, String str) throws IOExc static class FunctionDocsSupport extends DocsV3Support { private FunctionDocsSupport(String name, Class testClass) { - super("functions", name, testClass); + super("functions", name, testClass, () -> AbstractFunctionTestCase.signatures(testClass)); } @Override @@ -396,7 +395,6 @@ protected void renderSignature() throws IOException { @Override protected void renderDocs() throws IOException { FunctionDefinition definition = definition(name); - renderSignature(); EsqlFunctionRegistry.FunctionDescription description = EsqlFunctionRegistry.description(definition); if (name.equals("case")) { /* @@ -408,6 +406,7 @@ protected void renderDocs() throws IOException { "elseValue", trueValue.type(), "The value that’s returned when no condition evaluates to `true`.", + true, true ); description = new EsqlFunctionRegistry.FunctionDescription( @@ -434,32 +433,91 @@ protected void renderDocs() throws IOException { } boolean hasExamples = renderExamples(info); boolean hasAppendix = renderAppendix(info.appendix()); - renderFullLayout(info.preview(), hasExamples, hasAppendix, hasFunctionOptions); + renderFullLayout(info.preview(), info.appliesTo(), hasExamples, hasAppendix, hasFunctionOptions); renderKibanaInlineDocs(name, info); renderKibanaFunctionDefinition(name, info, description.args(), description.variadic()); } private void renderFunctionNamedParams(EsqlFunctionRegistry.MapArgSignature mapArgSignature) throws IOException { - String header = "| name | types | description |\n| --- | --- | --- |"; + StringBuilder rendered = new StringBuilder(DOCS_WARNING + """ + **Supported function named parameters** + + """); - List table = new ArrayList<>(); for (Map.Entry argSignatureEntry : mapArgSignature.mapParams().entrySet()) { - StringBuilder builder = new StringBuilder("| "); EsqlFunctionRegistry.MapEntryArgSignature arg = argSignatureEntry.getValue(); - builder.append(arg.name()).append(" | ").append(arg.type()).append(" | ").append(arg.description()); - table.add(builder.append(" |").toString()); + rendered.append("`").append(arg.name()).append("`\n: "); + var type = arg.type().replaceAll("[\\[\\]]+", ""); + rendered.append("(").append(type).append(") ").append(arg.description()).append("\n\n"); } - String rendered = DOCS_WARNING + """ - **Supported function named parameters** - - """ + header + "\n" + table.stream().collect(Collectors.joining("\n")) + "\n"; logger.info("Writing function named parameters for [{}]:\n{}", name, rendered); - writeToTempSnippetsDir("functionNamedParams", rendered); + writeToTempSnippetsDir("functionNamedParams", rendered.toString()); + } + + private String makeCallout(String type, String text) { + return ":::{" + type + "}\n" + text.trim() + "\n:::\n"; + } + + private String makePreviewText(boolean preview, FunctionAppliesTo[] functionAppliesTos) { + StringBuilder previewDescription = new StringBuilder(); + for (FunctionAppliesTo appliesTo : functionAppliesTos) { + if (appliesTo.description().isEmpty() == false) { + previewDescription.append(appliesTo.description()).append("\n"); + } + preview = preview || appliesTo.lifeCycle() == FunctionAppliesToLifecycle.PREVIEW; + } + String appliesToTextWithAT = appliesToText(functionAppliesTos); + String appliesToText = appliesToTextWithoutAppliesTo(functionAppliesTos); + StringBuilder previewText = new StringBuilder(); + if (preview) { + // We have a preview flag, use the WARNING callout + previewText.append(makeCallout("warning", appliesToText + "\n" + PREVIEW_CALLOUT + "\n" + previewDescription + "\n")); + } else if (previewDescription.isEmpty() == false) { + // We have extra descriptive text, nest inside a NOTE for emphasis + previewText.append(makeCallout("note", appliesToText + "\n" + previewDescription)); + } else if (appliesToTextWithAT.isEmpty() == false) { + // No additional text, just use the plan applies_to syntax + previewText.append(appliesToTextWithAT); + } + return previewText.toString(); + } + + private String appliesToText(FunctionAppliesTo[] functionAppliesTos) { + StringBuilder appliesToText = new StringBuilder(); + if (functionAppliesTos.length > 0) { + appliesToText.append("```{applies_to}\n"); + for (FunctionAppliesTo appliesTo : functionAppliesTos) { + appliesToText.append("product: ") + .append(appliesTo.lifeCycle().name()) + .append(" ") + .append(appliesTo.version()) + .append("\n"); + } + appliesToText.append("```\n"); + } + return appliesToText.toString(); } - private void renderFullLayout(boolean preview, boolean hasExamples, boolean hasAppendix, boolean hasFunctionOptions) - throws IOException { + private String appliesToTextWithoutAppliesTo(FunctionAppliesTo[] functionAppliesTos) { + StringBuilder appliesToText = new StringBuilder(); + if (functionAppliesTos.length > 0) { + appliesToText.append("\n"); + for (FunctionAppliesTo appliesTo : functionAppliesTos) { + appliesToText.append("###### "); + appliesToText.append(appliesTo.lifeCycle().name()).append(" ").append(appliesTo.version()).append("\n"); + } + } + return appliesToText.toString(); + } + + private void renderFullLayout( + boolean preview, + FunctionAppliesTo[] functionAppliesTos, + boolean hasExamples, + boolean hasAppendix, + boolean hasFunctionOptions + ) throws IOException { StringBuilder rendered = new StringBuilder( DOCS_WARNING + """ ## `$UPPER_NAME$` [esql-$NAME$] @@ -474,7 +532,7 @@ private void renderFullLayout(boolean preview, boolean hasExamples, boolean hasA """.replace("$NAME$", name) .replace("$CATEGORY$", category) .replace("$UPPER_NAME$", name.toUpperCase(Locale.ROOT)) - .replace("$PREVIEW_CALLOUT$", preview ? PREVIEW_CALLOUT : "") + .replace("$PREVIEW_CALLOUT$", makePreviewText(preview, functionAppliesTos)) ); for (String section : new String[] { "parameters", "description", "types" }) { rendered.append(addInclude(section)); @@ -501,15 +559,25 @@ private String addInclude(String section) { } } - static class OperatorsDocsSupport extends DocsV3Support { + public static class OperatorsDocsSupport extends DocsV3Support { + private final OperatorConfig op; private OperatorsDocsSupport(String name, Class testClass) { - super("operators", name, testClass); + this(name, testClass, OPERATORS.get(name), () -> AbstractFunctionTestCase.signatures(testClass)); + } + + public OperatorsDocsSupport( + String name, + Class testClass, + OperatorConfig op, + Supplier, DataType>> signatures + ) { + super("operators", name, testClass, signatures); + this.op = op; } @Override - protected void renderSignature() throws IOException { - OperatorConfig op = OPERATORS.get(name); + public void renderSignature() throws IOException { String rendered = (switch (op.category()) { case BINARY -> RailRoadDiagram.binaryOperator(op.symbol()); case UNARY -> RailRoadDiagram.unaryOperator(op.symbol()); @@ -525,8 +593,7 @@ protected void renderSignature() throws IOException { } @Override - protected void renderDocs() throws IOException { - DocsV3Support.OperatorConfig op = OPERATORS.get(name); + public void renderDocs() throws IOException { Constructor ctor = constructorWithFunctionInfo(op.clazz()); if (ctor != null) { FunctionInfo functionInfo = ctor.getAnnotation(FunctionInfo.class); @@ -564,6 +631,11 @@ public boolean preview() { return orig.preview(); } + @Override + public FunctionAppliesTo[] appliesTo() { + return orig.appliesTo(); + } + @Override public String description() { return description.apply(orig.description().replace(baseName, name)); @@ -611,7 +683,7 @@ void renderDocsForOperators(String name, Constructor ctor, FunctionInfo info, args.add(mapParam(mapParamInfo)); } else { Param paramInfo = params[i].getAnnotation(Param.class); - args.add(paramInfo != null ? param(paramInfo) : paramWithoutAnnotation(params[i].getName())); + args.add(paramInfo != null ? param(paramInfo, false) : paramWithoutAnnotation(params[i].getName())); } } } @@ -626,7 +698,7 @@ void renderDetailedDescription(String detailedDescription, String note) throws I StringBuilder rendered = new StringBuilder(); if (Strings.isNullOrEmpty(detailedDescription) == false) { detailedDescription = replaceLinks(detailedDescription.trim()); - rendered.append("\n").append(detailedDescription).append("\n"); + rendered.append(DOCS_WARNING).append(detailedDescription).append("\n"); } if (Strings.isNullOrEmpty(note) == false) { @@ -671,8 +743,7 @@ void renderTypes(String name, List args) thro separator.append("--- |"); List table = new ArrayList<>(); - var signatures = signatures(testClass); - for (Map.Entry, DataType> sig : signatures(testClass).entrySet()) { // TODO flip to using sortedSignatures + for (Map.Entry, DataType> sig : this.signatures.get().entrySet()) { // TODO flip to using sortedSignatures if (shouldHideSignature(sig.getKey(), sig.getValue())) { continue; } @@ -697,7 +768,8 @@ void renderTypes(String name, List args) thro } Collections.sort(table); if (table.isEmpty()) { - table.add(signatures.values().iterator().next().esNameIfPossible()); + logger.info("Warning: No table of types generated for [{}]", name); + return; } String rendered = DOCS_WARNING + """ @@ -770,16 +842,16 @@ void renderKibanaInlineDocs(String name, FunctionInfo info) throws IOException { """); builder.append("### ").append(name.toUpperCase(Locale.ROOT)).append("\n"); - builder.append(removeAsciidocLinks(info.description())).append("\n\n"); + builder.append(replaceLinks(info.description())).append("\n\n"); if (info.examples().length > 0) { Example example = info.examples()[0]; - builder.append("```\n"); + builder.append("```esql\n"); builder.append(loadExample(example.file(), example.tag())); builder.append("\n```\n"); } if (Strings.isNullOrEmpty(info.note()) == false) { - builder.append("Note: ").append(removeAsciidocLinks(info.note())).append("\n"); + builder.append("Note: ").append(replaceLinks(info.note())).append("\n"); } String rendered = builder.toString(); logger.info("Writing kibana inline docs for [{}]:\n{}", name, rendered); @@ -819,7 +891,7 @@ void renderKibanaFunctionDefinition(String name, FunctionInfo info, List false == a.optional()).count(); @@ -886,7 +958,7 @@ private String removeAsciidocLinks(String asciidoc) { } private List, DataType>> sortedSignatures() { - List, DataType>> sortedSignatures = new ArrayList<>(signatures(testClass).entrySet()); + List, DataType>> sortedSignatures = new ArrayList<>(signatures.get().entrySet()); Collections.sort(sortedSignatures, (lhs, rhs) -> { int maxlen = Math.max(lhs.getKey().size(), rhs.getKey().size()); for (int i = 0; i < maxlen; i++) { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/RailRoadDiagram.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/RailRoadDiagram.java index dfec2a563b429..95997564ff7f4 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/RailRoadDiagram.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/RailRoadDiagram.java @@ -56,27 +56,62 @@ static String functionSignature(FunctionDefinition definition) throws IOExceptio expressions.add(new Repetition(seq, 1, null)); expressions.add(new Repetition(new Literal("elseValue"), 0, 1)); } else { - boolean first = true; - List args = EsqlFunctionRegistry.description(definition).argNames(); - for (String arg : args) { - if (arg.endsWith("...")) { - expressions.add( - new Repetition(new Sequence(new Syntax(","), new Literal(arg.substring(0, arg.length() - 3))), 0, null) - ); + List argExpressions = new ArrayList<>(); + List args = EsqlFunctionRegistry.description(definition).args(); + for (int i = 0; i < args.size(); i++) { + EsqlFunctionRegistry.ArgSignature arg = args.get(i); + String argName = arg.name(); + if (arg.variadic) { + if (argName.endsWith("...")) { + argName = argName.substring(0, argName.length() - 3); + } + argExpressions.add(new Repetition(new Sequence(new Syntax(","), new Literal(argName)), arg.optional ? 0 : 1, null)); } else { - if (first) { - first = false; + if (arg.optional) { + if (definition.name().equals("bucket")) { + // BUCKET requires optional args to be optional together, so we need custom code to do that + var nextArg = args.get(++i); + assert nextArg.optional(); + Sequence seq = new Sequence(new Literal(argName), new Syntax(","), new Literal(nextArg.name)); + argExpressions.add(new Repetition(seq, 0, 1)); + } else if (i < args.size() - 1 && args.get(i + 1).optional() == false) { + // Special case with leading optional args + Sequence seq = new Sequence(new Literal(argName), new Syntax(",")); + argExpressions.add(new Repetition(seq, 0, 1)); + } else { + argExpressions.add(new Repetition(new Literal(argName), 0, 1)); + } } else { - expressions.add(new Syntax(",")); + argExpressions.add(new Literal(argName)); } - expressions.add(new Literal(arg)); } } + expressions.addAll(injectCommas(argExpressions, new Syntax(","))); } expressions.add(new Syntax(")")); return toSvg(new Sequence(expressions.toArray(Expression[]::new))); } + public static List injectCommas(List original, Expression comma) { + List result = new ArrayList<>(); + for (int i = 0; i < original.size(); i++) { + result.add(original.get(i)); + if (i < original.size() - 1 && hasComma(original.get(i), true) == false && hasComma(original.get(i + 1), false) == false) { + result.add(comma); + } + } + return result; + } + + private static boolean hasComma(Expression exp, boolean atEnd) { + if (exp instanceof Repetition rep && rep.getExpression() instanceof Sequence seq) { + Expression[] seqExp = seq.getExpressions(); + int index = atEnd ? seqExp.length - 1 : 0; + return seqExp[index] instanceof Syntax syntax && syntax.text.equals(","); + } + return false; + } + /** * Generate a railroad diagram for binary operator. The output would look like * {@code lhs + rhs}. diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/CastOperatorTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/CastOperatorTests.java new file mode 100644 index 0000000000000..97f2d02f07c9b --- /dev/null +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/CastOperatorTests.java @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.expression.predicate.operator; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.expression.function.DocsV3Support; +import org.elasticsearch.xpack.esql.expression.function.Example; +import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.Param; +import org.junit.AfterClass; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class CastOperatorTests extends ESTestCase { + public void testDummy() { + assert true; + } + + @AfterClass + public static void renderDocs() throws IOException { + if (System.getProperty("generateDocs") == null) { + return; + } + DocsV3Support.OperatorConfig op = new DocsV3Support.OperatorConfig( + "cast", + "::", + TestCastOperator.class, + DocsV3Support.OperatorCategory.UNARY, + false + ); + var docs = new DocsV3Support.OperatorsDocsSupport("cast", CastOperatorTests.class, op, CastOperatorTests::signatures); + docs.renderSignature(); + docs.renderDocs(); + } + + public static Map, DataType> signatures() { + // The cast operator cannot produce sensible signatures unless we consider the type as an extra parameter + return Map.of(); + } + + /** + * This class only exists to provide FunctionInfo for the documentation + */ + public class TestCastOperator { + @FunctionInfo( + operator = "::", + returnType = {}, + description = "The `::` operator provides a convenient alternative syntax to the TO_ " + + "[conversion functions](/reference/query-languages/esql/esql-functions-operators.md#esql-type-conversion-functions).", + examples = { @Example(file = "convert", tag = "docsCastOperator") } + ) + public TestCastOperator( + @Param( + name = "field", + type = { + "boolean", + "cartesian_point", + "cartesian_shape", + "date", + "date_nanos", + "double", + "geo_point", + "geo_shape", + "integer", + "ip", + "keyword", + "long", + "text", + "unsigned_long", + "version" }, + description = "Input value. The input can be a single- or multi-valued column or an expression." + ) Expression v + ) {} + } +} diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/NullPredicatesTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/NullPredicatesTests.java new file mode 100644 index 0000000000000..674a7fe77f586 --- /dev/null +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/NullPredicatesTests.java @@ -0,0 +1,95 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.expression.predicate.operator; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; +import org.elasticsearch.xpack.esql.expression.function.DocsV3Support; +import org.elasticsearch.xpack.esql.expression.function.Example; +import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.Param; +import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToStringTests; +import org.junit.AfterClass; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * In the documentation we document `IS NULL` and `IS NOT NULL` together. + */ +public class NullPredicatesTests extends ESTestCase { + public void testDummy() { + assert true; + } + + @AfterClass + public static void renderDocs() throws IOException { + if (System.getProperty("generateDocs") == null) { + return; + } + DocsV3Support.OperatorConfig op = new DocsV3Support.OperatorConfig( + "predicates", + "IS NULL and IS NOT NULL", + TestCastOperator.class, + DocsV3Support.OperatorCategory.UNARY, + false + ); + var docs = new DocsV3Support.OperatorsDocsSupport("predicates", NullPredicatesTests.class, op, NullPredicatesTests::signatures); + docs.renderSignature(); + docs.renderDocs(); + } + + public static Map, DataType> signatures() { + // TODO: Verify the correct datatypes for this + Map, DataType> toString = AbstractFunctionTestCase.signatures(ToStringTests.class); + Map, DataType> results = new LinkedHashMap<>(); + for (var entry : toString.entrySet()) { + DataType dataType = entry.getKey().getFirst(); + results.put(List.of(dataType), DataType.BOOLEAN); + } + return results; + } + + /** + * This class only exists to provide FunctionInfo for the documentation + */ + public class TestCastOperator { + @FunctionInfo( + operator = "predicates", + returnType = {}, + description = "For NULL comparison use the `IS NULL` and `IS NOT NULL` predicates:", + examples = { @Example(file = "null", tag = "is-null"), @Example(file = "null", tag = "is-not-null") } + ) + public TestCastOperator( + @Param( + name = "field", + type = { + "boolean", + "cartesian_point", + "cartesian_shape", + "date", + "date_nanos", + "double", + "geo_point", + "geo_shape", + "integer", + "ip", + "keyword", + "long", + "text", + "unsigned_long", + "version" }, + description = "Input value. The input can be a single- or multi-valued column or an expression." + ) Expression v + ) {} + } +}